模型上下文用了 80%,会比 20% 更慢吗?
提示:本文由 GPT-5.6-sol 整理正文,GPT-5.6-luna 负责资料检索。如有错误,全是他们的锅。
最近用 OpenCode 时,我经常看到上下文占用从 20% 一路涨到 80%。很自然就会想到一个问题:同一个模型,上下文已经用了 80%,是不是会比只用 20% 时更慢?
先说结论:通常会,而且慢的不只是响应速度,回答水平也可能受到影响。但 80% 不是一道突然降速、突然变笨的分界线,真正起作用的是上下文里的绝对 token 数,以及这些 token 到底装了什么。
这里讨论的前提始终是同一个模型。假设它的上下文窗口是 128K,20% 大约是 2.6 万 token,80% 则是 10.5 万 token。后者需要处理的历史内容大约是前者的四倍,但这不代表等待时间和生成速度也会严格变成四倍。
所以,上下文百分比只是容量表,不是性能跑分。真正该看的是绝对 token 数、缓存有没有命中,以及新增内容是有效资料还是垃圾。
慢主要慢在两个地方
大模型生成回答,大致可以分成两个阶段:先把已有上下文读完,再一个 token 一个 token 地往外写。
第一个地方:等它开始说话
模型在输出第一个 token 前,要先处理系统提示词、历史对话、工具返回和这次的新问题。这个阶段一般叫 Prefill,用户感受到的则是 TTFT(Time to First Token,首 token 延迟)。
上下文越长,模型开始回答前要读的东西越多。没有命中缓存时,80% 上下文通常会比 20% 等得更久,这是最容易察觉的差别:问题已经发出去了,界面却还在转圈。
不过,首字延迟不只取决于上下文。即使用的是同一个模型,API 排队、服务端负载、批处理方式和网络也会掺在里面。有时服务器刚好拥堵,上下文长度造成的差异反而被盖住了。
第二个地方:回答本身的速度
模型读完上下文后,并不是就把前面的内容扔了。它会为历史 token 保存一份 KV Cache,生成每个新 token 时都要用它去回看前文。
上下文越长,KV Cache 越大,每生成一步需要读取的历史信息也越多。这部分很吃显存容量和显存带宽,所以长上下文不仅可能让首字出来得更慢,也可能让后面的 tokens/s 下降。
如果 KV Cache 把显存挤得太满,情况会更难看。服务端可能减少并发、让请求等待,甚至把缓存换到 CPU、重新计算或者抢占请求。此时慢的就不只是当前这一条请求,整台机器能同时服务的请求数也会下降。
但这里同样没有“从 20% 到 80%,速度就固定慢四倍”这种简单规律。注意力实现、缓存状态、服务端调度和当时的并发都会改变结果。
Prompt Cache 能救首字,但救不了全部
多轮对话里,前面大段内容往往完全相同。服务商可以保存这段前缀已经算好的 KV Cache,下次只处理新增加的部分,这就是 Prompt Cache 或 Prefix Cache。
缓存命中后,长对话的首字延迟可能改善很多,重复输入的计费也可能下降。因此,有时上下文已经到 80%,实际等待时间却没有明显增加,很可能不是长上下文没有成本,而是前面的内容被缓存了。
不过缓存也不是把整件事免费做完。vLLM 的文档说得很直接:Automatic Prefix Caching 主要减少 Prefill,不会减少生成阶段的时间。模型输出新 token 时,仍然要面对完整上下文对应的 KV Cache。
而且缓存通常要求 token 前缀完全一致,不是“大概意思差不多”就能命中。改了系统提示词、调整了前面一段文字,或者服务商的缓存已经过期,都可能重新计算。
为什么有时感觉不到上下文变长
实际使用里,经常会出现上下文占用很高,但体感没有明显变慢的情况。原因一般有这些:
- 命中了 Prompt Cache,Prefill 被省掉了很大一块;
- 回答很长,输出时间远大于读取上下文的时间;
- API 排队和网络波动盖过了上下文长度的差异;
- 服务商用了 chunked prefill、连续批处理或 Prefill/Decode 分离。
因此,要认真比较,只能固定模型、问题、输出长度、缓存状态和并发条件,只改变上下文长度,再分别观察首字延迟与 tokens/s。随手问两次然后掐秒表,很容易测到的只是服务商当时忙不忙。
“慢”也包括回答水平下降
大家说模型变慢,有时不只是在说首字等得久、输出速度变低,也是在说它没有刚开会话时那么利索了:漏掉要求、抓错重点、忘记前面的决定,甚至在几份互相冲突的资料之间选错一个。这种体感不是纯粹的错觉。
同一个模型不会因为进度条到了 80%,权重就突然少了一块,所谓“智力下降”更准确地说是有效利用上下文的能力下降。更多上下文如果带来了真正相关、互补的信息,当然可能让回答更完整;但如果新增的是无关日志、旧版本文档、重复内容和相互冲突的结论,模型就要先从更大的垃圾堆里找针,再判断哪根针是真的。
《Lost in the Middle》发现,相关信息放在长上下文开头或结尾时,模型往往利用得更好;夹在中间时,表现可能下降。也就是说,上下文窗口能装进去,不等于模型能够同样有效地使用每一部分。
另一篇 2025 年的研究《Context Length Alone Hurts LLM Performance Despite Perfect Retrieval》更直接:即使研究者已经把相关信息准确定位出来,单纯增加输入长度,测试模型的表现仍然可能下降。论文报告的下降幅度在不同模型和任务中达到 13.9%—85%。这个数字不能拿来预测我们手上的某次对话,但至少说明问题不只出在“没找到资料”,长序列本身也会增加推理负担。
所以长上下文对回答水平不是单向影响,而是两股力量在拉扯:
- 新增的是可靠、互补的证据,回答可能更完整;
- 新增的是无关内容,注意力会被摊薄;
- 新旧资料互相冲突,模型可能错误融合;
- 同一说法重复太多,错误内容也可能显得更可信;
- 关键要求埋在中间,模型可能看过,却没有在最后真正用上。
实际表现往往是先受益,然后边际收益越来越小,最后持平甚至下降。名义窗口表示模型最多能接收多少 token,不等于它能稳定、均匀地理解这么多 token。
上下文更长,输入 token 的费用通常也更高。命中缓存后,一些服务商会给缓存输入更低的价格,但新增加的输入和输出仍然正常计费。对本地部署来说,账单虽然不按 token 来,显存占用、吞吐量和电费却不会消失。
普通上下文压缩的问题
常见的上下文压缩思路,是等会话快到上限时,把此前整段历史一次性概括成一个大摘要,然后让模型从摘要后面继续工作。这个办法至少能救急,但也很粗。
一场对话里,内容的状态并不相同。有些构建日志已经完成使命,有些用户要求一直有效;有些调查分支已经结束,有些代码正改到一半。把它们一起塞进同一个摘要,容易把仍在使用的细节提前压掉,也会让后续模型只看到一段来源不明的结论,不知道它原来对应哪次调查、哪段原文。
摘要本身还是有损的。数字、时间、单位、否定词、例外条件、证据出处和版本差异,都可能在概括时消失。压缩不是把一百斤材料无损装进十斤袋子,只是决定哪九十斤先不带。
ACP 相对传统压缩好在哪里
OpenCode 里的上下文膨胀得特别快。真正吃 token 的往往不只是聊天,而是完整文件、搜索结果、构建日志、报错堆栈和子任务返回。它们在调查时很重要,结论出来以后,大部分原文却已经没有继续留在上下文里的必要。
ACP(Active Context Pruning for OpenCode)不是等到最后再把整场会话搅成一锅摘要。它把压缩做成模型可以主动调用的工具:模型先判断哪些内容已经“消费完”,再按消息范围压缩,而不是默认改写全部历史。
这带来几个比一次性全局压缩更实用的区别。
只压已经结束的范围
ACP 可以选择具体的 startId 和 endId。一次排错、一轮资料搜索或者一组已经读完的工具输出结束后,就把这一段收起来;当前仍在修改的代码和用户的验收要求继续保留原文。
它还支持保护特定工具结果和文件内容。这个机制当然不能保证模型永远判断正确,但至少压缩对象不再只是“最老的那一坨内容”。
摘要有编号,也有来路
每次压缩会形成一个带范围、块编号和嵌套关系的摘要块。它知道自己覆盖了哪些消息,也知道自己包含了哪些更早的压缩块。后面看到一条结论时,不至于完全失去出处。
摘要通常会保留这些真正影响后续工作的内容:
- 用户到底要什么,以及中途有没有改过目标;
- 已经作出的决定和理由;
- 关键文件路径、函数名、配置值与错误信息;
- 哪些尝试失败了,失败原因是什么;
- 还有哪些问题没有解决。
至于几百行已经看过的日志、重复读取的代码和没有结果的搜索过程,就不再原样占着位置。压缩之后,模型下一轮需要 Prefill 的 token 少了,KV Cache 也能缩小,同时还保留了继续工作的线索。
先搜索,再按需恢复
传统摘要最麻烦的一点,是压完以后发现少了一个关键数字,通常只能重新调查。ACP 的压缩块可以先用 search_context 搜索摘要,找到相关块后再用 decompress 恢复原始内容。
这使它更像一套带索引、可以回查的上下文存储:平时只带着摘要继续走,需要核对数字、原话或完整代码时,再把对应的一小段取回来。正常压缩块仍然存在时,这个过程是可逆的;但上下文真的顶到 100% 后,旧块仍可能被 GC 截断,所以它也不是永久无损仓库。
摘要还能继续分层
会话继续增长后,摘要本身也会占地方。ACP 为此提供了三层压缩:原始消息先变成较详细的 T1 摘要,较旧的 T1 再提炼成只保留决定和结果的 T2,最后还可以把旧 T2 压成只剩关键事实的 T3。
重点不是层数本身,而是它没有强迫所有历史从一开始就只剩一句话。刚结束的工作保留更多细节,越久远的内容才逐步收束。
这和 Prompt Cache 不是一回事。Prompt Cache 是服务商复用相同前缀的计算结果,原来的长上下文仍然存在;ACP 是直接把送给模型的历史内容变短。前者主要省掉重复计算,后者减少实际需要携带的 token。两者可以同时起作用,但解决的不是同一个问题。
与其说 ACP 是一个“自动总结聊天记录”的插件,不如说它是在管理模型当前真正需要的工作集:已经完成使命的过程信息退出前台,结论留下;需要查原文时,再按块找回来。中文说明里有安装和工具用法。
压缩也不能只看百分比
我的做法不是看到上下文超过 50% 就立刻压缩,也不是顶到 99% 才肯收拾。如果当前任务连续、前面的代码和决定仍然正在使用,上下文长一点带来的延迟,通常比丢掉关键背景后让模型重新调查更划算。
到了 70%—80% 左右,我会开始看里面装的到底是什么:
- 已经用完的构建日志、搜索结果和重复文件内容,适合交给 ACP;
- 已经结束的分支任务,只需要保留结论、路径和关键错误;
- 当前还在修改的代码、用户原话和验收条件,不应该急着压;
- 准备切换到完全无关的新任务时,直接开新会话通常更干净;
- 需要长期生效的项目规则,应当写进项目说明文件,而不是埋在聊天摘要里。
这里最容易犯的错,是只盯着上下文百分比,仿佛清掉以后模型就会立刻满血复活。大模型不是这么简单。清理上下文确实可能减少 Prefill、KV Cache、费用和信息干扰,甚至让回答重新抓住重点;但压缩本身也会损失细节。该留下的东西如果被压没了,模型重新调查一遍,反而更慢、更费 token,回答也未必更准。
所以 ACP 真正有价值的地方,不是把进度条从红色变回绿色,而是判断哪些内容已经消费完毕,再用尽量少的 token 保住仍然有用的信息。压得太晚,上下文会越来越慢;压得太早,模型会失去正在使用的细节。这个分寸比压缩按钮本身更重要。
最后
在同一个模型下,上下文 80% 通常比 20% 慢,这个方向没有问题;但“占用率高所以慢”只是一个很粗糙的说法。
更准确的说法是:绝对 token 数增加后,Prefill 更长、KV Cache 更大,首字延迟和逐 token 生成都可能变慢;无关、冲突和位置不好的信息还可能降低模型有效利用上下文的能力。缓存和服务端优化可以缓解速度问题,却不能把长上下文的计算成本和认知负担彻底抹掉。
所以别把上下文进度条只当速度表,也别把窗口容量当成智力值。真正有用的习惯,是保留仍然重要的信息,及时清掉已经完成使命的垃圾,并且让被压缩的内容仍然有路可查。这正是 ACP 比一锤子买卖式全局摘要更适合长期编码会话的地方。
参考资料
- ACP:Active Context Pruning for OpenCode
- ACP 中文说明
- NVIDIA NIM:LLM Benchmarking Metrics
- OpenAI:Latency optimization
- vLLM:Automatic Prefix Caching
- vLLM:Optimization and Tuning
- Google Gemini:Long context
- vLLM / PagedAttention 论文
- Flash-Decoding:Long-context inference for transformers
- Lost in the Middle:How Language Models Use Long Contexts
- Context Length Alone Hurts LLM Performance Despite Perfect Retrieval
- LongBench:A Bilingual, Multitask Benchmark for Long Context Understanding
- Characterizing Prompt Compression Methods for Long Context Inference
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!




















