上下文窗口是什么?长上下文有哪些问题?
一句话回答
上下文窗口是模型一次调用能处理的 token 总数上限,输入(系统提示、工具定义、检索资料、历史消息)和输出加起来都不能超过它。窗口大不等于能用好:输入越长,成本和首 token 延迟越高,模型也更容易忽略中间部分的信息(lost in the middle)。实践中只放相关的内容,重要信息放在开头或结尾,超长时用检索、摘要或截断。
详细解析
窗口里装了什么
输入:系统提示 + 工具定义 + 检索资料 + 历史消息 + 本轮问题
输出:模型的回答(推理模型还包括思考过程)
要求:输入 + 输出 ≤ 上下文窗口
- 输入超出窗口时,多数接口直接报错;也有的服务提供自动截掉早期内容的选项
- 很多模型还单独限制最大输出长度,通常比窗口小得多。输出达到上限会被截断,响应里的结束原因会标明是长度限制
- 推理模型的思考过程也算输出 token,同样占窗口、同样计费,见 推理模型
- 多轮对话每轮都要带上历史,越聊越长,需要截断或摘要,见 多轮对话的上下文怎么管理
长上下文的代价
| 代价 | 原因 |
|---|---|
| 成本 | 输入 token 每次调用都要付费;多轮对话每轮都重发历史,累计 token 数随轮数近似平方增长 |
| 延迟 | 模型要先处理完全部输入才能输出第一个 token,输入越长首 token 越慢;注意力的计算量随长度平方增长,见 Transformer |
| 显存 | KV Cache 随长度线性增长,限制了服务端的并发能力,见 KV Cache |
| 效果 | 无关内容越多,模型越容易被干扰;中间位置的信息容易被忽略 |
固定的长前缀(比如系统提示、反复使用的同一份长文档)可以用 Prompt Caching 降低成本和首 token 延迟。
位置效应:lost in the middle
有研究把关键信息放在长上下文的不同位置测试,发现模型的表现呈 U 形:信息在开头或结尾时效果最好,在中间时明显变差。不同模型的程度不同,新模型有所改善,但"标称支持的长度"不等于"在这个长度上都能用好"。常见的"大海捞针"测试只考查能否找到一句话,比真实任务简单;需要综合多处信息的任务,效果随长度下降得更明显。
实践中的做法:
- 长文档放在前面,指令和问题放在最后,不少厂商的文档也这样建议
- 给每份资料加标签和编号(如
<doc id="3">),方便模型引用和定位 - 只放和任务相关的内容:先检索、筛选、重排,再放进上下文
- 关键约束可以在结尾简短重申一次
长上下文还是 RAG
| 直接放进长上下文 | RAG 检索后再放入 | |
|---|---|---|
| 适合 | 资料在窗口内,需要通读全文(总结、对比、找矛盾) | 知识库远超窗口,问题只涉及局部 |
| 成本 | 每次为全文付费 | 只为检索到的片段付费 |
| 延迟 | 首 token 慢 | 多一步检索,但输入短 |
| 风险 | 中间信息被忽略,干扰多 | 检索不到正确的片段就答不出 |
| 维护 | 每次传入最新资料即可 | 要维护索引和更新 |
两者可以结合:用 RAG 召回更多、更大的片段,再交给长上下文模型。文档放不进窗口时的处理方法见 文档太长放不进上下文怎么处理,RAG 的链路见 RAG 的完整链路。
代码示例
// 调用前检查预算;countTokens 用对应模型的分词器或厂商的计数接口实现
function checkBudget(messages: Message[], tools: Tool[], limits: { context: number; maxOutput: number }) {
const input = countTokens(messages) + countTokens(tools)
// 留一些余量:消息格式、角色标记本身也占 token
if (input + limits.maxOutput > limits.context * 0.95) {
throw new Error(`输入约 ${input} token,加上预留的输出会超出上下文窗口`)
}
}
const res = await llm.chat({ messages, tools, maxTokens: 2000 })
// 结束原因的字段名和取值各家不同,如 finish_reason 为 length、stop_reason 为 max_tokens
if (res.finishReason === 'length') {
// 输出被截断:提高输出上限、让模型分段输出,或者提示用户内容不完整
}
面试官可能追问
模型标称支持很长的上下文,为什么实际效果不好?
标称长度只说明能放进去,不保证每个位置都用得好。一个原因是模型在超长输入上的训练相对较少,对远距离信息的利用不如近处;另一个原因是内容越多,干扰信息也越多。应该用自己的任务和数据,在不同长度下实测。
为什么资料放得越多,回答反而越差?
相关的片段被大量无关、甚至互相矛盾的内容淹没,模型可能引用错误的片段,或者在几份资料之间摇摆。检索阶段要重视精确度:召回后用重排只保留最相关的几条,见 重排序。
上下文窗口就是模型的"记忆"吗?
不是。窗口只是单次调用时模型能看到的内容,调用结束就没了,模型本身不会记住任何对话。聊天应用里的"记得之前说过的话",是应用每次把历史重新发过去;跨会话的记忆要存在外部,按需检索后再放进窗口,见 Agent 的记忆系统。
Prompt Caching 能解决长上下文的问题吗?
只能解决一部分。它让重复的前缀不必重新计算,降低成本和首 token 延迟;但不改变窗口上限,也不能改善模型对长文本中间部分的利用。
易错点
- 窗口包括输出:输入把窗口塞满了,模型就没有空间生成回答
- 多轮对话的成本是每轮输入的累加,不是只算新增的消息
- "支持 X 长度"不代表在这个长度上的效果和短文本一样好
- 输出被截断时要检查结束原因,否则会把半截内容当成完整结果
AI 模拟面试官
用自己的话回答,AI 对照参考答案打分、指出遗漏,再追问,最多 3 轮
这道题你掌握了吗?
选一个最接近的状态,没掌握的题会出现在"我的进度 · 待复习"里。
学习记录暂存在本机浏览器。登录后自动同步到账号,换设备也能看到。