1. 为什么我要把 OpenClaw 的配置骨架单独拎出来讲
OpenClaw 是一个 AI Agent 运行时框架,不是模型,也不是 SDK。它更像一个坐在大模型和真实系统之间的控制平面:一边接住来自 Slack、Telegram、WebChat 等渠道的自然语言指令,另一边把指令翻译成工具调用、文件操作、API 请求,再把结果回灌给模型继续推理。适合谁?适合想把「聊天机器人」升级成「任务执行系统」的开发者,也适合想读懂 Agent Runtime 与 Skills 模块到底怎么串起来的技术读者。
很多人第一次读 OpenClaw 源码,会被src/agents/pi-embedded-runner/这一长串路径劝退。其实它的骨架非常清晰:Gateway 负责接入与路由,Agent Runtime 负责 ReAct 循环,Skills 负责把「能干活」的能力以插件形式注入。真正卡住复现的,往往不是源码逻辑,而是配置文件没写对——config.toml里 Agent 没注册、settings.json里 Skills 目录没挂载,结果 Runtime 起来了却没有任何技能可用。
这篇就围绕「Agent Runtime 到 Skills 的配置骨架」来拆。我会先给出可复制的config.toml与settings.json片段,再给出验证 Runtime 加载与 Skills 注册是否生效的具体动作,最后把常见报错逐条排掉。你不需要先通读全部源码,跟着配置和验证步骤走,就能在本地把关键路径跑通。
2. TaoToken 前置:给 Agent Runtime 准备一个稳定的模型入口
OpenClaw 的 Agent Runtime 本身不生产推理能力,它通过 Provider 层去调用外部 LLM。源码里src/providers/做了统一抽象,支持 Anthropic、OpenAI、Gemini、DeepSeek 以及任意 OpenAI 兼容端点。也就是说,只要你的模型入口兼容 OpenAI 的chat/completions协议,就能挂进 OpenClaw 的 Provider 体系。
我自己的做法是先用 TaoToken 把模型入口固定下来,再让 OpenClaw 去连。这样做的原因是:Agent Runtime 在 ReAct 循环里会频繁发起多轮请求,工具调用、上下文回灌、循环检测都会增加请求次数,如果模型入口本身不稳定,排障时很难判断是 Runtime 的问题还是上游的问题。
TaoToken 的 API 地址是https://taotoken.net/api,兼容 OpenAI 协议。你需要在控制台创建一个 API Key,然后把它写进 OpenClaw 的 Provider 配置里。创建 Key 的入口在这里:
控制台与 API Key 管理:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite
如果你只是想先验证模型能不能通,不想动 OpenClaw 的配置,可以直接用模型对话页面发一条消息试试:
模型对话验证:https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite
对于长期跑编码类 Agent、需要反复调用工具的场景,Coding Plan 会更合适,因为它的额度模型更贴近高频多轮调用:
Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite
拿到 Key 之后,先别急着写 OpenClaw 配置。用一条 curl 确认入口是通的,这一步能省掉后面大量「到底是 Key 错还是配置错」的纠结。
curl -s https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet", "messages": [{"role": "user", "content": "reply with ok"}], "max_tokens": 16 }'返回里能看到choices[0].message.content就说明入口没问题。接下来所有 OpenClaw 的 Provider 配置,都指向这个base_url。
3. 可复制配置:config.toml 与 settings.json 的骨架
OpenClaw 的配置分两层:config.toml管 Gateway 与 Provider 这类运行时级参数,settings.json管 Agent 与 Skills 这类能力级挂载。两者职责不同,混在一起写是新手最常见的坑。
3.1 config.toml:Gateway 与 Provider
先看config.toml。它决定 Gateway 监听在哪、用哪个 Provider、API Key 从哪来。注意 Key 不要硬编码,用环境变量引用。
# config/config.toml [gateway] host = "127.0.0.1" port = 8787 session_store = "./data/sessions.db" [provider.default] type = "openai-compatible" base_url = "https://taotoken.net/api/v1" api_key_env = "TAOTOKEN_API_KEY" model = "claude-sonnet" timeout_ms = 60000 [provider.fallback] type = "openai-compatible" base_url = "https://taotoken.net/api/v1" api_key_env = "TAOTOKEN_API_KEY" model = "deepseek-v3" timeout_ms = 60000 [runtime] max_tool_calls = 50 tool_call_history_size = 30 warning_threshold = 10 critical_threshold = 20这里几个参数和源码是对得上的。max_tool_calls = 50对应GLOBAL_CIRCUIT_BREAKER,也就是全局熔断器;tool_call_history_size = 30对应TOOL_CALL_HISTORY_SIZE,是循环检测器的历史窗口;warning_threshold和critical_threshold分别对应警告与临界阈值。把它们显式写出来,排障时你能一眼看到 Runtime 的边界在哪。
provider.fallback是回退策略。主模型失败时 Runtime 会自动切到备用模型,这在多轮工具调用里很关键,因为一次超时不该让整个 Agent 循环崩掉。
3.2 settings.json:Agent 与 Skills 挂载
settings.json决定有哪些 Agent、每个 Agent 挂哪些 Skills、Skills 从哪个目录扫描。
{ "agents": [ { "name": "researcher", "model": "claude-sonnet", "soul": "./agents/researcher/SOUL.md", "identity": "./agents/researcher/IDENTITY.md", "skills": ["weather", "github", "notion"], "workspace": "./workspaces/researcher" }, { "name": "coder", "model": "deepseek-v3", "soul": "./agents/coder/SOUL.md", "skills": ["code-gen", "code-review"], "workspace": "./workspaces/coder" } ], "skills": { "scan_dir": "./skills", "auto_reload": true, "inject_mode": "summary" }, "memory": { "events_file": "./data/events.jsonl", "summary_file": "./data/MEMORY.md", "session_db": "./data/sessions.db" } }skills.scan_dir指向./skills,Runtime 启动时会扫描这个目录下每个子目录里的SKILL.md,解析 YAML frontmatter,把技能摘要注入 System Prompt。inject_mode = "summary"表示只注入摘要而不是全文,避免 Token 堆积——这和源码里 Prompt Builder 的行为一致。
agents[].skills是白名单。只有列在这里的 Skill 才会被该 Agent 加载。如果你扫描目录里有 50 个 Skill,但 Agent 只挂了 3 个,那 Prompt 里只会出现这 3 个的描述。这是 Skills 模块「插件化内核」的体现:能力可热插拔,但每个 Agent 的可见范围是受控的。
3.3 SKILL.md 的最小骨架
Skills 目录里每个技能的核心是SKILL.md。它的 frontmatter 决定触发条件,正文决定执行步骤。
--- name: weather description: 查询指定城市的实时天气与未来预报 version: "1.0.0" triggers: - "天气" - "weather" tools: - name: get_weather description: "根据城市名获取天气数据" parameters: city: type: string description: "城市名称,如 Beijing" --- # 使用说明 当用户询问天气时,执行以下步骤: 1. 调用 get_weather,传入 city 参数 2. 解析返回的 JSON,提取温度、湿度、天气状况 3. 用自然语言格式化输出给用户triggers是给模型判断何时调用的线索,tools是实际可执行的工具定义。Runtime 在构建 Prompt 时会把这段 frontmatter 转成工具描述,模型通过 Function Calling 决定是否调用。
4. 验证请求:确认 Runtime 加载与 Skills 注册生效
配置写完不代表生效。OpenClaw 的启动流程是:CLI 入口 → Gateway boot → Channel 加载 → Session 路由 → Agent Runner → Agentic Loop。任何一环配置错位,Runtime 都可能「看起来起来了」但实际没挂上 Skills。下面给三个验证动作,从粗到细。
4.1 验证 Gateway 与 Provider 是否通
先启动 Gateway,看日志里有没有 Provider 初始化成功的记录。
export TAOTOKEN_API_KEY="你的Key" openclaw gateway start --config ./config/config.toml正常输出里应该能看到类似provider.default initialized: openai-compatible -> https://taotoken.net/api/v1的行。如果这里报api_key_env not found,说明环境变量没导出,或者变量名和config.toml里的api_key_env不一致。
然后用健康检查接口确认 Gateway 活着:
curl -s http://127.0.0.1:8787/health返回{"status":"ok","providers":["default","fallback"]}就说明 Provider 层注册成功。
4.2 验证 Agent Runtime 是否加载
Agent Runtime 的加载结果体现在 Agent 列表里。用 CLI 查询:
openclaw agents list --settings ./config/settings.json预期输出会列出researcher和coder两个 Agent,以及各自挂载的 Skills 数量。如果某个 Agent 没出现,检查settings.json里soul和identity指向的文件是否存在——Runtime 在加载 Agent 时会读取这两个 Markdown 文件,文件缺失会导致该 Agent 被跳过。
4.3 验证 Skills 是否注册进 Prompt
这一步最关键。Skills 注册是否生效,要看 Runtime 构建的 Prompt 里有没有技能描述。OpenClaw 提供了 dry-run 模式,可以打印出实际拼装的 Prompt 而不真正调用模型:
openclaw run --agent researcher \ --settings ./config/settings.json \ --message "北京今天天气怎么样" \ --dry-run输出里应该能看到 System Prompt 中包含了weather技能的工具描述,类似available_tools: [get_weather]。如果这里是空的,说明skills.scan_dir没扫到,或者agents[].skills白名单里没写weather。
我试过把scan_dir写成相对路径但启动目录不对,结果扫描到了空目录,dry-run 里工具列表一直是空的。后来改成从项目根目录启动,或者用绝对路径,问题就消失了。
4.4 完整跑一轮 ReAct 循环
dry-run 通过后,去掉--dry-run真正跑一次:
openclaw run --agent researcher \ --settings ./config/settings.json \ --message "北京今天天气怎么样"预期行为是:Runtime 构建上下文 → 调用模型 → 模型返回工具调用get_weather→ Runtime 执行 Skill 脚本 → 结果回灌 → 模型生成最终回复。日志里会看到多轮attempt记录,这正是src/agents/pi-embedded-runner/run/attempt.ts里的 ReAct 循环在跑。
如果模型直接回了文本而没有调用工具,通常是SKILL.md的triggers和用户输入匹配度太低,或者description写得太模糊,模型判断不出该用这个技能。
5. 本篇常见错排查
配置骨架跑不通,九成问题集中在这几类。我按报错现象倒推原因,方便你直接对号入座。
报错一:provider.default initialized之后立刻401 Unauthorized。Key 没传对。检查TAOTOKEN_API_KEY是否导出到当前 shell,以及config.toml里api_key_env的变量名是否完全一致。注意base_url要带/v1,写成https://taotoken.net/api会 404。
报错二:agents list为空。settings.json的 JSON 格式错了,或者soul/identity文件路径不存在。Runtime 对 Agent 加载是「全有或全无」,一个字段缺失就跳过整个 Agent。用jq . settings.json先验证 JSON 合法性。
报错三:dry-run 里available_tools为空。三个可能:skills.scan_dir路径不对;SKILL.md的 frontmatter 格式错(比如---没闭合);agents[].skills白名单没包含该技能。逐个排查,先确认scan_dir下确实有子目录且每个子目录有SKILL.md。
报错四:Runtime 跑几轮后报circuit breaker triggered。工具调用超过max_tool_calls = 50,全局熔断器生效。这通常意味着 Skill 脚本返回了模型无法理解的结果,导致模型反复重试同一个工具。检查 Skill 脚本的输出格式,确保返回的是结构化 JSON 而不是纯文本报错。
报错五:session_store写入失败。config.toml里session_store指向的目录不存在。OpenClaw 不会自动创建父目录,需要你手动mkdir -p ./data。同理,memory.events_file和summary_file的父目录也要先建好。
报错六:Skills 改了但 Runtime 没重新加载。settings.json里auto_reload为true时,Runtime 会监听scan_dir变化,但部分文件系统事件不可靠。稳妥做法是改完 Skill 后重启 Gateway,或者用openclaw skills reload手动触发。
6. 把配置骨架跑通之后,下一步往哪走
配置骨架跑通,意味着你已经把 OpenClaw 的五层架构里最容易被忽略的「装配层」打通了。Gateway 接渠道、Agent Runtime 跑 ReAct 循环、Skills 提供能力,这三者的连接点全在config.toml和settings.json里。源码再复杂,落到你手上的操作就是这两份文件加一个SKILL.md。
如果你要继续深入,建议按源码阅读路线走:先看src/gateway/boot.ts理解初始化顺序,再看src/agents/pi-embedded-runner/run/attempt.ts理解 ReAct 循环,最后看src/agents/tool-loop-detection.ts理解四种循环检测器怎么防止 Agent 失控。这三处看完,整个 Runtime 的骨架就立起来了。
接入文档里有 Provider 配置和 Skills 规范的完整说明,遇到字段不确定时可以直接查:
接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
如果你打算把 Agent 长期挂在编码或工具调用场景里跑,Coding Plan 的额度模型比按次调用更划算,适合高频多轮的 ReAct 循环:
Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite
最后留一个实用习惯:每次改完settings.json,先跑--dry-run看 Prompt 拼装结果,再跑真实请求。这一步能帮你把「配置错」和「模型行为不符合预期」两类问题彻底分开,排障效率会高很多。