AI Agent 友好的 CLI,不只是加一个 --json

很多 CLI 对人很好用:有彩色表格、进度条、确认提示和详细说明。但同一套交互交给 AI Agent 后,常常变得脆弱。Agent 需要猜表格列、等待一个无法回答的确认框,或者把几千行日志塞进上下文,最后在一句 “Something went wrong” 面前失去恢复路径。

问题不在于 Agent 不会用终端,而在于这类 CLI 只设计了人机界面,没有设计稳定的机器契约

一个 Agent 友好的 CLI,至少应该让调用方回答四个问题:我能做什么?执行前会改什么?执行后到底发生了什么?失败以后应该重试、修正输入,还是交给人?

终端输出和机器接口是两个产品面

--json 是起点,但不是终点。真正的目标是把 stdout 变成稳定接口,而不是把原来的表格临时包进 JSON。

机器输出需要稳定字段、明确类型和版本约束。列表命令还要支持字段选择、分页游标和数量上限,否则一次“查看事件”就可能吞掉整个上下文窗口。长任务则应返回任务 ID,让 Agent 查询状态,而不是持续输出无法定位的日志流。

人和 Agent 可以共享同一个命令入口,但不必共享同一种呈现:TTY 中保留适合阅读的表格;非 TTY 或显式指定机器模式时,返回结构化结果。这样既不牺牲人的体验,也不要求 Agent 解析视觉格式。

不要让控制流藏在交互提示里

传统 CLI 喜欢在危险操作前询问“是否继续”。这对坐在终端前的人有效,对无人值守的 Agent 却意味着流程永久阻塞。

更稳妥的做法,是把控制流变成显式参数和状态转换:

  1. 先读取当前状态;
  2. 生成结构化执行计划;
  3. 标出风险、影响范围和必要权限;
  4. 获得明确授权后执行;
  5. 返回结果与可查询的回执。

因此,dry-run 不应只打印一段“将要部署”的说明,而应返回资源、旧值、新值、风险等级和是否需要审批。高风险写入还应支持幂等键、计划哈希或确认令牌,避免 Agent 在超时后重复执行已经成功的操作。

{
  "plan_id": "plan_42",
  "changes": 3,
  "risk": "high",
  "approval_required": true,
  "expires_at": "2026-07-17T10:30:00Z"
}

这个结构的价值不在格式本身,而在于它把“准备做什么”和“已经做了什么”分开了。

错误信息应该驱动下一步动作

面向人的错误提示经常只需要让人看懂;面向 Agent 的错误还必须支持决策。

一个可操作的错误至少要包含:稳定错误码、失败阶段、相关输入、是否可重试、恢复建议和请求 ID。退出码也应区分输入或权限等永久失败,与超时、限流等瞬态失败。

{
  "ok": false,
  "error": {
    "code": "permission_denied",
    "retry": "never",
    "hint": "Request the deploy role before retrying"
  },
  "meta": {
    "request_id": "req_8f31",
    "schema_version": "1"
  }
}

retry: never 能阻止 Agent 用相同身份盲目重试;request_id 则让人和后端日志讨论的是同一次操作。相比更长的自然语言,这些字段更能降低错误恢复成本。

可发现性决定 Agent 能否正确调用

Agent 经常从 --help 开始理解工具。帮助信息应该简洁、稳定,明确参数类型、必填项、枚举值和副作用。更进一步,可以提供机器可读的命令描述,让 Agent 不必从自然语言逆向推导 schema。

输入同样需要机器通道。扁平参数适合人手工调用;复杂对象则适合通过 JSON 或 stdin 传入,减少嵌套数据在字符串转义、数组拆分和类型转换中的损失。

不过,机器可调用不等于放松校验。Agent 输入应当像外部 API 请求一样被视为不可信:路径必须限定在允许目录内,命令参数不能直接拼接进 shell,权限范围应尽量小,敏感值不能出现在日志和错误回显中。

设计重点是闭环,而不是格式

Agent 友好最终不是一张参数清单,而是一条能闭环的协议:

发现能力 → 描述意图 → 预览影响 → 授权执行
→ 获取回执 → 验证状态 → 失败恢复

如果只增加 JSON 输出,却没有 dry-run、幂等语义、状态查询和可操作错误,Agent 仍然只能“更方便地读到一个不可控结果”。反过来,一套结构化、可验证、可恢复的 CLI,可以同时服务脚本、CI、Agent 和人类操作者。

所以,判断 CLI 是否真正适合 Agent,不妨检查这些问题:

  • 输出 schema 是否稳定并支持版本演进?
  • 大结果能否裁剪、分页或异步查询?
  • 写操作能否先预览,再以明确授权执行?
  • 超时后能否查询状态,而不是直接重试?
  • 错误能否告诉调用方下一步该做什么?
  • 输入、权限和日志是否按不可信边界设计?

当这些问题都有明确答案,CLI 才不只是“能被 Agent 调用”,而是开始具备被 Agent 可靠编排的条件。

来源与说明

本文受 sorrycc 的文章《编写 AI Agent 友好的 CLI》启发。原文以八条规则、Bad/Good 对照和 Node.js 示例给出实践清单。本文未转载原文的完整示例与代码骨架,而是重新组织为机器契约、执行闭环和恢复语义三个层次,并补充了 schema 版本、幂等、异步回执与请求追踪等工程判断。具体实现请阅读原文。