aider Token 限制报错全解:上下文窗口与输出上限的成因、诊断与缓解方案
本篇技术指南聚焦开源终端 AI 结对编程工具 aider 在使用中频繁遇到的 token limit(Token 上限)报错,系统梳理"上下文窗口"与"单次输出 token 上限"两类限制的区别与触发场景,并结合 aider 的实际源码讲解 /tokens、/drop、/clear 等诊断命令与"无限输出"机制的底层原理。读完你将能够读懂报错信息中每一项数字的含义、精确判断是哪一类限制被触达,并用一套可复现的操作步骤把超限问题降到最低。
先分清两类 Token 限制
任何 LLM 对单次请求都有处理能力边界,aider 的报错通常对应其中两类约束:
- 上下文窗口(context window):限制模型在单次请求内"输入 + 输出"的 token 总量。一次对话中系统提示词、仓库地图、历史聊天记录、加入会话的源文件、你的新指令,再加上模型生成的内容,全部共享这一个窗口。
- 输出 token 上限(output token limit):单独限制模型一次响应最多能生成的 token 数。多数模型这一项很小,常见只有 4k 左右,却恰恰是最容易被忽略的瓶颈。
从源码结构看,aider 在 base_coder.py 与 base_coder.py 中分别处理"发送前预检"与"响应后归因"两条路径,两类限制最终都会以明确的建议列表呈现给用户。
读懂一次完整的 Token 限制报错
文档中给出的经典报错长这样:
Model gpt-3.5-turbo has hit a token limit!
Input tokens: 768 of 16385
Output tokens: 4096 of 4096 -- exceeded output limit!
Total tokens: 4864 of 16385
To reduce output tokens:
- Ask for smaller changes in each request.
- Break your code into smaller source files.
- Try using a stronger model like DeepSeek V3 or Sonnet that can return diffs.
For more info: https://aider.chat/docs/token-limits.html
逐行解读关键信息:
| 字段 | 含义 | 判断要点 |
|---|---|---|
Input tokens: 768 of 16385 |
本次请求估算输入 768 tokens,模型上下文窗口 16385 | 输入远未触顶,问题不在输入侧 |
Output tokens: 4096 of 4096 -- exceeded output limit! |
输出已用满 4096,触达该模型输出上限 | exceeded output limit! 是本次失败的直接归因 |
Total tokens: 4864 of 16385 |
总用量仍远低于窗口 | 证明"窗口够大,输出不够用"这一典型场景 |
需要注意报错中出现的 -- possibly exceeded output limit! 等后缀,来自 aider 自己的近似归因逻辑:当某类 token 用量达到模型上限的 70%(源码中的 fudge = 0.7) 时,base_coder.py 才会把对应类别标记为"可能超限"。换句话说:
aider 本身从不执行、也不强制 token 上限。 它只负责两件事:一是在发送前用估算做预警(见下文
check_tokens),二是把 API 提供方返回的超限错误翻译成可操作的建议。报错里出现的所有 token 数字都是估算值,并非服务端精确计数。
真正的硬性判据来自两条路径:发送请求时若 API 返回 ContextWindowExceededError,base_coder.py 会置 exhausted 标志;而响应因触达输出上限被截断时,会抛出 FinishReasonLength 异常,base_coder.py 捕获后按输出超限处理——这正是下方"无限输出"机制介入的入口。
输入 Token 与上下文窗口耗尽:最常见的超限场景
为什么会耗尽的窗口
把过大的输入塞给模型是最常见的触发方式。虽然技术上存在"输入单方超限"与"输入加输出合起来超限"两种情况,但像 GPT-4o、Sonnet 这类强模型通常拥有很大的上下文窗口,真正在窗口上栽跟头的多是较弱模型。会话中占据输入的主要是这几块(后续 /tokens 会逐项列出):
- system messages:aider 注入的系统提示与提醒;
- chat history:历史聊天与上一次编辑的内容;
- repository map:仓库地图;
- 加入会话的源文件(含 read-only 文件):aider 会读取其完整内容并拼入请求。
最直接的缓解:只加入"需要被编辑"的文件
原则只有一条——只把 aider 为了完成你的请求而必须编辑的文件加入会话。浏览参考用的文件与可写文件都挤占输入预算,建议按需用以下命令做减法:
/tokens:查看当前会话各项的 token 占用明细(详见下文);/drop:把不再需要的文件移出会话。对应 commands.py 的cmd_drop,若配合仓库地图还会触发其重建;/clear:清空全部聊天历史,对应 commands.py 的cmd_clear,实现上是将done_messages与cur_messages全部置空;- 把过大的代码拆分成更小的源文件,从源头降低单文件体积。
/reset(commands.py)则是一条更强的命令:丢弃所有文件并清空聊天历史,相当于 /drop 加 /clear 的组合。
发送前的主动预警:check_tokens
在真正把请求发出去之前,aider 会调用 base_coder.py 中的 check_tokens:它先用 token_count 估算本次全部消息的输入 token,一旦超过 max_input_tokens,就会打印 Your estimated chat context of X tokens exceeds the Y token limit for model!,逐条提示你使用 /drop、/clear 与拆小文件,然后询问 Try to proceed anyway?——即便你选择继续,多数提供方在超限时也不会扣费,这个预检主要是帮你避免无谓失败。
用 /tokens 精确诊断会话占用
当你想知道"到底是谁吃掉了窗口",运行 /tokens。其实现位于 commands.py,会按类别输出一张表格,报告格式大致如下:
Approximate context window usage for <model>, in tokens:
$0.0000 9,765 system messages
$0.0000 121,418 chat history use /clear to clear
$0.0000 7,713 repository map use --map-tokens to resize
$0.0000 22,101 path/to/file.py /drop to remove
==================================
$0.0000 160,997 tokens total
xxx,xxx tokens remaining in context window
200,000 tokens max context window size
各类别与对应建议一一映射:
- system messages:模型与提示词固定开销;
- chat history(提示
use /clear to clear):历史越积越长的主因,/clear最有效; - repository map(提示
use --map-tokens to resize):由--map-tokens启动项控制分配额度; - 每个会话文件(提示
/drop to remove):文本文件按内容估算;图片会走token_count_for_image(commands.py)按图像尺寸估算。read-only 文件会额外标注(read-only)。
命令还会结合模型的 input_cost_per_token 折算每类占用对应的美元成本,并在底部对比"剩余 token"与"最大窗口"。当剩余不足 1024 tokens 时,aider 会用醒目的 error 输出催促你 /drop 或 /clear 腾出空间(commands.py)。该命令有对应测试用例覆盖:测试中先 cmd_add("foo.txt bar.txt") 再加入文件,随后断言 /tokens 输出包含两个文件名,见 test_commands.py。
输出 Token 上限:改得多,吐不下
多数模型的输出上限低至 4k tokens 左右。当你要求一次改动波及大片代码时,模型要把所有变更一次性吐回来,极易顶穿输出上限——这正是示例报错 Output tokens: 4096 of 4096 -- exceeded output limit! 所描述的情况,此时窗口还很充裕,纯粹是"输出嘴小"。
要降低撞上输出上限的概率:
- 每次请求只要求更小范围的改动,把大重构拆成多轮小步;
- 把代码拆成更小的源文件,让单次需要重写的文本量下降;
- 换用能返回 diff 的强模型(如 GPT-4o、Sonnet、DeepSeek V3):diff 格式只回传变更片段,显著压缩输出体积。aider 在报错归因时甚至会检查当前模型的
edit_format中是否含diff,没有才会追加"建议换用能返回 diff 的模型"这条提示(base_coder.py); - 换用支持"无限输出"的模型,让大改动可以跨多次请求续写。
无限输出:把一次吐不完变成续写接龙
对支持 assistant prefill(预填) 的模型,aider 提供"无限输出"能力,原理可参考 无限输出指南:预填允许你给模型"嘴里塞话",让它从指定文本继续生成。当 aider 收集代码编辑时撞上输出上限并抛出 FinishReasonLength,若模型元数据中标明 supports_assistant_prefill,aider 不会直接放弃,而是把已生成的部分内容作为前缀发起新一轮请求,让模型接着写(base_coder.py)。这一"续写"可反复进行,再拼接跨边界文本,从而支撑超长输出。
启动时若主模型支持该能力,aider 会在公告行明确展示:
Aider v0.58.0
Main model: claude-3-5-sonnet-20240620 with diff edit format, prompt cache, infinite output
其他成因:代理服务与本地模型的服务端缺陷
并非所有超限都源于你的会话太大。有时问题出在不合规的 API 代理服务器,或你自建本地模型所挂载的 API 服务端本身存在 bug——例如服务端未按标准语义上报用量、过早截断响应等。此时无论如何精简会话都可能反复触发。
排查建议:直接绕开代理、改用 aider 官方充分验证过的云 LLM 提供方 API;若在跑本地模型,Ollama 集成说明 明确 Ollama 与 aider 协作良好,可作为首选。切到直连后若超限问题消失,基本可以断定根因在代理链路。
给"aider 不认识的模型"登记正确的上限
aider 依赖模型元数据里的 max_input_tokens / max_output_tokens / max_tokens 来画预检红线与生成报错文案。对模型库中尚未收录的自定义模型,你可以在以下任一位置创建 .aider.model.metadata.json 手动登记上下文窗口与成本(详见 高级模型设置):
- 主目录;
- git 仓库根目录;
- 启动 aider 的当前目录;
- 或用
--model-metadata-file <filename>显式指定。
JSON 以模型名为键,形如:
{
"deepseek/deepseek-chat": {
"max_tokens": 4096,
"max_input_tokens": 32000,
"max_output_tokens": 4096,
"input_cost_per_token": 0.00000014,
"output_cost_per_token": 0.00000028
}
}
多个位置的同名文件会按上述顺序加载、后加载者优先。文件加载逻辑见 models.py:读取元数据后,max_input_tokens 等字段会进入 info,同时 aider 还会把"最大聊天历史"预算裁成输入窗口的 1/16 并夹在 1024 到 8192 之间(models.py),用以控制历史消息的截断策略。这些字段正是 /tokens 底部 tokens max context window size 与 check_tokens 预检所依赖的数据源。不过要重申:绝大多数场景下你无需为此操心,默认值即可正常工作。
速查清单:面对 Token 报错按序处理
- 先看
-- exceeded output limit!还是-- exhausted context window!:前者走输出侧解法,后者走输入侧解法; - 运行
/tokens,确认哪一项占比最大:历史太多就/clear,文件太多就/drop,仓库地图过大就用--map-tokens收紧; - 只保留"本次需要编辑"的文件,把大文件拆小、把大需求拆成小步;
- 若输出侧频繁触顶:换 diff 编辑格式的强模型,或改用支持 prefill、公告行带
infinite output的模型; - 若问题依旧:怀疑代理或本地模型服务端异常,先直连云 API / 换 Ollama 对照测试;
- 若使用的是自建/小众模型:用
.aider.model.metadata.json为它登记真实的上限与成本,让预检与诊断数据恢复准确。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00