在内容网站中加入 Chatbot,真正有价值的并不是多一个聊天浮窗,而是让访客能用自然语言检索文章、理解内容并获得带来源的回答。本文以 Nuxt 3、Spring Boot 3、Spring AI 和 Milvus 为例,拆解一套从最小对话到 RAG 知识问答的完整实现。

先做一个边界清楚、能引用原文、允许回答“不知道”的助手,再考虑记忆、工具调用和自动执行。

一、先判断网站是否需要 Chatbot

适合的场景

  • 文章或文档较多,传统关键词搜索难以表达复杂问题。
  • 访客经常询问相似问题,需要导航到对应文章或章节。
  • 希望基于站内内容总结、对比,并同时展示来源链接。
  • 有明确的维护者,可以持续评估回答质量、成本和安全风险。

不一定适合的场景

  • 网站只有少量页面,清晰导航和搜索框比聊天入口更直接。
  • 医疗、法律、金融等高风险内容无法建立审核、免责声明和人工升级机制。
  • 知识内容长期过期或互相矛盾,又没有版本与发布时间管理。
  • 只是为了追逐“AI 功能”,没有可衡量的用户问题。
Chatbot 不是搜索、导航和 FAQ 的替代品。它应与这些基础能力并存,并在回答中把用户带回权威原文。

二、三种实现方式

方式一:第三方嵌入服务

托管平台通常提供网页抓取、知识库、模型配置和嵌入脚本,适合快速验证需求。上线前应确认数据保留、跨境传输、模型供应商、访问控制、删除能力、费用上限和内容更新机制。

方式二:调用模型 API,自建聊天界面

前端由自己控制,后端负责鉴权、提示词、模型调用、限流和日志。它适合通用对话或简单 FAQ,但如果不检索网站内容,模型不会自动知道站内最新文章。

方式三:自建 RAG Chatbot

RAG(检索增强生成)会先从知识库找出相关片段,再让模型基于片段回答。它无需重新训练模型即可更新知识,并能返回引用来源,是内容网站更常见的选择。


三、整体架构

  • 浏览器永远不保存模型 API Key。所有模型请求都经过后端。
  • 对话链路与文章入库链路分开:前者追求低延迟,后者负责可重试和增量更新。
  • 向量库保存可检索片段与元数据,文章数据库仍是事实来源。

四、第一步:实现最小流式对话

后端配置

使用当前稳定版 Spring AI 对应的模型 Starter,并通过环境变量注入密钥。不同模型供应商的属性名称和兼容程度不同,应以所用 Starter 的版本文档为准,不要把密钥提交到 Git。

spring:
  ai:
    openai:
      api-key: ${CHAT_API_KEY}
      base-url: ${CHAT_BASE_URL}
      chat:
        options:
          model: ${CHAT_MODEL}

流式接口

Spring AI 的 ChatClient 同时支持同步与流式调用。流式接口可直接返回 Flux,并使用 text/event-stream 向浏览器逐段发送内容。

生产接口还需要登录或匿名会话标识、并发限制、请求超时、取消传播、统一错误事件和模型调用预算。不要把供应商的原始异常直接返回给用户。

Nuxt 3 前端读取流

如果后端发送标准 SSE 事件,前端还需要按事件边界解析 data 字段,不能假设每次网络读取正好对应一个完整事件。也可以选择成熟的 SSE 客户端库。


五、第二步:加入会话记忆

大多数 Chat Model API 本身是无状态的。所谓“记忆”,本质上是应用保存必要的历史消息,并在下一次请求时带入上下文。Spring AI 可通过 ChatMemory 与 Advisor 管理窗口记忆。

  • conversationId 必须由服务端校验归属,不能让用户读取其他人的会话。
  • 窗口记忆只保存模型需要的上下文;完整聊天记录应单独持久化。
  • 设置消息数或 Token 上限,避免上下文无限增长。
  • 提供删除会话能力,并为匿名会话设置合理过期时间。

六、第三步:把网站文章接入 RAG

RAG 不是微调

微调更适合调整输出风格、格式或特定任务行为,并不是频繁更新事实知识的首选。RAG 在请求时检索最新内容,更适合持续更新的博客和文档站。两者也可以组合,但解决的问题不同。

文章入库流程

  1. 读取已发布文章,只同步用户有权问到的内容。
  2. 清理导航、脚本和重复模板,保留标题、正文、章节层级与发布日期。
  3. 按语义和标题分块,并保留适当重叠,避免把一个完整结论截断。
  4. 调用 Embedding Model 生成向量。
  5. 将向量、原文片段和元数据写入 Milvus。
  6. 文章更新时按 articleId 与 contentHash 增量替换;删除或隐藏时同步删除向量。
向量库里的每个片段都应能够追溯到文章、章节和版本。否则回答即使看起来正确,也无法给用户可靠引用。

七、第四步:检索、重排与生成

  1. 对用户问题做规范化,并根据当前页面、语言或栏目附加过滤条件。
  2. 生成查询向量,在 Milvus 中召回候选片段。
  3. 需要时结合关键词检索与向量检索,再对候选结果重排。
  4. 设置相关性阈值;没有可靠证据时不要强行回答。
  5. 把少量高相关片段作为不可信资料传给模型。
  6. 要求模型仅基于资料回答,并返回文章标题与链接。

只靠一段 Prompt 不能保证安全或事实正确。检索过滤、权限检查、输出校验、引用映射和人工评测必须在应用层完成。


八、回答质量如何评估

  • 检索召回:正确文章是否进入候选结果。
  • 证据一致性:回答中的关键结论能否由引用片段支持。
  • 拒答能力:知识库没有答案时是否会明确说明。
  • 引用准确性:链接是否存在,是否指向真正使用的文章与章节。
  • 多轮一致性:追问时是否正确理解上下文,又不会串到其他会话。
  • 延迟与成本:首字延迟、总耗时、输入输出 Token 和检索耗时是否可接受。

建立一组固定测试问题,至少包含直接事实、跨段总结、同义表达、无答案问题、过期内容、恶意提示和权限越界。每次更换模型、分块策略或提示词后重新执行。


九、安全与隐私

Prompt Injection

用户输入和检索到的网页都可能包含“忽略规则、泄露提示词、调用工具”等恶意指令。应把外部内容视为不可信数据,隔离指令与资料,并限制模型能够访问的工具和数据。

  • 后端保管密钥,并对密钥设置最小权限和轮换机制。
  • 先做资源权限过滤,再做向量检索;不能检索后仅依赖模型保密。
  • 限制输入、输出、并发、速率和每日预算,防止滥用与账单攻击。
  • 连接搜索、邮件或删除工具时,为高影响操作增加确定性校验与用户确认。
  • 日志默认不记录完整 Prompt、私密文章、密钥和个人信息。
  • 对生成内容做 Markdown/HTML 清洗,阻止 XSS、危险链接和任意 HTML。

隐私与数据生命周期

在界面说明对话会发送给哪些服务、保存多久、用于什么目的,并提供清除入口。若使用第三方模型或嵌入服务,还要核对其数据保留与训练政策。


十、用户体验细节

  • 聊天入口不要遮挡导航、Cookie 提示或移动端主要操作。
  • 发送后立即显示用户消息、加载状态和停止生成按钮。
  • 保留换行、代码块与列表,并对代码提供复制按钮。
  • 每个事实性回答展示可点击来源,而不是笼统写“来自知识库”。
  • 支持键盘操作、焦点管理、屏幕阅读器状态提示和足够的颜色对比度。
  • 模型不可用时提供普通搜索入口,而不是让整个内容发现流程失效。

十一、上线检查清单

  • 模型密钥只在服务端,仓库与前端构建产物中均不存在。
  • 匿名用户、登录用户、管理员的数据权限经过自动化测试。
  • 流式断开会取消下游模型调用,超时和异常不会泄露内部信息。
  • 文章新增、修改、隐藏和删除都会正确同步向量库。
  • 低相关问题能够拒答,引用链接可以追溯到真实片段。
  • 具备限流、预算告警、调用指标、追踪和质量反馈入口。
  • 完成 Prompt Injection、越权检索、XSS 和资源消耗测试。

十二、总结

网站 Chatbot 的最小闭环是:后端安全调用模型、前端可靠展示流式响应、RAG 只检索有权限的文章、回答提供真实引用、知识不足时能够拒答。完成这个闭环后,再逐步加入持久记忆、混合检索、重排和工具调用,系统会比一开始堆叠所有 AI 功能更容易评估和维护。