RAG 优化
学习目标
完成本节后,你将能够:
- 识别 RAG 系统里最常见的优化点
- 理解 chunk、top-k、rerank、prompt 对结果的影响
- 学会做一个简单的上下文拼装策略
- 建立“先找瓶颈,再调参数”的优化思路
一、优化前先定位问题出在哪一段
1.1 一个 RAG 系统通常有四段
可以粗略拆成:
- 文档处理
- 检索召回
- 上下文拼装
- 生成回答
如果回答效果差,你首先要问:
- 是没找到对的资料?
- 还是找到了但没塞进去?
- 还是塞进去了但模型没用好?
1.2 不同问题,对应不同优化方向
| 现象 | 常见问题点 |
|---|---|
| 明明有答案却没检索到 | 切块 / embedding / 检索策略 |
| 检索到了但答案还是偏 | prompt / context packing / 模型总结 |
| 回答很慢很贵 | top-k 过大 / 上下文太长 / 重排过多 |
二、从文档处理开始优化
2.1 Chunk 大小不是越大越好
chunk 太大:
- 召回不精准
- 上下文占用大
chunk 太小:
- 信息容易被切碎
- 证据不完整
所以常见优化不是“越大越保险”,而是找平衡。
2.2 保留结构信息经常很重要
很多文档的价值不只在句子本身,还在:
- 标题
- 段落层级
- 表格归属
- 页面位置
如果清洗时把这些结构全抹掉,后面检索质量常常会变差。
三、召回阶段最常调的几个杠杆
3.1 top_k:不是越多越好
很多人一开始觉得:
多拿一些资料,总不会错吧?
其实不一定。
top_k 太大时,可能会把无关内容也带进来,反而干扰模型。
3.2 Rerank:先广撒网,再精筛
当粗召回里混进了很多边缘内容时,rerank 很有帮助。
它不是单纯“多做一步”,而是在提高上下文质量密度。
四、上下文拼装比很多人想的更重要
4.1 模型不是“看到资料就一定会用”
即使召回到了正确内容,也可能出现:
- 关键证据埋在中间
- 多个 chunk 顺序混乱
- 信息重复太多
所以“把哪些块按什么顺序塞进去”本身就是优化点。
4.2 一个可运行的上下文打包示例
chunks = [
{"score": 0.95, "text": "退款政策:购买后 7 天内且学习进度低于 20% 可退款。"},
{"score": 0.80, "text": "证书说明:完成所有项目并通过测试后可获得证书。"},
{"score": 0.76, "text": "学习顺序:建议先学 Python,再学机器学习。"},
{"score": 0.72, "text": "补充条款:退款申请需提交订单信息。"}
]
def pack_context(chunks, max_chars=60):
packed = []
total = 0
for item in sorted(chunks, key=lambda x: x["score"], reverse=True):
text = item["text"]
if total + len(text) > max_chars:
continue
packed.append(text)
total += len(text)
return packed
selected = pack_context(chunks, max_chars=60)
print("最终塞进上下文的 chunk:")
for c in selected:
print("-", c)
这就是最简单的“上下文预算管理”。
五、生成阶段怎么优化?
5.1 Prompt 要明确告诉模型“怎么用资料”
很多时候不是资料没找到,而是模型没有被明确要求:
- 只能依据给定资料回答
- 证据不足时要承认不知道
- 要引用来源
一个常见的提示思路是:
“请仅根据以下资料回答;如果资料不足,请明确说资料不足。”