1. 为什么你的 OpenClaw Agent 总在“空转”很多人第一次把 OpenClaw 跑起来会下意识把它当成一个“会自己写脚本的执行器”给个目标它就应该像 Shell 脚本一样一步步往下走。结果实际观察日志时发现Agent 要么在同一个工具上反复横跳要么思考了半天却调了一个完全无关的工具最后任务超时退出。问题不在模型不够聪明而在于 Agent Loop 的闭环没有配好。OpenClaw 的 Agent Loop 本质上是 ReAct 范式的工程化落地Reasoning推理产生 ThoughtActing行动产生 Tool Call工具返回的 Observation 再喂回上下文触发下一轮 Reasoning。这个“思考-工具-再思考”的循环才是 Agent 从“脚本执行器”变成“任务规划者”的关键。但循环要跑得稳需要三个东西同时到位思维链的触发条件、工具注册的边界、以及沙箱对工具调用的前置校验。这篇就围绕 OpenClaw 的 Agent Loop 拆一次完整循环从触发条件、状态流转到可复制的配置骨架再到一轮最小验证动作。目标很明确——让你在自己的 OpenClaw 实例里跑通单次循环并且能在日志里看到中间态而不是只看到一个最终结果。适合已经在用 OpenClaw 做自动化、但被 Agent 的“随机行为”困扰的开发者。2. TaoToken 前置给 Agent Loop 一个稳定的模型入口OpenClaw 的 Agent Loop 每一轮都要调用一次模型来生成 Thought 和 Tool Call循环次数一多模型接口的稳定性就直接决定整个 Loop 能不能跑完。如果模型入口频繁超时或限流Agent 会在“思考”阶段就断掉工具沙箱根本来不及介入。我自己的做法是先把模型入口统一到 TaoToken 上再让 OpenClaw 通过兼容接口去调用。这样 Agent Loop 的每一轮请求都走同一个入口排查问题时不用在多个供应商之间来回切换。TaoToken 的 API 地址是https://taotoken.net/api兼容常见的对话补全格式OpenClaw 的模型配置里直接填这个 base URL 即可。如果你还没建 Key先去控制台生成一个https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentagentloop_console 。生成后建议单独建一个 Key 给 OpenClaw 用方便按 Agent 维度看调用量。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentagentloop_doc 里面有 OpenClaw 这类客户端的配置示例。注意Agent Loop 的每一轮都会消耗 Token循环深度越大消耗越明显。建议在配置里给单次任务设一个 max_iterations 上限避免 Agent 在死胡同里无限重试。3. 可复制的 Agent Loop 配置骨架下面这份配置骨架可以直接放进你的 OpenClaw 项目里改。核心是三块reasoning 控制思维链触发tools 注册工具并声明沙箱边界loop 控制循环的终止条件。# openclaw.agentloop.yaml agent: name: code-review-agent model: base_url: https://taotoken.net/api api_key: ${TAOTOKEN_API_KEY} model: claude-sonnet-4-20250514 temperature: 0.2 # 思维链触发与深度控制 reasoning: enabled: true trigger: before_tool_call # 每次工具调用前强制生成 Thought depth: structured # structured | freeform max_thought_tokens: 800 template: | Before calling any tool, output a thought block: 1. Current State: summarize last tool output 2. Gap: what is missing to reach the goal 3. Plan: which tool next and why # 工具注册与沙箱边界 tools: - name: file_read description: Read a file within the project root sandbox: allowed_paths: [./src, ./tests, ./docs] deny_patterns: [*.env, *secret*, *.pem] params: path: { type: string, required: true } - name: file_write description: Write or overwrite a file within the project root sandbox: allowed_paths: [./src, ./tests] allow_overwrite: false max_size_kb: 256 params: path: { type: string, required: true } content: { type: string, required: true } - name: shell_exec description: Run a whitelisted shell command sandbox: allowed_commands: [npm test, npm run lint, go vet ./...] timeout_sec: 60 network: false params: command: { type: string, required: true } # 循环终止条件 loop: max_iterations: 8 stop_on: [task_complete, max_iterations, repeated_error] repeated_error_threshold: 3 on_sandbox_deny: feedback_to_model # 拒绝后把原因回灌给模型再思考几个字段值得单独说。reasoning.trigger设成before_tool_call意味着 Agent 每次要调工具前都必须先产出一段 Thought这段 Thought 会进入上下文成为下一轮推理的依据。depth: structured会强制模型按模板输出实测下来能明显减少“没看清报错就盲目重试”的情况。tools[].sandbox是工具沙箱的核心。allowed_paths限定文件操作范围deny_patterns挡住敏感文件allow_overwrite: false防止 Agent 直接覆盖已有文件。shell_exec的allowed_commands是白名单只有列出的命令能执行network: false直接切断网络访问。这些边界不是可选项是 Agent Loop 能安全跑起来的前提。loop.on_sandbox_deny: feedback_to_model这个字段很关键。当工具调用被沙箱拒绝时OpenClaw 不会直接抛异常终止循环而是把拒绝原因作为 Observation 回灌给模型触发新一轮 ReAct。Agent 会看到“权限拒绝尝试写入 ./config/prod.yaml 超出沙箱范围”然后重新规划路径。4. 跑通一轮最小循环并观察中间态配置写好后先别急着上复杂任务。用一轮最小验证动作确认循环能跑通、中间态能看到。准备一个测试目录放一个故意有问题的文件mkdir -p ./src ./tests cat ./src/sample.js EOF function add(a, b) { return a b } console.log(add(1, 2)) EOF然后给 Agent 一个明确的小目标比如“检查 ./src/sample.js 的代码风格问题如果发现问题就报告不要修改文件”。启动 OpenClaw 并开启详细日志export TAOTOKEN_API_KEY你的Key openclaw run \ --config ./openclaw.agentloop.yaml \ --task Review ./src/sample.js for style issues. Report only, do not modify. \ --log-level debug \ --trace-loop--trace-loop会把每一轮的 Thought、Tool Call、Observation 都打出来。你会在日志里看到类似这样的状态流转[Loop 1] Thought: Current State: no tool called yet. Gap: need to read the file. Plan: call file_read on ./src/sample.js. [Loop 1] ToolCall: file_read(path./src/sample.js) [Loop 1] Observation: function add(a, b) { return a b } ... [Loop 2] Thought: Current State: file content known. Gap: check style rules. Plan: call shell_exec with npm run lint. [Loop 2] ToolCall: shell_exec(commandnpm run lint) [Loop 2] Observation: Missing semicolon at line 2. [Loop 3] Thought: Current State: lint reported missing semicolon. Gap: task is report-only. Plan: produce final answer, no more tools. [Loop 3] Final: Found 1 style issue: missing semicolon at line 2.看到[Loop 3] Final就说明单次循环闭环跑通了。整个过程里Agent 先思考再调工具工具返回后再次思考最后在没有新工具需求时收敛到最终答案。这就是“思考-工具-再思考”的完整状态流转。如果你想验证沙箱是否生效把任务改成“把 ./src/sample.js 覆盖成空文件”然后观察日志。你会看到file_write被沙箱拒绝Observation 里出现拒绝原因Agent 在下一轮 Thought 里重新规划而不是直接崩溃。5. 本篇常见错排查循环不收敛一直调工具不停。先看max_iterations是不是设太大再看reasoning.template有没有强制模型输出 Plan。如果模型每轮都在换工具但没有实质进展把temperature降到 0.1 左右减少随机性。工具调用被沙箱拒绝后 Agent 直接退出。检查loop.on_sandbox_deny是否设成了feedback_to_model。如果设成abort拒绝就会终止循环。另外确认tools[].sandbox的allowed_paths用的是相对路径绝对路径容易匹配失败。Thought 里看不到结构化输出。确认reasoning.depth是structured并且template字段没有语法错误。YAML 里的多行字符串用|保留换行缩进要对齐。模型接口报 401 或超时。检查TAOTOKEN_API_KEY环境变量是否生效base_url是否写成https://taotoken.net/api。如果循环轮次多导致超时可以在模型配置里加timeout和retry字段。需要重新生成 Key 的话走这里https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentagentloop_apikeys 。日志里只有最终结果没有中间态。启动时加--trace-loop并把--log-level设成debug。如果用的是自定义日志配置确认 Agent Loop 的 trace 输出没有被过滤掉。6. 把循环跑稳之后单次循环跑通只是起点。真正让 Agent Loop 在生产里稳定工作靠的是把思维链模板、工具沙箱边界、循环终止条件这三样东西当成配置资产来维护而不是每次临时改 Prompt。我自己的习惯是给不同任务类型建不同的 Profile代码审查类用严格沙箱加结构化思维数据清洗类放开读权限但禁写CI 助手类只允许白名单命令。如果你想让 Agent 在长任务里持续跑可以了解下 Coding Plan 的额度方案https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentagentloop_codingplan 。想先在对话里手动验证模型对 ReAct 模板的响应可以用模型对话页试几轮https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentagentloop_chat 。把 Thought 模板贴进去看模型能不能稳定按结构输出再决定要不要写进 OpenClaw 配置。