OpsPilot CLI 开发复盘:从命令包装到运行时控制面

OpsPilot 的 CLI 已经从早期设计稿进入可用状态。

最初讨论 CLI 时,重点是避免把命令层绑死在 Agent 内部实现上。那时系统还处在重构中,很多能力只能先设计成目标接口。现在核心运行时收口以后,CLI 的定位也清楚了:它不是一组临时脚本,而是 OpsPilot 面向操作者的控制面。

CLI 的入口和边界

项目现在通过 pyproject.toml 暴露命令:

opspilot = "opspilot.cli:main"

实现上使用 Typer 组织命令,Rich 负责面向人的表格输出,同时保留 JSON 输出给脚本调用。

命令组按运维对象组织:

opspilot config
opspilot projects
opspilot tools
opspilot server
opspilot alerts
opspilot sessions
opspilot approvals
opspilot notifications
opspilot reports

这套结构刻意没有暴露内部类名。操作者看到的是配置、项目、工具、告警、会话、审批、通知和报告,而不是 dispatcher、session manager、toolset 或 agent loop。

本地命令负责低风险检查

CLI 里有一类命令只需要读取本地配置,不需要连接正在运行的服务:

uv run opspilot config validate --config config/config.example.yaml
uv run opspilot config show --config config/config.example.yaml --format json
uv run opspilot projects list --config config/config.example.yaml
uv run opspilot tools list --config config/config.example.yaml --project my-project
uv run opspilot status --local --config config/config.example.yaml

这些命令的价值是快速确认本地配置是否能被运行时接受。

config show 会对 token、secret、API key、password、webhook URL 等敏感字段做脱敏,但不会误伤 max_tokens 这类普通配置。这个细节很实际,因为 CLI 输出经常会被贴到 issue、群聊或日志里。

tools list 没有自己解析工具配置,而是构造 OpsPilot,加载 ToolRegistry,再按项目生成工具视图。这样 CLI 展示出来的工具集合和运行时实际可用的工具集合保持一致。

Server 命令负责宿主装配

opspilot server start 是 CLI 的宿主模式。

它负责读取配置文件,创建 OpsPilot 运行时,挂载 Webhook 路由、控制 API 和钉钉审批确认页面,然后交给 uvicorn 启动:

$env:OPSPILOT_CONTROL_TOKEN = "dev-control-token"
$env:MIMO_KEY = "dummy-or-real-key"
uv run opspilot server start --config config/config.example.yaml

启动后的 HTTP 面主要有三类:

POST /api/webhook/{project}
/api/control/v1/*
/api/approvals/dingtalk/{approval_id}

Webhook 仍然使用项目级 ingestion.webhook.secret 认证。控制 API 使用独立 Bearer token。两者分开是必要的:告警源只应该能提交告警,控制 API 才能查询状态、取消会话、审批危险操作或测试通知。

控制 API 支撑远程 CLI

运行时命令默认走控制 API,而不是直接读本地内存。

例如:

uv run opspilot status --token $env:OPSPILOT_CONTROL_TOKEN
uv run opspilot alerts list --token $env:OPSPILOT_CONTROL_TOKEN
uv run opspilot sessions list --token $env:OPSPILOT_CONTROL_TOKEN
uv run opspilot approvals list --token $env:OPSPILOT_CONTROL_TOKEN

默认地址可以来自 OPSPILOT_SERVER_URL,token 可以来自 OPSPILOT_CONTROL_TOKEN。这让 CLI 同时适合本地开发和生产运维:本地可以直接启动 server,生产中则可以把 CLI 当成远程客户端。

控制 API 暴露的能力覆盖了当前操作闭环:

status
projects / tools
alerts send/list/show
sessions list/show/events/cancel/message
approvals list/approve/reject
notifications list/test
reports show

CLI 只是把这些接口包装成操作者熟悉的命令形态。这个分层让后续前端也可以复用同一套控制 API。

告警提交变成调试入口

alerts send 是一个非常实用的开发命令:

@'
{
  "status": "firing",
  "severity": "critical",
  "alert_name": "HighErrorRate",
  "title": "High error rate",
  "description": "demo-api is returning 5xx",
  "labels": {"service": "demo-api"}
}
'@ | uv run opspilot alerts send - --project my-project --source generic --token $env:OPSPILOT_CONTROL_TOKEN

它让开发者不需要手写 curl,不需要记 Webhook 认证头,也不需要绕过 normalizer。payload 会通过控制 API 进入运行时,再由对应 normalizer 转成 AlertEvent,最后进入 dispatcher。

这条路径和真实告警链路足够接近,适合做端到端调试。

会话和审批进入命令行闭环

CLI 现在可以查看会话、监听事件、取消会话、注入操作员消息:

opspilot sessions list
opspilot sessions show <session-id>
opspilot sessions watch <session-id>
opspilot sessions cancel <session-id>
opspilot sessions message <session-id> --text "只读排查,不要重启"

审批命令也按审批 ID 操作:

opspilot approvals list
opspilot approvals approve <approval-id> --message "低峰期,可以执行"
opspilot approvals reject <approval-id> --message "先不要做写操作"

这里有一个重要细节:审批 ID 不一定等于 session ID。运行时会优先按 pending approval id 找,如果找不到再兼容 session id。这样 CLI 可以从早期简化模型平滑过渡到更完整的持久化审批模型。

钉钉审批卡片接上 CLI Server

CLI server 还挂载了钉钉审批确认路由。

当危险工具调用需要审批时,通知渠道可以发送 action card。卡片按钮带签名和过期时间,打开确认页后再提交 approve 或 reject。server 端会校验签名、检查待审批状态,再调用运行时的审批接口。

这让审批有了三种入口:

CLI 命令
控制 API
钉钉卡片确认页

三种入口最终都回到 OpsPilot.decide_approval()。这才是正确的收口方式:入口可以很多,改变状态的地方只能有一个。

输出设计:给人看,也给脚本用

CLI 默认输出表格,适合人在终端里快速扫描。多数查询命令也支持:

--format json

这点不能省。运维 CLI 经常被接进脚本、CI、临时巡检任务或监控探针。只提供漂亮表格会限制自动化;只提供 JSON 又不适合值班人员快速阅读。两种输出都支持,才是实际可用的命令行工具。

测试覆盖了关键行为

这次 CLI 不是只写命令壳。测试覆盖了几个关键点:

  • CLI help 暴露核心命令组。
  • config show 脱敏敏感字段,同时保留普通字段。
  • 控制 API 必须带 Bearer token。
  • 控制 API 可以提交 generic 告警。
  • server 可以挂载钉钉审批确认路由。
  • 运行时测试覆盖告警进入、会话创建、持久化、审批通过、审批拒绝、审批超时、取消清理和热更新。

这些测试让 CLI 不只是“能跑一下”,而是和运行时闭环一起被验证。

结论

OpsPilot CLI 的核心价值不是多了几个命令,而是把系统的操作模型固定下来了:

本地配置检查
  -> server 宿主启动
  -> 控制 API
  -> 告警提交
  -> 会话观察
  -> 危险操作审批
  -> 通知测试
  -> 报告查询

它现在既是开发者的调试工具,也是运维人员的控制入口。后续无论增加 Web 控制台,还是把 server 部署到更正式的环境,CLI 都可以继续作为稳定的低摩擦操作面存在。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐