长上下文不是免费的:为什么塞满2M token反而更笨,以及该怎么用
上下文窗口越做越大,但把你所有资料都塞进去通常不是最优解。本文从有效上下文、检索精度、延迟成本与并发支持四个角度拆解长上下文的真实代价,并给出一套分配与压缩策略。
“窗口够大”是一个诱人的陷阱
厂商不断把窗口推到百万级,于是自然产生一个想法:把所有文档、整个代码库、全部聊天历史都塞进去,让模型自己找。省掉了检索工程,还避免了”检索漏掉关键段落”的问题。
但实测下来,这个做法在很多任务上不如小窗口+精准检索。原因不是营销话术,而是几个可测量的机制。
四个真实代价
一、有效上下文远小于标称窗口。 “支持1M token”和”在1M token上都可靠”是两件事。信息在超长输入中间被忽略(俗称lost in the middle)是普遍现象,位置敏感、任务相关。常见做法是把关键指令放在开头和结尾,中间部分放辅助材料。
二、多给了会稀释注意力。 输入里90%是无关内容时,模型要么漏检,要么被无关内容带偏。一部长文档里翻两页找到答案,比把全书丢进去更准。这与人类阅读其实一致。
三、延迟和成本是超线性的。 长上下文意味着更大的prefill计算和更高的单次成本,首token延迟显著上升。对于交互式产品,这直接决定体验是否可用。
四、并发被吃掉。 长请求占用显存,批次变小,吞吐下降。在高峰时段,长上下文的实际可用性远低于标称值。
此外还有一个隐性成本:你无法验证它的注意力。短上下文出错时你能定位到具体段落;长上下文出错时,你不知道它到底看了哪里。
什么时候该用长上下文
并非全盘否定。以下场景它是明确更优解:
- 需要全局一致性:跨章节的引用对齐、整份合同的条款交叉冲突检查、整个代码库的架构一致性
- 检索难以切分:表格密集、图文混排、逻辑依赖跨段落的文档
- 一次性任务:成本不敏感,且不复用上下文
- 调试与探索:不确定答案在哪,先让模型粗定位
而在高频、延迟敏感、内容相对稳定的场景(知识库问答、客服、日常助手),混合检索往往更划算。
一套可执行的分配策略
把上下文预算当作资源来分配,而不是”越大越好”:
系统指令 + 关键约束 ≈ 5%
当前任务与对话近况 ≈ 15%
高相关检索结果(前N条全文) ≈ 40%
次相关结果(摘要/片段) ≈ 25%
少量示例(few-shot) ≈ 10%
留白缓冲 ≈ 5%
四条实践原则:
- 先精排再扩窗:全文塞入前先做一次精排,把最相关的10-20段提到前面,其余只给摘要。
- 分层压缩:把历史对话做成”滚动摘要+最近原文”,而不是全量拼接。摘要负责事实,原文负责细节。
- 关键信息两端放:任务要求、输出格式放在最前和最后。中间的中段内容容易被忽略。
- 打标引用:给每个片段加ID,要求模型在输出中引用来源。这既提高准确性,也让错误可归因。
一个判断”该不该扩窗”的小实验
同一个任务,跑两次:一次用”全部塞入”,一次用”检索前k条”。比较三项:准确率、P90延迟、单次成本。
如果全量模式的准确率提升不到5%,而成本上升3倍,就不必扩窗。在多数知识问答场景,这个实验的结果都非常一致。
结论
上下文窗口是一个上限,不是一个策略。真正的能力在于:把对的15%放进窗口,并让模型知道该看哪里。省下来的token、延迟和显存,会以并发量和用户体验的形式还给你。