RAG 优化策略
RAG 优化应先定位问题所在的环节,再选择策略。一个实用的排查链路是:
知识是否覆盖
→ 文档是否正确解析
→ 切片是否保留语义
→ Embedding 是否适合领域
→ 是否召回正确片段
→ 模型是否正确使用上下文
先建立可观测性
每次查询至少记录:
- 原始问题和必要的会话上下文
- 改写后的查询(如果有)
- 召回的 Node、来源和相似度分数
- 最终提示词或其安全摘要
- 模型答案和评测结果
只看最终答案很难区分检索错误和生成错误。打印或保存 response.source_nodes 是最直接的第一步。
增加召回数量:只作为诊断手段
将 similarity_top_k 从 2 调大到 5 或 10,可能让遗漏的片段进入上下文:
query_engine = index.as_query_engine(
similarity_top_k=5,
llm=llm,
)
但这不是长期方案。过多片段会增加输入成本、超过上下文限制,并把多个同名员工或无关内容混在一起。应通过评测确定合理范围,而不是无限增大 top_k。
优化文档与切片
结构清晰的 Markdown 通常比结构被破坏的纯文本更容易检索。建议:
- 保留标题层级、表格和列表关系;
- 将一条完整事实尽量放在同一个片段中;
- 通过
chunk_overlap保留相邻片段的上下文; - 保留文件名、章节、页码和业务标签等元数据;
- 定期删除过期、重复和与业务无关的知识。
示例:
from llama_index.core.node_parser import SentenceSplitter
splitter = SentenceSplitter(
chunk_size=1000,
chunk_overlap=200,
)
nodes = splitter.get_nodes_from_documents(documents)
chunk_size 和 chunk_overlap 没有通用最优值,应使用业务评测集进行对比。
更换 Embedding 模型
Embedding 模型决定语义空间的质量。可以比较不同模型在同一数据、同一切片和同一评测集上的 Context Recall 与 Context Precision。升级模型时需要重新建立索引,不能直接将旧向量和新模型生成的向量混用。
检索前优化
用户问题往往过短或含有歧义,可以在检索前进行:
- 问题改写:补足省略的主体和上下文;
- 问题扩写:生成多个相关查询,提高召回覆盖;
- 用户画像扩展:结合岗位、组织或权限信息;
- 元数据过滤:先按岗位、时间、部门等标签筛选;
- 澄清提问:问题无法唯一确定目标时,先向用户确认;
- 多步检索:将复杂问题拆成多个有依赖关系的子问题。
例如,“张伟是哪个部门的?”在存在多名同名员工时并不充分,系统应列出候选或要求用户补充身份信息,而不是凭相似度猜测。
检索后优化
- 重排序(ReRank):先用向量检索快速召回,再用更精确的模型重新排序并过滤;
- 相似度阈值:过滤低于可信分数的结果;
- 滑动窗口:命中一个片段后补充其前后相邻片段,恢复被切分的上下文;
- 混合检索:结合关键词匹配与向量检索,兼顾专有名词和语义表达;
- 来源去重:避免同一事实的重复片段占满上下文。
知识空间与意图空间
优化不只是调模型参数,还要持续维护知识库:
- 收集真实用户问题,了解意图空间的变化;
- 补充知识库中缺失的业务内容;
- 优化文档结构和检索算法,减少无关知识;
- 由领域专家审核答案和 Ground Truth;
- 将结果加入回归评测集,形成持续迭代闭环。
如果知识库根本没有覆盖某个问题,工程和算法优化都无法生成可靠的事实答案;这类问题应明确拒答或进入知识补充流程。