1. OpenClaw 工具执行链路到底在解决什么问题
如果你最近在折腾 OpenClaw,大概率会遇到一个很具体的困惑:模型明明返回了tool_call,参数看着也对,但本地就是跑不起来。要么是exec卡在审批状态,要么是read读大文件直接截断,要么是write写到了工作区外面被拦下来。这些问题的根子不在模型,而在工具执行链路和 API 通道这两层。
OpenClaw 的核心工具其实就五个:exec、process、read、write、edit。它们各自负责一段执行链路——exec负责起进程,process负责管后台会话,read负责带分页地读文件,write负责落盘,edit负责精确替换。模型返回的tool_call会先被 OpenClaw 解析,按name找到对应的execute函数,再把参数传进去执行,最后把content + details回传给模型。这条链路里任何一环配置不对,都会表现为“工具调不动”。
这篇面向的是已经在本地跑 OpenClaw、想让工具真正执行起来的开发者。我会把config.toml和settings.json的可复制骨架给出来,用 TaoToken 作为统一的 Key/API 通道,然后演示一次从exec到process的完整验证动作。你照着配完,应该能直接看到命令输出回到模型侧。
需要先说明一点:TaoToken 在这里的角色是统一模型接入通道,不是替代 OpenClaw 本身。OpenClaw 负责工具执行,TaoToken 负责把模型请求稳定地送出去、把tool_call拿回来。两者是配合关系,别混在一起理解。
2. TaoToken 前置:Key、通道与配置位置
在动config.toml之前,先把 TaoToken 这边的准备工作做完。你需要一个可用的 API Key,以及确认走的是哪个接入地址。官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基址是 https://taotoken.net/api ,注意 API 地址后面不加 UTM 参数,保持干净。
Key 的创建在控制台的 API Keys 页面,路径是 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 。创建完复制出来,后面要填进settings.json。如果你还没决定用哪个模型,可以先去模型对话页面试一下 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite ,确认模型能正常返回tool_call再往下配。
这里有个容易踩的点:OpenClaw 的工具执行依赖模型返回结构化的tool_calls字段,不是所有模型都稳定支持。我实测下来,带 function calling 能力的模型在exec场景下表现更稳。如果你发现模型只返回文本、不返回tool_calls,先换模型验证,别急着改 OpenClaw 配置。
配置分两个文件:config.toml管 OpenClaw 的工具行为(超时、后台、工作区限制),settings.json管模型通道(base_url、api_key、model)。两者职责分开,改的时候别串。
3. 可复制配置:config.toml 与 settings.json 骨架
先给config.toml。这个文件控制工具执行层的默认行为,重点是exec的超时和后台窗口、read的分页上限、write的工作区限制。
# config.toml —— OpenClaw 工具执行层配置 [exec] # 前台等待窗口,超过这个时间自动转后台,单位毫秒 background_ms = 10000 # 是否允许后台运行 allow_background = true # 单条命令默认超时,单位秒 timeout_sec = 1800 # 安全模式:full / restricted security = "restricted" # 审批模式:off / on-miss / always ask = "on-miss" [exec.safe_bins] # 白名单命令,命中后无需审批 allow = ["ls", "cat", "grep", "find", "git", "node", "python3", "npm"] [process] # 已完成会话的清理时间,单位毫秒 cleanup_ms = 600000 [read] # 自适应分页单次最大字节数 max_bytes = 51200 # 最大分页数 max_pages = 8 [write] # 是否限制只能写工作区内 workspace_only = true # 工作区根目录 workspace_root = "/Users/you/workspace/openclaw-demo" [edit] # 编辑失败时是否尝试恢复判断 recovery = true几个参数值得单独说。background_ms设成 10000 意味着命令跑超过 10 秒就转后台,返回一个sessionId,后面用process工具去 poll。timeout_sec = 1800是硬超时,防止某个命令挂死。security = "restricted"配合ask = "on-miss",效果是白名单内的命令直接跑,白名单外的走审批,这样既安全又不至于每条命令都弹确认。
再给settings.json。这个文件把模型请求指向 TaoToken 通道。
{ "model": { "provider": "openai-compatible", "base_url": "https://taotoken.net/api", "api_key": "sk-你的TaoToken密钥", "model": "claude-sonnet-4-5", "timeout_ms": 120000, "max_retries": 2 }, "tools": { "enabled": ["exec", "process", "read", "write", "edit"], "param_aliases": true }, "logging": { "level": "info", "tool_calls": true } }base_url填https://taotoken.net/api,不要带尾部斜杠,也不要加 UTM。param_aliases: true打开后,read和edit会接受file_path、filePath、file这些别名,模型用哪种写法都能命中,这点在跨模型时特别有用。tool_calls: true会把每次工具调用的入参和结果打到日志,排障时全靠它。
注意:
api_key不要提交到 git。建议用环境变量注入,或者把settings.json加进.gitignore。OpenClaw 支持从TAOTOKEN_API_KEY环境变量读取,优先级高于文件里的值。
4. 验证请求:跑通一次 exec 到 process 的完整调用
配置写完后,别急着上复杂任务,先用一条最小命令验证链路。启动 OpenClaw 后,在对话里输入:
列出当前工作目录的文件,用 ls -la模型应该返回一个tool_call,name是exec,arguments里带command: "ls -la"。OpenClaw 收到后走这条链路:参数验证 → 解析后台请求 → 确定主机 → 白名单检查 → 启动进程 → 等待或转后台 → 返回结果。
如果命令很快结束,你会看到类似这样的返回:
{ "content": [{ "type": "text", "text": "total 48\ndrwxr-xr-x ..." }], "details": { "status": "completed", "exitCode": 0, "cwd": "/Users/you/workspace/openclaw-demo" } }status是completed,exitCode是 0,说明exec跑通了。接下来验证后台链路,输入一条会跑一会儿的命令:
执行 sleep 30,然后告诉我它在后台的 sessionId这次exec会在background_ms到期后转后台,返回status: "running"和一个sessionId。拿到sessionId后,模型会调用process工具去 poll:
{ "action": "poll", "sessionId": "abc123", "timeout": 5000 }process的poll会等待指定时间,然后返回当前输出和进程状态。如果进程还在跑,details.status是running;如果结束了,会带上exitCode。你还可以用process的logaction 读完整日志,用kill终止会话。这一套跑通,说明exec和process的联动没问题。
再验证read和write。让模型读一个稍大的文件:
读取 config.toml 的内容read会走自适应分页,如果文件超过max_bytes,它会自动翻页聚合,返回时可能带一行[Read output capped at 51200 bytes ... Use offset=N to continue.]。看到这行说明分页生效了,不是报错。写文件则用:
在工作区新建 notes.md,写入一行 hello openclawwrite会先做参数标准化,把file_path之类的别名统一成path,再检查workspace_only限制,最后mkdir -p加写文件。返回status: "completed"就对了。
5. 本篇常见错排查
报错一:elevated is not available right now
这是exec的提权请求被拒。原因通常是命令带了elevated: true,但config.toml里没开提权,或者当前主机不允许。排查顺序:先看命令是不是真的需要提权,大多数ls、cat、git都不需要;如果确实需要,检查[exec]段有没有配elevated相关项。别为了省事直接开security = "full",那等于关掉白名单。
报错二:Approval required (id xxx)
命令命中了白名单之外,ask = "on-miss"触发了审批。返回里会带status: "pending_approval"和approvalId。处理方式是回复/approve <id> allow-once或allow-always。如果你不想每次都审批,把常用命令加进[exec.safe_bins].allow。注意allow-always会持久化,加之前想清楚。
报错三:Session xxx is not backgrounded
调process的poll或log时,目标会话不是后台状态。这通常是因为命令在前台就跑完了,sessionId对应的会话已经结束。正确做法是先process的listaction 看当前有哪些会话,确认状态再操作。已结束的会话用poll也能拿到最终结果,但log会拒绝。
报错四:read返回被截断,内容不全
看到[Read output capped ...]不是错误,是分页保护。要拿完整内容,按提示用offset=N继续读,或者调大[read].max_bytes。但别调太大,一次性读几 MB 会把上下文撑爆,反而影响模型判断。大文件建议先grep定位再读。
报错五:write报路径越界
workspace_only = true时,写到工作区外会被拦。检查workspace_root配的路径,以及模型传的path是不是相对路径。相对路径会基于workspace_root解析,绝对路径如果不在根目录下就会被拒。要么把文件写到工作区内,要么临时把workspace_only关掉——但关之前确认你知道自己在写什么。
报错六:模型不返回tool_calls
这不是 OpenClaw 的错,是模型侧没触发 function calling。先确认settings.json里的model支持工具调用,再去模型对话页面单独测一下。如果模型只回文本,检查请求里有没有带tools定义。OpenClaw 会把启用的工具 schema 一起发出去,如果tools.enabled配错了,模型收不到定义自然不返回。
6. 把通道和工具链路固定下来
工具执行链路跑通之后,真正影响日常体验的是稳定性。我自己的做法是把settings.json里的base_url固定成 TaoToken 的 API 地址,api_key走环境变量,这样换机器不用改文件。config.toml里的白名单按项目逐步加,别一上来就全放开。
如果你后面要长期跑编码类任务或者 Agent 流程,可以考虑用 Coding Plan 把额度固定下来,入口在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。接入细节和参数说明在文档里 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,遇到tool_call格式对不上的情况,先翻文档确认模型侧的返回结构。
最后留一个实用习惯:每次改完config.toml,先用一条ls验证exec通不通,再用sleep 30验证process通不通。这两条过了,read、write、edit基本不会有大问题。工具链路的排障,永远是从最短路径开始试。