ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

RAG到Agentic RAG:知识库问答的检索增强实践与避坑指南

RAG到Agentic RAG:知识库问答的检索增强实践与避坑指南

前两年做企业知识库问答,我印象最深的一个场景是:某团队把几千份产品文档扔进系统,用户问“语音助手怎么设置唤醒词”,模型煞有介事地给出一段操作,步骤看着完整,和文档里的真实流程完全对不上。问题不在模型不够聪明,而在系统压根没告诉模型“该去哪份文档里找答案”。后来团队换成 RAG(检索增强生成)架构,才算是把“让模型背资料”扭转到“给模型开卷考试”的正道上。这篇内容面向完全没接触过 RAG 的小白,也面向准备上生产但还没吃透原理的程序员,我把从基础到实操的拆解、代码模板、还有实际部署中踩过的坑一起整理在下面。

RAG 说白了是一套系统架构,不是某个具体模型。它先把外部文档离线加工成一个可搜索的索引,等用户提问时,先从索引里捞出一批与问题最相关的片段,再把这些片段和问题一起交给大模型作答。这样一来,模型不再凭记忆硬编答案,而是基于检索到的真实资料说话。时效性、私有数据、幻觉这三大问题,都能被这套机制明显缓解。到了进阶阶段,Agentic RAG 更进一步:把“检索”从一次性动作升级为模型可自主决策的一连串行动,比如先判断问题类型、再决定去哪查、发现信息不够就换个工具继续查。这篇文章会把两条路线都讲透,并且附上可直接参考的最小实现方案。

1. 先搞懂 RAG 到底在解决什么问题

1.1 大模型的“知识边界”与幻觉来源

很多人对大模型的期待是“它什么都知道”,但严格来说,大模型是一个在静态训练语料上学习出来的文本概率生成器。它的所有“知识”停留在一个时间点的快照里,超出这个快照的内容,它并没有存储对应信息,可它依然会流畅地给出看起来合理的回答,只是内容没有事实锚点。这种现象就是“一本正经地胡说八道”,技术圈把它叫幻觉。幻觉不是模型偶尔犯错,而是它在没有事实依据支撑时,依然会按照语言概率把话“顺完”。

举个容易理解的类比你:一个刚入职的实习生,还没看公司历史项目文档,你问他某个老项目怎么部署,他会基于之前看过的其他项目经验告诉你一套部署流程,语气很确定,方向也大致不错,但细节和真实情况对不上。你真正希望他做的是先去看项目档案,再回来回答。RAG 做的事就是这个:强制模型“先查资料再说话”。它把检索到的文档片段放进 Prompt,并明确要求模型只能依据这些片段作答,如果片段里没有答案,模型应当回答“资料中未提及”,而不是自行想象。所以从原理上看,RAG 并不会让模型变聪明,它只是把记忆外置,并把生成路径约束在证据链上。理解这一点之后,后面所有的操作步骤就都有了解释:切片是为了让记忆可定位,向量化是为了让记忆可相似匹配,检索是为了找出候选证据,生成是基于候选证据做归纳。

1.2 一条流水线看懂 RAG:装载、切片、向量化、召回、生成

RAG 全流程可以分成离线准备和在线回答两个阶段,你可以用食堂后厨来类比:离线阶段相当于备菜,把各种食材洗干净、切好、装盘、放进货架;在线阶段相当于出菜,接到点单后,后厨快速从货架上选出最相关的几盘菜,交给大厨重新炒制一份完整菜品。

技术动作拆开来看,大致是六个步骤。第一步文档装载:把 PDF、Word、Markdown、HTML 等格式统一解析成纯文本,剔除页眉页脚、水印、导航链接等噪音。第二步切片:把长文档切成长度适中的片段,这是检索效果上限的关键。第三步向量化:用嵌入模型把每个文本片段映射成一串向量,向量距离近就代表语义接近。第四步建索引:把大量向量组织成可以快速检索的数据结构,工程上广泛使用近似最近邻算法,用一点精度换巨大的速度提升。第五步检索:用户的问题同样被向量化,在索引里找出相似度最高的 Top-K 个片段。第六步生成:把问题、检索片段、角色指令拼装成 Prompt,提交给生成模型完成最终回答。

这套流程里,新手最容易犯的错误是把注意力全放在“生成模型够不够强”上,而忽略“检索质量”。换一个更强的大模型,效果可能提升一截;但把切片做得更合理、把召回做得更准,效果常常是翻倍的。所以我一向建议团队在模型选型上求稳,在检索链路上求精。这也是为什么后文会花大量篇幅讲切片、嵌入和检索,而不是一直讨论模型参数数量。

1.3 RAG、微调、长上下文,怎么选

模型无法回答私有知识时,还有些团队会想到微调和超长上下文。微调是把企业数据训练进模型权重,让模型本身“记住”这些知识;超长上下文则是把整本文档直接塞进模型的上下文窗口。这两个方案在某些场景是合理的,但和 RAG 的定位明显不同,我习惯用三个问题来判断该选哪个。

第一,知识是否高频变化?如果知识库每周都在更新,RAG 可以当天重建索引,微调则需要准备训练数据、重新训练、验证,周期按天甚至按周计算,明显不划算。第二,答案是否需要溯源?很多业务场景要求回答必须标注依据,RAG 天然支持把“检索到的哪个片段”展示给用户,微调后的模型是一个不可解释的权重,它解释不了自己为什么得出这个结论。第三,需要提升的是“事实记忆”还是“表达风格”?如果模型要学公司特有的术语和输出模板,微调更有效;如果核心诉求是“知道最新版本支持什么功能”,那知识库本来就有这份资料,用 RAG 检索复述就够了。

超长上下文方案的实际表现常常不如预期:虽然模型能读进去几千页,但问题越具体,模型越容易漏掉藏在某个角落的关键信息,而且整篇文本进入 Prompt 的成本会随长度快速上涨。相比之下,RAG 用 Top-K 聚焦最相关内容,反而更利于生成可靠答案。我的默认建议是:RAG 作为地基,微调用于风格适配,超长上下文仅用于“单个文档、单次阅读”的补充场景。三者并不互斥,成熟系统往往先用 RAG 召回,再由 Agent 决定是否需要把某个完整章节拉入上下文。

2. 基础 RAG 实操:从文档到可回答的答案

2.1 工具怎么挑:嵌入模型、向量库、生成模型分别看什么

先讲嵌入模型,它负责把文本变成向量,直接影响召回效果。选型时不要只看公开榜单上的分数,因为榜单题目偏通用英文,未必适合你的中文文档或垂直领域术语。更可靠的办法是自测:从真实业务场景里抽 50 到 100 个问题,把对应的正确答案片段混进若干干扰文档,分别用几个候选嵌入模型跑召回,看在 Top-10 里谁能命中正确答案。这个测试只需要半天时间,却能筛掉一大批中看不中用的模型。中文场景要优先选择在中文语料上有优化效果的模型;向量维度不是越高越好,维度越高存储和计算成本越大,而效果提升往往有限。

向量数据库负责承载向量索引并提供检索能力。小规模验证阶段可以先用轻量级方案,把向量文件化、加载进内存做暴力检索,几万条数据以内这种方式比直接上分布式服务更简单,迭代也更快。生产规模再切换到正经的向量数据库。选型时问三件事:支持哪些索引类型、是否支持带过滤条件的混合查询、数据更新和删除方不方便。别为了那些花哨的多模态能力做选择,你的核心场景就是文本或多模态内容的检索,够用和易维护才是关键。

生成模型也就是最终作答的 LLM,选型关注三点:上下文长度是否足够、能否稳定遵循系统指令、JSON 输出能力是否可靠。这三条满足后,不同厂商模型切换起来不会有本质差别。推荐把生成层抽象成统一接口,后续换模型、做 A/B 测试时只改配置不改业务代码。我见过不少团队在检索还没稳定时反复折腾生成模型,这是本末倒置:检索准确率连及格线都不到,换再强的模型也只是把错误证据复述得更流畅。正确顺序是先稳定检索链路,再挑一个成本、速度、能力均衡的生成模型。

2.2 切片,最容易被低估的一步

切片决定了文档以什么粒度进入索引。拿一本两百页的产品手册举例,如果每一页切成一个切片,用户问“语音识别支持哪几种语言”时,包含答案的那一页可能只有三分之一内容和问题相关,噪声会污染最终答案;如果把页面继续切成几十个碎片,又可能把关键的表格或代码块拦腰截断,导致一个完整事实被切碎,召回了也没法用。

常见经验参数是:文本块大小 500 到 800 个 token,重叠长度 100 到 150 个 token。这个范围不是随便定的,切片太小,每个块的信息量撑不起一个完整论点;切片太大,又容易越过语义边界,把两个不同主题混进同一个片段。当然,业务特征更重要:如果文档大量是技术参数表格,就应该按表格结构切成独立片段;如果文档有清晰的层级标题,优先按标题结构切,而不是按固定字符数硬切;如果内容更像代码仓库,按函数或代码块边界切分效果最好。

验证切片质量有一个很直观的方法:在向量库里搜索几个真实问题,观察召回结果。如果前几条都是主题完整、逻辑连续的长段落,说明切片合理;如果召回结果“前言不搭后语”,或者一段里混着两个章节的内容,赶紧回头调整切片器。我在实际项目中见过不少团队上线后效果不佳,连夜排查到凌晨,最后定位到是切片环节的默认参数根本没有针对业务调过。这一步值得你多花一小时,它能省下周的调优时间。

2.3 嵌入、索引与检索链路

嵌入不是把每个字单独变成向量,而是把整个片段映射到一个语义空间。训练充分的向量空间中,“今天天气怎么样”和“明天会不会下雨”的距离,会明显小于和“报销流程怎么走”的距离,检索因此变成了“找距离最近的几个向量”的操作。新手容易有一个错觉,以为关键词必须完全匹配才算命中,其实向量检索的核心优势恰恰是语义匹配:用户问“价格贵不贵”,文档里写“性价比不高”,两者向量方向接近,可以被召回。

但向量检索也有覆盖不到的场景,比如缩写、型号名称、代码片段这类要求精确匹配的内容,词面不同但语义含混,向量召回往往不如关键词方案可靠。所以生产级方案普遍采用混合检索:向量检索为主,关键词检索兜底,最后用重排序模型把两路结果融合排序。索引参数不要照搬默认值,度量方式通常选余弦距离,它只关心向量方向、不关心向量长度,和大多数文本嵌入模型的输出匹配;查询时的 Top-K 也别拍脑袋,可以先定 5,再看回答是否完整,欠料就调到 10 或 15,内容太多导致模型抓不住重点就减少 K 或者加重排。

还提醒一句:检索出来的片段不是越多越好。把几十个片段一次性全塞给模型,模型反而会迷失在信息海洋里,同时推高时延和成本。好的做法是重排后只保留 3 到 5 个高质量片段,让模型聚焦在最强证据上。

2.4 最小可运行的 RAG 参考实现

下面这段代码是一个思路模板,你可以用任何语言和框架替换具体实现,核心流程是通用的。

# 离线索引阶段:解析、切块、向量化、写入向量库 def build_index(documents): chunks = [] for doc in documents: text = extract_plain_text(doc) # 解析并清洗成纯文本 for chunk in split_by_structure(text): # 按标题/长度切块并加重叠 chunks.append(chunk) embeddings = embed_model.encode(chunks) # 批量向量化 vector_store.add(chunks, embeddings) # 写入向量索引 return vector_store
# 在线回答阶段:检索、组装上下文、生成 def answer(question): q_vec = embed_model.encode([question]) top_chunks = vector_store.search(q_vec, top_k=10) context = "\n\n".join([f"[片段{i}] {c}" for i, c in enumerate(top_chunks)]) prompt = f"""你是一个严谨的文档助手,只能依据提供的片段作答。 如果片段中没有答案,请直接说“资料中未提及”。 片段如下: {context} 问题:{question} 请结合片段,给出简洁、带引用的回答。""" return llm.generate(prompt)

这套代码虽然短,但把三个重要原则都体现出来了:一是设定“资料中未提及”的出口,给模型一个合法的不作答选项,减少硬编幻觉;二是在每个片段前加编号,让模型回答时能引用编号,用户也能溯源;三是 Prompt 明确要求“只能依据片段作答”,给模型划清边界。跑通这个最小版本之后,你已经可以直观感受 RAG 的能力边界:哪些问题召回命中、哪些问题召回失败、哪些被切坏的片段在拖后腿。

我自己调试时有个习惯:把“检索到了正确片段但模型没用上”和“检索压根没命中”分开打日志。如果 Top-K 已经包含答案但最终回答仍然错误,问题大概率出在 Prompt 设计或模型遵循指令的能力上;如果 Top-K 压根没有正确片段,问题才在切片、嵌入、索引这一侧。这个二分法帮我省掉了大量无效排查。

2.5 给自己的第一个 RAG 打分

不要一上来就追求完整评测体系,先做一套最小可用 QA 集。从真实业务问题里挑 20 个,标注出对应的正确答案片段,然后跑一遍系统,观察三个维度:召回是否命中正确答案、生成是否基于正确的片段、回答是否简洁准确。每个维度分别计“通过/不通过”,统计百分比后你会立刻看到系统短板在哪里。等你把基础版调到稳定回答六成以上问题时,再考虑 Agentic RAG 的升级,否则更复杂的 Agent 行为只会掩盖底层检索的缺陷,让你更难定位问题。

3. 朴素 RAG 的边界在哪里,Agent 化为什么成为必然

3.1 哪些问题会一次难倒朴素 RAG

我在不同项目里反复遇到一些让朴素 RAG “当场翻车”的场景,第一类是多跳问题。用户问“A 客户用的方案满不满足我们这次项目的合规要求”,知识库里 A 客户方案和合规要求分别躺在两份不同文档里,单次 Top-K 检索很可能只召回其中一份,模型只拿着一半证据,只能强行推断,轻则漏答,重则错答。第二类是查询本身太模糊,用户只说“我们这个月情况怎么样”,没限定指标也没指定文档,朴素 RAG 把完整问题拿去向量检索,结果往往是宽泛文档排在前,真正有用的细节被淹没。第三类是语言和术语的错位,用户口语说“报销单据”,文档里术语写的是“费用结算凭证”,词面完全不匹配,嵌入模型如果没学过这组别名,召回就失真。

第四类是需要计算或比较的问题。用户问“去年全年销售额比前年增长多少”,系统先要检索到几个包含销售数据的表格片段,然后做减法、算比例、再生成结论,这种环节一根直通管道根本完成不了。第五类是答案根本不在知识库里,但朴素 RAG 只要检索到一定相似度的片段,模型就会倾向用片段“凑”出一个像模像样的答案,它没有机会先判断“这些资料其实回答不了”。

这些问题的共同点是:它们需要的不是一个更快的召回,而是“根据情况决定怎么做”的推理能力。推理能力恰好是 LLM 的长项,于是一个自然的思路出现了——让 LLM 参与检索决策,而不只是做纯生成。

3.2 Agentic RAG 的核心理念:把检索变成模型的可控行动

Agent 这个词在工程上已经被用得很泛滥,先收紧定义。在 Agentic RAG 里,大模型不再是一个单纯的“作答器”,而被赋予一个完整角色:观察者、决策者、行动者。它能看到用户问题,能看到当前已收集到的信息,也能选择下一步行动。典型行动包括“去向量库查一下”“去数据库查一下”“先改写这个查询再检索”“再读一遍某片段的具体内容”“我已经有足够信息,可以回答了”。每执行一步,系统把检索结果追加到上下文里,模型再决定下一步,直到它认为信息足够,或者到达最大步数被迫收手。

这个结构的核心价值是引入了反馈回路。朴素 RAG 是单向的,检索一次、生成一次、结束;Agentic RAG 是多轮的,首轮检索可能发现信息不足,它可以调整策略。回到多跳问题的例子:第一轮检索出客户方案文档,里面写着适用的合规条款编号,模型意识到还需要去查具体条款内容,于是发起第二次检索,把合规文档也拉进来,最终综合回答。这相当于把“人查资料时的迂回策略”搬进了程序。

3.3 三种最常见的 Agent 化路径:路由、子查询、自我反思

先说路由。这是改动最小、性价比最高的 Agent 化方案。用一个分类器,或者直接用大模型做一次轻量决策,判断“这个问题应该走文档检索、走数据库查询、还是走 SQL 分析”,系统再对应分支执行。举例来说,“报销单格式有什么要求”走文档检索;“某销售本月的回款额”走数据库;“帮我分析这个季度的趋势”走分析工具。路由可以避免大量错误召回,也避免把所有问题都往向量库里送。

其次是子查询分解。把复杂问题拆解成几个独立子问题,分头检索,再把结果合并。实现时不需要太复杂的规划,通常就是让模型输出一个“检索计划”,系统按计划执行多路检索。比如用户问“比较 X 方案和 Y 方案的接入成本与部署周期”,子查询就可以拆成“X 方案接入成本”“X 方案部署周期”“Y 方案接入成本”“Y 方案部署周期”四路,分头检索后统一交给模型归纳。

最后是自我反思。模型在作答之前先自问:当前片段是否足够支撑结论?是否存在互相矛盾的片段?我要不要补充证据?这种 Agent 特别适合合规风控场景,要求模型在给出结论前多次核实。但自我反思的代价是 token 消耗和时延明显上涨,本质是“用金钱换准确率”,要按业务价值决定是否启用。三条路径并不互斥,成熟的 Agentic RAG 往往是先路由,再对子任务做分解,最后用反思做质量校验。

4. 手写一套最小 Agentic RAG:状态、工具、循环、护栏

4.1 核心骨架:一个循环,而不是一段流水线

前面说过,Agent 本质是“观察–决策–行动–观察”的循环。实现起来并不玄学,只需维护一个状态对象,里面装着用户问题、已经收集到的片段、行动历史,以及可以调用的工具集合。大模型扮演决策者,每一轮读一次状态,输出一个行动;系统执行行动,把结果写回状态;模型再读状态决定下一步。几十行代码就能搭出最基本框架。

def run_agentic_rag(question, tools, max_steps=6): state = { "question": question, "evidence": [], "history": [], "finished": False, } for _ in range(max_steps): action = llm.decide(state) # 决策:调用哪个工具/直接回答 if action.type == "answer": state["answer"] = generate_with_evidence(question, state["evidence"]) state["finished"] = True break if action.type == "retrieve": chunks = tools[action.tool].search(action.query) state["evidence"].extend(chunks) state["history"].append(action) if not state["finished"]: state["answer"] = "资料检索超过限制,建议细化问题后重试。" return state

必须给循环设置最大步数,这是一个硬性护栏。我见过没有步数限制的 Agent 项目,用户问了个很抽象的问题,模型反复检索二十多轮还不肯收手,既烧钱又卡延迟。设了上限后,即使问题再难,系统也保证在几秒内给出一个“我能检索到的信息就这些”的合理收尾。另外,每一轮的上下文不能无限累积,通常只保留最近几轮的关键片段和行动摘要,避免 Agent 把自己绕晕。状态管理是 Agent 工程里最容易被低估的部分,但它直接决定了系统的稳定性和成本。

4.2 工具集设计:别只给一把锤子

Agentic RAG 里的“R”不再局限于向量库召回,它可以连接任意信息源。工具集设计有几个尤其实用的方向。

向量检索工具是主路,接收查询文本、返回 Top-K 片段,覆盖知识库的大部分内容。关键词搜索工具是兜底,缩写、型号、代码片段等场景下,向量召回往往不如 BM25 这类关键词方案,把两路结果合并或者让 Agent 按需选择,能修复很多召回黑洞。文档定位工具负责“用户想打开某文档的某个章节”这类请求,返回文档位置或链接,而不只是字符串片段。如果知识库背后有结构化数据,再加一个数据库查询工具,接收自然语言问题,模型先生成查询条件,执行后返回记录,适合“某个客户最近三个月提交了几次工单”这类问题。通用工具里,计算器用于数值校验,代码解释器用于直接计算表格中的汇总值。

工具数量不是越多越好。每增加一个工具,模型决策空间就变大,选错工具的概率也更大,所以只保留真实业务中高频使用的工具。关键设计原则是:工具说明写得越清楚,Agent 用得越准。用一两句话写清这个工具能做什么、适合回答什么问题、不需要用它做什么,能显著减少误调用。比如向量检索工具写明“用于检索产品手册、FAQ、操作指南”,模型就很少会把报销金额查询误送入这里。

4.3 查询改写与路由:最容易立竿见影的两个动作

查询改写听起来高级,实现却很朴素。第一轮检索之前,先让模型把用户问题转换成更适合检索的表达。最常见的动作包括:指代词消解,把“它”“这个”还原成完整名词;别名归一,把口语词改写为文档用语;子问题补充,把“A 和 B 比怎么样”改写成几路独立检索词。很多前期召回问题,靠这个技巧能提升好几个百分点,而且实现成本非常低。

路由的意义在于让系统知道“哪些问题不该走向量检索”。最省钱的做法是加一个前置小模型判断问题类型,只把真正需要文档检索的问题交给大流程;最灵活的做法是沿用前面的 Agent 循环,让决策模型在每一轮自己决定工具调用,天然内置路由能力。复杂路由模型会带来额外延迟和维护成本,所以建议先用关键词和规则做第一档分流,不够再升级到模型分类。

4.4 控制成本与延迟的五个经验

第一,能一次检索就不两次。有些子查询合并成一条优质查询,会比拆成多路更便宜。第二,检索结果不要无脑全送给大模型。先按分数截断,再用一个轻量重排模型做第二轮筛选,只把最相关的 3 到 5 个片段真正送进生成环节。第三,建立历史问答缓存。相似问题命中缓存直接返回,可以省掉大量重复检索费用。第四,按问题复杂度设置优先级:简单问题走小模型路由,只有复杂问题才升级成完整 Agent 循环。第五,在写 Prompt 时要求模型“简洁推理、不要展开无关分析”,限制每轮思考的长度。这五点在小规模演示里看不出差距,一旦上生产,账单和延迟会非常诚实地反映差别。

5. 上线前必须想清楚的五个坑

5.1 知识库清洁度比模型参数更重要

RAG 的回答质量上限,取决于你能检索到的文档质量。文档清洗这步看起来不起眼,却是无数生产事故的根源。页眉页脚混进正文,会让切出来的片段里带着无意义重复的导航文字;扫描版 PDF 不经过 OCR,你切出来的就是一堆乱码或空文本;双栏排版的论文转纯文本后,阅读顺序会变成先读左栏再读右栏,一段完整的论述被拆得七零八落;Excel 里的表格一旦丢失表头,模型就算检索到数字也不知道这些数字代表什么。

实际操作中,我建议在最前面加一道“文档体检”:抽查 10% 的解析结果,人工看文本顺序是否正确、特殊符号有没有被还原、表格是否保持了行列语义。如果文档数量不大,人工清洗一轮的成本远比上线后反复纠错低。对于每天都有新文档入库的场景,要建立格式规范,要求上游尽量提供 Markdown 或排版规整的数据源,而不是笼统发一包扫描件过来。

5.2 上下文组装直接影响答案成败,重排模型不能省

检索对了,答案还是错,这种情况一般出在上下文组装环节。最常见的问题是一次塞进太多片段,相关片段和非相关片段混杂,模型被无关信息干扰,抓不住重点;另一种是相关片段被挤到上下文很靠后的位置,模型对中段信息的注意力往往会衰减,导致它没引用关键内容。

对策分几步:先对召回的 Top-K 做重排,把最相关信息放在最前面;再限制最终进入 Prompt 的片段数量,经验值是 3 到 5 个;如果片段太长,可以先用一个小模型做摘要,把关键数字和结论抽出来,再送给生成模型。还有个细节容易被忽略:保留标题和页码信息。把这些元数据拼进片段文本,比如“来源:《产品手册》第三章第 2 节”,模型在引用时会更有条理,用户回溯也更方便。Prompt 组装顺序我建议按“最相关片段优先”排列,这和模型对文本头部更敏感的现象有关,把强证据前置能明显提升答案准确度。

5.3 Agent 失控比普通 RAG 更危险,护栏怎么设

Agentic RAG 引入多轮决策后,系统行为变得不可预测,风险也随之提高。最常见的失控有三类:第一类是死循环,模型反复调用同一个工具,查询条件变来变去但结果都不理想,就是不收手,解决办法就是前面提到的最大步数限制,必须硬编码在循环里。第二类是自证幻觉,模型在第一轮已检索到某个错误信息,后续反思时不是去核实它,而是在错误信息基础上继续推理,把错误越滚越大,这种时候需要引入“评审”机制,让第二遍检索或另一个模型对结论做验证。第三类是目标漂移,用户本来问 A 问题,模型在多轮工具调用后开始答 B 方向的内容,需要为系统设计一个固定的“最终回答检查”:输出的结论是否回到了原始问题。

我建议为每个 Agent 调用结果都生成一个 trace,记录每一轮模型看到了什么、选择了哪个工具、检索到了什么。这样即使线上出了问题,你也能源源回放整个决策过程,而不是面对一个黑盒干瞪眼。护栏越早设计越好,不要等系统先跑坏了再补。

5.4 评测与回归:用一套固定 QA 集守住质量基线

没有评测,你根本无法判断“新版本到底有没有变好”。我建议至少建一套 50 个样本的评测集,覆盖前面提到的多跳、模糊、数值计算、术语错位、知识库无答案这几类典型问题。每个样本记录三个维度的评分:召回是否命中正确答案、回答是否忠实于检索片段、回答对用户是否有用。这样跑一次评测,就能定位是检索坏、生成坏,还是整个链路坏了。

具体打分可以人工,也可以用另一个大模型做裁判。用模型做裁判时要注意校准:把裁判模型的评分结果和人工评分抽样比对一次,确认它的判断标准和你一致,再让它批量化打分。这套评测集每个月固定回归一遍,任何知识库变更、模型切换、Prompt 调整都要拿它先过一遍。守不住质量基线,后面的每一次“优化”都是盲人摸象。

5.5 监控上线后真正要盯的指标

上线之后别只盯着“回答看起来对不对”,要埋一些可量化的监控指标。最重要的几个:空召回率,也就是 Top-K 里没有返回任何内容的比例,太高说明索引或切片有严重问题;平均检索相关度,观测关键词检索和向量检索的融合效果;引用缺失率,系统要求回答带引用时,有多少回答没有正常带上来源;回答长度与耗时,异常飙升通常意味着某个域外问题让 Agent 循环失控;每请求的 token 消耗,这是成本波动的预警线。此外,把用户反馈回流做成一个标签系统,用户点“有帮助/没帮助”后,能关联到当时的检索片段和生成答案,这对持续改进是最宝贵的资料。

我自己长期维护一个企业知识库之后,最深的体会有三条。第一条,不要一开始就追求 Agent 化,先把手动切片和检索链路做扎实,基础不稳时更复杂的设计只会让问题更难定位。第二条,Agent 的每一轮决策都要留痕,否则出了线上事故你根本没法复盘。第三条,时刻提醒自己:大模型只是决策者,不是事实来源,事实来源永远是知识库文档。把这三点想清楚,从 RAG 升级到 Agentic RAG 只是水到渠成的事。希望你读完这篇文章之后,不只是记住了几个名词,而是能动手写出一条属于自己的最小实现,然后在真实业务里一步步把检索质量、评测体系、Agent 护栏都补上。踩过的坑,终究都会变成你有底气给别人讲 PPT 的素材。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进