调试流程而非大语言模型:RAG故障的实战思维模型
当RAG机器人回答错误时,LLM很少是原因。需通过数据摄入、检索、生成、评估及整个流程来追踪故障所在环节。
想象一下,在一家中型SaaS公司里,有一个客服机器人,有一天有两位客户同时询问退款时间,但它给两人的答复却不一样。
随即有人上报了这个问题,值班工程师的第一反应是该大型语言模型出现了幻觉,需要更换模型。这只是初步的诊断,他们将RAG视为一个黑箱,更换模型后便希望问题能随之消失。
经验丰富的工程师则会从其他角度入手,先查明是流程的哪个环节出了问题。仅仅说模型产生了名称上的幻觉只是描述了症状,并没有解释根本原因。
两天后,真正的问题出现了。退款政策虽然已经修改,但没人从检索语料库中删除过时的PDF文件,因此两个版本仍会以相似的相关度分数出现,模型便如实地总结了相互矛盾的上下文。它根本没有产生幻觉。(这是一个为说明目的而设计的综合场景,但类似情况很常见。)
这就是标准版RAG与实际应用中出问题的RAG之间的差异。教程通常会将其简化为一句话来说明:
Embed → Search → Generate
这仅够用于演示,不足以用于实际生产环境。真正的系统具有多个故障隔离边界。重要的工程问题不仅在于大语言模型能否写出优质答案,还在于生成该答案的每一层功能是否正常运行。
数据接入:在检索开始前就需确定质量标准
大多数RAG系统的调试都从错误的方向入手。人们往往调整提示词、更换嵌入模型或修改top-k参数,而实际上故障早在几周前的数据接入阶段就已经出现。
按结构解析
表格、代码块、标题和列表都通过其结构传递意义。如果将价格表转换为纯文本,行与列标题之间的关联就会消失。数据接入流程应保留这些结构,并选择适合检索的表示方式,而非将每份文档都视为无差别的文本块。
合适的方法取决于内容类型。表格可能需要结构化提取,文本则可能需要序列化处理、元数据,或是结合词汇与语义检索的方式。
按语义分块
简单的方法是每512个标记切分一块。然而标记数量与语义并不完全对应,因此某一块可能以背景信息开头,却在尚未表达完核心内容时就结束。
语义分块旨在根据主题变化进行分割,而非仅依据标记数量。这并非适用于所有情况的改进方法,且在数据导入过程中会消耗更多资源。对于政策、合同和技术文档等长篇内容,保持概念的完整性往往能提升检索结果的质量。
在嵌入之前为每个分块提供一些上下文
在一份共60页的文档中,从第40页提取出的片段可能是完全有效的文本,但在其原始上下文之外仍可能产生歧义。比如有一句话表明某项限制仅适用于企业客户,若没有周围的上下文内容,检索系统就无从知晓“此限制”具体指什么。
上下文检索通过在嵌入片段之前添加文档级上下文来解决这一问题:包括标题、章节路径、产品信息、版本号,或是关于该片段所在位置的简短说明。其目的是让每个片段都能保留那些否则会被分割掉的上文信息。
附加元数据
应将元数据视为功能性数据。后续的处理步骤需要来源信息、日期、文档类型、租户信息、权限设置以及版本号,以便进行过滤、访问控制、新鲜度检查以及故障排查。
这就引出了数据摄取过程中最重要的问题之一:如果源文档明天发生了变化会怎样?如果处理流程只能重新对所有内容进行索引,那么微小的内容修改就会变成沉重的运营负担。理想的数据摄取方式应该是增量式的且具有幂等性,这样在检测到更新后即可直接处理并传播,而无需重新构建整个语料库。
在最初的故事中,旧的退款政策并非大型语言模型的故障,问题出在数据摄取及语料库的管理方式上。
检索是一个流程,而非简单的查找
这个词让人联想到单一步骤,但实际上检索是一系列决策的连贯过程,其顺序会带来相应影响。
1. 重写
人们不会自然而然地写出搜索查询语句,他们通常会询问诸如退款是否已寄出之类的问题。大型语言模型可以将这类问题转化为更利于检索的形式,比如整合对话历史,或将复杂问题拆解为更具体的子问题。不过,重新编写查询并非毫无成本:糟糕的改写可能会遗漏关键细节或加入不必要的假设。应将其视为需要评估的另一个要素,而非神奇的解决方案。
2. 搜索前的范围界定
这是最重要的实际应用细节之一。如果系统是多租户架构或具备权限控制功能,搜索范围就必须遵循这些限制。在底层系统允许的情况下,应在检索操作中考虑租户、权限、可见性、日期以及来源等因素。
在全局前k项筛选之后会产生两个问题。首先,有用的文档可能已经被用户无权查看的文档挤出了前k项范围。其次,授权逻辑会与检索过程严重脱节。简而言之,不要先搜索所有内容再判断用户能查看什么,应先缩小搜索范围。
3. 两种搜索方式
密集向量搜索擅长处理语义相似性。例如,询问如何取消服务的人,即便与相关文本没有相同的字眼,也能因为语义关联被匹配到那些说明客户可随时终止服务的文本。
不过,对于精确的标识符,嵌入模型的效果较差。试想这样的字符串:
ERR_CONNECTION_RESET
SKU-48392
API-v3-beta
对于这类查询,原始词元本身就是信号,这也是诸如 BM25 这样的词汇检索方法发挥作用的地方。实际应用中的检索通常会将基于语义的密集搜索与基于精确字符串的词汇搜索相结合。
4. 融合
此时会有两个排序列表:密集搜索有自己的排序方式,BM25 也有自己的排序方式,而且它们的原始得分未必具有可比性。互反排名融合(RRF)提供了一种利用排名位置来合并这两种列表的简单方法:
RRF_score(d) = Σ 1 / (k + rank_i(d))
每个列表会根据文档在其中的位置来赋予相应的权重,这样就无需将两个互不相关的系统的得分分布相互校准。
5. 重新排序
融合机制仅能提供候选集,并非最终的上下文。交叉编码器重新排序器会同时读取查询语句与每个候选项,为该特定组合生成相关性得分。这与分别对查询和文档进行嵌入处理后再比较向量值的方式有本质区别。
这种方法的代价在于计算成本,因此不会对整个语料库都使用交叉编码器。检索系统可能会返回前20或50个候选项,然后由重新排序器从中挑选出最合适的上下文。
因此,实际的处理流程是先进行密集检索,再做词汇检索,接着进行融合处理,最后重新排序。这并非简单的“向量数据库即可解决所有问题”。
生成过程:良好的上下文仍无法保证优质答案
找到合适的文档是必要的,但还不够。大语言模型仍需正确使用这些文档。
管理上下文窗口
更多的上下文并不必然带来更好的答案。模型对长上下文的使用并不均匀。研究表明,长上下文中的中间信息比开头或结尾的信息更难被准确回忆。因此,将前20个片段放入提示语中反而可能使答案质量下降。目标应是最大程度的有用上下文,而非最大量的上下文。
提示语边界与归属说明
在提示语中明确说明应如何使用检索到的段落。模型应将其视为可引用的证据,而非必须遵守的指令。
引用来源也有助于建立信任和调试。当某个答案称企业客户有30天时间取消服务时,就需要一种方法将这一说法追溯到对应的原始资料。
弃权机制
弃权机制体现了演示版本与可靠系统之间的重大差异。如果检索没有找到任何结果,模型仍会尝试提供帮助,除非系统允许拒绝回应。而生产系统则应当能够说明证据不足。这通常是正确的处理方式,而非缺陷。
如果没有弃权机制,每一次检索失败都可能演变成编造的虚假内容。大语言模型会为给出错误答案承担责任,但实际上故障可能早在更早的环节就已经发生。
任何修复之前都需先进行评估
RAG存在一个棘手的特性:即便应用代码毫无变动,其质量仍可能下降。新的嵌入模型、不同的分块方法、文档的新增或删除、检索参数的调整以及提示词的修改,都可能改变输出结果,即便昨天的部署代码在字节级上完全一致。因此,生产环境中的RAG需要从多个层面进行评估。
检索质量。上下文精确度衡量的是检索到的上下文中有多少是相关的;上下文召回率则衡量的是实际检索出了多少可用的相关信息。二者共同区分了“根本找不到相关内容”与“找到了但被无关信息淹没”的情况。
生成质量。忠实度检测(也称为依据性检查)用于确认答案确实源自检索到的证据,而引用准确性检测则用于确保每项论点都有对应的来源支持。即便答案写得很好,也可能缺乏依据。
系统健康状况。运行指标同样重要:p95延迟、每次查询的成本以及放弃率。这些并非仅仅是基础设施方面的问题。如果由于智能体开始执行多次检索循环而导致延迟翻倍,那也是系统质量的一部分表现。放弃率突然上升可能意味着检索效果变差,而每次查询成本的增长则可能表明某个看似无害的变更引入了高成本的处理路径。
将各项指标分开分析有助于精准诊断。健康但接地性下降的召回率往往与生成环节有关;精度下降则可能与输入处理、过滤、检索或排序环节有关。如果只关注整体答案质量,所有的性能下降看起来都一样,无法为后续行动提供依据。
从处理流程到反馈循环
核心处理流程依然很简单:
Ingestion → Retrieval → Generation → Evaluation
许多系统无需更多功能。一个索引完善的知识库加上明确的查询问题,通常就不需要智能体来决定下一步操作。不过,确实也存在一些更复杂的查询问题。
比如,要求将第二季度的营收数据与董事会演示文稿中的数据进行对比,并解释两者之间的差异。要给出答案,可能需要第二季度的数值、董事会演示文稿、两份资料中的相关部分、对比分析,甚至可能需要从其他数据源获取信息。单次检索可能不够,这时智能体驱动的RAG技术就派上用场了。无需采用简单的“检索后再生成”的流程,而是可以通过循环来实现:
Retrieve
↓
Evaluate
↓
Enough evidence?
↓ no
Retrieve again
↓
Generate
这样的系统可以判断目前的证据不足,从而重新表述查询语句再次搜索,或者将子问题交由 SQL 数据库、知识图谱或实时 API 处理。信息检索因此变为迭代过程,而非一次性完成。
不过,代理型 RAG 并不自动就更优。每多一次循环都会增加延迟、token 成本以及出错概率,而且当代理没有明确理由继续时还可能引发不必要的搜索。只有在问题模糊、需要多步处理或涉及多个信息源时,其复杂性才有价值。关于退款政策的问题或许应该由设计良好的静态流程一次性解答。而牌组对比类问题则可能有必要通过迭代来解决。
关键问题在于系统是否有可衡量的理由需要再次查找,而非它是否必须使用代理。没有合理退出规则的循环只会增加延迟和成本。
生产环境中的思维模型
从大型语言模型入手是最常见的调试错误。糟糕的回答仅仅是最后出现的症状,其根源可能早在更上游的环节。过时的文档类似于幻觉现象,不良的分块处理类似于检索失败,较弱的检索能力类似于生成故障,而缺乏评估则会掩盖所有这些问题,直到客户提出投诉。
因此不要问该使用哪种模型,而应询问是哪一层出了问题。
INGESTION
↓
RETRIEVAL
↓
GENERATION
↓
EVALUATION
↖
└── feedback loop / Agentic RAG
数据过时意味着需要改进数据获取环节;文档缺失则意味着要优化检索功能;找到文档但排名靠后则需调整排序算法;给出错误答案但上下文正确则需审视生成过程。如果无法判断该适用哪种解决方法,首先应构建更完善的评估体系。而当单次处理永远不够时,可以考虑采用智能代理循环机制。
先从数据处理流程入手,最后再处理模型相关问题。
这些理念的来源
如需进一步阅读,Lewis及其同事在2020年NeurIPS会议上发表的原始检索增强生成论文阐述了该技术的基本模式。Anthropic在2024年发布的关于上下文检索的报告中指出,采用上下文嵌入、上下文BM25及重排后,检索失败率大幅下降,不过这些数据来自该公司自身测试。Cormack、Clarke和Büttcher在2009年SIGIR会议上提出了互斥排名融合方法。Liu及其同事的“Lost in the Middle”论文研究了模型如何利用长上下文,RAGAs论文描述了自动化的RAG评估方法,而Asai及其同事的Self-RAG论文则探讨了具有自我反思能力的智能检索技术。
相关阅读
- 实用笔记:RAG中向量搜索的局限——余弦相似度及其应用 — 该实用笔记的详细操作指南:针对采用此模式的团队提供的契约、检查项及可直接使用的代码模板。
- 意义即坐标:从嵌入模型到向量数据库与RAG — 对句子嵌入、余弦相似度、向量数据库以及RAG工作流程的通俗讲解,并通过四句关于狗、猫和巴黎的简短句子演示意义搜索的运作方式。