ACP:AI 时代的 Agent 接入标准
ACP:AI 时代的 Agent 接入标准
一、先从一个真实的场景说起
假设你想给自己做一个 AI 产品——可能是一个定制化的代码助手、一个内部知识库 Agent、一个贴合团队工作流的 Coding Copilot,或者就是一个能自动帮你写日报、跑脚本、改项目的"私人助理"。
你很快会面临一个现实问题:要不要自己从零实现一个 Code Agent?
- 自己从头撸,意味着你要处理 prompt 工程、工具调用、上下文管理、沙箱执行、权限系统……这些都是 Claude Code、Codex、Gemini CLI 这些产品已经打磨过无数遍的事情
- 而且这些头部 Agent 在代码理解和执行效果上已经非常能打,自己重新造一个,大概率不如直接复用
所以更合理的做法是:把 Claude Code / Codex / Gemini CLI 这类成熟 Agent 当作"引擎",自己只做上层的交互外壳和业务编排。
可问题接着就来了:
- Claude Code 有自己的 CLI 和交互方式
- Codex 有自己的 SDK 和调用协议
- Gemini CLI 又是另一套玩法
- 想让它们跑在你自研的 Web 界面 / 内部 IDE 插件 / 自动化工作流里,每接一个都得写一套适配
反过来,这些 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 是什么
一句话:ACP(Agent Client Protocol)是一个用来规范 IDE/UI 与 AI Agent 之间通信的开放协议。
几个关键信息:
- 全称:Agent Client Protocol
- 官网:https://agentclientprotocol.com/
- 主导方:Zed 编辑器团队
- 定位:在"Agent 能力"和"产品形态"之间,抽出一层标准接口
- 关键特性:双向——不仅 UI 能调 Agent,Agent 也能反过来请求 UI 的能力(读文件、请求授权、流式推送思考过程等)
用类比快速建立认知
如果你熟悉下面任何一个协议,ACP 都能找到对应:
| 协议 | 解决的问题 | 类比关系 |
| HTTP | 浏览器 ↔ Web 服务 | 任意浏览器访问任意网站 |
| LSP | 编辑器 ↔ 语言服务 | 任意编辑器支持任意语言 |
| MCP | LLM ↔ 工具 | 任意模型调用任意工具 |
| ACP | IDE/UI ↔ Agent | 任意 IDE 驱动任意 Agent |
如果你是后端出身,把它当 “Agent 版 HTTP” 理解;如果你写过编辑器插件,把它当 “Agent 版 LSP” 理解——结构几乎同构。
最容易混淆的一页:ACP vs MCP
这是我被问得最多的问题,所以直接放在最前面:
| MCP | ACP | |
| 连接谁 | LLM ↔ Tool | Client (IDE) ↔ Agent |
| 视角 | 给模型 | 给 UI |
| 典型场景 | Claude 调用 GitHub API | Zed 驱动 Claude Code 改代码 |
| 一句话 | “让模型长出手” | “让 Agent 长出脸” |
两者不是替代关系,是互补关系:一个 Coding Agent 内部用 MCP 调工具,对外用 ACP 和 IDE 对话,完全不冲突。
三、ACP 协议内容
聊到这里你可能会好奇:ACP 协议到底规定了什么?会不会很复杂?
我的结论是:ACP 本身并不厚。你可以用三个维度把它整个记住——角色、消息模型、传输方式。
3.1 两个角色
ACP 的世界里只有两个角色:
| 角色 | 职责 | 可以类比成 |
| Agent | 真正干活的一方:接收 prompt、管理会话、推送过程、必要时反向请求用户授权或 IDE 能力 | 后端服务 |
| Client | 直面用户的一方:发 prompt、渲染 Agent 推送的中间过程、响应 Agent 的反向请求 | 前端 / 浏览器 |
做上层产品的时候,你要么实现 Client(复用 Claude Code / Codex 这类成熟 Agent),要么实现 Agent(把自家能力接入 Zed 等 ACP 宿主),两者很少同时做。
3.2 双向消息模型
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 结对编程” 这类交互的全貌:思考过程要可见、危险动作要授权、跑到一半能叫停。
3.3 一次完整交互长什么样
用一次"用户让 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(可选)────────────▶│ 用户中途取消四个关键看点:
- 双向:Agent 不只是被动回答,它会反过来请求 IDE / 产品能力
- 流式:session/update 一路推送,用户能看到"AI 在想什么"
- 权限可控:改文件、跑命令等危险动作,最终由用户拍板,Agent 不能越权
- 可中断:用户随时能 cancel,协议天然支持
换句话说:如果你做的产品里需要 “AI 边思考边干活、干之前要请示、干到一半能叫停”,ACP 几乎是现成的一张协议模板。
3.4 传输方式:协议和运输分离
ACP 在设计上把"说什么"(语义)和"怎么运"(传输)分得很干净,同一套协议可以跑在三种传输上:
| 传输 | 特点 | 典型场景 |
| stdio | 子进程 + 标准输入输出,零依赖 | Zed 默认方式,本地把 Agent 当子进程拉起 |
| Streamable HTTP | POST 发请求 + SSE 收反向流 | 远程部署,对企业网络 / 防火墙最友好 |
| WebSocket | 全双工长连接 | 远程部署,追求低延迟 |
对做产品的你来说,选型其实很直白:
- 本地 Agent + 桌面端产品 → 首选 stdio,零部署、零网络配置
- 远程 Agent + Web 产品 / 多端接入 → 选 Streamable HTTP,SSE 穿透性最好
- 有长连接需求 / 对延迟敏感 → 选 WebSocket
换传输不需要改业务代码,只需要换一下连接初始化方式——这也是 ACP 比"自己造一套 HTTP API"更值得的一点。
3.5 除此之外:扩展机制
ACP 预留了 _ 前缀的自定义方法,你可以在不破坏标准兼容性的前提下给它加私有能力(比如你的产品有一个"埋点上报"的私有协议想走同一条连接),详见官方扩展文档。这一点让 ACP 既能"做标准"也能"留口子",对工程落地很友好。
四、生态现状
已有实现
- Zed 编辑器:原生支持 ACP,是 ACP 的首个主力宿主
- Claude Code Adapter:把 Claude Code 包成 ACP Agent,让它能在 Zed 里跑
- Gemini CLI Adapter:同上
- 越来越多的适配器正在涌现
生态的好兆头是:同一个 Agent 开始能在多个 IDE 里跑,同一个 IDE 开始能接入多个 Agent——N × M 正在变成 N + M。
Go 版 SDK:eino-contrib/acp
官方主要提供 TypeScript/Rust 的实现,而我们因为字节内部 Go 技术栈 + Eino Agent 框架 需要以 ACP 方式对外暴露,做了一个 Go 版的 SDK:github.com/eino-contrib/acp。
它提供的能力:
- 双向 RPC 抽象:conn.ClientConnection / conn.AgentConnection 屏蔽 JSON-RPC 细节
- 三种传输层全支持:stdio / Streamable HTTP / WebSocket,HTTP & WS 基于 CloudWeGo Hertz
- 远程服务器:server.ACPServer 在同一路由上同时支持 HTTP 与 WS 升级
- 协议扩展:原生支持 _ 前缀自定义方法
- 代码生成:从官方 schema.json 自动生成类型与方法,协议升级跟得上
完整示例代码在仓库 examples/ 目录下,涵盖 Agent / Client 两端。
五、每个人都值得一个自己的 AI 壳程序
写到最后,我想把视角收回到个人这一侧。
AI 时代,每个人都值得给自己做一个"AI 壳程序"——可能是个命令行工具、本地客户端、Web 应用,甚至是挂在 IM 机器人后面的脚本。形态不重要,把 AI 驯化成贴合你自己工作流的样子,持续给你提效,才是重点。
这件事过去几乎"想想就算了":前端 / 后端 / 部署 / 权限折腾一圈,人先累死。但现在 Cursor / Claude Code / Codex 已经能把一个 idea 推到能跑的原型,搭壳子的门槛正在断崖式降低——真正的难点,已经不是 UI,而是里面跑的那个 Agent:上下文管理、工具调用、沙箱执行、权限系统……每一项都是大坑,全自己填基本等于放弃。
ACP 恰好解决了这个问题。
它让你可以直接"借用"Claude Code、Codex、Gemini CLI 这些已经被打磨得非常能打的 Agent 作为可替换的内核,而你只需要在外面做两件你最懂、也最值得自己做的事:
- 流程编排:怎么把 AI 的能力串进你自己的工作流
- 贴合你工作流的 Skill:那些只有你自己在意、只有你自己知道怎么做对的"个性化能力"
这是一个非常划算的分工: 把最难、最耗资源的"智能内核"交给最强的产品去做; 把最懂你、最无法被外人复刻的"流程和 Skill"留给你自己。
而且因为是走协议,今天你跑 Claude Code,明天出了更强的 Agent,只要换一个 ACP 连接就能无缝切换——你的壳子是沉淀资产,引擎是可替换部件。
六、抛砖引玉:一些个人的最佳实践
6.1 CodeReview 场景
用 Agent 做 Code Review 时,你多半会踩到两个坑:
- 结果不稳定:LLM 输出本身带随机性,同一份 diff 跑两次,评审意见可能一次说 “有问题”、一次说 “没问题”
- 假阳性偏多:模型容易把"风格建议"、"可读性吐槽"和"真实 bug"混成一张 Issue List,让你在噪声里捞信号
所以在壳程序里,我把这件事拆成了一条流水线:
- Reviewer:通读 diff,产出一份粗粒度的 Issue List(允许有噪声)
- Double Checker:把 Issue List 逐条喂回去做二次校验,只保留"真的可能是 bug"的条目
- Cross Reviewer(换一个 Agent):把二次校验的结果交给另一家 Agent 再 Review 一遍,借不同模型的视角差异把剩下的假阳性再滤一轮,真正跑出去的全是被双方都认可的高置信 Issue
- Fixer:对最终确认的 Issue 生成修复补丁
- Loop(可重复 N 轮):把补丁合回 diff 后,再开一个新的 Session 从第 1 步跑一遍;按需重复 N 轮,直到这一轮 Reviewer 不再报新问题为止
这么一拆,随机性被多轮投票抹平,假阳性被双 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,工作流本身都不动。
6.2 定时任务:让 Agent 成为"永远在岗的后台同事"
作为 Claude Code 的重度用户,我习惯紧跟它的每次更新。但光看官方 Change Log 往往不够——很多改动描述得很含糊,真正想知道"这个新功能到底怎么实现的",还得去翻源码。而 Claude Code 的 cli.js 是打包压缩过的 bundle,肉眼几乎不可读。
以前我是出新版 → 手动下载 → 手动切分 → 手动贴给模型反编译 → 手动对着 Change Log 去找新功能的实现——每一步都不难,但加起来就是一件"值得做、但懒得做"的事。于是我把它整个做进了壳程序里的一条自动化流水线:
- 监听:一条定时 Shell 脚本每天轮询 GitHub,拿 Claude Code 最新 release 的版本号和 Change Log
- 取源码:发现新版本就自动拉取最新的 cli.js,按函数 / 模块边界切分成能塞进上下文的小块
- 反编译:把切分后的代码丢给 Agent,让它把压缩 bundle 还原成可读源码
- 定位新功能:让 Agent 结合 Change Log,在反编译结果里找到对应新功能的实现位置和关键代码片段
- 产出:把分析结果自动写成一份飞书文档,链接推到我的 IM
整个过程配好之后就是"版本发布 → 飞书链接到手",我只需要打开链接读结论。和 6.1 一样,这里的每个 Agent 节点也是按"效果 / 成本"独立选型的——前面的反编译任务量大但相对机械,用 ChatGPT(Codex)跑就够;到第 4 步"结合 Change Log 找关键实现"这种需要理解力的活,再切到 Claude Opus 收尾。
这就是我说的 “让 Agent 成为永远在岗的后台同事”:你不再是"有空了打开 AI 产品问一下",而是把一件件"值得知道但来不及跟进"的事,交给壳程序里的定时任务自动跑——等你回来,结论已经躺在那里了。
总结一下:
上面两个例子看起来风格不同——一个是交互式的 Code Review,一个是后台跑的定时任务——但本质其实是同一件事:基于 ACP,把多个 Agent 编排起来,让它们去跑那些"值得做但人工跑很烦"的长任务。
它们都踩中了个人提效最关键的两点:
- 把"长任务"交给 Agent 去跑:单次一两分钟的事人做无所谓,但一件事要连做 5、6 步才有结果,就是 Agent 该接手的时机——流水线一旦搭好,每次调用都是边际成本极低的收益
- 把"重复操作"从自己身上剥离:每天都要跑的 Review / 每次发版都要做的反编译 / 每周都要整理的日报……这些动作积少成多就是你一半的精力,交给壳程序后,你能把时间真正花在只有你能做的事情上
而 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,而是你围绕自己工作流编排出来的那一整套自动化能力——引擎可以随时换新,壳程序才是属于你自己的长期资产。