认识 Agent Client Protocol
什么是 Agent Client Protocol?
Agent Client Protocol(简称 ACP)是一种专门用于 AI Agent 与客户端(编辑器、IDE、终端、Web 应用等)之间通信的开放协议,用来规范 AI 编码智能体与代码编辑器 / IDE 等客户端之间如何交互、同步状态和下发命令。
简单来说,ACP 定义了一套统一的通信标准,让任何支持 ACP 的编辑器都可以连接任何支持 ACP 的 AI Agent。
ACP 的核心目标,是让任何代码编辑器可以连接任何 AI 编码智能体,通过一套统一协议完成会话管理、能力协商、状态同步和操作执行,解决的就是 “编辑器如何与 AI 编码代理通信” 的问题。
例如 VS Code、Cursor、Windsurf、JetBrains IDE、自研 IDE 等等类似的产品都属于 Client(客户端),而 Claude Code、OpenAI Codex Agent、Gemini CLI、Aider、自研 Coding Agent 都属于 Agent,ACP 就是他们之间通信连接的“通用语言”。
为什么会产生 Agent Client Protocol?
在 ACP 出现之前:
VS Code <--私有协议--> Claude Code
Cursor <--私有协议--> Claude Code
JetBrains <--私有协议--> Claude Code
Windsurf <--私有协议--> Claude Code
每一个编辑器都要单独适配 Claude Code、单独适配 Codex、单独适配 Gemini …,而每个 Agent 也要:单独支持 VS Code、单独支持 Cursor、单独支持 JetBrains …,产生出 N × M 个适配问题,可以想象如果没有一个统一的通信协议,这些 Client(客户端)和 Agent 之间通信连接的建立与维护,成本都是极高的。
同时,AI 智能体任务越来越长时、多步、需要频繁读写文件、调用终端,缺少统一协议会导致过程不可观测、结果不可复现、权限控制混乱,就难以满足企业落地和团队协作的需求。
以上这些问题正是 ACP 产生的根本原因:
AI 编码智能体越来越强大,而编辑器与智能体之间缺少统一标准,导致生态割裂、重复适配成本高。ACP 通过定义 Agent 与 Client 的标准通信协议,实现 “任意客户端连接任意 Agent” 的互操作能力。
理解 Agent Client Protocol
理解 ACP,最重要的不是把所有 method 名背下来,而是抓住它的几个核心概念和流程。
Client 和 Agent:谁负责什么?
在 ACP 的世界里有两个角色:
- Client(客户端)
- 典型角色:VS Code、JetBrains、Zed、Neovim 插件、自研 Web IDE、命令行工具等。
- 职责:
- 与用户交互(UI、输入输出)。
- 掌控本地能力:文件系统、终端/命令执行、网络访问、弹窗等。
- 决定是否给 Agent 授权执行某些操作,并记录日志做审计。
- Agent(智能体)
- 典型角色:一个使用大模型的编码助手服务,可以运行在本地进程或远程服务器。
- 职责:
- 理解用户需求、分析代码、规划修改方案。
- 通过 ACP 请求 Client 提供所需的环境能力(读文件、写文件、运行测试等)。
- 以流式消息、事件形式把思考过程和结果反馈给 Client。
两者之间通过 ACP 交流,一端发 JSON‑RPC 请求/通知,一端响应或推回事件,形成一个完整的事件流。
JSON‑RPC 是什么?
JSON‑RPC 的核心概念
JSON‑RPC(JavaScript Object Notation Remote Procedure Call):
- 是一种基于 JSON 的远程过程调用协议,本质是用 JSON 来描述“调用某个远程函数”的请求和结果。
- 它不规定我们调用时必须用什么传输层(可以是 HTTP、WebSocket、TCP、自定义管道甚至标准输入输出),只规定消息的格式。
- 目标是让两个进程/服务之间的通信看起来就像是本地函数调用:
- 指定方法名(method)
- 传入参数(params)
- 得到返回值(result 或 error)
我们可以把它当成用 JSON 写的 RPC 协议,和 REST 那种资源 + HTTP 动词风格不太一样,它更偏向直接调用函数。
JSON‑RPC 的三种消息类型
在 JSON‑RPC 2.0 里,有三种核心消息形式:
-
请求(Request)
-
有
id字段。 -
结构大致是:
{ "jsonrpc": "2.0", "id": 1, "method": "someMethod", "params": { "foo": "bar" } } -
含义:我要调用你那边名为
someMethod的方法,参数是params,请给我一个响应。
-
-
响应(Response)
-
必须带上对应请求的
id。 -
成功时包含
result,失败时包含error:{ "jsonrpc": "2.0", "id": 1, "result": { ... } }或
{ "jsonrpc": "2.0", "id": 1, "error": { "code": -32602, "message": "Invalid params" } }
-
-
通知(Notification)
-
没有
id,表示不需要响应。 -
结构类似请求:
{ "jsonrpc": "2.0", "method": "log", "params": { "level": "info", "message": "hello" } } -
场景:发日志、发进度事件、发状态变更,不需要对方回一个响应。
-
JSON‑RPC 的几个特点
- 轻量:消息就是 JSON,易读易调试。
- 无状态:协议层不强制会话概念(像 ACP 这样需要会话,会自己在
params里带sessionId)。 - 双向:只要底层连接是双向(如 WebSocket / stdio),双方都可以当「客户端」发请求,对方当「服务端」响应。
- 支持批量调用:可以一次发一个 JSON 数组,里面多个请求一起处理。
初始化与能力协商
ACP 一切交互的起点是 initialize。
当 Client 启动并连接到一个 ACP Agent 时,它会先发送一个 initialize 请求,用来协商:
- 协议版本(protocolVersion)
- 彼此支持的能力和扩展
- 协商身份验证方法
- 一些基础元信息(客户端名称、Agent 名称等)
这一步的意义在于:
- 避免版本不兼容:比如 Client 是 v1,Agent 是 v2,就可以在这里检测并处理。
- 让双方提前知道对方支持哪些扩展功能,比如是否支持某种文件系统 API、是否支持多 Agent 协作等。
写在代码层,我们基本可以抽象成一个 acpClient.initialize() 的高层调用,之后所有方法都建立在这一步成功的前提下。
这其实就是相当于在让客户端和智能体建立连接,连接建立后,我们可以进行身份认证,然后创建会话并开始与智能体的对话。
更详细信息的可查看官方文档:https://agentclientprotocol.com/protocol/v1/initialization
会话管理:session 是一条「长期关系」
ACP 里有一个非常重要的概念:session(会话)。
- Client 会调用
session/new创建一个新的会话,通常会附带一些上下文信息,比如当前工作目录、项目路径、打开的文件列表等。 - 返回的
sessionId用来标识接下来的一整段交互(类似一个长期聊天频道),后续的所有 prompt、工具调用、状态更新都挂在这个 session 下面。
可以这样类比:
如果说 HTTP 请求偏向于一次性的动作交换,那么 ACP 的 session 更像是一个长期的工作房间,你和 Agent 在同一个房间里做很多轮对话和修改。
在代码设计上,我们可以把 session 映射为一个对象,比如:
const session = await acpClient.newSession({ cwd: projectPath });
// 后续所有与这个项目相关的提示都用 session.id
这样我们的 UI 或后端可以轻松地把某个项目或某个 tab 绑定到一个 session 上面。
详细内容可见官方文档:https://agentclientprotocol.com/protocol/v1/session-setup
一次完整交互:prompt turn
在 session 之上,ACP 定义了一次完整往返的单位:prompt turn。
官方的定义是:一次 prompt turn 是从用户发出一条消息开始,到 Agent 完成这一轮响应(或被终止)为止的完整交互周期。
官方文档:https://agentclientprotocol.com/protocol/v1/prompt-turn
在我们的真实项目中:
- Client 通过
session/prompt发起一次 prompt turn:- 指定
sessionId - 带上当前这一轮的用户消息(可以是文本、代码片段等富内容)
- 指定
- Agent 收到后开始工作,在这一轮期间会以事件流的方式不断往回推:
- 流式输出 token / 分段消息(让你实现「打字机」效果)。
- 工具调用请求(比如请求读文件、执行命令)。
- 权限请求(例如想修改哪些文件)。
- 进度和状态事件。
- 当 Agent 觉得这轮结束了,会发一个「完成」的事件,该轮 turn 宣告结束,下一轮 prompt 可以开始。
我的理解就是,
session/prompt是 ACP 的函数调用,而 prompt turn 是这次调用从开始到结束的整个生命周期。为什么使用函数调用来打比方,是因为 ACP(以及底层的 JSON‑RPC)本质上就是:一端给另一端发 我要调用你某个方法 的请求,对方执行完再把结果返回。
这个模式和我们在代码里写
someFunction(params)很像,所以用函数调用来帮助理解协议里的一次请求与响应是什么关系。所以,我们可以暂时先忘掉高级 AI 概念,只把 ACP 当作两段程序之间远程互相调函数的规则。
工具调用、文件系统和权限
强大的 Agent 必须能够操作环境:读写文件、运行测试、调用外部服务。ACP 在这里提供了一个统一的工具调用接口层,典型能力包括:
- 文件系统(fs)相关方法:
- 读取文件内容、列目录、写入或创建文件等。
- 终端 / 命令执行:
- 运行
npm test、pytest、编译命令等,把 stdout/stderr 结果回给 Agent。
- 运行
- 权限请求:
- Agent 不直接「悄悄改文件」,而是通过类似
session/request_permission请求,告知我想修改 A、B、C 这几个文件,由 Client 弹窗给用户确认,然后再执行。
- Agent 不直接「悄悄改文件」,而是通过类似
这一层是 ACP 特别适合企业和团队场景的原因之一,它安全、可控、可审计,而不是让 Agent 获得完全不受控的本地能力。
官方文档:
总结
以上知识我在看 Agent Client Protocol 文档,了解学习 ACP 的一次初学习理解记录,如果想要深入,还是应该动手先跑一遍最小 demo,再实际中学习基础用法,然后再考虑将它落实道自己最熟悉的应用形态里面。但是以上提到的 ession + prompt turn + 事件流 + 工具调用,算是 ACP 的一个主线流程,我们可以先理解这个,再慢慢在实践中进行深入学习。

If you enjoyed this, leave a comment~