先记住这个答案
上下文窗口定义了大模型在一次生成中可访问的工作内存,通常以 token 为单位。它不只是输入限制,输出 token 同样从窗口扣除。一次请求消耗的总量包括系统提示、每轮消息、工具定义、图片和文档,以及本回合生成的文本。当输入本身超过窗口大小时,API 会返回错误;当输入与预计输出之和超出时,新模型可能接受请求但会在生成到窗口上限时以特殊 stop_reason 停止。理解这一机制才能设计多轮对话和长文档处理。
- 上下文窗口是所有输入加输出的总预算
- 长输入会引发上下文腐烂降低准确率
- 溢出行为需区分输入超限与生成截断
计数规则:输入与输出共享窗口
假设模型声明的上下文窗口是 200k token。发送一次请求时,系统提示词、已有多轮对话、工具定义和当前用户消息全部被换算成 token 并预先占用窗口。例如一个包含 3k 系统提示和 150k 历史对话的请求,其输入大小可能已达 153k token,剩余可用空间仅 47k。
真正的动态在生成阶段:模型每次输出新 token 都会在窗口内追加计算,直到用完剩余额度或产生停止标记。部分新模型允许输入加上 max_tokens 超过窗口,但生成到窗口上限时会被强制中断并给出模型上下文超出标志,使用者必须检查 stop_reason 才能感知截断。
// 仅用于理解预算逻辑,非API调用
function budgetCheck(inputTokens, maxOutputTokens, windowTokens) {
const totalBudget = inputTokens + maxOutputTokens;
if (inputTokens > windowTokens) {
return `输入超限:${inputTokens} > ${windowTokens}`;
}
if (totalBudget > windowTokens) {
const actualOutput = windowTokens - inputTokens;
return `生成将被截断:最多输出 ${actualOutput} token`;
}
return `预算正常:预计总耗 ${totalBudget}/${windowTokens}`;
}
console.log(budgetCheck(180000, 30000, 200000));
console.log(budgetCheck(210000, 10000, 200000));
console.log(budgetCheck(150000, 40000, 200000));查看输出与解释
生成将被截断:最多输出 20000 token
输入超限:210000 > 200000
预算正常:预计总耗 190000/200000该 JS 函数模拟上下文窗口预算判断,输出三条边界示例。实际请求消耗还受每轮准确 token 计算影响。
长对话逼近窗口的实际处理
某客服机器人使用 200k 窗口,用户每轮平均 2k token,系统提示占 5k。当对话进行到第 85 轮时,历史消息累计约 170k token,加上本用户消息约 1k,输入达到 176k。应用要求回答长度上限为 8k token,此时输入加预计输出为 184k,仍在窗口内,可正常完成。
但当对话继续到第 95 轮,历史约 190k,输入已达 195k(含最新消息),若继续申请 8k 输出则超限。工程上方案是提前对话压缩:保留前几轮摘要和最近 10 轮完整消息,将输入降回 60k 以下。若不做任何处理,API 会返回输入过长错误或生成截断,用户体验明显受损。
function conversationTokens(historyTokens, systemTokens=5000) {
return systemTokens + historyTokens;
}
const historyFull = 190000;
const historyTrimmed = 55000;
const outputLimit = 8000;
const windowSize = 200000;
function outcome(input, maxOut) {
if (input > windowSize) return '输入超限';
return input + maxOut > windowSize ? '生成截断' : '可完成';
}
console.log('压缩前', outcome(conversationTokens(historyFull), outputLimit));
console.log('压缩后', outcome(conversationTokens(historyTrimmed), outputLimit));查看输出与解释
压缩前 生成截断
压缩后 可完成展示对话摘要压缩如何将总耗降到窗口内;实际历史 token 由 tokenizer 计算。
精度衰减与溢出行为的分界
当输入 token 数增多后,模型在中间位置的内容召回率会下降,这种现象在长上下文里被称作上下文腐烂。例如把 150k token 的会议记录全部塞进窗口,位于中段的结论比开头或结尾更可能被忽略。窗口大不意味着模型能同等利用全部内容,相关研究反复证实位置偏差。
因此工程上的判断标准是:只有信息密集且需要精确引用时才保留原文;跨长文本的大型任务更依赖拆分为检索片段再注入上下文。此外,输入单独超过窗口上限时所有模型都会报出“prompt is too long”错误;当输入未超限但输入与 max_tokens 之和超过窗口时,较旧模型会返回验证错误,而较新模型接受请求但在生成到窗口上限时以特殊停止原因结束,这要求调用方读取 usage 和 stop_reason 字段做容错。
容易答错的地方
- 上下文窗口只约束输入
- 典型的错误是只计算提示词和历史的 token 数,却忽略模型输出也占用窗口。实际生成会被预算上限截断,导致答案不完整。纠正方法是用 API 返回的 usage 总 token 判断。
- 窗口越大越值得塞信息
- 错误地认为把全部资料塞进 1M token 窗口就万事大吉。过长的无序上下文会导致关键信息被忽略或混淆,准确率反而下降。正确做法是优先级排序,只保留与当前任务最相关的片段。
面试官还会怎么问?
如何在上送前准确估算请求消耗的 token 数?
最可靠的是调用厂商的 token 计数 API,它按实际模型的分词规则计算。粗略估算会因语言和空白字符偏差较大,双字节语言尤其容易低估。对于多轮对话,还要把历史轮次与当前消息、系统提示、工具定义一起传入。
max_tokens 参数与上下文窗口关系是什么?
max_tokens 仅限定单次生成的最大输出 token 数,而上下文窗口是输入和输出共享的总剩余空间。若输入已经很大,即使 max_tokens 设得足够大,模型也会在触达窗口上限时被迫截断。
上下文窗口耗尽后有哪些补救策略?
常用做法包括历史摘要压缩、丢弃无关早期轮次、把中间结果转存到外部存储后在需要时检索。新一些的 API 提供服务端自动压缩,但会丢失细节,不适合要求精确回忆的场景。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。