☰
OpenClaw 源码解读(18)用日志追踪 Embedded Agent Runner 执行全链路:从配置到验证
2026/9/29 8:17:41 网站建设 项目流程

1. 一条消息卡在“processing”时,日志到底该看哪几行

如果你正在读 OpenClaw 源码,或者本地跑着一个 Embedded Agent Runner,大概率遇到过这种场景:Matrix 通道里消息发出去了,界面一直显示 processing,既没有报错也没有回复。这时候翻日志,满屏都是[agent/embedded]、[diagnostic]、[model-fetch]前缀,根本不知道从哪一行开始看。

这篇就聚焦这件事:把 Embedded Agent Runner 从“配置注入”到“SSE 流式返回”的日志链路拆开,给你一份可以直接抄的日志配置骨架,再配合 TaoToken 的统一 Key/API 通道,把本地调试环境跑通。适合两类人:一是正在读 OpenClaw 源码、想搞清执行链路关键节点的同学;二是本地起了 Agent Runner、但日志级别没配对、看不到关键信息的同学。

核心检索词先摆出来:OpenClaw 的 Embedded Agent Runner 是内嵌在 Agent 进程里的执行引擎,负责把一条入站消息变成一次 LLM 调用;日志追踪是它暴露执行链路的主要手段;执行链路从 extraParams 注入开始,经过 Admission 并发控制、prompt 组装、上下文预检、max_tokens 钳制,最后到 provider-transport-fetch 发请求。你要做的是让这条链路的每一段都打出可读日志,而不是只看到一句“processing”。

我试过在默认配置下直接跑,日志里只有 lifecycle 的 start/end,中间 prompt 组装和预算检查全是 debug 级别,默认不输出。所以第一步不是读代码,是把日志级别和输出目标配对。

2. 前置:TaoToken 统一 Key 与 API 通道接入

OpenClaw 的 provider 配置支持自定义 baseUrl,这意味着你可以把请求指向一个统一的 API 通道,而不是在每个 agent 里分别填不同厂商的 Key。TaoToken 在这里的角色就是这层统一通道:一个 Key 覆盖多家模型,baseUrl 固定,省去在 config.toml 里反复改 provider 段的麻烦。

接入动作分三步。第一步,在 TaoToken 控制台创建一个 API Key,地址是 https://taotoken.net/api-keys ,创建后复制出来,后面写进环境变量。第二步,确认你要用的模型名,模型对话页 https://taotoken.net/models 可以看当前可用的模型标识,比如 qwen 系列、claude 系列。第三步,把 baseUrl 指向 https://taotoken.net/api ,注意这个地址不带任何查询参数,直接作为 OpenAI 兼容端点使用。

这里有个容易踩的坑:OpenClaw 的 provider 配置里api字段要写openai-completions,而不是openai。因为 Embedded Agent Runner 走的是 completions 传输层,日志里你会看到api=openai-completions,如果写成别的,transport 层不会触发 SSE 解析,日志里就看不到contentType=text/event-stream。

如果你后面要做长期编码或者多 Agent 编排,可以考虑 Coding Plan,地址 https://taotoken.net/coding-plan ,它更适合持续性的 agent 调用场景。但本篇先聚焦单次调试链路的打通。

3. 可复制的日志配置骨架

OpenClaw 的配置分两层:一层是config.toml,管 provider、model、agent 的静态配置;另一层是settings.json,管运行时行为和日志级别。两份都要改,缺一个都看不到完整链路。

3.1 config.toml 片段

[providers.taotoken] api = "openai-completions" baseUrl = "https://taotoken.net/api" apiKeyEnv = "TAOTOKEN_API_KEY" [models.qwen-debug] provider = "taotoken" id = "qwen3.7-plus" contextWindow = 150000 maxOutputTokens = 128000 [agents.code-analyst] model = "qwen-debug" systemPromptFile = "./prompts/code-analyst.md"

关键点:apiKeyEnv指向环境变量,不要把 Key 硬编码进 toml。contextWindow和maxOutputTokens这两个值会直接影响后面预检和钳制日志里的数字,配错了日志里的contextTokenBudget就对不上。

3.2 settings.json 片段

{ "logging": { "level": "debug", "targets": ["stderr", "file"], "file": { "path": "./logs/embedded-runner.log", "rotate": { "maxSizeMb": 64, "maxFiles": 5 } }, "namespaces": { "agent/embedded": "debug", "diagnostic": "debug", "openai-transport": "debug", "provider-transport-fetch": "debug", "context-diag": "debug" } }, "embeddedRunner": { "admission": { "maxConcurrentRuns": 4 }, "contextBudget": { "reserveTokens": 20000, "precheckEnabled": true } } }

namespaces这一段是重点。OpenClaw 的日志按命名空间分级,默认agent/embedded是 info,你把它调到 debug 才能看到embedded run prompt start和[context-diag] pre-prompt。provider-transport-fetch调到 debug 才能看到[model-fetch] start和response。

3.3 环境变量

export TAOTOKEN_API_KEY="sk-你的key" export OPENCLAW_LOG_LEVEL="debug" export OPENCLAW_LOG_FILE="./logs/embedded-runner.log"

环境变量优先级高于 settings.json,本地调试时用环境变量临时覆盖最方便。

4. 逐步验证:从启动到看到 SSE 返回

配置写完,按下面顺序验证,每一步都有对应的日志特征,对不上就说明那一段没打通。

4.1 启动并确认配置加载

openclaw run --agent code-analyst --log-level debug

启动后先 grep 配置加载日志:

grep "applying extraParams" ./logs/embedded-runner.log

期望看到类似:

[agent/embedded] applying extraParams to agent streamFn for taotoken/qwen3.7-plus

这行说明 extraParams 注入生效了,provider 和 model 解析正确。如果这行没有,检查 config.toml 里 provider 名和 model 名是否拼错。

4.2 发一条测试消息,观察 Admission 登记

通过 Matrix 通道或者本地 CLI 发一条消息,然后看:

grep "run registered" ./logs/embedded-runner.log

期望:

[diagnostic] session state: sessionId=... prev=processing new=processing reason="run_started" queueDepth=1 [diagnostic] run registered: sessionId=... totalActive=1

reason="run_started"说明是首次登记,totalActive=1说明当前只有一个并发 run。如果同一个 session 连发两条,第二条会显示reason="run_replaced",这是 Admission 并发控制在起作用。

4.3 确认 prompt 组装与上下文预检

grep -E "embedded run prompt start|context-diag|context-overflow-precheck" ./logs/embedded-runner.log

期望看到三行关键日志:

[agent/embedded] embedded run prompt start: runId=... provider=taotoken api=openai-completions endpoint=custom route=proxy-like policy=none [agent/embedded] [context-diag] pre-prompt: messages=6 roleCounts=assistant:3,toolResult:1,user:2 systemPromptChars=26492 promptChars=1711 [agent/embedded] [context-overflow-precheck] route=fits estimatedPromptTokens=10209 promptBudgetBeforeReserve=130000 overflowTokens=0

route=proxy-like说明 baseUrl 被识别为自定义代理端点,这会触发后面的 max_tokens 钳制分支。route=fits说明上下文没超,不需要压缩。如果这里显示compact_only或truncate_tool_results_only,说明你的 contextWindow 配小了,或者历史消息太长。

4.4 确认 max_tokens 钳制与请求发出

grep -E "clamp_max_tokens|model-fetch" ./logs/embedded-runner.log

期望:

[openai-transport] [completions] clamp_max_tokens provider=taotoken api=openai-completions model=qwen3.7-plus requested=128000 output=126533 effectiveContext=150000 estimatedInput=23466 [provider-transport-fetch] [model-fetch] start provider=taotoken api=openai-completions model=qwen3.7-plus method=POST url=https://taotoken.net/api/v1/chat/completions [provider-transport-fetch] [model-fetch] response provider=taotoken api=openai-completions model=qwen3.7-plus status=200 elapsedMs=1247 contentType=text/event-stream; charset=utf-8

看到status=200和contentType=text/event-stream,说明请求成功且是流式返回。elapsedMs是首字节时间,如果这个值特别大,问题在通道侧不在 OpenClaw 侧。

4.5 验证流式内容落盘

grep "stream chunk" ./logs/embedded-runner.log | tail -5

期望看到连续的 chunk 日志,最后一条带finish_reason=stop。到这里整条链路就通了。

5. 本篇常见错排查

5.1 日志里只有 lifecycle,没有 prompt 组装

现象:grepembedded run prompt start返回空。原因通常是agent/embedded命名空间还是 info 级别。检查 settings.json 的namespaces段,确认agent/embedded是 debug。另外确认环境变量OPENCLAW_LOG_LEVEL没有覆盖成 info。

5.2 报 401 或 403,但 Key 是对的

现象:[model-fetch] response status=401。先确认 baseUrl 是https://taotoken.net/api,不要多加/v1,OpenClaw 的 transport 层会自己拼/v1/chat/completions。如果 baseUrl 写成https://taotoken.net/api/v1,最终 URL 会变成/api/v1/v1/chat/completions,直接 404 或 401。另外确认apiKeyEnv指向的环境变量在当前 shell 里确实 export 了。

5.3 预检显示 compact_only,但消息并不长

现象:context-overflow-precheck route=compact_only。检查 config.toml 里的contextWindow,如果配成了 32000 而实际模型支持 150000,预检会误判溢出。把contextWindow改成模型真实上限,reserveTokens保持 20000 左右。

5.4 clamp_max_tokens 没出现

现象:grep 不到clamp_max_tokens。这个分支只在route=proxy-like且clampedMaxTokens有值时触发。如果你的 baseUrl 被识别成非 proxy-like,或者maxOutputTokens没配,就不会走这个分支。确认 config.toml 里 model 段有maxOutputTokens,且 baseUrl 是自定义域名而非官方域名。

5.5 流式返回中断,日志停在 response 没有 chunk

现象:看到status=200 contentType=text/event-stream,但后面没有 chunk 日志。这通常是 SSE 解析层的问题,检查openai-transport命名空间是否 debug。如果确认是 debug 还是没有 chunk,可能是通道侧在首字节后断流,用 curl 直接打一次同样的请求对比:

curl -N https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"qwen3.7-plus","stream":true,"messages":[{"role":"user","content":"ping"}]}'

如果 curl 能持续收到data:行,说明通道没问题,问题在 OpenClaw 的 transport 配置。

6. 把日志链路固定成调试习惯

整条链路跑通之后,建议把上面几个 grep 命令写成一个脚本,每次调试先跑一遍,三十秒内就能定位卡在哪一段。日志追踪的价值不在于日志多,而在于每一段都有明确的“通过特征”:extraParams 看 provider/model 解析,Admission 看 run_started,prompt 组装看 route=proxy-like,预检看 route=fits,钳制看 clamp_max_tokens,请求看 status=200 + text/event-stream。

如果你在接入阶段遇到 Key 或 baseUrl 的问题,直接去 https://taotoken.net/api-keys 重新生成一个 Key 对比测试,排除 Key 本身的问题。模型标识不确定的时候,https://taotoken.net/models 可以对照当前可用列表。需要长期跑编码类 agent 的话,Coding Plan 页面 https://taotoken.net/coding-plan 有更细的配额说明。接入文档在 https://taotoken.net/doc ,里面有针对 OpenAI 兼容端点的完整参数说明,配 config.toml 时对着看能少踩几个字段名的坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询