检索增强刚上手时,人的直觉是「多塞点资料更保险」。做久了会发现相反:塞得越多,答案常常越差。
原因不神秘——上下文是有限预算,抢位置的东西太多,模型反而抓不住重点。这篇写我怎么分配这份预算。
上下文是预算,不是容量
模型能装 100K,不代表这一轮该用满。塞满的代价有三方面:成本上升、延迟变长,以及最容易被忽略的一点——注意力被稀释。
在信息密度低的材料上,这个代价尤其不划算。十段内容里九段是废话,模型要做的是先学会忽略它们,这本身就在消耗它的判断力。
三类内容在抢同一个位置
- **指令**:你要它做什么、按什么格式回答
- **证据**:检索回来的文档片段
- **历史**:之前几轮的对话内容
三者互相挤压。历史太长会淹没指令,证据太多会淹没彼此。我的经验是先把指令和历史压到最小,把大部分预算留给证据——但证据要精挑,不是全塞。
还有一类容易被忘掉的内容:示例。给一两个输出样例,往往比多塞三段资料更能稳定格式。这部分预算要从证据里匀出来。
排序比召回更值钱
很多团队把精力花在「召回更多」上。但真正决定效果的是排序:最相关的那几段,有没有排在最前面。
做法上,粗召回可以放宽,精排要收紧。宁可只给三段最相关的,也别给二十段平庸的。
一个判断方法:把答案所需的那段内容,人为放到召回结果的第五位,看模型还能不能用上。用不上,说明你的排序环节还有空间。
压缩和摘要的代价
把长文档先摘要再喂给模型,能省很多预算。代价是细节会丢,而很多问题的答案恰恰藏在细节里——数字、日期、限定条件,都最容易在摘要里被磨掉。
一个折中办法:摘要负责定位,命中之后再把原文片段回捞一次,两段一起给。这样既省预算,又保留细节。
别忽略「答不出来」的情况
检索没命中时,最忌讳的是让模型硬答。上下文里没有依据,它就会用训练时的记忆去补,听起来很像真的。
所以在指令里明确一条:资料里找不到,就直接说找不到,并说明缺什么。这条规则的收益,往往比再调十个参数都大。
分块策略:怎么切比切多细更重要
把长文档按固定字数切开,是最省事也最容易出问题的做法——它会把一句话从中间截断,也会把结论和前提拆到两个块里。
更稳的做法是按结构切:标题层级、列表、表格各自成块;表格尽量整块保留,因为行列关系一断,数字就没了语境。
块与块之间还可以留一点重叠,让跨段的指代不至于丢失。代价是检索结果会有重复,需要在去重环节处理掉。
- 1定指令压到最短,说清格式与边界
- 2清历史只留必要轮次,其余摘要化
- 3精排证据少而准,按相关度排序
- 4补细节命中后回捞原文片段
用评测代替感觉
改完参数,效果是变好还是变坏,不能靠抽样几眼看。准备一组固定问题(其中要包含本该答不出的),改一次跑一次,记录命中率。
问题里最好夹几条「陷阱题」:看起来能答、其实资料里没有。能稳定拒答,说明你的约束真正生效了。
能被测量的调整才叫优化,其余都是折腾。
本文不构成任何技术建议,具体方案请结合自身数据与实测结果评估。