Binflare Plus
Blog / Field NotesSignal / Reading

SIGNAL / designing-cli-tools-for-ai-agents

如何为 AI Agent 设计 CLI 工具

传统 CLI 假设使用者是终端前的人类,当调用者变成 AI Agent 时这些隐式契约全部失效。本文定义一套面向 Agent 的 CLI 设计规范——非交互优先、渐进发现、结构化输出、可操作错误、幂等与安全预演,并附可直接嵌入 Agent 系统的 RFC 2119 风格规范文档。

如何为 AI Agent 设计 CLI 工具

背景

传统 CLI 假设使用者是坐在终端前的人类——能按方向键、能读懂模糊提示、能从上下文推断下一步。但当 CLI 的调用者变成 AI Agent 时,这些隐式假设全部失效。Agent 不能处理交互式 prompt,不能从模糊错误中恢复,不能猜测未文档化的行为。

CLI 设计规范在当前节点的紧迫性由三个趋势驱动:

  1. Agent 调用取代人类调用成为主流场景 —— Claude Code、Codex CLI、Cursor 等 Agent 已常态化通过 CLI 与工具交互,CLI 不再是人类专属界面
  2. Skill/Plugin 生态爆发 —— Skill 本质上就是「CLI 工具 + Agent 使用说明」,CLI 质量直接决定 Agent 的能力天花板
  3. 传统 CLI 的隐式契约全面失效 —— TTY 检测、交互式 prompt、模糊错误信息在 Agent 语境下都是致命缺陷,必须显式化

从架构上看,CLI 工具是 Agent 的行动接口(Action Interface)。模型不直接执行工具,而是通过编排层(orchestration layer)发起调用请求。编排层负责:

  1. 参数验证:检查 flag 是否合法
  2. 权限门控:验证 Agent 是否有权执行该操作
  3. 执行与捕获:运行命令,捕获 stdout/stderr 和退出码
  4. 结果反馈:将结构化输出返回给模型用于下一步推理

一个设计良好的 CLI 让编排层的工作变得简单——输入通过 flag 传入,输出通过 JSON 返回,错误通过退出码和 stderr 报告。编排层不需要解析人类文本、处理交互式 prompt 或猜测命令是否成功。

┌─────────────┐     structured call      ┌──────────────┐
│   LLM Model │ ──────────────────────── │ Orchestrator │
│  (决策层)    │ ◄── structured result ── │  (编排层)     │
└─────────────┘                          └──────┬───────┘
                                                │
                                    flags + stdin │ stdout + stderr + exit code
                                                │
                                         ┌──────▼───────┐
                                         │   CLI Tool   │
                                         │  (执行层)     │
                                         └──────────────┘

设计原则

输入

1. 非交互优先

规则:所有必要输入必须能通过 flag、环境变量或 stdin 传入。交互式流程只作为人类 fallback。

Agent 无法处理运行中途弹出的交互式选择。如果命令执行到一半要求用户按方向键选择环境,Agent 会直接卡死。

# 反模式:阻塞 Agent
$ mycli deploy
? Which environment? (use arrow keys)

# 正确:所有输入通过 flag 传入
$ mycli deploy --env staging --tag v1.2.3

设计要点:

  • 支持 --stdin 从管道读取复杂输入(如 JSON 配置)
  • 检测 CI=true 或 NO_TTY 环境变量时自动禁用交互
  • 当 flag 缺失且非 TTY 环境时,CLI 应报错退出而非进入交互模式

2. 渐进发现

规则:不要一次性倾倒全部文档。让 Agent 按需逐层探索命令能力。

Agent 的上下文窗口有限。如果顶层 --help 输出 200 行文档,大部分内容会被浪费。正确的做法是分层暴露:

# 第一层:顶层命令列出子命令
$ mycli --help
Commands:
  deploy    Deploy application to target environment
  build     Build container image
  config    Manage configuration
  status    Show deployment status

# 第二层:子命令给出聚焦选项和示例
$ mycli deploy --help
Options:
  --env     Target environment (staging, production)
  --tag     Image tag (default: latest)
  --force   Skip confirmation
  --dry-run Preview changes without executing

Examples:
  mycli deploy --env staging
  mycli deploy --env production --tag v1.2.3
  mycli deploy --env staging --force

设计要点:

  • 示例比描述更重要——Agent 从示例中模式匹配调用方式
  • 考虑提供 mycli completion --shell agent 输出机器可读的命令树

3. 可预测的命令结构

规则:命令遵循统一的 resource + verb 模式,让 Agent 能从已知命令推断未知命令。

如果 Agent 学会了 mycli service list,它应该能推断出 mycli deploy list、mycli config list 也存在。一致的命名模式降低 Agent 的探索成本。

# 统一的 resource-verb 模式
mycli service list
mycli service get <id>
mycli service create --name <name>
mycli service delete <id> --yes

mycli deploy list
mycli deploy get <id>
mycli deploy create --env <env> --tag <tag>
mycli deploy rollback <id> --yes

设计要点:

  • 选择一种模式并全局一致:noun verb 或 verb noun
  • 全局 flag 位置一致(如 --json、--verbose 始终可用)
  • 避免同义词混用(不要一处用 remove 另一处用 delete)

输出

4. 结构化输出

规则:成功输出应包含机器可提取的关键数据。支持 --json 切换。

Agent 需要从命令输出中提取信息用于后续步骤。纯人类友好的文本(带 emoji、颜色码、进度条)对 Agent 是噪音。

# 人类友好输出(默认)
$ mycli deploy --env staging --tag v1.2.3
✓ Deployed v1.2.3 to staging

# Agent 友好输出
$ mycli deploy --env staging --tag v1.2.3 --json
{
  "status": "success",
  "environment": "staging",
  "tag": "v1.2.3",
  "url": "https://staging.myapp.com",
  "deploy_id": "dep_abc123",
  "duration_seconds": 34
}

设计要点:

  • 即使是默认文本输出,也应包含关键 ID 和 URL 等可 grep 的字段
  • 避免在输出中混入 ANSI 颜色码(通过 --no-color / NO_COLOR 环境变量禁用)
  • 列表类命令支持 --output table、--json、--output csv

5. 可操作错误

规则:错误信息必须告诉 Agent 下一步该做什么,而不只是说哪里出了问题。

Agent 擅长自我修正,但前提是错误信息给出了足够的修正线索。

# 反模式:模糊错误
$ mycli deploy --env staging
Error: deployment failed

# 正确:给出修正路径
$ mycli deploy --env staging
Error: No image tag specified.
  Usage: mycli deploy --env staging --tag <image-tag>
  Available tags: mycli build list --output tags
  Latest tag: v1.2.3

设计要点:

  • 使用非零退出码区分错误类型(1=用户错误,2=系统错误,3=权限错误)
  • 错误输出到 stderr,正常结果输出到 stdout
# JSON 格式的错误输出
$ mycli deploy --env staging --json
{
  "status": "error",
  "code": "MISSING_TAG",
  "message": "No image tag specified",
  "suggestion": "mycli deploy --env staging --tag <image-tag>",
  "related_commands": ["mycli build list --output tags"],
  "retryable": false
}

retryable 字段让 Agent 区分瞬态错误(网络超时、限流)和永久错误(参数缺失、权限不足),从而决定是重试还是换策略。

执行

6. 幂等与可重试

规则:同一命令执行两次应产生相同结果,不应制造重复副作用。

Agent 会因为网络超时、上下文丢失或任务重试而重复执行命令。如果 deploy 执行两次创建了两个部署,Agent 无法安全地重试任何操作。

# 首次执行
$ mycli deploy --env staging --tag v1.2.3
deployed v1.2.3 to staging (deploy_id: dep_abc123)

# 重复执行:返回已有结果而非创建重复
$ mycli deploy --env staging --tag v1.2.3
already deployed v1.2.3 to staging (deploy_id: dep_abc123, no-op)

设计要点:

  • 对于天然非幂等操作(如发送消息),在文档中明确标注
  • 提供 status 或 get 子命令让 Agent 先检查状态再决定是否执行

7. 安全预演

规则:破坏性操作必须支持 --dry-run 预览和 --yes 确认跳过。

Agent 应该能在不产生副作用的情况下验证操作计划,然后再决定是否执行。

# 预览模式:展示将要发生什么
$ mycli deploy --env production --tag v1.2.3 --dry-run
Would deploy v1.2.3 to production:
  - Stop 3 running instances
  - Pull image registry.io/app:v1.2.3
  - Start 3 new instances
  - Run health checks
No changes made.

# 确认执行
$ mycli deploy --env production --tag v1.2.3 --yes
Deployed v1.2.3 to production (deploy_id: dep_xyz789)

设计要点:

  • dry-run 输出应与实际执行输出结构一致,方便 Agent 对比验证

进阶设计

以上 7 条核心原则确保单条命令可被 Agent 稳定调用。以下模式在此基础上叠加,覆盖跨命令组合、版本演进、长时间运行和权限管控等更复杂的场景。

组合性

Agent 以管道思维工作——把多个命令串联起来完成复杂任务。CLI 应支持命令间的数据流动。

# 从上游命令获取输入
mycli deploy --env staging --tag $(mycli build --output tag-only)

# 通过 stdin 传入复杂配置
cat config.json | mycli config import --stdin

# 列表输出可被下游消费
mycli service list --json | jq '.[] | select(.status == "unhealthy") | .id'

设计要点:

  • 提供 --output tag-only 或 --output id-only 等精简输出模式
  • 支持 --stdin 从管道读取输入
  • 列表命令的 JSON 输出应是数组,方便 jq 处理
  • 单条记录命令的输出应是对象
  • $() 嵌套存在命令输出注入风险,优先使用 --stdin + 管道传递复杂数据

版本与兼容性

Agent 的 skill 文件和 workflow 可能锁定特定的命令格式。CLI 的输出格式变更会破坏 Agent 的解析逻辑。

设计要点:

  • 使用语义化版本号,输出格式变更视为 breaking change
  • 提供 --api-version flag 或 MYCLI_API_VERSION 环境变量
  • 废弃字段先标记 deprecated,至少保留一个主版本周期
  • mycli version --json 返回版本信息供 Agent 检测兼容性

超时与取消

Agent 需要知道命令是否会长时间运行,以及如何安全取消。

设计要点:

  • 长时间操作支持 --timeout flag
  • 超时后返回明确的超时错误码(而非静默挂起)
  • 异步操作返回 job ID,提供 mycli job status <id> 查询进度
  • 支持 mycli job cancel <id> 安全取消
# 异步操作模式
$ mycli deploy --env production --tag v2.0.0 --async
Job started: job_abc123
Check status: mycli job status job_abc123

$ mycli job status job_abc123 --json
{
  "job_id": "job_abc123",
  "status": "running",
  "progress": "pulling image (2/4 steps)",
  "started_at": "2026-05-08T10:30:00Z",
  "estimated_completion": "2026-05-08T10:32:00Z"
}

权限与作用域

Agent 的操作应受到明确的权限边界约束。CLI 应让权限模型对 Agent 透明。

设计要点:

  • 权限不足时返回明确错误和所需权限名称
  • 提供 mycli auth whoami 查看当前身份和权限
  • 支持 --scope 或 --as 限制操作范围
  • 敏感操作的审计日志应包含调用者身份
$ mycli service delete prod-db --yes
Error: Permission denied.
  Required: service:delete on resource prod-db
  Current permissions: service:read, service:list
  Request access: mycli auth request-permission service:delete

Agent-Friendly CLI 设计规范

可直接嵌入 Agent 系统规则(如 AGENTS.md)或作为 Code Review 标准。MUST = 必须,SHOULD = 应该,MAY = 可选。

### 1. 调用规范

- [MUST] 所有必要参数通过 `--flag` 或环境变量传入,禁止运行时交互式 prompt
- [MUST] 未提供必要参数时输出错误并以非零退出码退出;不降级为交互模式
- [SHOULD] 检测到非 TTY 环境(`$CI`、`!isatty()`)时自动禁用交互,不得挂起等待
- [SHOULD] 提供 `--stdin` 或 `--file` 读取复杂输入(JSON / YAML)
- [MUST] 全局 flag 命名前后一致(禁止 `--env` 和 `--environment` 混用)
- [MUST] 命令遵循统一的 verb-noun 或 noun-verb 模式;禁止同义词混用(remove / delete)

### 2. 输出规范

- [MUST] 提供 `--json` 输出模式
- [MUST] `--json` 输出必须包含 `status` 字段(`"success"` / `"error"`)
- [SHOULD] `--json` 输出包含关键 ID、URL、耗时等可程序消费的字段
- [MUST] 数据输出到 stdout;日志、进度、诊断输出到 stderr
- [SHOULD] 支持 `--verbose` / `--debug` 输出中间步骤和调用链信息(通过 stderr,不污染 stdout 可解析数据)
- [SHOULD] 支持 `NO_COLOR` 或 `--no-color`;默认不在 stdout 输出 ANSI 颜色码
- [SHOULD] 列表类命令的 `--json` 输出为 JSON 数组
- [MAY] 列表类命令额外支持 `--output table` / `--output csv`

### 3. 错误规范

- [MUST] 错误信息包含三个部分:问题描述 + 正确用法示例 + 获取缺失信息的命令
- [MUST] 使用非零退出码区分错误类型(建议:1=参数/用户错误、2=系统/运行时错误、3=权限不足)
- [MUST] `--json` 模式下错误也输出结构化 JSON(含 `code`、`message`、`suggestion`、`retryable` 字段)
- [MUST] `retryable` 字段告知调用方可否重试:`false` 表示参数缺失等永久错误;`true` 表示网络超时等瞬态错误

### 4. 安全与幂等

- [MUST] 破坏性操作必须提供 `--dry-run`
- [MUST] 破坏性操作默认要求确认;提供 `--yes` 跳过确认
- [SHOULD] 创建/部署类命令支持幂等键或基于参数去重;重复调用返回已有结果,标注 `"created": false`
- [SHOULD] 长时间操作支持 `--timeout <seconds>`;超时后明确返回错误,不静默挂起
- [SHOULD] 权限不足时在错误信息中输出所需权限名称和当前权限列表

### 5. 可发现性

- [MUST] 顶层 `--help` 只列子命令名称和一句话描述;不展开参数
- [MUST] 每个子命令 `--help` 末尾包含 `Examples:` 段
- [SHOULD] 顶层的每条子命令描述长度不超过 60 字符
- [SHOULD] 提供 `version` 子命令,且支持 `--json` 组合输出结构化版本信息
- [MAY] 提供 `completion --shell agent` 输出机器可读的命令树

### 6. 兼容性

- [MUST] 使用语义化版本号(SemVer)
- [SHOULD] `--json` 输出格式变更视为 breaking change(MAJOR 升级)
- [SHOULD] 废弃字段先标记 `deprecated`,至少保留一个主版本周期
- [SHOULD] 支持 `--api-version` 或 `$MYCLI_API_VERSION` 锁定接口版本

参考来源