返回博客

Agent 回答里的 [1] 和「据原文」,背后是一条引用链

有谷不是让模型自己编脚注。检索工具返回 citation_sources,模型用 [citation:N] 标注,UI 把 kb: 链打开阅读器——证据不足就明说,不编造。

问知识库:「我们的数据保留政策最长多久?」

模型回答:「根据公司政策,客户数据最长保留 24 个月。」——听起来合理,但点不开任何出处,你也不知道是编的还是从哪份 PDF 里来的。

有谷大脑的产品承诺是回答附带出处,重要结论可回到原文核对。这不是让模型在文末加一句「仅供参考」,而是一条工程链路:工具检索 → 结构化 citation_sources → 模型在正文里打 [citation:N] → 前端解析 kb:<documentId> 打开阅读器。

Agent 引用链:工具 → citation_sources → 模型标注 → UI 跳转。

引用不是 markdown 脚注,是结构化证据

query_knowledge_base 调 RAG 服务返回 chunk 后,后端格式化为两类输出:

  1. 给模型看的工具文本 — 带 [kb N begin] … [kb N end] 包裹的证据块,内含 documentId、标题、正文
  2. 给 UI 存的 citation_sources — JSON 数组,每项含 index、type(kb / webpage / asset)、documentId、title、snippet、url 等

模型被系统提示约束:

  • 正文用 [citation:1][citation:3] 标注使用了哪些来源
  • 提及知识库文档时用 [文档标题](kb:<documentId>),禁止裸 UUID
  • 网页来源用 [citation:X] 对应 search_web 结果
  • 素材图片用 ![标题](url) 并标注 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 里有没有真东西;引用链决定用户能不能验证模型有没有用真东西。

产品层面的底线

有谷把「可核对」当作和「能回答」同级的能力:

  • 企业合规场景:Retention 多久、赔偿上限多少——必须点到 PDF 第几页
  • 研发场景:API 行为以哪版设计文档为准——必须链到代码库旁的 spec
  • 个人学习:外文资料翻译后——仍应回到原文段落

Agent 再流畅,如果没有可点击的引用,知识库就退化成「另一个 ChatGPT」。结构化 citation_sources + 强制 [citation:N] 标注,是把「RAG」和「聊天」区分开的那条细线。