上下文窗口
模型一次能「看见」的 token 总量上限
Context Window · 上下文长度 · Context Length
- 是什么——窗口里装的到底是哪些东西。
- 关键澄清——模型是不是真的「记住」了对话。
- 为什么有限——为什么不干脆做成无限大。
- 塞满就好吗——窗口够大,把所有资料都塞进去行不行。
- 怎么应对——内容超出窗口时有哪些办法。
- 上下文窗口是单次能看见的 token 上限,装着提示+历史+检索+输出,窗口外看不见。(§1)
- 模型本身没记忆,「记得前面」是因为前面还在窗口里被重新喂入;被挤出就真忘了。(§2)
- 窗口不能无限大:标准全局注意力的平方开销、KV 缓存、硬件、位置表示与训练长度共同形成约束。(§3)
- 计算、KV 容量、有效利用和应用装配是四个不同瓶颈,声明长度不能互相替代它们。(§4)
- 就算窗口够长,塞满也不等于用好:有中间迷失、有噪声稀释。(§5)
- 应对:RAG 只放相关的、上下文工程分配预算、压缩摘要、外挂记忆。(§6)
1什么是上下文窗口:16K 数值例子直觉
模型每次生成下一个 token 时,能直接“看到”的输入总量是有限的,这个上限就是上下文窗口。窗口大小通常以 token 数表示——16K 即约一万六千个 token——它划定了单次调用中哪些信息能直接影响后续生成:只要还在窗口内,模型就可以使用;一旦滑出去,本次生成就再也无法直接用到它。
窗口里装的远不止用户刚打出的那句话,而是这一次要一起喂给模型的全部内容。具体包括:系统提示与指令(例如“你是一个客服助手……”这类规则)、对话历史(之前来回说过的每一句)、检索来的材料(RAG 捞回来的文档片段),以及模型正在生成的回答本身——输出同样占用窗口。
因此,上下文窗口可以理解为一次调用中模型能直接看到的内容预算。它接收系统规则、历史、检索证据、工具结果和输出预留,先按分词器计数,再按产品策略被接受、裁剪或压缩,最终形成一个不超过上限的布局。
当各部分组成之和超过上限时,系统必须拒绝、裁剪或压缩。若应用采用“丢掉最早内容”的策略,开头的信息会最先消失,但具体行为取决于产品实现,并非所有服务都这样做。窗口大小只表示容量上限,并不表示窗口内每个位置的信息都能被同样准确地使用。
图 1 展示了一个 16K token 窗口的预算分配与超预算重排。它强调:上下文窗口是共享预算,不是“输入最多 16K、输出永远另算”;实际计数规则因服务而异,设计时应同时核算输入、输出预留和工具往返。
用一个数值例子把这笔账算清楚:在 16K 预算里,规则 1K + 历史 7K + 证据 6K + 计划输出 4K = 18K,超出 2K。若粗暴地截掉最早的 2K,可能正好丢掉用户姓名或关键约束;更稳的方案是把历史压成 3K、只检索 4K 高价值证据,总占用 12K,留下 4K 余量给工具结果波动或更长的回答。
| 窗口里装着 | 例子 |
|---|---|
| 系统提示 / 指令 | 「你是一个客服助手…」 |
| 对话历史 | 之前来回说过的每一句 |
| 检索来的材料 | RAG 捞回来的文档片段 |
| 它正在生成的回答 | 输出也占窗口 |
2关键澄清:它不是「记忆」直觉
开头那个例子的真正原因,藏在一个常见误解里:模型是不是把对话“记住”了?答案是否定的——基础推理调用通常是无状态的。模型不会自动保留上一次请求;应用需要把相关历史、摘要或外部记忆重新放进本次输入,模型才能在这次生成中用上它们。
聊天产品可以在服务端保存会话,所以用户体验上像“记得”,但真正参与当前生成的仍是被装配进本次上下文的内容。某句话若既未保留、也未摘要或检索回来,模型本次就无从使用。
无状态可以理解为:模型每次调用都不自动保留上一次的内容。它解释了模型为何看似记得对话、却会突然失忆——所谓“记得”,其实是应用在每次调用时把相关历史、摘要或检索结果重新装进输入,再据此生成,输出只以这些内容为条件的回答。回答能提到旧信息,说明该信息本轮仍在窗口里;若既未保留也未检索回来,模型本次就不是真的记得。
这一澄清顺带解释了两件事。其一,为什么用 API 做多轮对话时,每次都要把历史一起发过去——因为模型不会自己存;其二,为什么长对话越聊越贵——历史越长,每次重发的 token 越多,而计费按 token 算。
3为什么不能无限大数学
既然窗口越大越方便,为什么厂商不干脆做成无限?最直接的约束来自注意力的计算方式。对标准全局自注意力,n 个位置会形成 n² 个注意力分数,朴素实现的相关算量和显存因此随长度呈平方增长。
平方级开销的来源是:每个位置都要与所有位置两两算注意力。它的输入是序列长度,先让每个位置与全部位置两两算分,再对这张分数表做归一化,输出的计算与显存便随长度平方增长。长度扩大十倍,位置对约扩大一百倍,代价是超线性的——每把窗口拉长一档,都要付这种代价,这正是长上下文又慢又贵的根源。
可以算一笔账:1 千 token 的输入,注意力约算 100 万对;10 万 token 就是约 100 亿对。
不过,平方开销是重要约束,但不是唯一原因。实际推理还受 KV 缓存、带宽、位置外推和训练分布影响;滑窗、稀疏注意力与高效内核可以改变复杂度或常数。因此把窗口做大的代价不能只归结为注意力平方增长,它是多种因素叠加的结果。
4注意力计算、KV 容量和有效上下文不是一回事数学系统
同样宣称支持 16K 的模型,为什么有的请求慢、有的并发一高就 OOM,还有的虽然跑完却答错?因为同一个声称长度背后藏着四种不同的限制。诊断这类问题的输入是请求长度、并发、硬件、证据位置和任务结果:先分别核算计算与读写、缓存容量、训练长度和装配,再定位真正的瓶颈,才能对四类问题给出分别判断。接口返回成功只表示输入被接收,不表示模型能有效利用整段长度,因此不能用一类指标替代另一类。
四种限制各自约束不同的东西:
KV cache 容量可以用近似式估算:B_KV ≈ 2 × L × H_KV × d_h × n × b。其中 B_KV 是单个请求的 KV cache 字节数;系数 2 表示每层同时保存 Key 和 Value;L 是层数,H_KV 是每层 KV 头数,d_h 是每个头的维度,n 是已经缓存的 token 数,b 是每个数值元素占用的字节数。这个近似式只用于估算容量,不包含模型权重、临时工作区和内存碎片。
代入一个具体配置:32 层、8 个 KV 头、头维度 128、FP16、16K token,则 2×32×8×128×16000×2 ≈ 2.10×10⁹ 字节,约 1.95 GiB/请求——这还没算模型权重、激活工作区和碎片。采用分组查询注意力、KV 量化或分页管理会改变数字,但“上下文长度同时消耗并发容量”这条关系仍在。
由此得到一个核心区分:声明窗口 ≠ 有效上下文。接口能接收某个长度,只证明输入没有被立即拒绝;要真正评估,需要按长度、证据位置、任务类型和语言画准确率曲线,并同时记录首 token 延迟、KV 占用和失败率。
| 限制 | 它约束什么 | 典型观察 | 不能由什么替代 |
|---|---|---|---|
| 注意力计算/IO | 处理长前缀的时间和中间读写 | 输入越长,首 token 越慢 | 显存放得下不代表算得快 |
| KV cache | 活跃 token 与并发请求容量 | 单请求能跑,并发后 OOM/驱逐 | FlashAttention 不会消除长期 KV |
| 位置与训练分布 | 模型是否学会在该长度取用信息 | 短文本好,长文本准确率下降 | API 接受 16K 不证明有效利用 16K |
| 应用装配 | 关键证据是否进入且摆在可用位置 | 换顺序或去噪后答案改变 | 换更长窗口不修复错误证据 |
5「塞得进」不等于「用得好」直觉工程
就算模型支持很长的窗口,把所有资料一股脑塞进去,就万事大吉了吗?并不是。长窗口有两个陷阱。
其一,中间迷失:放在上下文中段的信息,利用率明显低于放在开头和结尾的信息,模型容易“看漏”中间。其二,噪声稀释:塞进大量无关内容会稀释注意力、混入噪声,反而让回答变差。
由此可以定义有效上下文——模型在当前任务里真正能取用并用对的信息。它的输入是候选材料及其顺序:先由注意力从大量内容中挑线索,再据此作答,输出带证据的答案。同一份材料放在开头、结尾还是中段会明显改变结果,说明位置和噪声都在起作用;而一次答对并不表示整段窗口都被可靠使用。
一句话概括:长上下文是一种能力,不是“无脑往里塞”的许可。放什么、放多少、放在哪,比“能放多少”更影响效果——关键材料尽量放在开头或结尾。
6怎么应对窗口限制工程
当要处理的内容超过窗口,或长对话开始失忆,可以用一组方法做窗口治理。窗口治理是在内容超预算时决定保留、检索、压缩和排序的一套方法:它的输入是超预算材料、任务目标和失败代价,先保护不可丢的规则与当前任务,再检索高价值证据、压缩可恢复历史并留出输出余量,最终产出一份可用的窗口布局。答案质量、证据覆盖和成本一起变好,才表示治理有效;同时要清楚其边界——摘要可能漏细节,检索可能漏召回。
具体手段有四种,彼此互补。
只放相关的(RAG):不把整个知识库塞进去,而是检索出与当前问题最相关的少量片段再喂给模型。它把“装不装得下”的问题转成“该装哪几条”的问题。
精心分配预算(上下文工程):决定每次调用窗口里到底放什么、按什么顺序,这比雕琢单条提示更上层,是对整份上下文布局的设计。
压缩与摘要:把过长的历史压缩成摘要再带上,腾出窗口给当前任务和新证据。
外挂记忆:让 Agent 把装不下的信息存到外部、需要时再取回,用存储换取窗口空间。
7把整条因果链连起来综合
把前面各步串起来,就是从一次调用的共享预算,推到无状态、计算代价、有效利用与外部记忆的一条因果链。
上下文窗口是单次能看见的 token 上限,装着提示、历史、检索材料和输出,窗口外的内容看不见。模型本身没有记忆,“记得前面”只是因为前面还留在窗口里、被应用重新喂了进来;一旦被挤出窗口,就真的忘了。
窗口不能无限大:标准全局注意力的平方开销、KV 缓存、硬件、位置表示与训练长度共同形成约束。进一步看,计算、KV 容量、有效利用和应用装配是四个不同的瓶颈,声明长度不能互相替代它们。
就算窗口够长,塞满也不等于用好:中间迷失和噪声稀释都会让长上下文“看着能装、实际用不上”。应对手段因此分四路:RAG 只放相关的片段、上下文工程分配预算、压缩摘要腾出空间、外挂记忆把装不下的内容放到外部按需取回。
这条链回答了两个关键问题:模型为什么其实没有记忆、却像记得对话——因为历史一直被重新装配进窗口;窗口为什么不能无限大、以及塞满为什么不等于用好——因为平方开销等约束限制了容量,而位置与噪声限制了利用。
8概念依赖与延伸学习路线
学习本页前,需要先掌握 Token 与分词、注意力机制和大语言模型的基本概念——知道 token 如何计数,注意力如何两两计算,模型如何按上下文逐 token 生成,才能真正理解窗口上限的由来。
本页的核心概念是 token 预算、无记忆、平方级开销、中间迷失,以及“塞满 ≠ 用好”。
紧邻的延伸概念包括:中间迷失、RAG、上下文工程、上下文压缩和 Agent 记忆——它们是本节应对手段的展开,彼此直接衔接。更远一些的延伸是推理优化、提示缓存和思维链,讨论如何让长上下文推理在工程和效果上更进一步。
| 学习层级 | 涉及概念 |
|---|---|
| 先修 | Token 与分词、注意力机制、大语言模型 |
| 本页核心 | token 预算、无记忆、平方级开销、中间迷失、塞满≠用好 |
| 紧邻延伸 | 中间迷失、RAG、上下文工程、上下文压缩、Agent 记忆 |
| 更远 | 推理优化、提示缓存、思维链 |
- Vaswani et al., Attention Is All You Need:标准自注意力的序列长度复杂度。
- Liu et al., Lost in the Middle:长上下文信息位置对任务表现的影响。
- Dao et al., FlashAttention:精确注意力的内存访问瓶颈与优化边界。
- Bai et al., LongBench:跨任务、跨语言的长上下文理解评测。