ACP:AI 时代的 Agent 接入
ACP:AI 时代的 Agent 接入标准
还没有评论。
假设你想给自己做一个 AI 产品——可能是一个定制化的代码助手、一个内部知识库 Agent、一个贴合团队工作流的 Coding Copilot,或者就是一个能自动帮你写日报、跑脚本、改项目的"私人助理"。
你很快会面临一个现实问题:要不要自己从零实现一个 Code Agent?
所以更合理的做法是:把 Claude Code / Codex / Gemini CLI 这类成熟 Agent 当作"引擎",自己只做上层的交互外壳和业务编排。
可问题接着就来了:
反过来,这些 Agent 厂商也头疼:每出一款新 IDE、每冒出一个新平台,他们都得重新做一遍前端对接。
这就是典型的 N × M 问题:
Agent A ─┐ ┌─ 你的产品 X
Agent B ─┼── N × M 适配 ────┼─ 自研 IDE Y
Agent C ─┘ └─ 自动化平台 Z软件工程史上解决这种问题的办法只有一个——在中间抽一层标准协议,把 N × M 压成 N + M:
Agent A ─┐ ┌─ 你的产品 X
Agent B ─┼────── ACP ───────┼─ 自研 IDE Y
Agent C ─┘ └─ 自动化平台 ZACP 就是这一层。它让你可以只做好"壳子",复用生态里最强的 Agent “内核”——这也是它在当下这个时间点最务实的价值。
还有一个很现实的好处容易被忽视:ACP 让你可以"不走 API"就用上 Claude Code / Codex。自己基于模型 API 造 Agent,意味着每一次思考、每一次 tool_call、每一次长上下文回看,都在按 token 烧钱——稍微跑几个重活,一个月账单轻松三位数美金。而 Claude Code / Codex 这类产品自带订阅额度(Claude Pro / ChatGPT Plus 的 Max 套餐),你通过 ACP 把它们"借"进自己的壳程序,消耗的是固定月费的订阅池,不是按量计费的 API。
对个人和小团队来说,这一条差价大到几乎可以单独成为选 ACP 的理由。
一句话:ACP(Agent Client Protocol)是一个用来规范 IDE/UI 与 AI Agent 之间通信的开放协议。
几个关键信息:
如果你熟悉下面任何一个协议,ACP 都能找到对应:
| 协议 | 解决的问题 | 类比关系 |
| HTTP | 浏览器 ↔ Web 服务 | 任意浏览器访问任意网站 |
| LSP | 编辑器 ↔ 语言服务 | 任意编辑器支持任意语言 |
| MCP | LLM ↔ 工具 | 任意模型调用任意工具 |
| ACP | IDE/UI ↔ Agent | 任意 IDE 驱动任意 Agent |
如果你是后端出身,把它当 “Agent 版 HTTP” 理解;如果你写过编辑器插件,把它当 “Agent 版 LSP” 理解——结构几乎同构。
这是我被问得最多的问题,所以直接放在最前面:
| MCP | ACP | |
| 连接谁 | LLM ↔ Tool | Client (IDE) ↔ Agent |
| 视角 | 给模型 | 给 UI |
| 典型场景 | Claude 调用 GitHub API | Zed 驱动 Claude Code 改代码 |
| 一句话 | “让模型长出手” | “让 Agent 长出脸” |
两者不是替代关系,是互补关系:一个 Coding Agent 内部用 MCP 调工具,对外用 ACP 和 IDE 对话,完全不冲突。
聊到这里你可能会好奇:ACP 协议到底规定了什么?会不会很复杂?
我的结论是:ACP 本身并不厚。你可以用三个维度把它整个记住——角色、消息模型、传输方式。
ACP 的世界里只有两个角色:
| 角色 | 职责 | 可以类比成 |
| Agent | 真正干活的一方:接收 prompt、管理会话、推送过程、必要时反向请求用户授权或 IDE 能力 | 后端服务 |
| Client | 直面用户的一方:发 prompt、渲染 Agent 推送的中间过程、响应 Agent 的反向请求 | 前端 / 浏览器 |
做上层产品的时候,你要么实现 Client(复用 Claude Code / Codex 这类成熟 Agent),要么实现 Agent(把自家能力接入 Zed 等 ACP 宿主),两者很少同时做。
ACP 最不同于传统 HTTP API 的一点,是它的消息流是双向的:
传统 HTTP:
Client ───── request ─────▶ Server
Client ◀──── response ───── Server
ACP:
Client ───── prompt ─────────▶ Agent ← 你让 Agent 做事
Client ◀──── 读文件 / 要授权 ── Agent ← Agent 反过来请你帮忙
Client ◀──── 流式思考 / diff ── Agent ← Agent 把过程持续推给你
Client ───── cancel ─────────▶ Agent ← 你随时能打断它也就是说,Agent 不是一个"请求 / 响应"式的被动 API,而是一个能主动说话的参与方。这一点决定了 ACP 能承载 “AI 结对编程” 这类交互的全貌:思考过程要可见、危险动作要授权、跑到一半能叫停。
用一次"用户让 Agent 改代码"的完整流程把上面这些东西串起来:
Client (你的产品) Agent (Claude Code 等)
│ │
│────────── initialize ───────────────────────▶│ 协商协议版本与能力
│◀───────── initialize response ───────────────│
│ │
│────────── session/new ──────────────────────▶│ 开一个会话
│◀───────── session_id ────────────────────────│
│ │
│────────── session/prompt ───────────────────▶│ 用户:"帮我把 foo 改成 bar"
│ │
│◀───────── fs/read_text_file ─────────────────│ Agent:先读一下相关文件
│────────── file content ─────────────────────▶│
│ │
│◀───────── session/update (thought) ──────────│ 流式推送思考过程
│◀───────── session/update (tool_call) ────────│ 流式推送工具调用
│ │
│◀───────── session/request_permission ────────│ "我要改这个文件,可以吗?"
│────────── allow ────────────────────────────▶│
│ │
│◀───────── session/update (diff) ─────────────│ 流式推送 diff
│◀───────── session/prompt response ───────────│ 任务完成
│ │
│────────── session/cancel(可选)────────────▶│ 用户中途取消四个关键看点:
换句话说:如果你做的产品里需要 “AI 边思考边干活、干之前要请示、干到一半能叫停”,ACP 几乎是现成的一张协议模板。
ACP 在设计上把"说什么"(语义)和"怎么运"(传输)分得很干净,同一套协议可以跑在三种传输上:
| 传输 | 特点 | 典型场景 |
| stdio | 子进程 + 标准输入输出,零依赖 | Zed 默认方式,本地把 Agent 当子进程拉起 |
| Streamable HTTP | POST 发请求 + SSE 收反向流 | 远程部署,对企业网络 / 防火墙最友好 |
| WebSocket | 全双工长连接 | 远程部署,追求低延迟 |
对做产品的你来说,选型其实很直白:
换传输不需要改业务代码,只需要换一下连接初始化方式——这也是 ACP 比"自己造一套 HTTP API"更值得的一点。
ACP 预留了 _ 前缀的自定义方法,你可以在不破坏标准兼容性的前提下给它加私有能力(比如你的产品有一个"埋点上报"的私有协议想走同一条连接),详见官方扩展文档。这一点让 ACP 既能"做标准"也能"留口子",对工程落地很友好。
生态的好兆头是:同一个 Agent 开始能在多个 IDE 里跑,同一个 IDE 开始能接入多个 Agent——N × M 正在变成 N + M。
官方主要提供 TypeScript/Rust 的实现,而我们因为字节内部 Go 技术栈 + Eino Agent 框架 需要以 ACP 方式对外暴露,做了一个 Go 版的 SDK:github.com/eino-contrib/acp。
它提供的能力:
完整示例代码在仓库 examples/ 目录下,涵盖 Agent / Client 两端。
写到最后,我想把视角收回到个人这一侧。
AI 时代,每个人都值得给自己做一个"AI 壳程序"——可能是个命令行工具、本地客户端、Web 应用,甚至是挂在 IM 机器人后面的脚本。形态不重要,把 AI 驯化成贴合你自己工作流的样子,持续给你提效,才是重点。
这件事过去几乎"想想就算了":前端 / 后端 / 部署 / 权限折腾一圈,人先累死。但现在 Cursor / Claude Code / Codex 已经能把一个 idea 推到能跑的原型,搭壳子的门槛正在断崖式降低——真正的难点,已经不是 UI,而是里面跑的那个 Agent:上下文管理、工具调用、沙箱执行、权限系统……每一项都是大坑,全自己填基本等于放弃。
ACP 恰好解决了这个问题。
它让你可以直接"借用"Claude Code、Codex、Gemini CLI 这些已经被打磨得非常能打的 Agent 作为可替换的内核,而你只需要在外面做两件你最懂、也最值得自己做的事:
这是一个非常划算的分工: 把最难、最耗资源的"智能内核"交给最强的产品去做; 把最懂你、最无法被外人复刻的"流程和 Skill"留给你自己。
而且因为是走协议,今天你跑 Claude Code,明天出了更强的 Agent,只要换一个 ACP 连接就能无缝切换——你的壳子是沉淀资产,引擎是可替换部件。
用 Agent 做 Code Review 时,你多半会踩到两个坑:
所以在壳程序里,我把这件事拆成了一条流水线:
这么一拆,随机性被多轮投票抹平,假阳性被双 Agent 交叉复核过滤,Review 和 Fix 也不再是同一个 Agent 自说自话。而在 ACP 的模型下,这一套流水线就是"开几条 ACP 连接 + 在壳程序里写一小段编排代码"的事——每个节点都能按"效果 / 成本"独立选型。
举个我自己的搭配:前两轮 Reviewer 和 Double Checker 的工作量大、但任务相对简单(过滤明显噪声),我一般用 ChatGPT(Codex) 顶——跑起来快、消耗便宜;到了第 3 步 Cross Reviewer 和第 4 步 Fixer,要的是判断力和代码能力,这时我才切到 Claude Opus 来收尾。整条链路跑下来,效果接近"全程 Opus",但 Token 账单能省一大截。
这就是 ACP “引擎是可替换部件” 的真正威力——不仅可以换,还可以在一条流水线里按需混用,今天 Claude Code,明天 Codex,甚至同一个任务里不同阶段跑不同 Agent,工作流本身都不动。
作为 Claude Code 的重度用户,我习惯紧跟它的每次更新。但光看官方 Change Log 往往不够——很多改动描述得很含糊,真正想知道"这个新功能到底怎么实现的",还得去翻源码。而 Claude Code 的 cli.js 是打包压缩过的 bundle,肉眼几乎不可读。
以前我是出新版 → 手动下载 → 手动切分 → 手动贴给模型反编译 → 手动对着 Change Log 去找新功能的实现——每一步都不难,但加起来就是一件"值得做、但懒得做"的事。于是我把它整个做进了壳程序里的一条自动化流水线:
整个过程配好之后就是"版本发布 → 飞书链接到手",我只需要打开链接读结论。和 6.1 一样,这里的每个 Agent 节点也是按"效果 / 成本"独立选型的——前面的反编译任务量大但相对机械,用 ChatGPT(Codex)跑就够;到第 4 步"结合 Change Log 找关键实现"这种需要理解力的活,再切到 Claude Opus 收尾。
这就是我说的 “让 Agent 成为永远在岗的后台同事”:你不再是"有空了打开 AI 产品问一下",而是把一件件"值得知道但来不及跟进"的事,交给壳程序里的定时任务自动跑——等你回来,结论已经躺在那里了。
总结一下:
上面两个例子看起来风格不同——一个是交互式的 Code Review,一个是后台跑的定时任务——但本质其实是同一件事:基于 ACP,把多个 Agent 编排起来,让它们去跑那些"值得做但人工跑很烦"的长任务。
它们都踩中了个人提效最关键的两点:
而 ACP 在整件事里的位置,是让"编排多 Agent"这件事从一个工程难题变成一段 orchestration 代码。没有 ACP,你得为每家 Agent 写一套对接;有了 ACP,不同 Agent 可以像乐高一样按成本 / 效果组合,工作流稳稳沉淀在你自己的壳程序里,引擎随时可以换——这也是我为什么说,真正值得你攒的不是某个 Agent,而是你自己那套"能把 Agent 编排起来"的壳程序。
在你的壳程序里实现一次 ACP Client,就能像换引擎一样,随时接入 Claude Code、Codex、Gemini CLI 等各类 CLI 型 Agent,无需为每家单独做适配。
ACP 的价值,本质上就是把 Agent 生态里的 N × M 适配压成了 N + M:让强大的 Agent 成为可随时替换的"引擎",让每个人都能安心去攒自己的"壳程序"。而真正值得沉淀的,也从来不是某个具体的 Agent,而是你围绕自己工作流编排出来的那一整套自动化能力——引擎可以随时换新,壳程序才是属于你自己的长期资产。