[控场AI]
· 6 分钟阅读· 3,168 字

Footnote:句子级引用的 Agentic RAG,让回答句句可查

Footnote:句子级引用的 Agentic RAG,让回答句句可查

Footnote 用 Agent 循环和句子级引用校验,让 RAG 答案句句可查。

Footnote 是一个句子级引用的 Agentic RAG 项目,它把传统"单轮检索+模型自写引用"的流水线,改为一个会规划检索、能重试、会承认不知道的 Agent 循环。它通过 search_handbook 与 read_page 两个工具反复检索,用文档自身措辞组织查询;引用由 API 基于句子级 block 校验,点击即可高亮原文句子,而非模型手打编号。当文档确实未覆盖问题时,它明确说明边界而不是编造答案。检索层为手写 BM25 加本地 bge-small 向量,用带权 RRF 融合,并在 59 题评测集上调参,同时支持三种检索模式切换。作者的核心判断是:检索只是简单的一半,让答案每句可核实才是难的一半。

Footnote:句子级引用的 Agentic RAG,让回答句句可查

"跟你的文档聊天"这类应用,通常的做法是用用户的原话搜一次,然后祈祷搜对了。一个包含两部分的提问,只会触发一次检索,于是你拿到半个答案。Footnote 把这条固定流水线换成了一个像研究员那样工作的 Agent,它的铁律只有一条:无法核实的答案,不算答案。

Footnote 句子级引用效果示意

它和普通 RAG 差在哪里

传统 RAG 是单轮检索:把问题丢进向量库,取回几个 chunk,拼进上下文让模型生成。问题在于,模型生成的引用是"手打"的——它自己写引用编号,检索系统并不校验这段话是否真的来自那个位置。

Footnote 的做法是把检索结果切成句子级 block 返回,引用由 API 校验,而不是由模型自己输入。所以每一条引用都对应到一个可定位、可高亮的原文句子。这个设计上的小改动,直接决定了答案的"可核实性"。

RAG(Retrieval-Augmented Generation,检索增强生成) 是目前"跟文档聊天"类应用的主流架构:先从资料库里找回与问题相关的片段,再把这些片段作为上下文喂给大模型生成答案。它的一个常见工程做法是把文档按固定长度切成 chunk(如 512 token),再向量化入库。

句子级 block 是对 chunk 粒度的一次细化。传统 chunk 往往跨越多句话甚至多个段落,模型引用时只能标出"这段话来自某个 chunk",却无法精确定位到具体哪一句。句子级 block 让检索返回的每一条记录就是一个句子,并带有稳定的 ID 和位置信息,引用时就能锚定到唯一那句原文。粒度变细通常会让召回结果更碎,因此需要配合融合与重排来保持上下文完整。

Footnote 的四个核心能力

1. 自己规划检索节奏

Agent 拿到的是一个包含两部分的提问,它会拆成两次检索,并且用文档自身的表述方式来组织查询词——而不是照搬用户的口语。每一次检索步骤都会在侧边栏实时显示,研究过程是透明可观察的。

这背后是 Claude 被赋予了两个工具:search_handbook 和 read_page,然后在一个循环里反复调用,直到它能作答为止。结果太单薄就再搜一次,这是研究员的基本习惯,也是固定流水线做不到的。

Agent 循环(Agentic Loop) 指的是模型在"思考—调用工具—观察结果—再思考"的往返中持续推进任务,直到满足终止条件。这里的两个工具——search_handbook 负责按查询词召回候选句子,read_page 负责读取某个具体页面的完整内容——形成了"先粗搜、再精读"的分工。模型可以在一次回答里多次调用它们,例如第一次检索结果单薄时改写查询词再搜一遍,或对某条命中句子所在页做通读以确认上下文。

与固定的"检索一次就生成"相比,这种循环把"结果够不够"的判断权交给了模型本身。代价是 token 消耗与延迟上升,因此实际系统通常需要设定最大轮数、超时和预算上限,避免陷入无休止的检索。

2. 引用精确到句子

点击引用 chip,源文档会滚动到对应位置,并把被引用的那一句高亮出来。

据作者说明,这条链路里引用不是模型"自报"的,而是由 API 基于句子级 block 校验的。对于交付场景——员工手册问答、合规文档查询、内部知识库——这一点比答案流畅度重要得多,因为一条错位的引用会让整份答案失去可信度。

3. 不知道就说不知道

如果重试之后仍然没有相关内容,Footnote 会直接告诉你文档没有覆盖这个问题,而不是编一个看起来合理的答案。

截图里能看到它的处理方式:被问到手册未涉及的内容时,它明确说明这一点,同时引用最接近的段落,让你自己判断边界在哪里。这种"诚实的边界感"在 RAG 系统里并不常见,但对任何一个要被真实使用的研究工具来说,它是底线。

4. 检索方式可替换

Footnote 支持在 hybrid、纯关键词、纯向量三种检索模式之间切换运行,并且会把每段内容在两种检索方式下的排名都展示出来。对于想研究检索策略影响的开发者,这是一个现成的对照实验台。

三种检索模式各有侧重。纯关键词(如 BM25) 依赖词项匹配与词频统计,对专有名词、编号、缩写等精确术语召回强,但无法处理同义改写。纯向量检索 把句子编码成稠密向量并按余弦相似度排序,能捕捉语义相近但用词不同的表达,却容易漏掉罕见术语。hybrid(混合检索) 同时跑两路,再用融合算法合并排名。

RRF(Reciprocal Rank Fusion,倒数排名融合) 是常用的融合方法:把每条结果在两路排名中的名次取倒数后相加(带权版本则对每路乘上权重),再按总分重排。它只依赖排名而不依赖具体分值,因此天然适合量纲不同的关键词与向量分数。文中在 59 题评测集上调参,主要就是在校准这组权重与融合参数。

技术栈与实现细节

  • 语言与框架:Python + FastAPI,UI 是一个单文件 HTML。
  • 模型调用:通过 Anthropic SDK 直接调用 Claude,没有用任何 Agent 框架。
  • CLI:会打印每一次工具调用,方便调试和观察。
  • 检索层:手写 BM25 + 本地 bge-small 向量,用带权重的 reciprocal rank fusion 做融合,并在一个 59 题的评测集上做过调参。
  • 演示语料:公有领域的 18F 员工手册,共 232 页。
  • 演示模式:截图来自一个免密钥 demo,模型回合是脚本化的,但检索和引用是真实运行的。

源码在 GitHub 上的 IbrarYunus/footnote。

bge-small 是智源(BAAI)发布的 BGE 系列句向量模型中的小尺寸版本,参数量约数千万,输出 384 维向量,常被本地部署用于对延迟和显存敏感的场景。它把一句话编码为稠密向量后,检索就退化为向量近邻搜索。本项目中向量库直接在本地运行,没有外部托管服务,因此演示时无需联网推理。

值得注意的是,作者刻意没有使用 LangChain、LlamaIndex 之类的 Agent 框架,而是用 Anthropic SDK 直接编排循环。这样做的收益是链路完全可控:每一次工具调用、每一条检索结果、每一个引用 ID 都能在 CLI 里打印出来,便于调试和复现实验。对于以"可核实性"为核心目标的系统,减少黑盒间接层比提升开发速度更重要。

为什么这个方向值得关注

作者在原文里有一句话很关键:检索是简单的那一半,难的是让答案的每一句都可被核实。

这句话点出了当前 RAG 应用的一个普遍短板。大多数团队把精力花在召回率、chunk 大小、embedding 模型上,却默认"模型生成的引用"是可信的。Footnote 反过来,把工程的难点放在引用的可验证性上,用句子级 block 和 API 校验来兜底。

这也解释了为什么 Agent 循环在这里是必要的:单次检索无法判断"结果是否足够",而一个能重试、能说"不知道"的循环可以。加上检索策略可切换的设计,Footnote 更像是一个面向开发者的研究模板,而不是一个成品应用。谁在文档问答里被"编造引用"坑过,大概都会想看看它是怎么做的。

#Agentic RAG#句子级引用#RAG 引用可验证#BM25 向量混合检索#Claude Agent#文档问答#reciprocal rank fusion
分享:

相关推荐