OpenClaw 实战 04|配置管理:双层模型注册 + Token 双源 + 4 处真实陷阱原创
# 配置管理:双层模型注册 + Token 双源 + 4 处真实陷阱
这一篇不讲"配置热加载、YAML vs TOML"那一套抽象话题,只讲OpenClaw 在真实配置变更中暴露的 4 类陷阱 + 标准修复流程。
本文所有内容都来自
~/.hermes/workspace/blog-material/notes/claude-code/下的 4 条真实会话记录(2026-06-16 ~ 2026-06-25),分别是:配置文件合理性审查、给 Provider 新增 model id、OpenWebUI 三个同名模型、Telegram Bot Token 轮换。关键认知:OpenClaw 的配置不是单一文件,是"主配置 + SQLite + env"三处协同的分布式状态。任何一处漏改,Agent 就掉线。
# §1 钩子:审查 上 OpenClaw 配置的那次
今年 4 月我想给
真实场景(来自 <session-file>):
我在 supervisorctl status openclaw 显示 RUNNING,但实际已经"假死"——CLI 完全连不上,Telegram Bot 走降级轮询还能用。
陷阱 1:Token 双源不一致
openclaw config get gateway.auth.token 返回 __OPENCLAW_REDACTED__(OpenClaw 自己脱敏),让我以为 Token 一样。实际:
# 读运行进程的 env(最可靠)
tr '\0' '\n' < /proc/$(pgrep -f openclaw-gateway)/environ | grep OPENCLAW_GATEWAY_TOKEN
# 读配置文件明文
python3 -c 'import json;print(json.load(open("/home/<USERNAME>/.openclaw/openclaw.json"))["gateway"]["auth"]["token"])'
# 两个值 sha256 比对(避免明文打印)
python3 -c "import hashlib;print(hashlib.sha256(b'<TOKEN_A>').hexdigest())"
2
3
4
5
6
7
8
发现两个 sha256 不一样。Gateway 启动读 env,CLI 读 config,两边谁也不管谁。
陷阱 2:Provider 改名没迁移 SQLite
Provider 从 claude-haiku 改名为 claude-internal 后,SQLite auth_profile_store 表里 claude-haiku 的 API Key 没动,Agent 一调模型就报 No API key found。
陷阱 3:模型 ID 加在 Provider 里但没加 Allowlist
models.providers.claude-internal.models 加了 minimax-m2.5,但 agents.defaults.models 没加,结果 /models 命令看不到新模型,Agent 路由不到。
陷阱 4:Telegram Bot Token 换了但日志里没确认
换了 botToken 后 Supervisor 日志出现 PermissionError: /usr/lib/python3/dist-packages/supervisor/xmlrpc.py,我以为是 OpenClaw Bug,去查 OpenClaw 源码浪费时间。实际是 Supervisor 守护进程通信层的噪音,不是 OpenClaw 问题。真正的验证要靠 OpenClaw 启动日志里的 Detected bot identity change。
这 4 个陷阱揭示了 OpenClaw 配置管理的 3 条本质:
- 3 处入口协同:主配置
openclaw.json+ SQLitestate+ env 变量,缺一不可 - 配置生效必须重启:仅 reload 不重启进程,Agent 看到的还是旧配置
- 日志噪声 ≠ 故障:要分清"应用层日志"和"进程管理层日志"
下面展开。
# §2 OpenClaw 配置的 3 类入口(不是单一文件)
多数人以为改个 JSON 就完事。实际 OpenClaw 有 3 处独立的配置存储:
| 入口 | 路径 / 形式 | 谁读它 | 改完要做什么 |
|---|---|---|---|
| 主配置 | ~/.openclaw/openclaw.json | CLI 客户端、Gateway(次要) | supervisorctl restart openclaw |
| SQLite 数据库 | ~/.openclaw/state(表 auth_profile_store / auth_profile_state / device_scope / cron_runs) | Gateway | supervisorctl restart openclaw |
| 环境变量 | Supervisor OPENCLAW_GATEWAY_TOKEN 等 | Gateway daemon 启动时 | 改了必须重启进程 |
# 2.1 主配置:openclaw.json
主配置是 JSON,按功能分 4 个顶层节点(来自 4 条素材综合):
{
"gateway": { // Gateway 自身行为
"bind": "lan", // localhost vs lan
"auth": {
"token": "${OPENCLAW_GATEWAY_TOKEN}" // 推荐引用 env,不硬编码
},
"http": {
"endpoints": {
"chatCompletions": { "enabled": true } // OpenAI 协议网关开关
}
}
},
"models": { // Provider + 模型注册(双层原则的"层 1")
"providers": {
"<PROVIDER_NAME>": {
"baseUrl": "https://api.example.com/v1",
"apiKey": "${<PROVIDER_NAME>_API_KEY}",
"models": ["kimi-k2.5", "minimax-m2.5"] // 模型 ID 列表
}
}
},
"agents": { // Agent 路由配置
"defaults": {
"models": { // 双层原则的"层 2"——路由白名单
"<PROVIDER_NAME>/kimi-k2.5": {},
"<PROVIDER_NAME>/minimax-m2.5": {}
}
}
},
"channels": { // 外部通道
"telegram": {
"botToken": "<TELEGRAM_BOT_TOKEN>",
"enabled": true
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
关键命令:
# 整段 patch(推荐)
openclaw config patch --stdin <<'JSON5'
{ "models.providers.<PROVIDER>.models": ["kimi-k2.5", "minimax-m2.5"] }
JSON5
# 单字段 set
openclaw config set gateway.auth.token '${OPENCLAW_GATEWAY_TOKEN}'
# 读字段(注意:token 会被脱敏为 __OPENCLAW_REDACTED__)
openclaw config get gateway.auth.token
2
3
4
5
6
7
8
9
10
# 2.2 SQLite 数据库:被忽视的"隐藏配置"
~/.openclaw/state 是个 SQLite 数据库,OpenClaw 把很多"配置数据"塞进数据库而非 JSON,导致改 JSON 没用:
| 表 | 存什么 | 修改后果 |
|---|---|---|
auth_profile_store | Provider 的 API Key 明文 | 改名后 Key 不自动迁移 |
auth_profile_state | Provider 状态(在线/限流) | 不影响配置,但影响路由 |
device_scope | CLI 设备的 Scope 权限 | CLI 权限变更不重启不生效 |
cron_runs | Cron 任务历史 | 只读,重置用 DELETE FROM |
Provider 改名陷阱(来自 2026-06-22 配置审查):
-- Provider 从 claude-haiku 改名 claude-internal 后,必须:
UPDATE auth_profile_store
SET provider_name = 'claude-internal'
WHERE provider_name = 'claude-haiku';
-- 或者,更稳:直接重配 Provider(OpenClaw 会重新写入)
openclaw config patch --stdin <<'JSON5'
{ "models.providers.claude-haiku": null }
JSON5
2
3
4
5
6
7
8
9
复用规则:改 Provider 名称前先备份 ~/.openclaw/state,改后验证 auth_profile_store 表同步。
# 2.3 环境变量:进程级的"隐藏配置"
env 变量只在进程启动时读一次,改 env 必须重启 daemon。常见 env:
| 变量 | 用途 |
|---|---|
OPENCLAW_GATEWAY_TOKEN | Gateway 启动时读,与 config 的 token 必须一致 |
PATH | 决定 CLI 命令能否找到 openclaw(nvm/pnpm 路径常漏) |
HOME | 决定 ~/.openclaw 的位置 |
致命陷阱(来自 2026-06-22 配置审查):
通过 ssh → docker exec → bash -lc 多层嵌套执行 openclaw config set 时,括号、引号、${...} 会被 shell 解释/转义。复杂命令应先 Base64 编码再远程解码:
# 错:嵌套转义灾难
ssh <USER>@<IP> "docker exec <CONTAINER> bash -lc \"openclaw config set ...\""
# 对:先编码再解码
SCRIPT_B64=$(echo 'openclaw config set gateway.auth.token "${OPENCLAW_GATEWAY_TOKEN}"' | base64 -w0)
ssh <USER>@<IP> "docker exec <CONTAINER> bash -lc 'echo $SCRIPT_B64 | base64 -d | bash'"
2
3
4
5
6
# §3 Provider 模型注册:双层原则(最容易踩的坑)
新增 model id 时,最常犯的错误是只改一层(来自 <session-file>)。
# 3.1 双层原则
OpenClaw 注册一个新模型需要改 2 个独立位置:
| 层 | 路径 | 作用 |
|---|---|---|
| 层 1 — Provider 注册 | models.providers.<PROVIDER>.models | 告诉 Provider:"我能调这个模型" |
| 层 2 — Agent 路由白名单 | agents.defaults.models | 告诉 Agent:"路由时允许选这个模型" |
只改层 1 不改层 2:
$ openclaw config patch --stdin <<'JSON5'
{ "models.providers.<PROVIDER>.models": ["kimi-k2.5", "minimax-m2.5"] }
JSON5
$ supervisorctl restart openclaw
$ openclaw models
# ❌ 列表里看不到新模型
2
3
4
5
6
完整流程(层 1 + 层 2 同步):
# 层 1:在 Provider 注册模型 ID
openclaw config patch --stdin <<'JSON5'
{
"models": {
"providers": {
"<PROVIDER>": {
"models": ["kimi-k2.5", "minimax-m2.5"]
}
}
}
}
JSON5
# 层 2:在 Agent 默认 allowlist 注册(--strict-json --merge 防止覆盖现有)
openclaw config set agents.defaults.models \
'{"<PROVIDER>/kimi-k2.5":{},"<PROVIDER>/minimax-m2.5":{}}' \
--strict-json --merge
# 重启
supervisorctl restart openclaw
# 验证:日志出现 [gateway] ready
supervisorctl tail -f openclaw
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 3.2 为什么是双层(设计哲学)
- 层 1 = "Provider 物理能力"——这个 Provider 在 API 层面能不能调这个模型
- 层 2 = "Agent 路由策略"——Agent 在多种模型中应该暴露哪些给用户
分开的好处:
- 一个 Provider 可能有 100 个模型,但 Agent 只让用 3 个
- 切换 Provider 但保留 Agent 路由白名单不破坏
分开的代价:
- 必须两处同步,缺一即失败
复用规则:任何模型 ID 的新增/删除都走"双层同步 patch",并跑 openclaw models 验证。
# §4 Token 配置:双源 + 引用 env(最隐蔽的故障)
Token 配置是 OpenClaw 故障率最高的环节,因为 Token 存在两个地方:env(进程级)+ config(文件级),两处不一致是经典陷阱。
# 4.1 双源问题
| 来源 | 谁读 | 影响 |
|---|---|---|
env (OPENCLAW_GATEWAY_TOKEN) | Gateway daemon 启动时 | Gateway 实际接受的 Token |
config (gateway.auth.token) | CLI 客户端 / 重新启动时 | CLI 直连用的 Token |
症状(来自 2026-06-22 配置审查):
GatewayClientRequestError: unauthorized: gateway token mismatch
Telegram 通道走降级轮询,Agent 看上去"活着",但 CLI 完全连不上。
# 4.2 脱敏误导
openclaw config get gateway.auth.token 会返回 __OPENCLAW_REDACTED__,让你以为两边一样:
$ openclaw config get gateway.auth.token
__OPENCLAW_REDACTED__ # ← 别被骗,真实值是别的
2
必须用以下方法读明文:
# 方法 1:读进程 env(最可靠)
tr '\0' '\n' < /proc/$(pgrep -f openclaw-gateway)/environ | grep OPENCLAW_GATEWAY_TOKEN
# 方法 2:直接 JSON 解析
python3 -c 'import json;print(json.load(open("/home/<USERNAME>/.openclaw/openclaw.json"))["gateway"]["auth"]["token"])'
# 方法 3:sha256 比对(避免明文打印漏看空格)
python3 -c "import hashlib;print(hashlib.sha256(b'<TOKEN_A>').hexdigest())"
2
3
4
5
6
7
8
# 4.3 修复:让 config 引用 env
根除方案:让 config 动态引用 env,永远单一来源:
# 让 config 永远跟随 env
openclaw config set gateway.auth.token '${OPENCLAW_GATEWAY_TOKEN}'
# 重启 Gateway 让它重新加载
supervisorctl reread && supervisorctl update && supervisorctl restart openclaw
# 验证:日志出现 [gateway] ready
supervisorctl tail -f openclaw | grep -i 'gateway\|token\|ready'
2
3
4
5
6
7
8
复用规则:config 永远引用 env,不要硬编码 Token。一处改,两处同步不存在的方案。
# §5 Telegram Bot Token 轮换:忽略 Supervisor 噪音
换 Telegram Bot Token 是 OpenClaw 日常维护的常见操作,但日志噪声最容易让人误判(来自 <session-file>)。
# 5.1 标准流程
# 1. 编辑主配置(修改 botToken)
openclaw config patch --stdin <<'JSON5'
{
"channels": {
"telegram": {
"botToken": "<NEW_BOT_TOKEN>"
}
}
}
JSON5
# 2. 重启 Gateway
supervisorctl restart openclaw
# 3. 验证:看 OpenClaw 启动日志(不是 Supervisor 日志!)
tail -f /tmp/openclaw/openclaw-$(date +%Y-%m-%d).log
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 5.2 验证 Token 生效的关键日志
正确日志:
[telegram] Detected bot identity change (was 123..., now 456...) discarding stale update offset
[telegram] starting provider for bot @<NEW_BOT_NAME>
[telegram] ready
2
3
Detected bot identity change= Token 生效,旧消息偏移丢弃(这是正常行为,不用清数据库)starting provider= Telegram 通道开始 poll 新消息ready= Gateway 整体就绪
# 5.3 过滤 Supervisor 噪音
典型错误日志(忽略,不是 OpenClaw Bug):
PermissionError: [Errno 13] Permission denied: file: /usr/lib/python3/dist-packages/supervisor/xmlrpc.py
这是 Supervisor 守护进程与子进程通信时 Python 内部状态同步的噪音,不影响 OpenClaw 自身工作。只看 OpenClaw 自己的启动日志判断是否成功。
复用规则:supervisorctl status openclaw 显示 RUNNING ≠ 应用层就绪。必须看 OpenClaw 自己的 [telegram] ready 日志。
# 5.4 account_id 变化是正常
换 Token 后 Bot 的 account_id 会变(日志会显示 discarding stale update offset)。不要尝试清数据库修复,这是 OpenClaw 的正常丢弃逻辑。
# §6 OpenWebUI 模型精简:3 个同名模型的真相
OpenWebUI 接 OpenClaw 后,UI 上可能显示 3 个相同名字的模型。这是 Agent Target(寻址别名)vs 底层 LLM 模型 的混淆(来自 <session-file>)。
# 6.1 三个同名模型的来源
OpenClaw 上游暴露的 /v1/models 返回:
- openclaw ← 一个寻址别名
- openclaw/default ← 默认寻址
- openclaw/main ← 主路由
三者实际都指向同一个 Agent (`main`),只是不同路由名。
2
3
4
5
6
# 6.2 验证:上游 Agent 路由
# 1. 登录 OpenClaw 主机
ssh <USER>@<IP>
# 2. 列出所有 Agent
openclaw agents list
# 3. 确认三个 model ID 都指向同一个 Agent
2
3
4
5
6
7
# 6.3 精简:白名单过滤(推荐)
修改 OpenWebUI 连接配置 JSON(不是 OpenClaw 端),在 OPENAI_API_CONFIGS 中设置 model_ids 白名单:
{
"OPENAI_API_CONFIGS": {
"1": {
"enable": true,
"prefix_id": "openclaw",
"model_ids": ["openclaw/default"]
}
}
}
2
3
4
5
6
7
8
9
配置说明:
model_ids只保留default,多模型场景下统一通过prefix_id前缀路由。
效果:UI 下拉菜单只显示 1 个,其余别名消失。
# 6.4 UI 层重命名(不改路由)
{
"id": "openclaw.openclaw/default",
"name": "openclaw/nova",
"base_model_id": null
}
2
3
4
5
效果:UI 显示 openclaw/nova,实际 API 调用仍路由至 openclaw/default——展示和路由解耦。
# 6.5 多 Profile 网关端口排查
如果同时跑了多个 Hermes Profile,每个 Profile 占用不同端口:
# 列出所有 Hermes gateway 服务
systemctl list-units 'hermes-gateway-*'
# 检查当前活跃 Profile
cat ~/.hermes/active_profile
# 端口对应以各自的 systemd drop-in 为准(不同 profile 不同端口),
# 不要照搬记忆里的映射——用 `ss -tlnp | grep <port>` 或读 unit 文件确认
2
3
4
5
6
7
8
踩坑:CLAUDE.md 文档记录默认 safeline Profile,但 active_profile 实际是 casa。永远以运行时为准,不要相信过时文档。
# 6.6 JWT 密钥长度警告
生成 OpenWebUI Admin JWT 时出现 InsecureKeyLengthWarning:HMAC 密钥 28 字节 < SHA256 推荐的 32 字节。不影响功能,但建议后续换长密钥。
# §7 配置变更的 5 条铁律(综合 4 条素材)
把 4 条素材里的踩坑抽成 5 条铁律:
| # | 铁律 | 出处 |
|---|---|---|
| 1 | 本文这些改动(provider/model/token/telegram)改完必重启:仅 reload 不重启进程,Agent 看到旧值。⚠️ 但不是所有配置都要重启——workspace markdown(AGENTS.md/HEARTBEAT.md)和 plugins.entries 插件配置是热重载,见 01 §5 | |
| 2 | 双源统一:config 引用 env,不要两处分别维护 Token | |
| 3 | Provider 改名同步 SQLite:手动迁移 auth_profile_store 或重配 | |
| 4 | 双层模型同步:Provider 注册 + Agent allowlist 必须一起改 | |
| 5 | 看应用层日志不看 Supervisor 噪音:supervisor/xmlrpc.py PermissionError 不是 OpenClaw 问题 |
# §8 真实配置审计清单(参考)
# 1. 拓扑判定
ssh <USER>@<IP> "which openclaw; systemctl --user status openclaw-gateway"
# 2. Token 双源一致性
HASH_ENV=$(tr '\0' '\n' < /proc/$(pgrep -f openclaw-gateway)/environ | grep OPENCLAW_GATEWAY_TOKEN | sha256sum)
HASH_CFG=$(python3 -c 'import json,hashlib;print(hashlib.sha256(json.load(open("/home/<USERNAME>/.openclaw/openclaw.json"))["gateway"]["auth"]["token"].encode()).hexdigest())')
[ "$HASH_ENV" = "$HASH_CFG" ] && echo "✅ Token 一致" || echo "❌ Token 不一致"
# 3. 配置合法
openclaw config validate
# 4. Provider 在线
openclaw infer model providers
# 5. Allowlist 完整性
openclaw models # 看每个 Provider 注册的模型都在 allowlist 中
# 6. SQLite API Key 存在
sqlite3 ~/.openclaw/state "SELECT provider_name, api_key FROM auth_profile_store;"
# 7. Telegram Bot 健康
openclaw channels test telegram
# 8. OpenWebUI 上游精简
curl http://<IP>:8702/v1/models | jq '.data[].id'
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# §9 Next-up
下一篇 05 OpenClaw 安全机制(待写),会基于 6 条 untrusted-metadata 真实素材(来自 <nas-notes>/ + <aws-notes>/),重点讲6 类 Sender 攻击模式 + untrusted-metadata 三级信任体系 + SOUL.md 脱敏模板。
# §10 Agent 可直接解析的元数据块
{
"_meta": {
"doc_version": "2026-06-27",
"article_id": "openclaw-config",
"profile_context": "blog",
"estimated_read_time": "12min",
"real_material_count": 4,
"material_sources": [
"notes/claude-code/<session-file>.md",
"notes/claude-code/<session-file>.md",
"notes/claude-code/<session-file>.md",
"notes/claude-code/<session-file>.md"
]
},
"config_locations": {
"main_config": "~/.openclaw/openclaw.json",
"state_db": "~/.openclaw/state",
"log_path": "/tmp/openclaw/openclaw-<DATE>.log"
},
"double_layer_rule": {
"layer_1": "models.providers.<NAME>.models — Provider 注册模型 ID",
"layer_2": "agents.defaults.models — Agent 路由白名单",
"must_sync": true
},
"token_rule": {
"two_sources": ["env.OPENCLAW_GATEWAY_TOKEN", "config.gateway.auth.token"],
"recommended": "config_follows_env",
"fix_cmd": "openclaw config set gateway.auth.token '${OPENCLAW_GATEWAY_TOKEN}'",
"verify_cmd": "sha256 对比 /proc/<PID>/environ 与配置文件"
},
"telegram_rotation": {
"verify_log_pattern": "Detected bot identity change",
"ignore_supervisor_noise": true,
"account_id_change_is_normal": true
},
"openwebui_trim": {
"whitelist_field": "OPENAI_API_CONFIGS.<ID>.model_ids",
"ui_override_pattern": {"id": "openclaw.openclaw/default", "name": "openclaw/nova"}
},
"safety_rules": [
"改配置后必须 supervisorctl restart openclaw",
"Token 永远单一来源:config 跟随 env",
"Provider 改名必须同步迁移 SQLite auth_profile_store",
"模型注册双层同步:Provider + Allowlist",
"只看 OpenClaw 自身启动日志,忽略 Supervisor 噪音"
],
"verification": {
"topology": "ssh <USER>@<IP> 'which openclaw; systemctl --user status openclaw-gateway'",
"config_validate": "openclaw config validate",
"models_list": "openclaw models",
"providers_check": "openclaw infer model providers"
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
AI Agent 使用指南:
- 当用户说"加个模型" → 走 §3 双层原则,patch + set + restart +
openclaw models验证 - 当用户说"Token 不对" → 走 §4.2 脱敏绕过,读
/proc/<PID>/environ后 sha256 比对 - 当用户说"换 Telegram Bot Token" → 走 §5,看
[telegram] ready日志确认,忽略 Supervisor 噪音 - 当用户说"OpenWebUI 模型太多" → 走 §6.3
model_ids白名单过滤 - 当用户说"换 Provider 名字" → 走 §2.2,备份 SQLite 后
UPDATE auth_profile_store