AI Know · 技术研究笔记
长上下文的成本主要来自 KV 缓存驻留,token 数量本身不是主因
分页管理决定显存碎片率,直接影响并发上限;召回精度比窗口长度更影响最终效果;前缀复用能省下一半以上的重复计算
三分钟读懂
先看结论,再决定是否深读
- 长上下文的成本主要来自 KV 缓存驻留,token 数量本身不是主因
- 分页管理决定显存碎片率,直接影响并发上限
- 召回精度比窗口长度更影响最终效果
- 前缀复用能省下一半以上的重复计算
- 长尾输入会拉高尾延迟,必须单独限流
核心原理
理解长上下文成本,需要把一次请求拆成三段:输入侧怎么组织上下文、推理执行侧怎么管理缓存、输出与评测侧怎么验证效果。三段里任何一段设计粗糙,成本都会成倍放大。
先说一个常被忽略的事实:当上下文从 8K 增长到 128K 时,注意力的计算量按平方增长,但真正的瓶颈通常是显存。每生成一个 token,模型都需要为每一层、每一个注意力头保留 Key 和 Value 张量。以常见的 70B 级模型为例,单个序列在 128K 上下文下的 KV 缓存可以轻松达到数十 GB 量级。一旦并发上来,显存很快被占满,GPU 利用率骤降,吞吐塌方。
这就引出了分页。传统做法是为每个请求预分配一段连续显存,按最大长度预留,结果是大量空间被浪费,而且碎片化严重。分页式 KV 缓存把显存切成固定大小的块,按需分配、按块索引,类似操作系统里的虚拟内存。它的价值不只是省显存,更在于让不同长度的请求共享同一个显存池,把并发从个位数拉高到几十甚至上百。
第三个关键词是召回。窗口再长,模型也不会均匀地利用所有位置的信息。中间位置的信息容易被稀释,这就是常说的“迷失在中间”。所以长上下文系统的真正竞争力,不在于能塞多少 token,而在于能否把最相关的片段精准地放在靠前或靠后的高注意力区域。
技术细节
输入侧,核心是上下文编排。要明确区分三类内容:系统指令、检索片段、对话历史。系统指令应固定在最前,形成稳定的前缀,便于缓存复用;检索片段要按相关性排序,高相关片段靠近两端;对话历史要定期摘要压缩,避免无意义堆积。token 预算要显式分配,比如系统 5%、检索 60%、历史 20%、预留输出 15%,而不是让拼接函数自由增长。
推理/执行侧,重点是三件事。第一是前缀缓存,相同系统提示和相同文档前缀的请求可以复用已计算的 KV,避免重复前向;第二是分页调度,块大小、驱逐策略、抢占优先级都要调,长请求和短请求混跑时需要防止短请求被长请求饿死;第三是量化,KV 缓存用 FP8 甚至 INT8 存储,能在精度损失可控的前提下把显存占用压到一半左右。
输出/评测侧,要建立分层指标。延迟看 P50 和 P99 两条线,P99 才反映用户体验;成本看每千 token 的显存秒数和实际 GPU 小时;效果看召回命中率、答案忠实度和“无关上下文干扰下的稳定性”。评测集里必须包含长尾样本:超长但低信息密度的输入、大量近似重复片段、以及关键信息藏在中间位置的用例。
| 环节 | 主要成本项 | 优化手段 |
|---|---|---|
| 输入侧 | 无效 token 占比 | 预算分配、摘要压缩、相关性排序 |
| 执行侧 | KV 显存与重复计算 | 前缀缓存、分页调度、KV 量化 |
| 输出侧 | 尾延迟与重试 | 流式输出、超时熔断、分层评测 |
工程实践
建议一:把 token 预算写成配置,而不是散落在代码里。 用一个统一的上下文编排模块,显式声明各段配额,并在超限时按优先级截断。这样成本可预测,调参也有据可依。
建议二:默认开启前缀缓存,并把系统提示设计成稳定前缀。 把易变内容放到后面,把检索文档的固定头部(标题、来源、摘要)放到前面,能显著提升缓存命中率,重复请求的成本可以下降一半以上。
建议三:为长尾输入单独设限流和降级路径。 超过阈值的输入先走摘要或分段召回,而不是直接塞进主链路。同时给 P99 延迟设熔断,超时后返回部分结果或提示重试,避免长请求拖垮整个队列。
风险边界
成本边界:长上下文的边际成本不是线性的。窗口翻倍,显存和延迟可能翻数倍。必须按实际调用分布做容量规划,而不是按最大值预留。
幻觉边界:上下文越长,模型越容易在无关片段间建立虚假关联。召回片段必须带来源标识,输出侧要求引用可追溯,否则长窗口只是放大了自信的错误。
越权调用边界:检索层如果把不同租户、不同权限的文档混进同一个上下文,模型可能把它们当作可引用内容输出。必须在召回阶段做权限过滤,缓存键也要隔离租户。
长尾与延迟边界:绝大多数请求很短,少数超长请求会主导尾延迟。分级队列、请求抢占、异步化是必要手段,否则平均值好看、用户体验崩坏。
长上下文的能力上限由模型决定,但成本上限由系统设计决定。把 KV 缓存当资源来调度,把召回当排序问题来做,把评测当回归测试来跑,长窗口才真正可用。