← 洞见AI 科普

上下文窗口不是记忆,塞满也没用

泛友数字2026/10/27 11:4257 阅读
上下文窗口不是记忆,塞满也没用

chunk_size、chunk_overlap、top_k、rerank_threshold,四个配置项决定检索质量,也决定账单。下面按这四项逐项给区间,每项都给两种口径:研究实验里这个参数怎么处理、厂商文档里怎么写。两种口径对不上的地方,就是必须拿自己的标注集去测的地方。

四个检索配置项与两套口径的对照示意
同一套材料,参数来自两个不同的地方:实验里被当成控制变量的,工程上被当成推荐值的。

先立一条前置约束,否则四项都调不明白。位置和长度是两件事。相关信息落在长输入中段的得分低于落在开头或结尾,Liu 等人在 TACL 2023 的 Lost in the Middle 里用多文档问答与键值检索两类任务测过,专为长上下文训练的模型同样如此(arXiv 2307.03172)。长度本身也压分:Chroma 2025 年 7 月的 Context Rot 报告用重复词、需要语义匹配的大海捞针、LongMemEval 三类任务测出,输入越长得分越低,且退化不均匀,不同模型在不同长度上出现台阶(Chroma 研究页面)。同一份报告指出 Needle in a Haystack 只做词面匹配,接近满分不代表长输入下能力均匀。四个配置项改的是相关块落在哪、周围有多少噪声,不是窗口够不够长。

块大小。厂商口径有具体数字:Azure AI Search 的切块文档给连续文本的参考是 200 词或 600 字符左右,并附块数示例,1000 字符一块、不加重叠切出 172 块,加 200 字符重叠变成 216 块(Microsoft Learn 切块文档)。研究口径里没有这个参数:Lost in the Middle 操纵的自变量是相关文档放开头、中间还是结尾,块长固定;Context Rot 操纵的是输入总长。块大小在研究里是控制变量,没有推荐值,只有一条间接约束——块越小、块数越多,中段越长,衰减越明显。落到工程上先按文档结构切,标题、条款号、表格行、问答对各成一类;连续无结构文本取 300 到 600 字符,落在厂商给的 600 字符附近。一块只放一个可回答的单元,条款块带适用范围与例外,表格块带表头。表格按行切会让每行失去表头,把表头拼进每个块的前缀,字段名保留英文原名,不翻译。切完随机抽 20 块读一遍,读不懂的块,模型也读不懂。

重叠。厂商口径是 10% 到 15%,同一份 Azure 文档的示例则用到了两成,块数从 172 涨到 216,多出 44 块,涨幅四分之一。研究口径照样没有这个变量,两类实验都靠位置与长度做对照,不测重叠,所以它没有研究侧的结论可引。重叠只有一条自己的算法:把块数涨幅换算成索引体积与召回耗时,再问这四分之一的开销买回了什么。买不回可验证的召回提升,就往下压。它真正起作用的地方只有一个,防止一个完整条款被切断在两个块里;条款边界已经由结构切开时,重叠可以接近零。

召回条数。厂商口径给的是上限,不是建议值:Cohere 的重排文档写明单次最多 10000 个文档、查询侧上限 2048 token(Cohere Rerank 最佳实践)。研究口径把 k 当自变量,Ragas 的 context precision 定义是各位置 precision@k 的均值,相关块越靠前分越高(Ragas 指标定义)。也就是说 k 在研究里不是拍出来的,是扫出来的:同一批题,k 取 3、5、10、20 各跑一遍,看指标在哪一档走平。工程起点可以取候选 50 到 100 条、重排后送进上下文 5 到 10 条,但这是经验值,不是任何一方的推荐值,要换成自己扫出来的曲线。候选再往上放就得按 Cohere 那条上限分段重排,批次之间按分数归并,不能只留第一批的前几条;重排模型与向量模型分开部署时,网络往返也算进这段预算。单次重排耗时乘候选数,不能超过首字响应预算,用户多等的那几秒就产生在这里。

重排阈值。厂商口径给区间加免责:relevance_score 归一化在 0 到 1,但分数依赖查询、跨查询不可比,0.91 不代表比 0.044 相关两倍。研究口径不给阈值,context precision 与 Context Rot 的指标里都没有截断这一步。所以阈值只能自己标定,方法看两条分布:对每类问题算正确答案所在块的最高分、无关块的最高分,两条分布的交叠区间就是误判高发区,初始阈值取交叠区间上沿,宁可多召回几条交给重排去筛。写死 0.5 的结果是一部分问题全被滤掉、另一部分全放过。阈值写进配置文件,不写进代码。

四项之外还有一项预算。输入预算写成硬上限,超了按分数从低到高丢块,不从中间截断,中间正好是位置效应最脆弱的一段;系统提示不丢。窗口里不只有检索块,系统提示、工具返回、对话历史各占一份,检索块不超过一半。最相关的三块放在系统指示之后、对话历史之前,最不相关的直接删,不挪到中间占位。历史超过十轮压成结构化摘要,保留订单号、金额、已确认事实、未解决问题四类字段。

块上带什么字段,比参数更能决定结果:doc_id、version、effective_date、section_path。缺 effective_date,新旧两版政策一起被召回,答案自相矛盾,这时候调块大小没有用。召回阶段先按 effective_date 与权限标签过滤,再做向量与关键词两路召回,按 doc_id 去重,同一块的分数取两路最大值而不相加,相加会让两路都命中的块过度加权,把答案挤到后面。型号、单号、条款编号这类精确词走关键词更稳,同义词与口语说法靠向量。

阈值上线后靠一个数维护:零命中率,即最高分低于阈值、检索直接返回空的比例。每周回放 20 条线上问题,这个数偏高就把候选数放大一档,不要降阈值,降阈值等于把噪声请回窗口。标注集从真实会话里抽,最近三个月的高频问题与已知出错问题各一半,去掉答案只落在一句里的简单题,只记块 ID 与标准答案。验证用 30 到 50 条题跑三组对照,整本塞入、召回 5 条、召回 10 条,同一问题重复五次并打乱块序;答案随位置变化,说明位置效应还在,此时该动摆放与重排,不是换窗口。

这套参数有一类任务不适用:需要通读全文的活不该切块。整份合同的风险审查、几份材料之间的跨章节对照、要求覆盖全文的归纳,切块会把判断依据切碎。单份几千字文档、只问一处事实,比如发票金额与开票日期,整本塞入比切块省事,切块还会切断表头。

四个配置项对应四类症状,一次只改一处,改完用同一批标注题复测:

  • 答案错在文档中段,改重排与块的位置,不动 chunk_size;
  • 块数涨了而指标没涨,先压 chunk_overlap,按块数涨幅算这笔账;
  • top_k 从 5 加到 10 指标不动,把输入预算降回去,别再扫下一档;
  • 阈值调完零命中率升而准确率没升,把候选数放大一档,阈值回到交叠区间上沿。

参数没有一次调好的版本。按季度重跑三组对照,把新错题补进标注集,四个值跟着标注集一起改,别让它们停在当初上线那天的数值上。