1. 处理时机
OpenClaw 的“上下文处理”不是只在对话开始时做一次,也不是只在超限时报错才处理。
更准确地说:
它是“每一轮开始都要重新组装一次当前可用上下文”,而在运行中如果发现上下文太大、结构不合法、工具结果太长,就会进入额外的修复、压缩、截断、重试分支。
所以它不是一个静态固定流程,而是一个运行时流程。
2. 一轮开始时,上下文到底包括什么
2.1 会话历史层
就是 session transcript 里的历史消息,主要包括:
user 消息 assistant 消息 tool call / tool result compaction summary 部分 custom entry
这部分是“跨轮持久化”的。
2.2 system prompt 控制层
这是每轮都重新拼出来的控制说明,不是历史消息本身,但每轮都会参与模型输入。
典型内容包括:
产品身份和行为规则 当前工具列表 sandbox / workspace 信息 skills 目录摘要 bootstrap/context files 当前时间、时区、channel 能力 docs 路径、runtime 信息
这部分的入口在 buildEmbeddedSystemPrompt(...)。
2.3 本轮临时注入层
这一层只服务当前 prompt,不一定进入长期 transcript,例如:
hook prepend 的临时上下文 当前 prompt 中引用的图片 context engine 给的 systemPromptAddition
2.4 运行时恢复与诊断层
这层不一定直接喂给模型,但会影响后续决策:
context window 大小 overflow 判断 当前 attempt 是否已经 auto-compaction pre-compaction snapshot prompt error tool result 是否超大
它更像“控制面”,不是“正文内容”。
3. 这套检测是每轮都做,还是只在特定时刻做
需要分两种情况讨论
3.1 每轮开始都会做的
每次 runEmbeddedAttempt(...) 开始,都会重新做这些事:
打开 session file 修复损坏 transcript 组装 system prompt 清洗历史消息 校验历史结构 限制历史轮数 修复 tooluse / toolresult 配对 让 context engine 再装配一次 给 agent 安装 tool result context guard 最后才真正调用模型
所以“上下文检测”不是只看一次,而是每轮调用模型前都重新过一遍。
3.2 只在特定条件下才会做的
这些不是每轮必走,而是触发式:
contextEngine.bootstrap(...)
条件:已有 session file,而且 engine 实现了 bootstrap
prompt 图片检测
条件:当前 prompt 里看起来有图片引用
compaction wait
条件:本轮运行中出现 auto-compaction 事件
显式 contextEngine.compact(...)
条件:attempt 结束后判断像 context overflow,且本轮没先 auto-compact 成功收敛
tool result truncation
条件:overflow 后,检测到 session 里存在超大 tool result
所以系统既有“每轮固定动作”,也有“按条件触发动作”。
4. 一轮的主流程,按时序讲清楚
阶段 0:外层 run 先定边界
入口在 run.ts。
外层先确定:
provider / model auth profile context window 大小 这个模型窗口是否太小 允许最多重试多少次 用哪个 context engine
阶段 1:attempt 打开会话并做物理修复
入口在 run/attempt.ts。
先做:
repairSessionFileIfNeeded(...) 打开 SessionManager guardSessionManager(...)
这一步解决的是最底层问题:
文件坏没坏 transcript 能不能读 工具消息能不能写入
阶段 2:构建 system prompt
在真正送 prompt 前,先把控制面重新拼出来。
这里会收集:
skills prompt bootstrap/context files workspace notes tool summaries sandbox info runtime info owner / channel / TTS / docs 等
注意:
system prompt 不是从历史里抽出来的,而是每轮根据当前环境重新生成的。
阶段 3:清洗历史 transcript
在模型看到历史之前,OpenClaw 会先做标准化处理:
sanitizeSessionHistory(...) provider 相关校验 limitHistoryTurns(...) sanitizeToolUseResultPairing(...)
这一步的目的不是压缩,而是先把历史变成“结构合法、可继续使用”的状态。
阶段 4:让 context engine 做最后装配
contextEngine.assemble(...)
当前默认 legacy 实现其实几乎是 pass-through。
这个过渡态在之前的文章中已经多次提到。
阶段 5:给本轮输入装临时保护
在 prompt 真的发出去前,还有几层“本轮级保护”:
hook 可能再 prepend prompt 或改写 system prompt detectAndLoadPromptImages(...) 检测当前 prompt 的图片 installToolResultContextGuard(...) 给本轮模型输入做 tool result 上下文保护
这一步很关键,因为它说明:
有些压缩不是写回磁盘的,而是只为了“这一轮先别把上下文撑爆”。
阶段 6:真正调用模型
调用的是:
activeSession.prompt(...)
这时模型看到的是:
当前轮 system prompt 清洗后的历史 hook 注入内容 当前用户 prompt 当前 prompt-local 图片 经过 context guard 后的上下文视图
5. tool result 为什么会成为上下文系统的一部分
工具结果会经历至少两层处理:
5.1 写入 transcript 前的处理
installSessionToolResultGuard(...) 会在 append 前处理 tool result。
结构修复
比如补缺失的 tool result,避免 transcript 协议损坏
比如 capToolResultSize(...),用 HARD_MAX_TOOL_RESULT_CHARS 防止超长结果直接写进会话
这一步是“写入前防污染”。
5.2 送模型前的上下文保护
installToolResultContextGuard(...) 不是改磁盘,而是改“这一轮送给模型的消息视图”。
它主要做两件事:
如果单个 tool result 太大,就先截短它 如果整体上下文还是太大,就把旧 tool result 直接替换成占位符
占位符是:
[compacted: tool output removed to free context]这一步你可以理解成:
不一定删掉会话里的原记录,但至少别让它们继续拖垮下一次模型调用。
6. 为什么说“检测”是多次发生的
它实际上有 3 个检测点:
6.1 模型调用前检测
检查:
历史结构是否合法 历史是否过长 tool result 是否明显过重 当前 prompt 是否包含图片 当前 system prompt 是否过大
6.2 模型调用中检测
通过订阅事件观察:
是否触发 auto-compaction 是否还在 compaction 中 是否需要等 compaction retry 收敛
6.3 模型调用后检测
外层 run.ts 会看:
promptError / assistantError 像不像 context overflow 本轮是否已经 compaction 过 是否还有 oversized tool result 是否还值得继续 retry
所以这套机制本质上是:
前检测 + 中监控 + 后恢复判断而不是单次检测。
7. 一轮结束后,上下文如何延续到下一轮
运行结束后会执行:
contextEngine.afterTurn(...) 如果没有,就退化到 ingestBatch(...) 再不行就逐条 ingest(...)
但当前默认 legacy 基本是 no-op。
所以今天 OpenClaw 的现实是:
transcript 的持久延续主要还是 SessionManager context engine 生命周期接口已经预留好了 未来可以让 engine 更主动地管理摘要、索引、子 agent
8. 总结
OpenClaw 的上下文是历史会话、system prompt、本轮临时注入、恢复控制信息四层叠加。 每一轮开始前都会重新做上下文装配。 真正的“检测”分成模型前、模型中、模型后三个时机。 当前默认 legacy context engine 还比较保守,很多核心处理仍在 attempt.ts 和 run.ts。 tool result 既是工具输出,也是后续轮次的上下文负担,所以系统会在“写入前”和“送模型前”分别治理它。 一轮结束后,当前结果会进入 transcript,并成为下一轮重新装配时的上下文历史。
夜雨聆风