工程日记・第十九天:我们做了个CLI,因为AI Agent讨厌浏览器
核心论点:CLI是新的API
2026年,有些东西变了。AI Agent生态不再试图让Agent使用浏览器,而是开始在Agent真正工作的地方与它们会面——终端。Devin、Cursor、Claude Code、Windsurf、Cline——每个正经的Agent运行时都有一流的shell访问能力。数据也证实了这一点:
- 任务完成率:在基准测试中,CLI命令的成功率比等效的MCP工具调用高28%
- Token效率:一条
volo search "NYC to London"命令消耗的token比浏览网页UI或解析HTML少4-32倍 - 可组合性:
volo fleet list | jq '.[] | select(.range_km > 10000)'—— Unix管道是最初的函数组合 - 确定性:没有会崩的DOM,没有会失效的CSS选择器,没有需要关闭的Cookie横幅
E2B、Stripe、Vercel、Supabase、Neon——每个面向开发者的公司现在都把CLI当作一流的Agent接口。VOLO已经有REST、GraphQL、MCP和OpenAI Plugin。缺失的那块拼图很明显。
架构:四个依赖和一个原则
设计约束很简单:stdout给机器,stderr给人类。
默认情况下,每个命令都向stdout输出干净的JSON。没有加载动画,没有颜色,没有进度条。AI Agent可以直接把输出管道到 jq 或用 JSON.parse() 解析。加上 --pretty 就有彩色表格、加载动画和格式化输出——但只在stderr上,永远不会污染数据流。
# Agent模式(默认)—— 干净的JSON
volo search "NYC to London 4 pax" | jq '.data.flights[0].price'
# 人类模式 —— 彩色表格
volo fleet list --pretty --category heavy
生产依赖:恰好四个。
| 包 | 用途 | 大小 |
|---|---|---|
| commander | CLI框架 | ~50KB |
| chalk | 终端颜色(仅--pretty模式) | ~16KB |
| cli-table3 | 表格格式化(仅--pretty模式) | ~30KB |
| ora | 加载动画(仅--pretty模式) | ~20KB |
HTTP?Node 18+原生 fetch。零依赖。配置存储?fs.writeFileSync 配合 0600 权限。没有钥匙串库,没有凭据管理器——就是一个只有所有者能读的JSON文件。
16个命令,一个API面
CLI直接映射到VOLO的REST API。每个命令都是HTTP调用的薄封装:
volo search "上海到东京下周五,4位乘客"
volo quote --from ZSPD --to RJTT --pax 4 --date 2026-04-15
volo track CX520
volo weather Singapore --forecast 3
volo fleet list --category heavy
volo fleet compare "Gulfstream G650ER" "Bombardier Global 7500"
volo airports search "changi"
volo empty-legs --region asia-pacific --limit 10
volo routes --tag popular
volo destinations --region europe
volo content --type fleet --locale zh
volo agent register --name MyBot --email bot@example.com
volo agent dashboard --pretty
volo chat "帮我找一架重型公务机,8位乘客"
volo api GET /v1/openapi.json
volo config list
不需要认证的命令(search、weather、fleet、airports、track)用 npx volo-cli 立即可用。无需注册,无需API key,无需配置。Agent命令(dashboard、referrals)需要通过 volo agent register 获取的密钥。
安全架构
这是最重要的设计决策,也是需要最多纪律性的决策。VOLO集成了多个上游航空数据供应商。CLI必须永远不暴露它们中的任何一个。
原则:CLI是一个纯API客户端,只知道 flyvolo.ai。它不知道上游供应商的存在。
用户/Agent ──> volo-cli ──> flyvolo.ai/api/v1/* ──> [VOLO后端] ──> 上游供应商
│ ↑
│ 所有供应商调用
│ 仅在服务端发生
└── CLI只知道flyvolo.ai,不知道其他任何东西
实践中的意义:
- 无上游URL:CLI源码中只包含一个域名——
flyvolo.ai。没有供应商API地址,没有代理URL,没有CDN端点。 - 无内部ID:内嵌的机队数据只包含公开信息——飞机名称、座位数、航程、价格区间。没有供应商内部标识符。
- 无泄露的错误详情:当上游API失败时,CLI显示"服务暂时不可用"——永远不显示上游错误消息或URL。
- 无供应商导入:CLI包对内部包的导入为零。不依赖
@volo/ai、@volo/database或任何供应商客户端库。
认证链遵循纵深防御:
优先级:VOLO_API_KEY 环境变量 > --api-key 参数 > ~/.volo/config.json > 匿名
~/.volo/config.json 中的凭据以 0600 权限存储(仅所有者可读写)。volo config list 在显示时遮蔽API key(volo_abc...xyz)。volo auth logout 安全删除文件。
离线能力
两个命令无需任何网络连接即可工作:
volo fleet list:内嵌4个类别15款飞机的数据(轻型、中型、超中型、重型/超远程)。完整规格:名称、制造商、座位数、航程、速度、客舱尺寸、价格区间。volo fleet compare:基于内嵌数据的并排对比。试试volo fleet compare "Citation CJ4" "Phenom 300E" --pretty。
内嵌数据与网站上公开展示的信息完全一致——没有内部定价模型,没有供应商利润率,没有机密数据。
交互式聊天:终端里的AI管家
volo chat 把VOLO的14工具AI管家带到了命令行。两种模式:
# 单次调用(适合Agent)
volo chat "找找这周从伦敦出发3万美元以下的空腿航班"
# 交互式REPL(适合人类)
volo chat
volo> 我需要一架下个月从上海到东京的飞机,6个人
volo> Global 7500怎么样?
volo> /quit
REPL跨对话轮次保持上下文记忆,管家会记住之前聊的内容。单次模式返回JSON——完美适配Agent流水线。
前端集成:CLI成为第五协议
构建CLI只是一半的工作。另一半是让它被看见。我们把CLI集成到了Agent主页的每个部分:
| 组件 | 变更 |
|---|---|
| CodeTabs | 添加第8个"CLI"标签页,包含安装和命令示例 |
| AgentHero | 在统计数据下方添加 npx volo-cli --help 可复制安装卡片 |
| EndpointCards | 每个API端点在展开视图中显示对应的CLI命令 |
| ProtocolStatus | 添加第5个"CLI"协议卡片(状态:LIVE) |
| AgentHome | 在Quick Start部分添加CLI入口点 |
CLI现在与REST、GraphQL、MCP和OpenAI Plugin并列——从Agent或开发者访问 /for-agents 的那一刻起就能看到。
核心数据
| 指标 | 数值 |
|---|---|
| 命令数 | 16(+ config/auth) |
| 源文件 | 28 |
| 代码行数 | ~2,500 |
| 生产依赖 | 4 |
| 测试 | 17(全部通过) |
| 暴露的上游API | 0 |
| 离线命令 | 2(fleet list、fleet compare) |
| 修改的前端组件 | 5 |
| 从规划到部署 | 1个会话 |
我学到的
1. JSON-first对Agent接口来说没有商量余地
你在stdout中混入人类可读格式的那一刻,就破坏了每一个下游消费者。Agent无法解析表格,无法可靠地去除ANSI颜色码。stdout/stderr的分离不是"有更好"——它是根本契约。
2. 通过架构而非策略来保证安全
我们没有添加"不要暴露上游API"的lint规则。我们让它在结构上不可能——CLI包不依赖任何内部包,没有通往任何供应商客户端的导入路径,只硬编码了一个域名。最安全的代码是那些根本无法触及不应触及之物的代码。
3. 离线能力赢得信任
volo fleet compare G650 "Global 7500" 在没有WiFi的飞机上也能用。这不是噱头——它证明了你的工具尊重用户的环境。当Agent在受限沙箱中运行时,离线命令依然有效。
4. Monorepo模式很重要
向Turborepo monorepo添加新包几乎没有摩擦。packages/cli/ 自然地放在 packages/mcp-server/ 旁边。相同的构建模式,相同的tsconfig基础,相同的CI管道。MCP server就是模板——我们完全匹配了它的结构。
5. CLI是从零到价值的最快路径
npx volo-cli search "NYC to Aspen" ——就这样。不需要浏览器,不需要注册,不需要API key,不需要安装SDK。一个命令,立即获得结果。对于一个正在评估是否与VOLO集成的AI Agent来说,摩擦基本为零。
下一步
- npm publish:将
volo-cli推送到公共npm registry,让npx volo-cli全球可用 - Shell补全:bash/zsh/fish的Tab补全
- 插件系统:让Agent开发者用自定义命令扩展volo-cli
- 流式输出:用
--watch标志实时追踪航班 - CI/CD集成:用GitHub Actions构建自动化航空数据流水线
准备好飞行了吗?几秒钟获取个性化包机报价。
订阅资讯
空腿航班优惠、新航线与航空洞察,直达您的邮箱。