CLI 入门:从终端命令到 AI Agent 调用

一、CLI 是什么

CLI,全称 Command-Line Interface(命令行界面)。你打开终端,敲一行字,按回车,程序干活,打印结果,退出------这就是 CLI。

复制代码
$ ls -l               ← 输入
total 24
drwxr-xr-x  5 user  staff   160 Jun  1 10:00 src/
-rw-r--r--  1 user  staff   120 Jun  1 10:00 README.md
                       ↑ 输出
$                      ← 退出了,等下一个命令

CLI 和 GUI(图形界面)的区别:GUI 一直开着,你点按钮它响应;CLI 敲完就跑,结果打出来就结束。

CLI 和 Web 服务的区别:Web 服务一直等请求,每个请求进来响应完继续等下一个;CLI 一次执行完毕就退出,不保持连接。

CLI 的三个本质特征:输入(命令行参数)→ 处理(程序逻辑)→ 输出(stdout + 退出码)。 少了任何一个都不算 CLI。

二、CLI 的零件

一个完整的 CLI 由以下几个部件组成。

解剖图

复制代码
┌─────────────────────────────────────────────────────┐
│                  CLI Tool Anatomy                   │
├─────────────────────────────────────────────────────┤
│                                                     │
│  $ my-cli calc add 1 2 --verbose                    │
│         │     │   │ │    │                          │
│         │     │   │ │    └── 选项参数               │
│         │     │   │ └─────── 位置参数               │
│         │     │   └───────── 子命令                 │
│         │     └───────────── 子命令组               │
│         └─────────────────── 主命令                 │
│                                                     │
│  ┌─────────┐  ┌────────┐  ┌──────────────────┐     │
│  │ Parser  │─▶│ Logic  │─▶│    Output        │     │
│  │ (拆参数) │  │ (干活)  │  │                 │     │
│  └─────────┘  └────────┘  │ stdout → 结果    │     │
│                           │ stderr → 错误    │     │
│                           │ exit 0  → 成功   │     │
│                           │ exit 1  → 失败   │     │
│                           └──────────────────┘     │
└─────────────────────────────────────────────────────┘

五要素

子命令体系 :类似 git commitdocker ps。一个 CLI 可以拆成多个子命令,每个子命令做一件事。

参数解析:分两种------

  • 位置参数:calc add 1 2 里的 12,按顺序匹配
  • 选项参数:--output json-v,通过名字匹配

stdout 和 stderr:标准输出(结果)和标准错误(日志/错误信息)走两个通道,分开处理。

退出码:0 表示成功,非 0 表示失败。这是程序化的判断依据------无论是人还是 AI,都通过退出码知道命令有没有跑通。

--help :每个合格的 CLI 都必须能打印帮助信息。calc --help 要告诉用户有哪些子命令,每个子命令要什么参数。

举个例子

假设我们要设计一个计算器 CLI:

python 复制代码
# 伪代码示意
$ calc add 1 2       → 3
$ calc multiply 3 4  → 12
$ calc --help        → 列出 add, multiply, divide...

这就是 CLI 的全部零件。不多不少。

三、"写脚本"和"做 CLI 程序"的区别

很多初学者觉得"写一个 .py 文件跑起来"就是 CLI 了。对,但也不对。随手写的脚本正式发布的 CLI 程序之间,差了一套工程规范。

随手写脚本:python cli.py 才能跑,依赖手动安装,没有 --help,没有退出码。

正式 CLI 程序:my-cli 直接跑,pip install 一键安装,自动生成 --help,严格退出码。

特性 随手脚本 正式 CLI 程序
运行方式 python cli.py my-cli
安装 手动装依赖 uv tool install .
--help 没有 自动生成
输出 print() 随便打 stdout(结果)/ stderr(错误)
退出码 没有 0=成功,1=错误,2=参数错
依赖管理 全靠 README 写 pyproject.toml 声明

关键在于:这些标准不是 AI 领域发明的,而是 Python 包管理的通用规范。

你写一个 FastAPI Web 服务、一个数据处理脚本、一个 CLI 工具------它们用的都是同一套 pyproject.toml 标准。区别只有一行配置:

toml 复制代码
# Web 服务
[project.scripts]
uvicorn = "myapp.main:app"

# CLI 工具
[project.scripts]
my-cli = "my_cli.cli:main"

这一行决定了 pip install 之后,用户敲的是什么命令。

四、从 pyproject.toml 倒推目录结构

很多教程会直接甩给你一个目录结构,说"这就是标准"------但初学者看不懂为什么。我们反过来,从"想要什么效果"倒推。

第一步:想让用户敲 my-cli 就能用。

需要在 pyproject.toml 里声明入口点:

toml 复制代码
[project.scripts]
my-cli = "my_cli.cli:main"

这告诉 Python:用户敲 my-cli 时,执行 my_cli/cli.py 里的 main() 函数。

第二步:需要一个包名,不和别的项目冲突。

于是有了:

复制代码
src/my_cli/
    ├── __init__.py
    └── cli.py

src/ 包装一层(src-layout),是为了避免项目根目录的 .py 文件和别的包路径冲突。

第三步:子命令多了,一个文件装不下。

于是拆出 commands/ 目录:

复制代码
src/my_cli/
    ├── __init__.py
    ├── cli.py
    └── commands/
        ├── __init__.py
        ├── calc.py
        └── config.py

第四步:想让用户也能 python -m my_cli 跑。

加一个 __main__.py

python 复制代码
from .cli import main
main()

每一步都是"因为想要某个效果,所以这么做",而不是"标准就是这样"。

真实案例:项目中的 mcp-server

你可以在项目源码 mcp-server/pyproject.toml 里看到实际配置:

toml 复制代码
[project.scripts]
mcp-server = "mcp_server.main:main"

安装后直接 uv run mcp-server 就能启动 MCP 服务。这就是一个标准的 Python CLI 入口。

五、AI 时代给 CLI 加了几条要求

CLI 本身没变。但 AI Agent 作为新的"用户",对 CLI 的输出方式提出了额外要求。其实就三条:

1. --output json

AI 看不懂"结果是: 3 🎉",但 AI 看得懂 {"result": 3}

bash 复制代码
# 给人看
$ calc add 1 2
3

# 给 AI 看
$ calc add 1 2 --output json
{"result": 3, "status": "ok"}

所以所有 AI 兼容的 CLI 都应该支持 --output json(或 --json)选项。默认给人看可读文本,加 --output json 给程序解析。

2. 严格退出码

AI 通过退出码判断命令是否成功:

  • 0 = 成功
  • 1 = 通用错误
  • 2 = 参数错误

如果所有情况都返回 0,AI 无法知道操作是否真的完成了。

3. 无交互式提示

bash 复制代码
# ❌ AI 没法回答这个
$ calc add
请输入两个数字: _

# ✅ 所有参数一次给全
$ calc add 1 2
3

AI 不会弹对话框,不会选择 Y/N。CLI 必须一次性接收所有必要参数。

就这三条。其他所有规范(pyproject.toml、src-layout、入口点)都和 AI 无关,是 CLI 本身就该有的。

六、AI 时代的完整链路:CLI → MCP → Skill

现在我们把 CLI 放到更大的图景里看。

三层架构

复制代码
         ┌──────────────────┐
         │     Skill        │  ← 操作手册:告诉 Agent 怎么用工具
         │  (指导层)         │     什么时候该用、参数怎么填
         └────────┬─────────┘
                  │
         ┌────────▼─────────┐
         │     MCP          │  ← 通信协议:Agent 和工具之间的标准接口
         │  (协议层)         │     tools/list → 发现工具
         │                  │     tools/call → 调用工具
         └────────┬─────────┘
                  │
         ┌────────▼─────────┐
         │     CLI          │  ← 工具本身:真的在干活的那个
         │  (工具层)         │     人敲命令也是它,AI 调也是它
         └──────────────────┘

关键原则:每一层不依赖上层,可以独立存在。

  • CLI 不需要 MCP 也能用------人直接敲命令
  • MCP 不需要 Skill 也能用------Agent 可以自己决定怎么调工具
  • Skill 只是给 Agent 提供更多上下文,让 Agent 决策更准确

用项目实际案例理解

在 nacos-learn-example 项目中:

CLI 层mcp-server 模块。一个 Python 程序,注册了三个工具(hello、calculator、weather)。人可以直接启动它,也可以把它当普通 CLI 用。

MCP 层nacos-mcp-router 模块。它作为 MCP 协议代理,一端连接 Nacos MCP Hub(服务注册中心),一端通过 SSE 协议暴露 MCP 接口。Agent 通过它发现和调用服务。

Skill 层 :项目中没有显式的 Skill 定义,但 agentic 模块的 Planner 和 Validator 承担了类似角色------它告诉 LLM"有哪些工具可用、每个工具做什么用、什么场景该用什么工具"。

调用流程

复制代码
人用 CLI:   $ mcp-server calculator add 1 2    → 3

AI 用 CLI:  Agent → MCP tools/list → 发现 calculator
             Agent → MCP tools/call calculator → 
             MCP Server → 执行逻辑 → 返回结果给 Agent

底层干活的那个没变------无论是人还是 AI,最终执行的都是同一段业务逻辑。

CLI、MCP、Skill 的本质

概念 本质 谁在用 创新程度
CLI 命令行工具,跑完就退 人和 AI 1970s Unix 就有
MCP AI 调工具的标准化协议 AI Agent 新标准(2024)
Skill 给 AI 的操作手册 AI Agent 新模式,框架+自由决策

CLI 没有创新,它是基础设施。MCP 是真正的创新------它让所有 Agent 用同一种方式发现和调用工具。Skill 是 MCP 之上的辅助层,让 Agent 用得更对。

七、参考案例:飞书 lark-cli

飞书官方 CLI(github.com/larksuite/cli)是"给人和 AI 用的 CLI"的标杆实现,13k stars,Go 语言编写。

三层命令体系

复制代码
lark-cli calendar +agenda           ← Shortcut(快捷命令,含智能默认值)
lark-cli calendar calendars list    ← API 命令(1:1 映射平台接口)
lark-cli api GET /open-apis/...     ← Raw API(全覆盖 2500+ 接口)

层级递进:从最常用的快捷操作,到精准的 API 调用,再到任意接口访问。

Skill 机制

lark-cli 提供了 24 个领域 Skill,每个 Skill 是一个模块:

Skill 覆盖的功能
lark-calendar 日历事件创建、议程查询
lark-im 消息发送、群聊管理
lark-doc 文档读写、搜索
lark-base 多维表格操作
lark-task 任务管理

Agent 按需加载 Skill,不会一次性暴露所有工具给 AI。

AI 友好设计

  • --format json 是默认输出--format pretty 给人看
  • 输出格式可选:json / ndjson / table / csv
  • OAuth 登录:支持交互式(人用)和非交互式(AI 用)两种登录流程
  • Dry-run 模式:有副作用的操作先预览再执行

八、动手建议

想学 CLI,最好的方式不是看教程,而是

从小做起

找一件你日常重复做的事------文件重命名、批量处理图片、查询系统状态------把它做成 CLI。

推荐工具链

bash 复制代码
uv init my-tool          # 初始化项目
uv add typer             # 安装 CLI 框架
# 写代码...
uv sync                  # 测试

Typer 是最适合初学者的 Python CLI 框架,4 行代码就能跑起来:

python 复制代码
import typer

app = typer.Typer()

@app.command()
def hello(name: str, count: int = 1):
    for _ in range(count):
        print(f"Hello {name}!")

if __name__ == "__main__":
    app()

不要一开始就搞 MCP

先把 CLI 本身做对------子命令、参数解析、退出码、--output json。这些都是通用的 CLI 技能,不管以后要不要对接 AI,都值得掌握。

MCP 和 Skill 是锦上添花,CLI 才是那匹锦。

相关推荐
大象说1 小时前
朱雀大模型检测对降AI改写内容的适配性实测与原理拆解
人工智能
kisdiem1 小时前
GAN(Generative Adversarial Network)生成对抗网络
人工智能·神经网络·生成对抗网络
咖啡星人k1 小时前
AI友好的全栈架构设计:接口规范、状态管理与组件拆分的最佳实践
人工智能
财迅通Ai1 小时前
智迪科技斥资1.52亿元收购越南工厂:当“租赁出海”走向“资产出海”
人工智能·科技·智迪科技
RD_daoyi1 小时前
Google SEO第三周:网站站内基础优化——决定排名快慢的核心基建
大数据·人工智能·学习·搜索引擎·百度·googlecloud
zhangfeng11331 小时前
超算中心 高性能计算 slurm的linux版本 centos7,如何安装docker,如何安装torch2.4
linux·运维·服务器·开发语言·人工智能·机器学习·docker
xiami_world2 小时前
Multi-Agent架构选型实战:5个主流平台工具深度横评
人工智能·ui·ai·agi·用户界面
weixin_407443872 小时前
OCR材料信息提取工具(附件中含代码和数据)
人工智能·python·计算机视觉·ocr
YOLO数据集集合2 小时前
无人机低空安防巡检AI落地方案|航拍小目标人员入侵检测、多场景跨领域目标检测数据集与YOLO算法工程实战
人工智能·yolo·目标检测·无人机