Context Length Exceeded上下文窗口TokenAI API上下文压缩AI Agent

Context Length Exceeded 怎么解决:上下文超限与裁剪策略

AI API 提示 context length exceeded?本文解释输入、输出、工具结果和图片如何占用上下文,并给出 Token 预估、消息裁剪、摘要、RAG 与 Agent 压缩方案。

Context Length Exceeded 怎么解决:上下文超限与裁剪策略

AI API 上下文超限与裁剪策略

context length exceededmaximum context lengthprompt is too longinput token limit exceeded 看起来像不同报错,本质上都表示:本次请求需要放进模型上下文窗口的内容,超过了当前模型或接口允许的容量。

最直接的解决办法不是无限调大 max_tokens。你需要先弄清:

输入消息
+ 系统提示
+ 工具定义
+ 工具调用与结果
+ 图片 / 文档
+ 历史回复
+ 为本轮输出预留的空间
≤ 可用上下文窗口

本文给出一套从快速止血到生产级上下文管理的完整方案,适用于聊天应用、RAG、OpenAI 兼容 API 和长时间运行的编程 Agent。

上下文窗口到底包含什么

系统提示、历史、工具和输出共同占用上下文窗口

上下文窗口不是“用户输入框最多能放多少字”。模型在一次推理中需要看到的所有内容都会占用预算:

内容常见来源
System / Developer 指令产品规则、角色设定、安全要求
用户消息当前问题和历史问题
助手消息之前的回答、推理项目或状态
工具定义JSON Schema、MCP 工具说明、函数参数
工具调用与结果搜索结果、终端日志、文件内容、API 响应
检索内容RAG 文档片段、引用与元数据
多模态输入图片、PDF、音频或视频表示
输出预留本轮答案、工具参数或推理预算

因此,一个只有十个对话回合的 Agent,也可能因为读取了大型日志、几十个文件和复杂工具 Schema 而超限。

上下文窗口不等于最大输出

假设一个模型的上下文上限是 W,本次输入占用 I,希望保留的最大输出为 O,还应留出安全余量 S

I + O + S ≤ W

如果把输出上限从 2,000 调到 8,000,而输入已经接近窗口边界,错误反而更容易发生。不同 API 对输入与输出上限的计算方式可能不同,应以当前模型文档和实际错误响应为准。

为什么明明没输入很多字也会超限

工具定义每轮都会占空间

Agent 可能向模型发送几十个工具及其完整 JSON Schema。参数说明越长、嵌套越深,固定开销越高。即使本轮没有调用某个工具,它的定义也可能进入上下文。

工具输出比聊天记录更容易膨胀

常见高风险内容包括:

  • 完整构建日志;
  • node_modules 或依赖锁文件;
  • 大型 JSON 响应;
  • 数据库查询结果;
  • Base64 图片;
  • 重复读取的同一文件;
  • 搜索结果中大量相似片段。

Token 不等于字符数

英文、中文、代码、JSON 和随机字符串的 Token 比例不同。不能用固定的“一个 Token 等于四个字符”作为硬性判断。模型、Tokenizer 和多模态计费方式也可能不同。

服务商的实际限制可能更小

第三方网关可能:

  • 为同名模型配置较小的上下文;
  • 限制单次输入 Token;
  • 对输出另设上限;
  • 在路由到备用模型时改变容量;
  • 对图片、缓存或工具使用不同计算方式。

不要只看模型营销页。应核对当前 Model ID、Provider 文档和错误响应中的实际限制。

先做这五步快速止血

1. 减少本轮输入

删除无关历史、重复文档、完整日志和不必要附件。只保留解决当前任务需要的内容。

2. 降低输出预留

如果客户端允许,先把最大输出设置为合理值。例如需要简短分类结果时,不要预留数万 Token。

3. 新建会话

当旧对话已经累积大量无关分支时,新会话通常比继续修补更可靠。先生成一份任务交接摘要,再把摘要和必要文件带入新会话。

4. 使用更大且经过确认的上下文模型

切换模型前确认:

  • API 中准确的 Model ID;
  • 输入和输出限制;
  • 工具调用是否兼容;
  • 长上下文是否需要特定请求头或方案;
  • 第三方网关是否真正提供相同容量。

5. 关闭暂时不需要的工具和附件

为当前任务只提供必要工具。图片、PDF、网页快照和大型工具 Schema 都可能显著增加上下文。

如何在请求前估算 Token

最可靠的方法是使用 Provider 的 Token Counting API 或与目标模型匹配的官方 Tokenizer。不要等请求失败后才处理。

生产代码可建立预算器:

const budget = {
  contextWindow: model.contextWindow,
  reserveOutput: requestedOutput,
  safetyMargin: Math.ceil(model.contextWindow * 0.05),
};

const maxInput =
  budget.contextWindow -
  budget.reserveOutput -
  budget.safetyMargin;

if (estimatedInputTokens > maxInput) {
  // compact, retrieve less, or reject before calling the model
}

安全余量用于覆盖消息包装、工具 Schema、Tokenizer 差异和服务端附加内容。不要把窗口用到理论上的最后一个 Token。

记录分项预算

不要只记录总 Token。至少拆分为:

system_tokens
tool_schema_tokens
history_tokens
retrieval_tokens
current_input_tokens
reserved_output_tokens

分项数据能直接告诉你应该裁剪聊天历史、工具还是 RAG 文档。

消息裁剪:不要简单删除最旧消息

从原始历史到摘要、近期消息和关键事实的分层压缩

最简单的滑动窗口会删除最旧消息,但可能同时删除:

  • 用户最初目标;
  • 已确认约束;
  • 关键错误原因;
  • 工具调用与工具结果的配对;
  • 尚未完成的计划。

更稳健的方法是分层保留:

固定保留:系统规则、用户目标、安全约束
结构化状态:已完成事项、待办、关键决定、文件列表
压缩历史:较早对话的事实摘要
原始近期消息:最近若干轮
按需检索:旧日志、文件和文档

保持消息语义完整

裁剪时不要留下孤立的工具结果,也不要删除工具调用却保留对应结果。某些协议要求严格的消息顺序;破坏配对可能从“上下文过长”变成“请求格式无效”。

摘要应保留事实,而不是文风

好的任务摘要包含:

  • 当前目标;
  • 已确认约束;
  • 已做决定及原因;
  • 重要路径、对象 ID 与错误码;
  • 已完成和下一步;
  • 仍未解决的问题。

不要把长对话机械压缩成一段模糊叙述。结构化摘要更容易验证,也更适合再次压缩。

RAG:只检索真正需要的片段

把整个知识库、手册或代码仓库塞进 Prompt 既昂贵又容易超限。RAG 应控制:

  • top_k
  • 单片段长度;
  • 总检索 Token;
  • 相似内容去重;
  • 元数据和引用开销;
  • 当前问题与片段的相关性阈值。

一种实用流程是:

  1. 先检索少量高相关片段;
  2. 对结果去重并按文档分组;
  3. 必要时二次重排;
  4. 只发送能支持答案的段落;
  5. 缺少证据时再扩大检索,而不是一开始就取大量内容。

长上下文不是替代检索质量的理由。无关内容越多,模型找到关键事实的难度也可能增加。

编程 Agent 如何控制上下文

文件先搜索,再读取局部

不要默认读取整个仓库。推荐顺序:

搜索文件名或符号
→ 读取命中位置附近
→ 确认相关后扩大范围
→ 修改后只返回差异和验证结果

截断并摘要终端输出

对测试和构建日志保留:

  • 退出码;
  • 首个关键错误;
  • 相关堆栈;
  • 失败测试名;
  • 必要的前后文。

成功日志通常只需命令、退出码和摘要,不需要把数千行构建产物再次发送给模型。

对工具结果设置硬上限

工具层应支持:

max_bytes
max_lines
pagination
field selection
server-side filtering

超出上限时返回“内容已截断”以及继续读取的方法,而不是静默丢失尾部。

将长期状态放在上下文之外

任务数据库、工作区文件、向量库和可查询日志比无限增长的聊天历史更适合保存长期状态。模型需要时再检索相关部分。

OpenAI、Claude 与 Gemini 的上下文管理差异

OpenAI

对话可以由客户端手动重放,也可以使用 Responses API 的会话状态能力。官方同时提供 compaction 和 token counting 相关功能。无论由谁保存状态,进入下一轮模型上下文的内容仍受窗口限制;引用前一响应不代表历史免费或无限。

Claude

Claude 文档明确说明,长会话和 Agent 工作流最终会接近上下文限制,并将 server-side compaction 作为主要管理策略。工具使用、扩展思考和历史内容都需要按当前模型规则计入或管理。

Gemini

Gemini 支持长上下文,但官方仍建议理解输入 Token、模型限制和长上下文性能。大窗口不代表应发送所有内容;缓存、文件处理和检索策略仍然影响延迟、成本与答案质量。

跨 Provider 应建立统一的业务预算,再由适配层映射各自 Token 计数、会话状态和压缩功能。

常见错误做法

只调大 max_tokens

这通常增加输出预留,不能减少已有输入。应先确认错误描述和参数语义。

每次请求重发全部历史

实现简单,但成本和上下文会线性增长。应引入摘要、滑动窗口或服务端会话压缩。

超限后随机删除消息

这会破坏目标、工具配对和关键约束。裁剪策略必须可预测、可测试。

只换一个“更大上下文”的模型

若应用继续无限积累日志和文件,新窗口迟早也会用完,且调用成本和延迟可能显著增加。

自动重试完全相同的请求

上下文超限是确定性配置问题。原样重试不会缩短输入,只会浪费时间和请求额度。

一套生产级处理流程

请求前计数、裁剪、检索、压缩与重试流程

1. 请求前估算输入和输出预算
2. 超过软阈值时先压缩历史与工具结果
3. 限制 RAG 总 Token 和工具输出
4. 保留目标、约束、决定及工具配对
5. 再次计数
6. 仍超限则切分任务或新建会话
7. 最后才考虑切换更大上下文模型
8. 记录压缩前后 Token 与被删除内容类型

建议设置两个阈值:

  • 软阈值:例如窗口的一定比例,触发预防性压缩;
  • 硬阈值:超过后拒绝发送,避免 API 返回错误。

比例需要根据模型、输出需求和业务风险测试,不应把某个固定百分比当成所有模型的标准。

通过 Nbility 处理上下文超限

Nbility 模型广场复制准确 Model ID,并核对当前模型的上下文和输出限制。OpenAI 兼容客户端通常使用:

https://api.nbility.ai/v1

出现上下文错误时,提交工单前准备脱敏信息:

Model ID
API 路径
错误 code 和 message
输入 Token 估算
输出上限参数
是否包含工具、图片或文档
是否经过第三方客户端
请求 ID 与发生时间

可通过 Nbility 工单提交。不要附带真实 API Key、完整 Prompt 或敏感文件。

如果错误同时涉及状态码或 Endpoint,可参考 AI API 错误排查指南;若模型返回成功但正文为空,可阅读 AI API 返回空内容排查

FAQ

context length exceeded 是输入太长还是输出太长?

两者都可能影响总预算。检查错误信息、输入 Token、输出预留和模型对两者的独立限制。

换成更大上下文模型就能彻底解决吗?

不能。它只能推迟超限。没有裁剪、摘要和工具输出控制的长会话仍会继续增长。

可以直接删除最早的消息吗?

可以作为简单滑动窗口,但应保留用户目标、系统约束、关键决定及工具调用配对。重要历史更适合先摘要。

为什么图片或 PDF 很快占满上下文?

多模态输入会按 Provider 规则转换并计入输入预算,页数、分辨率和处理方式都可能影响 Token。应只发送必要页面或区域。

Prompt Cache 能扩大上下文窗口吗?

通常不能。缓存主要减少重复输入的延迟或费用;内容仍需符合模型上下文限制。以 Provider 当前文档为准。

总结

解决 Context Length Exceeded 的核心不是盲目增加参数,而是管理预算:

  1. 计算系统提示、历史、工具、检索和输出的总占用;
  2. 在请求前计数并保留安全余量;
  3. 分层保留目标、结构化状态、摘要和近期消息;
  4. 限制 RAG 片段与工具输出;
  5. 对长 Agent 任务使用压缩、新会话和外部状态;
  6. 只有在需求确实需要时才切换更大上下文模型。

上下文是一种有限资源。把它当作可观测、可分配、可压缩的预算,才能让聊天、RAG 和 Agent 在长任务中保持稳定。

参考资料

相关文章

用 Nbility 跑通你的 Agent 工作流

获取 API Key,统一接入 OpenAI 兼容模型和开发工具。

管理 API Key