OpenClaw 飞书多Agent配置实战
OpenClaw 飞书多Agent配置实战
本文基于我自己机器上跑的
openclaw@2026.6.11,配置文件就是那份~/.openclaw/openclaw.json。下面出现的 appId、token、open_id 全部脱敏过,你别直接抄。适合谁看:第一次在自己电脑上把 OpenClaw 跑起来、还想接到飞书里挂多个 Agent 的同学。
一、OpenClaw 到底是个啥(顺便八一卦改名史)
项目最早叫 Clawdbot(Clawd + robot,灵感就是 Claude 那个龙虾爪的梗),2026 年初突然爆火。结果火得太大,Anthropic 注意到了,1 月 27 日直接发律师函,说 Clawd / Clawdbot 跟 Claude 太像了。项目当天紧急改名 Moltbot(Molt 是蜕壳的意思,吉祥物是只蜕壳的小龙虾 Molty 🦞),算是过渡。到了 1 月底,最终定名 OpenClaw,一直用到现在。所以你要是看到老文章里写 Clawdbot、Moltbot,别懵,都是同一个东西,旧命令 clawdbot 现在也还兼容。
作者是 Peter Steinberger,就是做 PSPDFKit 的那位,大佬出品。项目完全开源、跑在本地,地址在 github.com/openclaw/openclaw,中文文档在 docs.openclaw.ai/zh-CN。
那它到底能干啥?一句话:它是个本地跑的多 Agent 编排网关。
- 把各种聊天渠道的消息(飞书、Slack、Discord、Telegram、邮件……)统一收到一个本地服务里;
- 按
bindings这张路由表,把每条消息送到对应的agent; - 每个
agent拿到消息后,去调大模型 → 决定该调哪些 skill / 工具 → 把结果发回原来的渠道。
整个运行时就一个进程(openclaw gateway),全靠 openclaw.json 这一份配置驱动。这点我觉得设计得挺干净,改配置基本等于改整个系统的行为。
我这套环境的结构大概是这样:
[飞书 bot1(日常)] ─┐
[飞书 bot2(分析)] ─┼─→ [openclaw gateway :18789] ─→ [agent: main / aff / zhaochao]
[飞书 bot3(杂活)] ─┘ │ │
├→ [skills] ├→ [大模型 provider]
├→ [plugins(feishu/acpx)] ├→ [skills]
└→ [hooks] └→ [channels: feishu]
二、配置文件在哪儿,长啥样
路径固定:~/.openclaw/openclaw.json(Windows 是 C:\Users\<你>\.openclaw\openclaw.json)。它其实是 JSON5,所以你可以写注释、尾逗号也无所谓,这点对人类挺友好。
如果你改过环境变量,位置可能不一样:OPENCLAW_CONFIG_PATH 能覆盖文件路径,OPENCLAW_STATE_DIR 能覆盖整个状态目录。但一般不用动。
我这份配置顶层一共 15 个 key,按字典序排:
| Key | 类型 | 一句话作用 |
|---|---|---|
acp |
dict | Agent Client Protocol,接 Claude Code / Codex 这类编码 CLI |
agents |
dict | Agent 配置 + 列表(灵魂) |
auth |
dict | 大模型 provider 的鉴权 profile |
bindings |
list | 渠道 → Agent 的路由表(最容易踩坑) |
channels |
dict | 渠道配置(飞书、Slack……) |
commands |
dict | CLI 命令行为开关 |
gateway |
dict | 本地 HTTP 服务配置 |
hooks |
dict | 内部 hook(启动时跑那些) |
meta |
dict | 文件元数据(版本 / 改动时间) |
models |
dict | 大模型 provider + 模型目录 |
plugins |
dict | 插件(feishu / memory-core / acpx……) |
session |
dict | session 复用策略 |
skills |
dict | skill 的启用 / 禁用 |
tools |
dict | 工具集策略(决定 Agent 能调哪些内置工具) |
wizard |
dict | 上次跑 openclaw doctor 之类的记录 |
下面一个一个说。
三、meta / wizard:这俩别手贱改
"meta": {
"lastTouchedVersion": "2026.6.11",
"lastTouchedAt": "2026-07-02T16:42:29.329Z"
},
"wizard": {
"lastRunAt": "2026-07-02T16:42:29.228Z",
"lastRunVersion": "2026.6.11",
"lastRunCommand": "doctor",
"lastRunMode": "local"
}
这俩是 OpenClaw 自己写进去的:
meta:每次 OpenClaw 写配置时,顺手记一下版本号和 ISO 时间;wizard:每次你跑openclaw doctor/configure/onboard,它记一笔。
别手改,下次 OpenClaw 自己写配置会直接覆盖掉,白费劲。我一开始不知道,还手动把 lastTouchedAt 往前调过,想着能不能"骗"它,结果毫无卵用。
四、auth:API key 到底存哪了
先看配置里这段:
"auth": {
"profiles": {
"minimax-cn:default": { "provider": "minimax-cn", "mode": "api_key" },
"minimax:cn": { "provider": "minimax", "mode": "api_key" }
}
}
字段意思:
profiles的 key 长这样<provider>:<profile名>,后面那个名字纯粹是给你自己好认的;provider对应下面models.providers里的 provider id;mode目前只支持api_key(OAuth 是预留的,还没开放)。
重点来了,也是我一开始最懵的地方:真正的 API key 根本不在这份 json 里。
网上有些老教程会让你把 apiKey 直接写在 models.providers.xxx 下面,那样确实能跑,但等于把 key 明文扔配置文件里了,不太安全。OpenClaw 实际的设计是:openclaw.json 只记"用哪个 provider + 哪个 profile",真正的凭证单独放在 Agent 的状态目录下:
~/.openclaw/agents/<agentId>/agent/auth-profiles.json
老版本的话在 ~/.openclaw/credentials/ 下。会话记录那些则在同目录的 openclaw-agent.sqlite 里。所以别在配置文件里找你的 key,找不到的。
那怎么把 key 填进去?两条路:
# 方式一:配置向导,一步步选
openclaw configure
# 选 model providers → 选 minimax-cn → 粘贴 api_key
# 方式二:直接命令行登录
openclaw models auth setup-token
我比较推荐第二种,一行搞定,不用在向导里翻菜单。
五、models:怎么把大模型接进来
这段配的是"有哪些大模型可以用、走哪个端点"。我接的是 MiniMax:
"models": {
"mode": "merge",
"providers": {
"minimax-cn": {
"baseUrl": "https://api.minimaxi.com/anthropic",
"api": "anthropic-messages",
"authHeader": true,
"models": [
{
"id": "MiniMax-M3",
"name": "MiniMax M3",
"reasoning": true,
"input": ["text", "image"],
"cost": {
"input": 0.6,
"output": 2.4,
"cacheRead": 0.12,
"cacheWrite": 0
},
"contextWindow": 1000000,
"maxTokens": 131072
}
]
},
"minimax": {
"baseUrl": "https://api.minimaxi.com/anthropic"
// ... 同上
}
}
}
挨个说:
mode: "merge":把你这里写的模型和 OpenClaw 内置的模型合并起来用,而不是覆盖。一般都填 merge;providers.<名字>.baseUrl:provider 的 HTTP 端点;providers.<名字>.api:API 协议风格。MiniMax 这个填anthropic-messages——这里我专门查过,MiniMax 官方确实提供了 Anthropic 兼容端点https://api.minimaxi.com/anthropic/v1/messages,M3 还支持 thinking 和工具调用,所以配成 anthropic 风格是没问题的;如果你接的是通义、Kimi 之类走 OpenAI 兼容的,就填openai-chat-completions;providers.<名字>.authHeader: true:把 key 放在x-api-key头里(Anthropic 风格)。OpenAI 风格是Authorization: Bearer ...,那种就不用开这个;providers.<名字>.models[]:模型目录。
模型那一项里的字段:
id:模型的真实 id,调 API 时用的就是它;name:界面上显示的名字,随你喜欢;reasoning: true:这个模型支持扩展思考(思维链);input:能吃text/image/audio哪几种输入;cost:每 100 万 token 的价格(美元),OpenClaw 拿它来估算成本;contextWindow:上下文窗口大小;maxTokens:单次最多吐多少 token。
顺便解释个新手常见的疑惑:我这儿配了 minimax-cn 和 minimax 两个 provider,baseUrl 还一模一样,这不是写错了吗?其实是历史遗留,最早一个走国内端点、一个走国际端点,后来 MiniMax 统一了,我也就没动。正常你留一个就行。多个 provider 的常见场景是:国内外端点不同、不同厂商(OpenAI / Anthropic / 自部署)、或者不同协议风格。
六、agents:整个配置的灵魂
多 Agent 的核心就在这一段。先看我配的三个:
"agents": {
"defaults": {
"model": { "primary": "minimax-cn/MiniMax-M3", "fallbacks": [] },
"models": {
"minimax-cn/MiniMax-M3": { "alias": "M3" },
"minimax/MiniMax-M3": { "alias": "Minimax" }
},
"workspace": "/Users/ajun/.openclaw/workspace"
},
"list": [
{
"id": "main",
"tools": { "alsoAllow": ["message"] }
},
{
"id": "aff",
"name": "分析",
"workspace": "/Users/ajun/projects/github/aff-data-analysis",
"agentDir": "/Users/ajun/.openclaw/agents/aff/agent",
"model": "minimax-cn/MiniMax-M3",
"tools": { "alsoAllow": ["message"] }
},
{
"id": "zhaochao",
"name": "早朝官",
"workspace": "/Users/ajun/.openclaw/workspace-zhaochao",
"agentDir": "/Users/ajun/.openclaw/agents/zhaochao/agent",
"model": "minimax-cn/MiniMax-M3",
"tools": { "alsoAllow": ["message"] }
}
]
}
defaults:所有 Agent 的默认值
model.primary:默认主模型,格式是<provider>/<模型id>;model.fallbacks:主模型挂了的时候,依次往下试的备胎列表;models.<主模型>.alias:模型在界面 / 提示词里的小名,方便看;workspace:默认工作目录,Agent 就在这儿执行 shell、读写文件。
list[]:每个 Agent 的具体配置
id:唯一标识,后面bindings和命令行的--agent都靠它认人;name:界面显示名;workspace:每个 Agent 可以有自己独立的工作目录,这点特别重要。比如我的aff这个分析 Agent,工作目录直接指到了~/projects/github/aff-data-analysis,这样它就能直接读改那个项目的代码,不用我再搬文件;main默认用~/.openclaw/workspace;agentDir:OpenClaw 给这个 Agent 留的"私人小金库",存它的 session、模型配置、长期记忆;model:覆盖defaults.model.primary,让某个 Agent 单独换个模型;tools.alsoAllow:在tools.profile基础上额外开几个工具。我给所有 Agent 都加了["message"],意思是允许它们主动给我发消息,不光是被动回消息——不然我的"早朝官"就做不到每天早上主动给我汇报了。
一个容易搞混的点:agentDir 不是 skill 目录
一开始我以为 agentDir 是放技能的地方,后来才发现不是。它存的是这个 Agent 的会话、记忆、凭证、模型注册表这些状态。
关于 skill 的加载,我得纠正一个网上常见的说法。有人(包括我自己一开始)以为"skill 全局共享、没法按 Agent 隔离",这其实不对。官方文档写得很清楚:
Skills 从每个 Agent 的工作区以及
~/.openclaw/skills共享根目录加载,然后按每个 Agent 的有效允许列表筛选。
也就是说,池子是共享的,但能上桌的菜可以按 Agent 限。用 agents.defaults.skills 设一个公共基线,再用 agents.list[].skills 给单个 Agent 开白名单 / 黑名单(注意:单个 Agent 里显式写的会替换默认值,不是合并,这点别踩)。
还有个配套设计:每个 Agent 可以有自己的 sandbox 和工具限制,比如给家庭群里那个 Agent 关掉 write / exec 这种危险工具:
{
"id": "family",
"sandbox": { "mode": "all", "scope": "agent" },
"tools": {
"allow": ["read"],
"deny": ["exec", "write", "edit", "browser"]
}
}
这点我觉得设计得很贴心,不同 Agent 给不同权限,不至于一个失控全家升天。
七、tools:给 Agent 发什么工具
"tools": {
"profile": "coding"
}
OpenClaw 内置了几套工具集 profile,按场景打包好:
coding:编程场景(我用的就是这个),带file_fetch/file_write/dir_list/pdf/tts这些;minimal:极简,只留最基本的消息类工具;full:全开;- 其它 profile 看版本。
你去看日志,经常能翻到这种:
[agents/tool-policy] tool policy removed 24 tool(s) via tools.profile (coding):
agents_list, browser, canvas, dir_fetch, ...
意思就是:这个 Agent 用了 coding 工具集,下面列出的这些工具被屏蔽掉了(OpenClaw 内部会按 Agent 类型再细分一遍)。第一次看到这行日志别慌,这不是报错,是正常的策略输出。
八、commands / session / hooks
这三个比较短,一起说。
commands
"commands": {
"native": "auto",
"nativeSkills": "auto",
"restart": true,
"ownerDisplay": "raw",
"ownerAllowFrom": [
"feishu:ou_24c83fff63626f2b627e43046160d6d0"
]
}
native: "auto":自动决定把哪些内置命令(/help、/status这种)暴露给模型;nativeSkills: "auto":要不要把 skill 也当命令暴露;restart: true:网关自愈开关,配合 launchd 的 KeepAlive 双保险;ownerDisplay: "raw":owner 标识原样显示,不打码;ownerAllowFrom:owner 白名单,只有这里的 user id 能调管理类命令。
这个白名单一定要配,不然理论上谁发消息都能调你的管理命令,那就裸奔了。后面那个 ou_24c83fff... 就是飞书里你自己的 open_id,去飞书管理后台能查到。
session
"session": {
"dmScope": "per-channel-peer"
}
dmScope 决定私聊的 session 怎么复用,三种:
per-channel-peer:同一个(渠道, 用户)共享一个 session。推荐,我的aff用的就是这种,跟同一个人聊就一直有上下文;global:所有消息共用一个 session,会串话,一般别用;per-channel:同渠道所有人共用一个 session,也会串。
hooks
"hooks": {
"internal": {
"enabled": true,
"entries": {
"boot-md": { "enabled": true },
"bootstrap-extra-files": { "enabled": true },
"command-logger": { "enabled": true },
"session-memory": { "enabled": true }
}
}
}
这几个是 OpenClaw 启动时内部跑的 hook:
boot-md:启动时读 Agent 工作区里的 markdown,注入到 system prompt。它读的核心是AGENTS.md、SOUL.md、USER.md这几个,完整的还有MEMORY.md、HEARTBEAT.md、IDENTITY.md、BOOT.md,这几个文件写得好不好,直接决定你的 Agent 好不好用,后面可以单开一篇细说;bootstrap-extra-files:扫agentDir里的额外文件;command-logger:所有命令行 / API 调用记日志,排查问题的时候特别香;session-memory:把会话历史压缩进长期记忆,让它越用越懂你。
装的时候向导最后会让你勾选这几个,我建议都开,没坏处。
九、channels:飞书多 Bot 怎么挂
这段是接飞书的关键,我配了多账号结构:
"channels": {
"feishu": {
"enabled": true,
"connectionMode": "websocket",
"domain": "feishu",
"groupPolicy": "open",
"defaultAccount": "default",
"accounts": {
"default": {
"enabled": true,
"name": "default",
"appId": "cli_a9315dd166789bb3",
"appSecret": "<YOUR_LARK_APP_SECRET>",
"connectionMode": "websocket",
"domain": "feishu",
"groupPolicy": "allowlist",
"groupAllowFrom": ["ou_24c83fff63626f2b627e43046160d6d0"],
"allowFrom": ["ou_24c83fff63626f2b627e43046160d6d0"]
},
"bot2": { "name": "aff-bot", "appId": "...", "appSecret": "..." },
"bot3": { "name": "bot3", "appId": "...", "appSecret": "..." }
}
}
}
顶层几个字段
enabled:飞书集成的总开关;connectionMode: "websocket":长连接模式,强烈推荐。本机直接和飞书服务器保持一条长连接,不需要公网 IP。另一个选项是webhook,那个要公网回调地址,本地玩不转,别选;domain: "feishu":国内飞书。境外 Lark 填"lark";groupPolicy: "open":群消息策略,顶层我开了 open;defaultAccount: "default":匹配不到具体账号时的兜底。
每个飞书账号
appId/appSecret:去 open.feishu.cn/app 建个自建应用,凭证页面就能拿到。App Secret 跟密码一样,别泄露;name:给人看的名(aff-bot、bot3 之类);groupPolicy:群消息策略(open/allowlist/closed);groupAllowFrom/allowFrom:群消息 / 私聊的白名单,放 user open_id。
如果你的场景简单(就挂一个 bot),其实不用这么复杂,写成顶层的扁平结构也行:
"channels": {
"feishu": {
"enabled": true,
"appId": "cli_xxx",
"appSecret": "xxx",
"connectionMode": "websocket"
}
}
多账号到底图啥
一句话:一机多 Agent,用不同飞书 bot 隔离开。
- 飞书
default这个 bot → 绑mainAgent(日常聊天); - 飞书
bot2 = aff-bot→ 绑affAgent(数据分析); - 飞书
bot3→ 绑zhaochaoAgent(杂活汇报)。
这样同一台机器上,三个 Agent 互不打扰,各自有自己的记忆、各自的飞书入口。对外的体验就是:我在飞书里跟不同 bot 说话,就是在跟不同的"员工"派活。
配对(pairing)这个坎儿
接飞书还有一步新手特别容易卡:配对。机器人刚加上不会马上回消息,得先走配对流程,相当于加个好友验证。
# 看谁在请求配对
openclaw pairing list feishu
# 批准(CODE 换成实际的配对码)
openclaw pairing approve feishu <CODE>
我当时就是没配对,对着机器人发了半天消息没反应,还以为是配置错了,查半天日志。记住:机器人不回消息,先 openclaw pairing list 看看是不是卡在配对上。
十、gateway:本地这个 HTTP 服务
"gateway": {
"port": 18789,
"mode": "local",
"bind": "loopback",
"auth": {
"mode": "token",
"token": "<YOUR_GATEWAY_TOKEN>"
},
"tailscale": {
"mode": "off",
"resetOnExit": false
}
}
port: 18789:本地 HTTP 端口,这是默认值。网页控制台(Control UI)和 ACP 后端都挂在它上面。访问http://127.0.0.1:18789/就是管理界面;mode: "local":本地模式(另一个是"tailscale",走 Tailscale 网络);bind: "loopback":只监听 127.0.0.1,安全。想从外网访问得用 Tailscale、ngrok 或者反向代理,别图省事直接 bind 到 0.0.0.0;auth.mode: "token":用静态 token 鉴权;tailscale.mode: "off":我没用 Tailscale,关掉。
token 自己生成一个就行:
openssl rand -hex 32 # 生成 64 位 hex
端口被占了怎么办:这是最常见的启动失败原因。先查一下端口:
# macOS / Linux
lsof -i :18789
# 或者
ps aux | grep openclaw
# Windows
netstat -ano | findstr 18789
确认是旧进程没退干净就 kill 掉,或者干脆换个端口。要换端口的话,除了改 gateway.port,launchd 那边如果有显式端口绑定也得同步改。
另外提一个很实用的点:配置改完怎么生效。第一选择永远是这条:
openclaw gateway restart
跨平台、官方推荐。改完配置记得先校验 JSON 没写错再重启:
# 校验配置合法性(这命令救过我好几回)
openclaw config validate
# 重启
openclaw gateway restart
macOS 上如果你是手动装的守护进程,也可以用 launchctl 那一套(但能用 openclaw gateway restart 就别折腾 launchctl 了):
launchctl unload ~/Library/LaunchAgents/ai.openclaw.gateway.plist
launchctl load ~/Library/LaunchAgents/ai.openclaw.gateway.plist
OpenClaw 还有个热重载机制,默认 hybrid 模式——能热加载的就热加载(不中断连接),必须重启的才重启。所以有些小改动其实不用手动 restart。但新手老老实实 restart 最稳。
十一、plugins:插件加载
"plugins": {
"load": {
"paths": [
"/Users/ajun/.openclaw/npm/projects/openclaw-feishu-.../node_modules/@openclaw/feishu"
]
},
"entries": {
"feishu": { "enabled": true },
"minimax": { "enabled": true },
"memory-core": { "config": { "dreaming": { "enabled": true } }, "enabled": true }
}
}
load.paths:从哪些本地路径加载插件,一般是 npm 全局装完后的真实路径;entries.<插件名>.enabled:插件开关;memory-core.dreaming:memory-core 插件的"梦境"配置,后台会周期性跑叙事生成、整理记忆,让它记得更牢。
装插件用命令,别手动往 paths 里塞:
openclaw plugins list # 看装了啥
openclaw plugins install @openclaw/voice-call # 装官方插件
openclaw plugins enable feishu # 启用
openclaw gateway restart # 装完记得重启
十二、skills:技能开关
"skills": {
"entries": {
"api-gateway": { "enabled": false },
"gog": { "enabled": false },
"summarize": { "enabled": false }
}
}
这里有个反直觉的点,我愣了一会儿才反应过来:这里出现的,都是默认禁用的 skill;已经启用的反而不在这里出现(默认就是启用)。
所以你想彻底关掉某个 skill,就往这儿加一条 "enabled": false。
技能的来源,新手我强烈推荐走 ClawHub(官方技能市场,clawhub.ai,国内有镜像 skillhub.tencent.com),别随便从野路子装,风险很大:
# 装 clawhub 工具(推荐 npx,不用全局装)
npx clawhub@latest --version
# 搜技能
clawhub search "postgres backups"
# 装一个
clawhub install my-skill-pack
# 批量更新
clawhub update --all
装完看一眼状态:
openclaw skills list # 列出所有技能
openclaw skills info <名字> # 看详情
skills list 输出里,技能状态分几种:
✓ ready:环境齐了,Agent 能直接用;△ Needs setup:缺环境变量,得去service-env/*.env里补;disabled:被skills.entries关了;- 啥都没有:文件在,但元数据不够,OpenClaw 认不出来。
十三、bindings:消息路由表(最容易踩坑)
⭐ 这一段是整个系统里最关键的部分:一条飞书消息到底该送给哪个 Agent。
"bindings": [
{ "agentId": "main", "match": { "channel": "feishu", "accountId": "default" } },
{ "agentId": "aff", "match": { "channel": "feishu", "accountId": "bot2" } },
{ "agentId": "zhaochao", "match": { "channel": "feishu", "accountId": "bot3" } }
]
bindings 是个有序数组,从上往下匹配,第一条命中的生效:
default飞书账号 →mainAgent;bot2 = aff-bot→affAgent;bot3→zhaochaoAgent。
几个匹配规则,必须记住
- 顺序就是优先级。把最具体的规则放前面,最宽的放后面。顺序错了,就会出现"明明发给 bot2 的消息被 main 收了"这种鬼故事;
- 多个字段是 AND 关系。一条 binding 里同时写了
peer和guildId,那必须俩都匹配才生效; - 省略
accountId只匹配默认账号,不是匹配所有账号。要"渠道级兜底"用accountId: "*"; - 对端(peer)匹配永远优先于渠道级规则。想给某个特定的人 / 群单独路由,就用
match.peer,把它写在前面。
举个高级点的例子——WhatsApp 一个号,按发件人拆给不同 Agent:
"bindings": [
{ "agentId": "alex", "match": { "channel": "whatsapp", "peer": { "kind": "direct", "id": "+15551230001" } } },
{ "agentId": "mia", "match": { "channel": "whatsapp", "peer": { "kind": "direct", "id": "+15551230002" } } }
]
加一个新 Agent 的标准三连
# 1. 创建 Agent
openclaw agents add myagent --workspace /path/to/project
# 2. 手动在 channels.feishu.accounts 加一个 bot 账号(比如 bot4)
# 填上对应的 appId / appSecret
# 3. bindings 加一条
# { "agentId": "myagent", "match": { "channel": "feishu", "accountId": "bot4" } }
# 然后验证一下
openclaw agents list --bindings
openclaw channels status --probe
最后别忘了 openclaw gateway restart。
十四、acp:让 Claude Code 给你打黑工
这一段我最开始理解错了,得重点纠正一下。
"acp": {
"enabled": true,
"backend": "acpx",
"defaultAgent": "claude",
"allowedAgents": ["claude", "codex", "cursor", "gemini", "qwen", "copilot"],
"maxConcurrentSessions": 4,
"stream": {
"coalesceIdleMs": 300,
"maxChunkChars": 1200
},
"runtime": {
"ttlMinutes": 120
}
}
先说 ACP 是什么。我以前以为它是 Anthropic 家的协议,后来查了才搞明白:ACP 全称 Agent Client Protocol,是一个开放协议(规范在 agentclientprotocol.com),不是哪一家私有的。在 OpenClaw 里,它通过 acpx 插件实现,作用是把本地那些命令行编码 Agent——Claude Code、Codex、Gemini CLI、Cursor、OpenCode——统一接进来当"执行层"。
说白了,架构是分层的:
你(在飞书发消息)
↓
OpenClaw Agent(决策层:理解你要干嘛)
↓ 通过 ACP
acpx(中层:管 session、任务队列、上下文)
↓
Claude Code / Codex / Gemini CLI(执行层:真去改代码、跑 git)
这样我在飞书里说一句"把登录接口加上限流",OpenClaw 的 Agent 就能 spawn 一个 Claude Code 去真改代码、提交,完全不用我开终端。
字段意思:
backend: "acpx":用 acpx 这个实现,它是 openclaw/acpx 这个仓库,headless CLI 客户端;defaultAgent: "claude":默认 spawnclaude(Claude Code);allowedAgents:白名单,只允许这里列的 CLI 被 spawn,防止 Agent 乱拉进程;maxConcurrentSessions: 4:同时最多 4 个 ACP session;stream.coalesceIdleMs:流式输出的合并间隔,减少飞书卡片刷新次数(飞书卡片更新太频繁会限流);stream.maxChunkChars:单个 chunk 最大字符数,也是为了迁就飞书卡片限制;runtime.ttlMinutes: 120:ACP session 的缓存时间,两小时。
一个必填项,我踩过坑
acpx 装好之后,还有一个配置特别容易漏:因为 ACP 会话是非交互式的(没人坐在那儿点同意),所以必须把权限模式设成全部放行,不然 Claude Code 卡在那儿等批准,一直没动静:
// 在对应 Agent 或 acpx 配置里
"permissionMode": "approve-all"
装 acpx 插件本身:
openclaw plugins install @openclaw/acpx
openclaw gateway restart
弄好之后,让 Agent 内部调 acp spawn claude,OpenClaw 就会自动拉起 Claude Code 去干活。普通用户到这一步就够了,ACP 底层的 WebSocket 细节完全不用管,它自己跑。
十五、几个常见改动场景
把上面零碎的字段串一下,挑几个最常干的事。
场景 A:加个新飞书 bot + 新 Agent
# 1. 建 Agent
openclaw agents add devops \
--name "DevOps" \
--workspace ~/projects/devops-scripts
# 2. 手动编辑 openclaw.json,在 channels.feishu.accounts 下加 bot4
# (填从飞书开放平台拿到的 appId / appSecret)
# 3. bindings 加一条
# { "agentId": "devops", "match": { "channel": "feishu", "accountId": "bot4" } }
# 4. 校验 + 重启
openclaw config validate
openclaw gateway restart
场景 B:换个默认模型
把 models.providers.<名字>.models[].id 改成新模型,然后在 agents.defaults.model.primary 把 <provider>/<模型id> 引用也同步更新。别只改一半,会出现"模型没配置"的提示。
场景 C:禁掉某个 skill
"skills": {
"entries": {
"summarize": { "enabled": false }
}
}
场景 D:换 gateway 端口
改 gateway.port,launchd 那边如果有显式端口绑定也要一起改,然后重启。
十六、新机器第一次配置清单
换台机器从头配,按这个顺序走基本能起来:
- 装本体。一行命令(macOS / Linux):
curl -fsSL https://openclaw.ai/install.sh | bash;Windows PowerShell:iwr -useb https://openclaw.ai/install.ps1 | iex。或者npm i -g openclaw(要 Node.js ≥ 22); - 跑引导:
openclaw onboard --install-daemon(--install-daemon让它开机自启); - 配模型:向导里选 provider、填 key,或者后面
openclaw models auth setup-token; - 接飞书:
openclaw channels add选 Feishu,填 appId / appSecret; - 建 Agent:
openclaw agents add; - 写
bindings路由; - 检查:
openclaw agents list --bindings、openclaw skills list; - 健康检查:
openclaw doctor(支持--deep); - 看环境变量齐不齐:
openclaw config get或者直接翻~/.openclaw/service-env/下的 env 文件; - 重启 + 测试:
openclaw gateway restart,然后飞书发条消息,记得先openclaw pairing list/pairing approve走配对。
跑顺了之后,日常就靠这几个命令活着:
openclaw status # 整体状态
openclaw gateway status # 网关进程状态
openclaw logs --follow # 实时日志,排查必备
openclaw dashboard # 浏览器打开控制台( http://127.0.0.1:18789/ )
openclaw tui # 终端里直接聊,SSH 进服务器也能用
十七、我踩过的坑(按时间顺序)
| 坑 | 现象 | 解法 |
|---|---|---|
| webhook 模式收不到消息 | 本机怎么都不回 | 改用 connectionMode: "websocket",长连接不需要公网 |
没配 ownerAllowFrom |
谁都能调管理命令 | 填自己的 feishu:ou_xxx |
| 忘了配对 | 机器人死活不回消息 | openclaw pairing list feishu 看请求,再 pairing approve |
bindings 顺序乱 |
发给 bot2 的消息被 main 收了 | 调顺序,具体规则在前,兜底在后 |
acp.allowedAgents 没配 |
ACP 默认啥都不让 spawn | 把 "claude" / "codex" 加进白名单 |
ACP 没设 permissionMode |
Claude Code 卡住不干活 | 设成 "approve-all"(非交互式必需) |
模型没填 id |
openclaw skills info 显示模型未配置 |
补上 id 字段 |
| 改完配置没生效 | 新配置像没起作用 | openclaw config validate 校验 → openclaw gateway restart |
| 端口冲突起不来 | gateway 启动失败 | lsof -i :18789 查占用,kill 掉或换端口 |
| 以为 skill 全局共享没法隔离 | 给敏感 Agent 配了危险工具 | 用 agents.list[].skills 和 tools.allow/deny 按 Agent 限权 |
十八、字段速查表(收藏用)
按字母序排,方便以后翻:
| 字段 | 类型 | 默认 | 备注 |
|---|---|---|---|
acp.allowedAgents |
list | — | 白名单 CLI 名 |
acp.backend |
str | "acpx" |
ACP 实现 |
acp.defaultAgent |
str | — | 默认 spawn 哪个 |
acp.enabled |
bool | false |
总开关 |
acp.maxConcurrentSessions |
int | 4 |
并发上限 |
acp.runtime.ttlMinutes |
int | 120 |
session 缓存分钟 |
agents.defaults.model.primary |
str | — | <provider>/<模型> |
agents.defaults.skills |
dict | — | 共享 skill 基线 |
agents.list[].agentDir |
path | — | Agent 私有状态目录 |
agents.list[].skills |
dict | — | 每 Agent 的 skill 允许列表(替换默认值) |
agents.list[].workspace |
path | — | Agent 工作目录 |
auth.profiles |
dict | — | <provider>:<名字> → profile |
bindings[].agentId |
str | — | 必须对上 agents.list[].id |
bindings[].match.accountId |
str | — | 必须对上 channels.<渠道>.accounts 的 key,"*" 表示渠道兜底 |
bindings[].match.channel |
str | — | "feishu" 等 |
channels.feishu.accounts |
dict | — | 每个 account = 一个飞书 bot |
channels.feishu.connectionMode |
str | — | 推荐 "websocket" |
commands.ownerAllowFrom |
list | — | owner 白名单 |
gateway.auth.token |
str | — | 随机 hex token |
gateway.bind |
str | "loopback" |
"loopback" / "all" |
gateway.port |
int | 18789 |
本地端口 |
models.providers[].api |
str | — | "anthropic-messages" / "openai-chat-completions" 等 |
models.providers[].baseUrl |
url | — | 大模型端点 |
models.providers[].models[].id |
str | — | 模型真实 id |
models.providers[].models[].reasoning |
bool | — | 支不支持 thinking |
session.dmScope |
str | — | "per-channel-peer" / "global" |
skills.entries |
dict | — | 显式禁用某些 skill |
tools.profile |
str | — | coding / minimal / full |
小结
OpenClaw 这份 openclaw.json 看着字段多,其实顺着"渠道进来 → bindings 路由 → agents 处理 → models 出答案 → tools/skills 打辅助 → acp 接外部编码 CLI"这条线捋一遍,就清楚了。
真正卡人的就那几个地方:飞书用 websocket 别用 webhook、bindings 顺序、pairing 配对、acp 的 allowedAgents 和 permissionMode、改完记得 restart。这几个坎过了,剩下就是按需调参。
要是你也在折腾 OpenClaw 接飞书,欢迎评论区交流。下一篇我打算写写那几个 workspace 里的 markdown(SOUL.md、AGENTS.md、USER.md、MEMORY.md),那几个文件才是决定 Agent "好不好用、像不像你想要的那个人"的关键。

浙公网安备 33010602011771号