openclaw doctor 体检输出怎么读:五种姿态、findings 字段与退出码对号入座
openclaw doctor 是那种「出问题了先跑一下」的命令。官方文档给它的定位是:对网关、渠道、插件、技能、模型路由、本地状态和配置迁移做健康检查与快速修复,当某个东西行为不对、你又想用一条命令搞清楚哪里坏了的时候用它。
问题是它的输出真的长。文档里列出来的检查项覆盖了配置规范化、遗留 key 迁移、磁盘布局迁移、会话锁清理、状态目录完整性、模型 OAuth 过期、沙箱镜像、服务与 supervisor 配置、设备配对、systemd linger、shell 补全……十几个大类。第一次跑完盯着一屏字,很容易搞不清楚哪几行是真要处理的、哪几行只是信息。
更容易踩的一点是:doctor 不是一个命令,是五种姿态。同样叫 doctor,加不加 --lint、加不加 --fix,读不读写、退不退非零码,行为完全不一样。搞混了会出现两种典型翻车——在 CI 里用了不会失败的那个,或者在生产机上用了会改配置的那个。所以读输出之前,先得知道自己跑的是哪一种。
一、先分清 doctor 的五种姿态
官方文档明确列出 doctor 有五种 posture:
| 姿态 | 命令 | 行为 |
|---|---|---|
| Inspect | openclaw doctor / openclaw doctor --json | 建议性检查,人读或机器读两种形式 |
| Repair | openclaw doctor --fix | 应用受支持的修复,除非非交互修复是安全的,否则走提示确认 |
| Lint | openclaw doctor --lint [--json] | 只读findings,带基于阈值的退出码,用于 CI 门禁 |
| 共享 SQLite 维护 | openclaw doctor --state-sqlite compact | 显式对规范共享状态库做 checkpoint、压缩与校验 |
| 会话 SQLite 迁移 | openclaw doctor --session-sqlite <mode> | 检查、导入、校验、压缩、恢复或还原会话状态 |
文档给的选择原则很直接:运维或脚本想要建议性报告就用 openclaw doctor --json;希望 CI 在某个严重级别以上非零退出,就用显式的 openclaw doctor --lint --json;想让 doctor 真的去改配置或状态,才用 --fix。
另一份网关侧文档还补了一张更细的对照表,把「会不会提示」「会不会写」分开列了:
| 模式 | 提示 | 写配置/状态 | 输出 |
|---|---|---|---|
openclaw doctor | 会 | 不写 | 友好的健康报告 |
openclaw doctor --json | 不会 | 不写 | JSON 建议性报告 |
openclaw doctor --fix | 有时会 | 会,按修复策略 | 友好的修复日志 |
openclaw doctor --lint | 不会 | 不写 | 结构化 findings |
注意 --repair 是 --fix 的别名,两者等价。还有一条容易忽略的说明:--lint 比 --non-interactive 更严格——--non-interactive 还会跑安全迁移,--lint 是彻底只读,连安全迁移都不做。
--severity-min、--all、--only、--skip 这四个参数只有配合 --lint 才被接受。裸 --json 允许单独用,但它走的是默认只读 lint 检查集,同时保留普通 doctor 的建议性退出行为。
二、findings 长什么样:先看 ok,再看 checkId
人读输出是紧凑的一行式:
doctor --lint: ran 6 check(s), 1 finding(s)
[warning] core/doctor/gateway-config gateway.mode - gateway.mode is unset; gateway start will be blocked.
fix: Run `openclaw configure` and set Gateway mode (local/remote), or `openclaw config set gateway.mode local`.
机器读的是 JSON:
{
"ok": false,
"checksRun": 5,
"checksSkipped": 0,
"findings": [
{
"checkId": "core/doctor/gateway-config",
"severity": "warning",
"message": "gateway.mode is unset; gateway start will be blocked.",
"path": "gateway.mode",
"fixHint": "Run `openclaw configure` and set Gateway mode (local/remote), or `openclaw config set gateway.mode local`."
}
]
}
一条 finding 的字段是固定的几项:checkId 是稳定 id,用来做 --skip / --only 过滤和 CI 白名单;severity 只有 info、warning、error 三档;message 是人读的问题陈述;path 是配置、文件或逻辑路径;line / column 是源位置;ocPath 是检查能指到的精确 oc:// 地址;fixHint 是建议的操作或修复摘要。网关侧文档还提到 findings 可能带 source、target、requirement 这几个可选字段。
顶层的 checksRun / checksSkipped 别当装饰看。文档专门提醒:如果用 --only 做定向门禁,--only 的 id 没注册的话,那个 id 不会跑任何检查——所以要靠这两个计数确认你以为选中的检查真的被选中了。
三、退出码:0/1/2,以及裸 --json 的例外
显式 lint 的退出码只有三个:
| 码 | 含义 |
|---|---|
0 | 没有达到所选严重级别阈值的 finding |
1 | 至少有一条 finding 达到阈值 |
2 | 在能产出 findings 之前命令/运行时就失败了 |
--severity-min 同时控制「打印什么」和「按什么阈值退出」,默认值是 warning。这意味着 openclaw doctor --lint --severity-min error 完全可能什么都不打印、退出 0,而低级别的 info / warning findings 其实还在。做 CI 门禁时这是最容易自己骗自己的地方。
反过来,裸 openclaw doctor --json 只要产出了 payload 就退出 0,哪怕 ok 是 false。只有参数错误或者在能产出 payload 之前就崩了才会非零。所以脚本消费裸 --json 时必须自己读 ok 和 findings,指望退出码会漏判。
--all 影响的是「严重级别过滤之前选哪些检查」。默认 lint 跑的是广泛安全的自动化档:静态、本地、在 CI 或预检里有用的检查;那些偏深度、历史遗留、或者更可能翻出可修复的老残留的检查会被跳过。想要完整清单就加 --all,想精确到一条就用 --only <id>。
还有一个单独的模式:openclaw doctor --post-upgrade 跑的是插件兼容性探针,findings 走 stdout,只要有 level: "error" 的 finding 退出码就是 1。加 --json 会拿到 { probesRun, findings } 这个信封;即便已安装的插件索引缺失或损坏,JSON 模式仍会输出信封,里面带一条 plugin.index_unavailable 的 error finding。这条适合挂在构建或升级之后。
四、高频提示对号入座
下面这张表只收录官方文档明确写了「doctor 报什么、下一步做什么」的条目,其余没写的不要自行脑补:
| 输出里出现的东西 | 文档说的含义 | 官方给的下一步 |
|---|---|---|
| Secret runtime degradation | 网关状态报告 SecretRef owner 处于 cold 或 stale | 按提示的重试命令 openclaw secrets reload |
| 渠道 ingress 事件进入死信 | doctor 点名受影响的渠道账号 | openclaw channels dead-letters list 查看与恢复 |
| Telemetry exporters | 报告最新可信的各信号状态与传输方式 | 摘要是脱敏的,不含端点、请求头、证书、载荷或原始错误 |
gateway.mode is unset | 网关启动会被阻断 | openclaw configure 选模式,或 openclaw config set gateway.mode local |
网关端口冲突(默认 18789) | doctor 报告可能原因 | 文档给的两种典型成因:网关已在运行、SSH 隧道 |
| 服务已安装但没在运行 | doctor 检查服务运行时的 PID 与上次退出状态 | 文档未给单一命令,需结合服务侧排查 |
| 沙箱已启用但 Docker 不可用 | 高信号警告 | 安装 Docker,或 openclaw config set agents.defaults.sandbox.mode off |
| 默认 Agent 的技能在当前环境不可用 | 缺 bin、环境变量、配置或 OS 要求 | --fix 可写 skills.entries.<skill>.enabled=false;想保留就补齐依赖 |
| 未配置 command owner | owner-only 命令与危险操作审批没有归属人 | 显式设置 commands.ownerAllowFrom |
| 会话写锁陈旧 | 判定条件是死 PID、owner 元数据损坏、超过 30 分钟、或活 PID 被证实属于非 OpenClaw 进程 | --fix 只删这几类;活着的 OpenClaw 进程持有的老锁保留不动 |
| 服务跑在 Bun 或版本管理器路径 | Bun 打不开 OpenClaw 的 node:sqlite 状态库 | doctor 提议迁移到系统 Node 安装 |
macOS 上还有一个独立的坑值得单独记:如果你以前执行过 launchctl setenv OPENCLAW_GATEWAY_TOKEN ...(或 ...PASSWORD),这个值会覆盖配置文件,造成持续的 unauthorized 报错。文档给的排查命令是:
launchctl getenv OPENCLAW_GATEWAY_TOKEN
launchctl getenv OPENCLAW_GATEWAY_PASSWORD
launchctl unsetenv OPENCLAW_GATEWAY_TOKEN
launchctl unsetenv OPENCLAW_GATEWAY_PASSWORD
这类「明明配置是对的却一直没权限」的现象,和网关本身起不来是两码事,具体见网关起不来时的锁文件、端口与后台进程排查。凭据本身怎么存、SecretRef 是什么,见OpenClaw 的密钥与凭据管理。
五、按下 --fix 之前该知道的四件事
第一,它会改配置文件,但留了备份。任何配置写入(包括 --fix 的修复)都会把备份轮转到 ~/.openclaw/openclaw.json.bak,并维护 .bak.1 到 .bak.4 的编号环。另外 --fix 会丢弃 schema 校验报出的未知配置键,并逐条列出删除内容;不过在更新进行中它会跳过这一步,免得半写状态的升级配置在迁移完成前被清掉。
第二,配置彻底解析不了时它不会硬写。如果 openclaw.json 无法解析、也找不到最后一次已知正常的配置,doctor --fix 会把原文件保留为 openclaw.json.clobbered.<时间戳>,当前文件原样不动,然后报错退出,而不是写进去一个残缺的替代品。
第三,某些环境下 --fix 是被禁用的。在 Nix 模式(OPENCLAW_NIX_MODE=1)下,只读检查照常工作,但 doctor --fix、--repair、--yes 和 --generate-gateway-token 都被禁用,因为 openclaw.json 是不可变的,要改得去改这个安装的 Nix 源。
第四,服务生命周期未必归 doctor 管。当另一个 supervisor 拥有网关生命周期时,应设置 OPENCLAW_SERVICE_REPAIR_POLICY=external:doctor 仍然报告网关与服务健康、仍然执行非服务类修复,但跳过服务的安装、启动、重启、bootstrap 与遗留服务清理。此外 doctor --fix --non-interactive 会报告缺失或过期的服务定义,却不会在更新修复模式之外去安装或重写它们——缺服务跑 openclaw gateway install,要换启动器跑 openclaw gateway install --force。
还有两个关于交互的细节:交互式提示(钥匙串、OAuth 修复等)只在 stdin 是 TTY 且没设 --non-interactive 时才会出现,cron、Telegram 这类无终端的运行会直接跳过提示;非交互的 doctor 运行会跳过插件的急切加载,让无头健康检查更快。想把更细的运行期证据打出来,参考网关诊断开关与日志怎么开。
六、两套 SQLite 维护不要混
doctor 底下挂着两套完全不同的 SQLite 维护,名字很像但对象不同。
--state-sqlite compact 针对的是 <state-dir>/state/openclaw.sqlite 这个规范共享状态库。它不接受任意数据库路径,正常网关运行时永远不会触发它,也不是 doctor --fix 的一部分。它会拿和网关启动同一把状态所有权锁,并在校验、checkpoint、VACUUM 和最终完整性检查全程持有;如果网关或另一个 SQLite 维护命令占着这把锁,它会拒绝运行。文档给的标准顺序是先停网关、先做带校验的备份:
openclaw gateway stop
openclaw backup create --verify
openclaw doctor --state-sqlite compact --json
openclaw gateway start
--session-sqlite <mode> 针对的是每个 Agent 自己的会话库,运行期会话行在 ~/.openclaw/agents/<agentId>/agent/openclaw-agent.sqlite,旧的 sessions.json 是迁移来源。模式一共七个:inspect 只读计数、dry-run 解析但不写、import 导入、validate 比对、compact 回收页、recover 恢复失败的迁移并准备脱敏的 issue 报告、restore 还原归档的转录产物。其中 import、compact、recover、restore 这四个破坏性模式会持有和网关启动相同的状态所有权锁,inspect、dry-run、validate 是只读且不取锁。跑破坏性模式前先停网关,否则它们会直接失败而不是和实时写入抢。
七、doctor 管不到的地方
有几类问题即使 doctor 跑得干干净净也查不出来,因为文档明确把它们划到了别的命令:
- 渠道的具体权限:用渠道探针,不是 doctor。
openclaw channels capabilities --channel discord --target channel:<channel-id>报告机器人在某个目标上的有效权限,openclaw channels status --probe审计所有已配置渠道和语音自动加入目标。 - 完整的安全清单:doctor 只在发现问题时才输出一条 Security 提示,完整安全盘点要用
openclaw security audit。 - 健康状态的清单:doctor 只打印问题和动作,不打印健康的库存。技能细节看
openclaw skills check,插件清单看openclaw plugins list。
另外有两点会让「跑完 doctor 就万事大吉」的直觉失效。一是配置迁移是有保质期的:文档写明 doctor 只在一个 key 退役后大约两个月内携带自动迁移,更老的遗留 key 已经没有迁移路径,配置里还留着它们会直接校验失败,必须对着当前配置参考手工改。二是容器场景是常规流程的例外:openclaw gateway run 在新版本上启动时会先跑安全的状态与插件修复再报 ready;如果修复没法安全完成,启动会退出并告诉你先用同一个镜像、对着同一份挂载的 state/config 跑一次 openclaw doctor --fix,然后再正常重启容器。
最后一件事:doctor 默认不会执行你配置的 exec 类 SecretRef 来验证密钥,要它执行必须显式加 --allow-exec。这个开关意味着 doctor 会去跑你配置的解析器命令,所以只在确实需要验证时才加。装不上、跑不起来这一类更靠前的问题,doctor 未必是第一站,参考安装失败的官方排查路径会更省事。
延伸阅读
- 从头读起:OpenClaw 架构总览:网关、Agent、渠道、节点、插件五层各管什么,出问题该往哪查
- 本专题共 40 篇,完整分组目录见专题页
- OpenClaw 用 Docker 部署:镜像怎么选、状态存在哪、升级卡住怎么救
- 树莓派部署 OpenClaw:型号怎么选、swap 怎么加、SD 卡为什么是最大隐患
本文依据 OpenClaw 官方仓库(github.com/openclaw/openclaw)docs/ 下的官方文档整理,核对日 2026-08-17。
我们没有安装或运行过 OpenClaw,因此不涉及界面外观、操作手感与实测耗时的任何描述;
文中的默认值、命令与配置项均为文档口径,不构成对实际运行结果的保证。
该项目迭代很快,请以仓库最新内容为准。接入即时通讯平台前,请自行确认所在平台的规则与合规要求。