Agent 回答里的 [1] 和「据原文」,背后是一条引用链
有谷不是让模型自己编脚注。检索工具返回 citation_sources,模型用 [citation:N] 标注,UI 把 kb: 链打开阅读器——证据不足就明说,不编造。
问知识库:「我们的数据保留政策最长多久?」
模型回答:「根据公司政策,客户数据最长保留 24 个月。」——听起来合理,但点不开任何出处,你也不知道是编的还是从哪份 PDF 里来的。
有谷大脑的产品承诺是回答附带出处,重要结论可回到原文核对。这不是让模型在文末加一句「仅供参考」,而是一条工程链路:工具检索 → 结构化 citation_sources → 模型在正文里打 [citation:N] → 前端解析 kb:<documentId> 打开阅读器。
引用不是 markdown 脚注,是结构化证据
query_knowledge_base 调 RAG 服务返回 chunk 后,后端格式化为两类输出:
- 给模型看的工具文本 — 带
[kb N begin] … [kb N end]包裹的证据块,内含 documentId、标题、正文 - 给 UI 存的 citation_sources — JSON 数组,每项含
index、type(kb / webpage / asset)、documentId、title、snippet、url等
模型被系统提示约束:
- 正文用
[citation:1][citation:3]标注使用了哪些来源 - 提及知识库文档时用
[文档标题](kb:<documentId>),禁止裸 UUID - 网页来源用
[citation:X]对应 search_web 结果 - 素材图片用
并标注 citation - 完全没有证据时简短说明不足,不要编造
- 不要在结尾加「以上信息来自知识库检索」之类的元说明
前端把 kb: 协议解析成站内路由,点击即打开对应文档并定位 chunk;citation_sources 同时持久化到 chat_message,历史对话里的引用仍可点。
为什么工具要串行:编号不能乱
同一轮里如果并行调 query_knowledge_base 和 search_web,两个工具各自从 1 编号,模型看到的 [citation:2] 可能指 kb 也可能指网页——编号串号,UI 对不上。
有谷默认 parallel_tool_calls=False:同一轮工具调用串行执行,citation_sources 在 state 里累加,index 单调递增。
此外 CitationResetMiddleware 在每条用户消息开始时重置 citation_sources 和 tools_used——新一轮问答从 [citation:1] 重新计,不会继承上一轮编号。
知识库 chunk 在工具文本里长什么样
RAG 命中不只是裸文本丢进 context,而是带边界标记,方便模型区分证据与指令:
[kb 1 begin]
documentId: abc-123
title: 数据保留政策 v3
cite: [数据保留政策 v3](kb:abc-123)
(chunk 正文……)
[kb 1 end]
LightRAG 的 hybrid 模式还会附带 Entity、Relationship 段,帮助模型理解实体关系——但最终 footnote 仍回到 [citation:N] 与 kb 链接,不让模型「凭图谱幻觉」不标来源。
网页与素材两种特殊来源
search_web — 返回 webpage 类型 citation,带 URL 和 snippet。用户问需要最新新闻、统计数字时,Agent 在 kb 不足时联网;有网页材料时,提示词禁止声称「没有外部信息」。
recommend_assets — 从知识库召回图片/图表 asset(和PDF 抽图入库的资产同一索引)。用户问「有没有架构图」时,文本证据仍用 query_knowledge_base,配图用 recommend_assets;回答里用 markdown 图片展示,并 citation 标注。
阅读模式下的优先级
用户打开某篇 PDF 问「这篇文章的主旨是什么」——系统注入本轮活动阅读上下文,要求优先围绕当前文档作答。
工具策略:
- query_knowledge_base 优先:已索引则 RAG;未索引则返回预提取 Markdown
- read_document 仅在 RAG 片段不足、需要原文措辞或特定页表格时,按页少量读取(通常 1~3 页),避免整篇扫描
引用仍走同一套 citation 链,只是 documentId 锁定在当前阅读文档。
和 AG-UI 的衔接
流式生成时,token 一边出,citation 列表通过 State 事件同步到前端——用户不必等全文结束才看到角标。Run 结束时 citation_sources 写入数据库,与 checkpoint 对齐,regenerate 时重新跑工具则 citation 列表整体替换。
MCP 接入的外部 Host 拿到的 chunk 格式与网页 Agent 工具返回一致——引用标准在检索层统一,不在每个客户端各写一套脚注解析。
常见失败模式与对策
| 现象 | 原因 | 有谷侧对策 |
|---|---|---|
| 答对了但无出处 | 模型未打 citation | 系统提示 + 工具强制返回 sources |
| 出处张冠李戴 | 编号串号 | 串行工具 + 每轮 reset |
| 瞎编 documentId | 模型造 kb 链接 | 提示禁止裸 UUID,UI 只认返回的 id |
| 检索到但说「没有信息」 | 模型忽略工具结果 | 工具文本带明确证据块边界 |
RAG 质量(chunk 策略、表格解析)决定 citation 里有没有真东西;引用链决定用户能不能验证模型有没有用真东西。
产品层面的底线
有谷把「可核对」当作和「能回答」同级的能力:
Agent 再流畅,如果没有可点击的引用,知识库就退化成「另一个 ChatGPT」。结构化 citation_sources + 强制 [citation:N] 标注,是把「RAG」和「聊天」区分开的那条细线。