5.6 KiB
一次「Context Limit Exceeded」错误排查:我以为是小问题,结果踩了大坑
问题初现
那天正在和星枢(xingshu/main agent)聊天,突然蹦出来一句:
反复出现的错误
我寻思着这不就是一个 context 满了需要清一下的常规问题吗?改改配置,重启一下 gateway,应该就完事儿了。 结果证明——我太天真了。
我一开始没有多想,直接按照字面的提示去修改reserveTokensFloor的值,这个配置是在openclaw.json里的。
"compaction": {
"mode": "safeguard",
"notifyUser": true,
"postCompactionSections": ["Session Initialization", "Behavioral Rules & Constraints"],
"timeoutSeconds": 900,
"reserveTokensFloor": 24000
}
但是修改完,重启gateway之后还是不管用。
接着我又开始删掉一些 session 文件,重启 gateway,再试一次。好了没几分钟,又来了。还是在说同样的话,甚至还没开始说什么实质内容,就直接爆了。 这就很诡异了。按理说:
- session 文件删了
- 新 session 是空的
- 怎么还是瞬间 overflow?
我开始怀疑人生。
排查思路
第一步:检查 session 和 memory
先把所有 session 文件清空——几十个历史的、reset 的、deleted 的,全部删掉。然后去看 memory plugin(memory-lancedb-pro)有没有问题。结果:memory 正常注入,没问题。
第二步:看 Gateway 日志
openclaw logs 拉出来一顿看,关键信息出来了:
provider=custom-api-deepseek-reasoner/deepseek-reasoner ctx=16000
estimatedPromptTokens=393 overflowTokens=392 reserveTokens=16384
看到这行我当场就愣了—— 不知道何时默认的model被切换成了fallback 列表里的deepseek-reasoner模型。我默认使用的一直都是minimax 2.7
deepseek-reasoner 的 context window 只有 16K?
再往下看,问题更清楚了。reserveTokens=16384——这是 compaction 机制预留的 token 数。也就是说,实际能用的只有 16K - 16K = 0。
好家伙,这谁扛得住。
第三步:找到真凶
问题不在 compaction 配置,不在 memory plugin,不在 session 文件。
问题在于:星枢的 Telegram channel 绑定到了一个只有 16K context 的模型。
模型本身 context window 就小,再加上 OpenClaw 的 safeguard 模式会预留一半给 compaction,两边一夹击,prompt 还没开始就爆了。
而且这个模型配置是写在 OpenClaw 的 agent 路由规则里的,不在 openclaw.json 的全局 compaction 配置里——所以我改了 compaction 配置完全没卵用。
Fallback(回退)机制切换到次选模型?
通常有以下几种典型的“触发器”:
1. 显式的 API 服务不可用 (Service Outage)
这是最常见的情况。当你的默认模型(比如 MiniMax-M2.7)的 API 接口返回以下 HTTP 状态码时,系统会自动尝试 fallback 列表中的下一个模型:
- 503 Service Unavailable / 502 Bad Gateway: 服务商服务器宕机。
- 429 Too Many Requests: 触发了频率限制(Rate Limit),比如单位时间内 Token 消耗过快或请求次数过多。
- Connection Timeout: 你的 Gateway 访问服务商网络超时。
2. 隐性的 Token 长度溢出预判
有些智能路由(Routing Rules)会预判 Prompt 长度。
- 如果系统检测到当前 Session 加上上下文后的 Estimated Tokens 已经接近或超过了默认模型的最大 Context Window(虽然 MiniMax 有 200K,但如果配置中误写了上限),它可能会尝试寻找一个具有更高上限或不同处理逻辑的模型作为备选。
- 但在你这个案例中,反而是切到了一个更小的模型,这通常是因为路由权重配置错误。
3. 配置文件的“优先级”覆盖
在 OpenClaw 的逻辑里,配置是分层的:
- Global Config:
openclaw.json里的全局定义。 - Agent/Channel Specific Config: 针对特定 Telegram Channel 或特定 Agent 的映射规则。
- 环境变量: 有时启动脚本里的
MODEL_DEFAULT可能会覆盖配置文件。 - 误触: 在调试过程中,可能在某个路由规则里手抖把
deepseek-reasoner设为了首选,或者将其放在了数组的第一位。
4. 节点选择算法 (Balancing / Randomness)
如果你的模型列表是一个数组而非严格的优先级队列,某些负载均衡算法可能会以“随机”或“轮询”的方式分发请求。如果 DeepSeek 在列表里,它就有可能被抽中。
解决思路
根本解法是:让星枢 Telegram 用回 MiniMax-M2.7(200K context),而不是这个 deepseek-reasoner。
学到的教训
- 不要 默认认为错误信息 就是表面意思。「Context limit exceeded」不一定是因为对话太长,可能是模型配置本身就有问题。
- 两层配置要分清:全局 compaction 配置和 agent 模型配置是两码事。改全局不行,就得往 agent 级别去找。
- 日志真的有用:之前嫌麻烦不想看日志,结果被事实教育了——Gateway 日志把问题写得明明白白,只是我自己没仔细看。
- 工具/系统越复杂,问题的隐藏路径越深:OpenClaw 这种分布式 agent 系统,一个问题可能藏在七八个地方——session、memory、model config、routing rules、compaction 策略……排查的时候得逐一排除。
这件事还有个后续——我把这篇写下来,是想提醒自己,也提醒和我一样在跑自托管 OpenClaw AI agent 系统的人:
别小看任何报错,也别急着改配置。先问一句:到底哪儿出问题了?
