从面向过程,到面向对象,再到函数式,编程范式每次转向改变的都不只是语法,而是组织代码和思考问题的方式。
现在轮到了面向 AI 编程。
这次的变化发生在两个维度上。开发方式在变:AI agent 开始直接写代码、提交 PR,OpenAI 内部一个三人团队用五个月、零行手写代码交付了百万行级产品。软件产品也在变:AI agent 成了用户,产品得为机器提供和人类一样顺畅的操作界面。
这篇文章从 OpenAI 提出的 Harness Engineering 讲起,再聊 CLI 为什么在 AI 时代重新变得重要,最后把两条线串起来。
太长不看版
- Harness Engineering 是为 AI agent 建造约束系统(测试、文档、工具链),不是"用 AI 写代码"
- 工程师的核心工作从写代码转向设计约束。agent 出错,修的是基础设施,不是 prompt
- CLI 是 AI agent 的原生界面,结构化、可组合、可验证,天然适合机器消费
- CLI 管本地开发,MCP 管跨系统集成,API 管外部产品化,三者分层互补
- 两个维度指向同一件事:让软件系统对机器可读、可操作、可验证
第一个维度:开发过程面向 AI
Harness Engineering 到底在说什么?
现在很多团队已经在用 AI agent 做开发了。描述需求,让 agent 拆分任务、生成代码,甚至直接提交 PR。效率确实提升了,但问题也很明显:agent 经常跑偏,生成的代码质量参差不齐,出了问题只能靠人肉 review 兜底。缺的不是 AI 的能力,而是约束和自动修复的机制。
Harness Engineering 要解决的就是这个问题。不是让 AI 更聪明,而是给 AI 修路、装护栏、设红绿灯。
Harness 是围绕 AI agent 建造的基础设施:测试、文档、工具链、约束规则。让 agent 在可控环境里自主完成任务,出了错能被自动检测和纠正。打个比方,AI agent 是发动机,Harness 是整辆车。方向盘、刹车、GPS、安全带,缺了这些,发动机再强也没用。
graph LR
A[工程师] -->|设计约束| B[Harness 层]
B -->|密封测试| C[AI Agent]
B -->|机器可读文档| C
B -->|模块化架构| C
B -->|工具链 & CI| C
C -->|生成代码 & PR| D[代码仓库]
D -->|自动验证| B
classDef engineer fill:#1A9090,stroke:#147070,color:#fff
classDef harness fill:#1a5c5c,stroke:#147070,color:#fff
classDef agent fill:#0d3b3b,stroke:#1A9090,color:#1A9090
classDef repo fill:#0a2e2e,stroke:#1A9090,color:#1A9090
class A engineer
class B harness
class C agent
class D repo
这套体系立在三根支柱上:
- 密封测试(Hermetic Tests):每个测试在隔离环境独立运行,不依赖外部服务。Agent 生成的代码需要明确的对错判定器,没有密封测试,agent 就像没有考试卷的学生。
- 机器可读文档:API 契约用 OpenAPI 描述,架构决策用 ADR 记录,编码规范写成 lint 规则。Agent 读不懂"参考上面的架构图"这种话。
- 模块化架构:Agent 的上下文窗口有限,五千行的单体文件对它来说就像没有目录的百科全书。模块边界就是 agent 的认知边界。
Agent 出错了,修什么?
这是最反直觉的一点。常规做法是 agent 出 bug 就去调 prompt。Harness Engineering 反过来:agent 出错说明 Harness 缺了东西。测试不够?文档不清?工具缺失?
Martin Fowler 在分析这个概念时引用了 OpenAI 团队的原话:"当 agent 挣扎的时候,我们把它当作一个信号:识别缺少了什么,工具、护栏、文档,然后把它反馈回仓库。" 这个闭环把"修 AI"变成了"修工程基础设施",而修基础设施是工程师擅长的事。
工程师的角色也随之转变:
| 传统角色 | Harness Engineering 下的角色 |
|---|---|
| 写功能代码 | 设计测试策略和验证规则 |
| 调试和修 bug | 分析 agent 失败模式,改进 Harness |
| 写技术文档 | 维护机器可读的架构和 API 规范 |
| Code Review | 审查 agent 生成的 PR,优化约束规则 |
| 技术选型 | 设计模块边界和 agent 可操作的工具链 |
这不是说工程师不再需要理解代码。你得更深地理解系统,才能设计出好的约束条件。
第二个维度:软件产品面向 AI
CLI 怎么又火了?
2026 年初,Andrej Karpathy 发了一条推文,说 CLI 作为一项"遗产技术",正在因为 AI agent 获得新生。讨论很快扩散开来。
四十年前,所有成功的软件都需要一个精心设计的 GUI。好的 GUI 把用户从记忆命令行参数的认知负担中解放出来。
但现在用户不只是人类了。AI agent 也是用户。
对 AI agent 来说,GUI 是个噩梦。Agent 需要截屏,把图片喂给视觉模型,分析结果,猜测下一步该点哪里。这就像让一个人用望远镜通过窗户操作别人的电脑。
CLI 天然就是结构化的:
# 人类用 GUI 点五次才能完成的操作
# AI agent 用 CLI 一行搞定
gh pr create --title "fix: resolve auth timeout" --body "..."
结构化输入,结构化输出,可组合,可脚本化。这些 CLI 四十年前就有的特性,恰好是 AI agent 最需要的。
CLI 为什么适合 AI agent
具体来看有四个原因。
可解析。 CLI 的输出是文本,通常还是结构化文本(JSON、表格、状态码)。Agent 直接解析,不需要看图猜意思。
可组合。 Unix 哲学里"做一件事,做好它"的管道模式,天然适合 agent 编排多步骤工作流。command1 | command2 | command3 就是最早的 agent 工具链。
可自描述。 CLI 工具自带 --help、man page、完整的参数说明。这就是最好的机器可读文档,agent 自己就能读懂工具怎么用。
可验证。 退出码、标准输出、标准错误,提供了明确的成功/失败信号。Agent 不需要猜"刚才那个操作到底成功了没有"。
graph TB
subgraph "GUI 交互路径"
G1[Agent] -->|截屏| G2[视觉模型解析]
G2 -->|猜测 UI 元素| G3[模拟点击]
G3 -->|等待渲染| G4[再次截屏验证]
G4 -->|循环| G2
end
subgraph "CLI 交互路径"
C1[Agent] -->|构造命令| C2[执行 CLI]
C2 -->|结构化输出| C3[解析结果]
C3 -->|退出码验证| C4[下一步操作]
end
classDef gui fill:#4a3030,stroke:#8b5e5e,color:#ddd
classDef cli fill:#1a5c5c,stroke:#1A9090,color:#fff
class G1,G2,G3,G4 gui
class C1,C2,C3,C4 cli
怎么设计面向 AI 的软件接口
如果你在建新产品,或者考虑给已有产品增加 AI 可访问性,一个实用的原则是:先 CLI,后 GUI。
不是说不要 GUI,而是说:
- 先设计 CLI 层,定义清晰的命令、参数、输入输出格式
- CLI 就是你的 API,确保每个功能都能通过命令行完成
- GUI 是 CLI 的视觉封装,GUI 调用 CLI,而不是绕过它
- 输出默认机器友好,支持
--json或--format参数
GitHub CLI(gh)是个好例子。它让 AI agent 能像人一样操作 GitHub 的完整工作流:创建 PR、查看 CI 状态、管理 Issue,全部结构化、可组合。
CLI、MCP、API 怎么分工
有了 MCP(Model Context Protocol),还需要 CLI 吗?需要。它们解决的是不同层面的问题。
| 接口类型 | 适合场景 | 特点 |
|---|---|---|
| CLI | 本地开发、快速迭代 | 零额外开销,启动快,结果确定 |
| MCP | 外部系统集成、跨服务编排 | 标准化协议,动态发现,适合复杂编排 |
| REST API | 服务间通信、产品集成 | 最通用,但需要认证、网络、序列化 |
CLI 管本地开发工作流,MCP 管跨系统集成,两者互补。
实践中被验证过的做法:
- 核心功能先实现为 CLI 命令
- 用 MCP Server 封装 CLI,暴露给 AI agent 工具链
- API 层面向外部集成和产品化场景
两条线,同一个方向
把两条线放在一起看:
Harness Engineering 要求代码仓库对 AI 可读、可测、可操作。CLI-first 设计要求软件产品对 AI 可读、可调、可验证。
说到底是同一件事:让软件系统同时为人类和 AI agent 服务。
graph TB
subgraph "面向 AI 的软件开发"
direction TB
A1[密封测试] --> B1[Agent 可验证]
A2[机器可读文档] --> B2[Agent 可理解]
A3[模块化架构] --> B3[Agent 可操作]
end
subgraph "面向 AI 的软件产品"
direction TB
C1[CLI 接口] --> D1[Agent 可调用]
C2[结构化输出] --> D2[Agent 可解析]
C3[自描述参数] --> D3[Agent 可发现]
end
B1 & B2 & B3 --> E[对机器可读 可操作 可验证]
D1 & D2 & D3 --> E
classDef left fill:#1A9090,stroke:#147070,color:#fff
classDef right fill:#1a5c5c,stroke:#147070,color:#fff
classDef center fill:#0d3b3b,stroke:#1A9090,color:#1A9090
class A1,A2,A3,C1,C2,C3 left
class B1,B2,B3,D1,D2,D3 right
class E center
实际操作中,做 Harness Engineering 的团队顺手就能让内部工具链更 CLI 友好;设计面向 AI 产品接口的经验也能反哺开发流程。
现在可以做什么
不用等 AI 更强了再动手。
开发流程
- 检查测试能不能在隔离环境独立运行。不能的话先解决这个,这本身就是工程基本功。
- 把 API 规范从 Wiki 迁到 OpenAPI spec,编码规范从文档变成 lint 规则,架构决策记录为 ADR。
- 超过 500 行的文件考虑拆分。这既帮 AI agent 管理上下文,也帮人管理认知。
- 记录 agent 在哪里犯错。如果你已经在用 Claude Code 或类似工具,这些错误模式就是 Harness 需要补强的地方。
产品设计
- 给最常用的功能加 CLI 入口,不需要一步到位。
- 至少支持 JSON 输出,让 agent 能直接解析。
--help信息写完整、写准确,这就是 agent 的使用说明书。- 如果工具需要被 AI agent 编排,用 MCP Server 封装 CLI。
结尾
面向 AI 编程的两个维度,成熟度不同。
开发过程面向 AI 已经有了实际案例。OpenAI 的百万行代码项目跑通了 Harness Engineering,但目前还是少数团队的做法。多数团队的现实路径是渐进式的:先把测试补齐,让文档机器可读,把模块拆干净。这些本身就是好的工程实践,AI 只是让回报变高了。
软件产品面向 AI 刚刚起步,但动得很快。CLI 的复兴、MCP 协议的推广、"AI agent 也是用户"这个认知的扩散,都在推动接口设计的变化。未来几年,"是否对 AI agent 友好"大概率会成为软件产品的基本要求,就像十年前的移动端适配一样。
两个维度交汇的地方,是一个具体的工程判断:你的系统对机器来说,可读吗?可操作吗?出了错能自动发现吗?
能回答这三个问题,就算入门了。