dev.to #ai短讯
构建更优的 RAG 系统:四个关键杠杆
大多数在生产环境中表现不佳的 RAG 系统,问题通常出在检索而非生成环节。本文指出从演示到生产需要全链路工程优化,并介绍了决定 RAG 系统稳定性的四个关键杠杆:检索前后的处理、文档分块策略以及嵌入模型的调优。
大多数在生产环境中令人失望的 RAG 系统,其失败点在于检索而非生成:模型在错误的上下文中回答得很好,或者根本没有上下文。让演示版本运行起来只需一个下午;但要让它能在真实查询、真实文档和真实流量下稳定工作,则需要在管道的每个阶段进行深思熟虑的工程化设计。
本文探讨了决定 RAG 系统能否经受住考验的四个杠杆:检索前后的操作、文档分块方式、嵌入向量与向量库的调优,以及如何衡量这些措施是否有效。请将它们视为一个循环。评估结果会告诉你接下来应该修复其他三项中的哪一项。
- 检索前处理与检查策略
用户查询通常简短、模糊,且措辞与回答它们的文档不同。检索前处理旨在触及索引之前缩小这一差距,而检查机制则能在不良上下文到达模型之前将其拦截。
检索前
- 查询重写:使用大语言模型将模糊或对话式的提问转化为独立的、便于搜索的问题。在聊天场景中,这也意味着利用对话历史来解析诸如“第二个怎么样?”之类的指代。
- 查询扩展与多查询:生成问题的多个 paraphrase(释义),分别对每个释义进行检索,然后合并结果。当用户和文档使用不同的词汇时,这能提高召回率。
- HyDE(假设文档嵌入):先让模型撰写一个合理的答案,然后对该答案而不是原始问题进行嵌入。在嵌入空间中,答案往往比问题更接近文档。
- 查询分解:将多部分问题(例如“比较方案 A 和方案 B 的价格和限额”)拆分为子查询,分别检索,然后综合结果。
- 路由:对查询进行分类并将其发送到正确的位置:特定的索引、SQL 数据库、网络搜索,或者对于模型可以直接回答的问题则完全不进行检索。在不必要时跳过检索可以节省延迟并避免干扰模型。
- 元数据过滤:从查询中提取约束条件(如日期范围、产品、语言、文档类型),并将它们作为过滤器应用,从而使搜索空间更小且更相关。
检索后
- 重排序:检索一个充足的候选集(例如 30 到 50 个),然后使用交叉编码器或重排序模型重新评分,该模型会同时阅读查询和每个段落。这通常是单位投入下最大的质量提升来源。
- 相关性检查:让轻量级的评分器判断检索到的段落是否与问题真正相关。如果不相关,则重写查询并重试,或回退到其他来源。这是 CRAG 等纠正性方法背后的理念。
- 上下文压缩:将检索到的段落精简至关键句子,以免模型被无关内容稀释,从而减少 token 消耗。
- 事实核查与答案检查:生成后,验证每个主张是否有检索文本的支持,并要求提供引用。如果缺乏支持,应返回“我不知道”或提出澄清问题,而不是猜测。
每一步都会增加延迟和成本,因此应根据测得的故障情况添加这些步骤,而不是默认启用。
- 管理分块策略
分块决定了检索器眼中的“知识单元”长什么样。过大的分块会将相关句子淹没在噪声中并稀释嵌入向量;过小的分块则会丢失使其可理解的上下文。没有通用的最佳大小,因此目标是将分块与内容的实际结构和查询方式相匹配。
| 策略 | 工作原理 | 最佳适用场景 | 注意事项 |
|---|---|---|---|
| 固定大小 | 每 N 个 token 分割,通常带有重叠 | 快速基线、均匀文本 | 会切断句子中间和意思中间 |
| 递归式 | 先按段落分割,再按句子,最后按单词,直到块大小合适 | 通用散文;一个可靠的默认选项 | 忽略分隔符之外的文档结构 |
| 结构感知 | 按标题、章节、代码块、表格边界分割 | 文档、维基、Markdown、HTML、法律文本 | 每种格式都需要解析器 |
| 语义式 | 当相邻句子之间的嵌入相似度下降时开始新块 | 长文本、主题转换文本 | 需要额外的嵌入调用;块大小不均匀 |
| 父子式 | 嵌入小块,返回较大的父级部分 | 精确匹配并保留完整上下文 | 存储和索引更复杂 |
| 句子窗口 | 嵌入单个句子,返回每个命中结果周围的邻居 | 密集事实性文本 | 窗口大小需要调整 |
实用指南
- 从简单开始:使用大约 300 到 800 个 token 的递归分割,重叠率为 10% 到 15%,这是一个合理的基线。在此基础上使用你的评估集进行调整,而不是凭直觉。
- 尊重结构:永远不要将表格、代码块或编号流程切成两半。保持标题与其下方的文本关联。
- 为块添加上下文:在嵌入之前,在每个块前附加文档标题和章节路径,或者生成一个简短的 LLM 摘要来说明该块在文档中的位置(通常称为上下文检索)。如果不知道“它”指的是什么,那么说“它增加了 12%”的块毫无用处。
- 存储丰富的元数据:来源、章节、页码、日期、作者和访问权限允许你在查询时进行过滤并精确引用。
- 有意处理非文本内容:表格、图像和扫描的 PDF 需要自己的提取路径。将表格转换为保留行和列的文本格式,并为图像添加说明或使用 OCR,而不是直接丢弃它们。
- 对分块进行版本控制:当你更改块大小或逻辑时,必须重新嵌入。将分块配置与索引一起保存,以便公平地比较不同版本。
- 优化向量存储和嵌入
即使分块完美无缺,检索质量也受限于你的嵌入在领域内捕捉意义的能力,以及你的索引在规模上找到最近邻的效果。
嵌入选择
- 为你的数据选择模型,而不是排行榜:公共基准只是起点。在你的查询和文档上测试两三个候选模型,因为领域词汇(法律、医疗、代码、多语言)会改变排名。
- 权衡维度与成本:高维向量通常能捕捉更多细微差别,但会增加存储、内存和搜索延迟。支持截断(Matryoshka 风格)嵌入的模型允许你缩小向量,同时只造成适度的质量损失。
- 使用正确的输入格式:有些模型期望查询和文档有不同的前缀或指令。忽略这一点会悄悄损害质量。
- 考虑微调:如果你有标记的查询和相关段落对,在这些数据上微调嵌入模型可以显著提升特定领域的检索效果。合成查询生成可以在没有数据的情况下启动训练数据。
- 保持一致的归一化:将你的距离度量(余弦、点积或欧几里得)与模型的训练方式相匹配,并在所有地方使用它。
向量存储和索引调优
- 根据规模选择索引:对于小型集合,精确(扁平)搜索即可。对于较大的集合,近似最近邻索引(如 HNSW 或 IVF)会以少量的召回率损失换取巨大的速度提升。针对你自身数据测得的召回率目标,调整 HNSW 的 ef_search 和 M 等参数。
- 当内存成为瓶颈时进行量化:标量量化或乘积量化能显著缩小索引规模,通常只会带来微小的召回率损失。务必在量化前后分别测量指标。
- 采用混合检索:将密集向量搜索与关键词搜索(BM25)相结合。密集检索处理同义 paraphrase 和语义匹配;关键词搜索处理精确术语、产品代码、名称和罕见行话。使用倒数排名融合(Reciprocal Rank Fusion)或加权分数融合结果,然后进行重排序。
- 高效过滤:对你用于过滤的元数据字段建立索引,并了解你的存储是在向量搜索之前还是之后执行过滤,因为后置过滤可能导致返回结果过少。
- 规划数据新鲜度:确定更新和删除如何传播,如何检测变更文档,以及在更换模型时如何重新嵌入。保留别名或版本化索引,以便在不中断服务的情况下部署新的嵌入模型。
- 关注运维方面:除了质量外,还要跟踪查询延迟百分位数、索引构建时间、内存占用和每次查询的成本,因为一个过于缓慢或昂贵的准确方案是无法上线的。
- 评估 RAG 性能
无法衡量就无法改进。对于 RAG,你需要分别衡量两件事:检索是否找到了正确的材料?生成是否有效地使用了这些材料?将它们混在一起会导致故障无法诊断。
| 阶段 | 问题 | 常见指标 |
|---|---|---|
| 检索 | 我们是否获取了包含答案的段落? | Recall@k, precision@k, MRR, nDCG, hit rate |
| 生成 | 答案是否正确且基于上下文? | Faithfulness (groundedness), answer relevance, answer correctness |
| 上下文使用 | 我们是否只检索了所需的内容? | Context precision, context recall |
| 系统 | 它是否适用于生产环境? | Latency (p50, p95), cost per query, refusal rate |
构建黄金数据集
从 50 到 200 个真实的问答对开始,每个问题都配有所需回答的源段落,理想情况下还应包含参考答案。尽可能从真实用户日志中提取问题。涵盖简单查找、多跳问题、模糊查询以及在你的语料库中没有答案的问题,因为一个好的系统应该能够明确告知无答案。利用文档合成问题是扩展数据集的快速方法,但需要人工审查样本。
谨慎评估生成质量
- LLM-as-judge 是大规模评估忠实度和相关性的实用方法。为裁判提供清晰的评分标准、问题、上下文和答案,并要求其给出带有简短理由的分数。
- 校准裁判:在样本上将裁判的分数与人类标签进行对比,注意其对长答案或更自信答案的偏见倾向,并在每次更改裁判模型时重新检查。
- 框架助力:RAGAS、TruLens、DeepEval 和 LangSmith 等工具实现了这些指标,使你无需从头构建,但在信任某个数值之前,务必理解每个指标实际衡量的是什么。
将其作为循环运行
- 在对任何内容做出更改之前,先在黄金数据集上建立基线。
- 一次只改变一个变量(块大小、嵌入模型、重排序器)并重新运行。
- 按查询类型分解结果,因为平均值可能会掩盖表现极差的类别。
- 手动阅读失败案例。将每个失败归类为检索遗漏、排序问题、上下文问题或生成问题,然后修复真正负责的阶段。
- 在 CI 中通过评估集限制发布,以便在用户看到之前捕获回归问题。
- 在生产环境中监控:记录查询、检索到的块、答案和用户反馈(点赞、纠正、后续改写),并将困难案例反馈回你的黄金数据集。
整合起来
合理的操作顺序是:首先构建评估集,使用递归分块和优秀的嵌入模型获得一个简单的基线,然后引入混合搜索和重排序,因为它们往往能较早带来收益。接着,仅在故障分析指向特定环节时,才调整分块策略并添加查询侧的技术。每一次改动都应以可衡量的提升来证明其存在的合理性。
RAG 的质量源于整个管道的协同运作,而做得好的团队能够逐条查询地指出是哪个阶段让用户失望了。
译文已达到本站中文翻译的字数上限,剩余内容请查看原文。