返回文章列表
AI 实践

从候选检索到带引用回答:我在个人网站里补上的 RAG 问答边界

RAG 的关键变化,是让模型回答受到检索证据约束,并让用户看到可追溯的公开来源。 no_evidence 不是普通回答,也不是系统故障;它表示当前索引、过滤条件和阈值下没有足够证据。 相似度分数只能表示语义相关性,不能直接当成事实置信度。 来源展示应与答案引用分开设计,并且只投影公开字段。 专项协议测试和类型检查通过,不等于真实 Provider、数据库和浏览器端到端已经完成。

从“有候选”到“能回答”还差什么

第五周完成了个人网站公开资料的 Embedding、pgvector 存储、活动索引和候选检索 API。查询接口可以返回公开标题、路径、片段内容和相关性信号,也可以在没有足够候选时返回 no_evidence。

但候选检索本身不会回答用户问题。完整的 RAG 还需要把候选片段放进模型上下文,让模型只能根据这些证据生成答案,并把答案中的声明和公开来源关联起来。否则,系统只是一个“相似内容查询接口”,不是一个可追溯的问答系统。

本周实现的最小链路

第六周在 my-world 的流式助手 Worker 中增加了检索优先的处理顺序:先校验并规范化用户问题,再查询活动索引;检索得到候选后,把公开片段投影为 S1、S2 这样的回答引用标记,再将这些证据加入模型上下文。

模型提示明确要求:可验证声明必须带对应的 [Sx] 引用,没有证据支持的内容要明确说明不确定。模型完成生成后,服务端会检查回答是否至少引用了一个真实来源。没有任何有效引用时,不直接把回答标记为可靠结果,而是返回无法核验的提示。

no_evidence 必须先于答案生成

当候选检索返回 no_evidence 时,系统不会继续调用模型生成确定答案,而是直接结束任务并告知用户当前公开知识库没有检索到足够证据。这种状态不等于“知识库绝对不存在相关内容”,因为结果还受到活动索引、metadata 过滤、TopK 和相似度阈值影响;它只表示当前检索条件下没有足够依据。

这和系统错误也必须分开。索引不存在、模型契约不一致、Embedding Provider 失败或存储不可用属于服务错误,需要返回稳定错误和可重试边界;no_evidence 则是一次正常完成但证据不足的业务结果。

引用来源不能泄露内部结构

候选记录内部可能包含源记录 ID、数据库 chunk ID、权限字段和 Provider 信息。这些字段不能直接交给前端或模型。当前实现只投影公开标题、公开路径、片段摘要、chunk 序号、来源更新时间和相似度信号,并把相似度明确当作相关性参考,而不是事实置信度。

前端沿用现有来源链接卡展示公开标题、路径、片段摘要和更新时间。这样用户能回到实际文章或项目页面核对依据,而不是只能看到一个无法解释的内部标识。

相关性分数不是事实置信度

cosineSimilarity 可以帮助判断候选内容和问题在语义上是否接近,但它不能证明内容真实、最新或权威。回答是否可靠,还需要考虑来源是否公开、内容是否已发布、更新时间、版本和不同来源之间是否存在冲突。

因此,当前协议不会把高相似度直接转换成 confidence: high。如果声明没有来源支持,即使候选分数很高,也不能直接展示为确定事实。

推荐链接和证据来源要分开

最初的实现把 RAG 来源和站点默认导航入口一起放入推荐链接列表,因此技术问题也可能出现“联系我”入口。第六周后续优化将两者分开:技术问题只展示达到展示阈值的相关 RAG 来源;只有检测到合作、报价、预算、委托或联系意图时,才添加联系入口。

来源展示还使用独立于召回的阈值。当前建议保留 EMBEDDING_RETRIEVAL_MIN_SIMILARITY=0.3 以维持召回能力,再用 RAG_SOURCE_DISPLAY_MIN_SIMILARITY=0.65 控制哪些候选可以显示成前端卡片。低于展示阈值的候选仍可作为模型上下文的一部分,但不会被用户误解为强推荐。

已验证的内容和仍未完成的边界

本周已新增 RAG 协议测试,覆盖来源投影、引用存在性、无证据状态、非法配置回退、技术问题不展示联系入口、合作意图展示联系入口,以及低于展示阈值的来源不进入推荐卡片。npm run test:rag-protocol 和 npx tsc --noEmit 均已通过。

这仍不等于所有生产边界都完成。当前尚未完成真实 Provider、Embedding、pgvector 和 LLM 的完整端到端回归;Query Rewrite 目前是无副作用的规范化和失败回退,不是独立改写模型;Rerank 尚未接入独立模型;旧内容和冲突版本还没有自动裁决;引用校验目前确认 [Sx] 标记存在,还没有逐声明验证语义蕴含关系。

结语

RAG 的第一步不是让模型说得更像答案,而是明确什么内容可以作为证据、什么状态表示证据不足,以及用户如何回到公开来源核对。候选检索提供了受控输入,引用协议和失败分支则把这些输入变成可验收的问答边界。

第六周的实现让我把“模型回答”拆成了几个可以单独测试的部分:检索是否找到证据、证据是否公开、回答是否引用证据、来源是否安全投影,以及没有证据时系统是否愿意停下来。只有这些边界都清楚,RAG 才开始从 Demo 走向可维护的应用能力。

有想法或建议? 联系我