让 RAG 从“回答”变成“可信回答”:zglab-rag 的 Grounded Generation 与 Citation
目录
Sources 为什么不够
一个回答末尾列出三篇来源,并不能证明每个事实都由它们支持。模型仍可能把来源中的相邻信息拼接、 把常识补充成个人事实,或引用一篇相关但不能支撑当前 claim 的文档。对个人知识助手而言,问题不在于 “有没有链接”,而在于“这一句具体依据哪条已选证据”。
这与 Evidence 驱动的内容生成与校验 的思想相近, 但 zglab-rag 的输出对象是可公开回答与 Sources,而不是简历 PDF。
证据驱动生成链
检索完成后,ContextBuilder 不直接把数据库对象交给 LLM。它先把公开、已过滤的检索结果转换为带短
ID 的 EvidenceItem,如 E1、E2;每项携带 title、section 与内容,并在固定预算下按 rank
确定性截断。
flowchart LR
R[public RetrievalResult] --> C[ContextBuilder]
C --> E[EvidenceItem: E1, E2...]
E --> L[结构化 LLM 输出\nclaim + citation IDs]
L --> V[CitationValidator]
V --> D[确定性 Rendering]
D --> A[answer + Sources]
Persona 与 Evidence 分开写入 Prompt:前者约束表达风格,后者被标注为只读数据。网页或文档中的 指令不能获得 system message 的优先级,模型也不应把 Evidence 中的命令当作需要执行的任务。
Citation Validator 检查什么
生成输出是带 claim 级 citation 的结构化 JSON,不是自由 Markdown。CitationValidator 在普通程序
中检查:引用格式是否合法、Evidence ID 是否属于当前 Context、每个应引用 claim 是否被覆盖、引用是否
支持不足状态等。校验不通过时最多允许一次语义修复重试;仍无法安全恢复就不渲染为正常回答。
flowchart TD
O[LLM 结构化输出] --> F{格式正确?}
F -->|否| X[一次修复或失败]
F -->|是| I{ID 属于当前 Evidence?}
I -->|否| X
I -->|是| K{claim 覆盖充分?}
K -->|否| X
K -->|是| R[渲染答案与 Sources]
最终 Sources 由已验证的 Evidence 映射回 source_path 和 section_path,不是让模型自由生成 URL、
文件名或引用文本。这样可以把“回答中的证明”重新连接到原始 Markdown 的位置。
证据不足是成功的业务结果
系统在三类情形返回 insufficient_evidence:检索为空;模型在约束下判断不能回答;citation 校验无法
把输出安全恢复。它不是 Provider 故障,也不是为了隐藏异常的泛化兜底。
公开 API 的虚构项目问题已实际返回 200 insufficient_evidence,answer 为“当前公开知识库中没有
足够信息回答这个问题”,且 Sources 为空。这比生成一段看似合理的解释更符合个人事实边界。
实验结果与设计决策
生成评测集有 22 条 Query,其中 18 条带 expected evidence。一次记录的向量检索 +
qwen3.7-plus 运行中,evidence hit rate、citation validity rate、平均 citation coverage、
should-answer accuracy 与 refusal queries 的 insufficient correctness 都为 1.0。该运行也记录了
逐条 retrieval、generation 与 total latency。
这些结果不是“模型永远不幻觉”的证明。它们只验证了固定数据集、固定 provider 配置和现有 validator 下的回归合同。项目刻意没有用 LLM Judge 替代确定性引用检查,因为另一次概率判断不能证明原回答的 引用关系正确。
方法论总结
- Retrieval 是候选选择,Grounding 是生成资格控制,Citation 是输出可追溯性;三者不能互相替代。
- Sources 是回答级视图,claim-level citation 才能检查一句事实的依据。
- Persona 不拥有事实权力;证据不足不是“回答得不够好”,而是系统正确停止。
- 确定性渲染放在校验之后,避免不安全的原始模型文本直接抵达用户界面。
可信回答不是让模型语气更谨慎,而是让没有可验证证据的内容没有进入最终答案的路径。