1. 为什么你的 OpenClaw Skill 总在关键时刻罢工
你大概也遇到过这种场景:明明在SKILL.md里把步骤写得清清楚楚,Agent 却在执行到第三步时突然“失忆”,转头去调用一个完全无关的工具;或者更气人的是,它压根就不触发你写的 Skill,自顾自地用通用能力瞎猜一通。你盯着日志里那句tool not found或者skill not triggered,开始怀疑是不是 OpenClaw 本身有 bug。
先别急着甩锅给框架。我实测下来,九成以上的“罢工”都不是 OpenClaw 的锅,而是 Skill Engineering 层面的设计缺陷。OpenClaw 作为一个 Agent 运行时,它做的事情其实很纯粹:读取config.toml里的模型与工具声明,加载 Skill 目录下的SKILL.md,然后把用户输入、Skill 描述、可用工具列表一起塞进上下文,让模型自己决定“要不要用这个 Skill、用哪个工具、传什么参数”。问题就出在这个“让模型自己决定”上——你的 Skill 描述如果写得像一份晦涩的 API 文档,模型在长上下文里根本抓不住重点,触发率自然惨不忍睹。
更隐蔽的坑在于config.toml的骨架配置。很多人从社区抄了一份配置,改了个模型名就直接跑,结果base_url指向了一个不支持 function calling 的端点,或者model_id写的是对话模型却指望它做工具编排。这种配置层面的错配,表现出来就是 Agent 频繁“罢工”:要么请求直接 401,要么返回的choices里根本没有tool_calls字段,OpenClaw 解析不到工具调用,只能干瞪眼。
所以这篇排错清单的思路很明确:先别动 Skill 的逻辑,先把config.toml骨架和最小验证动作跑通,确认“配置链路”没问题,再去排查“Skill Engineering”的设计问题。顺序反了,你会在错误的地方浪费大量时间。
2. TaoToken 前置:把模型接入这层先理清楚
在深入config.toml之前,得先把模型接入这层理清楚。OpenClaw 本身不绑定任何模型供应商,它通过 OpenAI 兼容的 API 协议去调用后端模型。这意味着你需要一个稳定的、支持 function calling 的 API 端点。我目前用的是 TaoToken 的 API 服务,它的接口地址是https://taotoken.net/api,完全兼容 OpenAI 的/v1/chat/completions格式,OpenClaw 可以直接对接。
为什么强调“支持 function calling”?因为 Skill 的本质就是让模型输出结构化的工具调用指令。如果后端模型不支持这个能力,或者 API 网关在转发时把tools字段吞掉了,OpenClaw 收到的响应里就不会有tool_calls,Agent 自然无法执行 Skill。TaoToken 这边我实测下来,Claude 系列和 GPT 系列的工具调用都能正常透传,响应结构里的finish_reason会正确返回tool_calls,这是跑通 Skill 的前提。
你需要准备的东西很简单:一个 TaoToken 的 API Key,以及确认你要用的模型 ID。模型 ID 的命名规则跟官方保持一致,比如claude-sonnet-4-20250514或者gpt-4o这类。拿到 Key 之后,先别急着写 Skill,用一条 curl 命令验证一下工具调用是否正常。这一步能帮你排除掉“API 端点不支持工具调用”这个最底层的坑。
如果你还没有 Key,可以去 TaoToken 的 API Keys 页面创建一个。创建时注意权限范围,如果你只是本地开发调试,给一个默认的读写权限就够了。Key 拿到后先存到环境变量里,别硬编码进config.toml,后面我会讲怎么在配置里引用环境变量。
3. 可复制的 config.toml 骨架与 Skill 目录结构
OpenClaw 的配置核心是config.toml,它决定了模型怎么连、Skill 从哪加载、工具怎么注册。很多人罢工的根因就藏在这个文件的细节里。下面这份骨架是我踩过坑之后稳定下来的版本,你可以直接复制修改。
# ~/.openclaw/config.toml [model] provider = "openai-compatible" base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" model_id = "claude-sonnet-4-20250514" max_tokens = 4096 temperature = 0.2 [agent] name = "my-openclaw-agent" system_prompt_file = "./prompts/system.md" max_iterations = 15 tool_choice = "auto" [skills] enabled = true skill_dirs = ["./skills"] auto_reload = true [tools] enabled = ["read_file", "write_file", "run_shell", "http_request"]几个关键点需要展开说。base_url这里填https://taotoken.net/api,注意不要在后面多加/v1,OpenClaw 内部会自动拼接路径。api_key_env指向环境变量名,你在 shell 里export TAOTOKEN_API_KEY="sk-xxx"就行,这样配置文件可以安全地提交到 git。model_id必须选支持工具调用的模型,如果你填了一个纯对话模型,Agent 会在需要调用工具时返回纯文本,OpenClaw 解析不到tool_calls就会报no tool calls found in response。
max_iterations这个参数很关键。它限制的是 Agent 在一次任务里最多进行多少轮“思考-调用工具-观察结果”的循环。设得太小,复杂 Skill 跑到一半就被截断;设得太大,一旦 Skill 逻辑有死循环,你会看到 Agent 疯狂调用同一个工具直到烧完 token。我一般设 15 到 20 之间,配合后面要讲的 Skill 边界设计,基本不会出问题。
Skill 的目录结构也有讲究。OpenClaw 默认会扫描skill_dirs下的每个子目录,每个子目录里必须有一个SKILL.md,开头是 YAML front matter,声明name、description和可选的tools。一个最小可用的 Skill 长这样:
--- name: fetch-weather description: 当用户询问某个城市的天气时,调用此技能获取实时天气数据。适用于“今天天气怎么样”“明天要下雨吗”这类问题。 tools: - http_request --- ## 步骤 1. 从用户输入中提取城市名称。 2. 调用 http_request 工具,请求天气 API。 3. 将返回的 JSON 中的温度、天气状况整理成自然语言回复。注意description的写法。它不是给你看的说明书,而是给模型看的“触发提示”。模型在决定是否调用这个 Skill 时,主要依据就是这段描述。如果你写得太泛,比如“处理天气相关任务”,模型在长上下文里可能根本注意不到它;如果你写得太窄,比如“查询北京市朝阳区天气”,换个城市就不触发了。我后面会专门讲怎么调这个描述。
4. 验证请求:用最小 Skill 确认链路通畅
配置写完之后,别急着上复杂 Skill。先做一个最小验证:建一个只做加法运算的 Skill,确认 OpenClaw 能正确触发、调用工具、拿到结果。这一步能帮你把“配置问题”和“Skill 设计问题”彻底分开。
先建目录和文件:
mkdir -p ~/.openclaw/skills/calc-test cat > ~/.openclaw/skills/calc-test/SKILL.md << 'EOF' --- name: calc-test description: 当用户要求做两个数字的加法运算时使用此技能。例如“帮我算一下 3 加 5 等于多少”。 tools: - run_shell --- ## 步骤 1. 从用户输入中提取两个加数。 2. 调用 run_shell 工具执行 `echo $((a + b))`。 3. 将计算结果返回给用户。 EOF然后启动 OpenClaw 并发送一条测试消息:
export TAOTOKEN_API_KEY="sk-your-key-here" openclaw chat --config ~/.openclaw/config.toml在交互界面里输入“帮我算一下 3 加 5 等于多少”。如果链路正常,你会看到 Agent 先输出一段思考,然后触发run_shell工具,最后返回“8”。日志里应该能看到类似这样的结构:
{ "finish_reason": "tool_calls", "tool_calls": [ { "name": "run_shell", "arguments": "{\"command\": \"echo $((3 + 5))\"}" } ] }如果这一步跑通了,说明config.toml的模型接入、API Key、工具注册、Skill 加载全部正常。接下来如果复杂 Skill 还是罢工,问题就出在 Skill Engineering 层面,而不是配置。如果这一步就失败了,对照下一节的报错清单逐条排查。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
排错的时候,报错信息是最诚实的线索。下面这几个是我在 OpenClaw 社区里看到频率最高的,基本覆盖了 90% 的罢工场景。
401 Unauthorized:这个最直接,API Key 没传对。检查三件事:环境变量TAOTOKEN_API_KEY是否真的 export 了(用echo $TAOTOKEN_API_KEY确认);config.toml里的api_key_env拼写是否和实际环境变量名一致;Key 本身是否过期或被禁用。注意不要在config.toml里直接写api_key = "sk-xxx"然后又设了api_key_env,两者同时存在时 OpenClaw 的行为可能不符合预期,统一用环境变量最稳。
local proxy failed / connection refused:这个报错通常出现在你本地配了 HTTP 代理,但代理进程没启动或者端口不对。OpenClaw 底层用的是标准 HTTP 客户端,会读取HTTP_PROXY和HTTPS_PROXY环境变量。如果你之前为了调试设过这些变量,记得unset掉。另外检查base_url是否写成了https://taotoken.net/api/带尾斜杠,某些版本的 OpenClaw 在拼接路径时会产生双斜杠导致 404,表现上也可能被误报为连接失败。
reading choices 相关报错:典型信息是failed to read choices from response或者index out of range。这说明 API 返回的 JSON 结构里没有choices数组,或者数组为空。根因通常是model_id填错了,比如填了一个不存在的模型名,API 返回了错误对象而不是正常的 completion 结构。另一个可能是base_url指向了一个非 OpenAI 兼容的端点。用 curl 直接打一次 API 确认返回结构:
curl -s https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"claude-sonnet-4-20250514","messages":[{"role":"user","content":"hi"}]}' | jq '.choices[0].message.content'如果这条命令能正常返回内容,说明 API 侧没问题,问题在 OpenClaw 的配置解析。
OAuth 相关报错:如果你用的是 Claude Code 或者某些需要 OAuth 流程的客户端,可能会遇到OAuth token expired或invalid_grant。这类报错跟 OpenClaw 本身无关,是上游认证层的问题。解决办法是重新走一遍授权流程,或者改用 API Key 方式接入。TaoToken 的 API 接入不需要 OAuth,直接用 Key 就行,省掉这层麻烦。
排查的时候有个技巧:把 OpenClaw 的日志级别调到 debug,能看到完整的请求体和响应体。请求体里重点看tools字段有没有被正确序列化,响应体里重点看finish_reason是不是tool_calls。这两个信息一对照,问题基本就定位了。
6. 从配置到 Skill Engineering:让 Agent 稳定干活的几个心法
配置链路跑通之后,剩下的就是 Skill 本身的设计。这部分才是真正拉开差距的地方。我总结了几条实战心法,每一条都对应着一种常见的“罢工”模式。
Description 要抢注意力,不要写说明书。模型在长上下文里对信息的注意力是有限的。你的 Skill 描述如果淹没在一堆工具声明和系统提示里,触发率就会暴跌。写法上,把最核心的触发场景放在第一句,用具体的用户问法举例。比如不要写“此技能用于处理文件相关操作”,而是写“当用户说‘帮我读一下这个文件’‘看看 xxx.log 里有什么’时,使用此技能”。具体的例子比抽象的描述更能激活模型的模式匹配。
用“讲道理”代替 MUST/NEVER。传统编程思维喜欢用强制命令,但在大模型这里,大写的 MUST 反而可能引发逻辑短路。更好的方式是在 Skill 里解释“为什么”要这么做。比如不要写“MUST call read_file before write_file”,而是写“在写入之前先读取原文件内容,这样可以避免覆盖掉用户已有的修改”。模型理解了意图,执行起来会更灵活也更稳定。
LLM 管控制流,脚本管数据流。这是最核心的一条。如果你让模型自己去解析 JSON、做字符串拼接、算数值,它迟早会出错。正确的做法是把确定性的计算逻辑封装成脚本,Skill 里只负责决定“什么时候调用这个脚本、传什么参数”。OpenClaw 的run_shell工具就是干这个的。模型负责判断和编排,脚本负责精确执行,各司其职。
渐进式披露,别一次塞太多。一个 Skill 如果步骤超过 7 步,模型在中途“失忆”的概率会显著上升。解决办法是把大 Skill 拆成多个小 Skill,每个只做一件事,通过description里的触发条件让模型按需加载。OpenClaw 支持auto_reload,你改完SKILL.md不用重启就能生效,调试起来很方便。
最后说一个我踩过的坑:Skill 的name字段不要用中文,也不要用空格。用短横线连接的英文小写,比如fetch-weather、parse-log。某些版本的 OpenClaw 在解析 YAML front matter 时对非 ASCII 字符处理不一致,可能导致 Skill 加载失败但又不报错,表现就是“Skill 明明存在但 Agent 就是不用”。改成纯英文名之后,这个问题再没出现过。
如果你在排障过程中需要对照 API 的返回结构,可以直接用 TaoToken 的模型对话页面发一条带 tools 的请求,看看原始响应长什么样。接入文档里也有完整的请求示例,对着调比盲猜快得多。长期跑编码类 Agent 的话,Coding Plan 的额度比按量计费更划算,适合把 OpenClaw 挂在后台持续干活。