数据截至 (上游 commit 788fdeda3adf)
ACP (Agent Client Protocol) — 架构与原理
30 秒导读: ACP 是一套 JSON-RPC 协议,让「代码编辑器」(Zed、JetBrains、Neovim…)和「编码 AI agent」(Claude、Gemini CLI、Codex…)互通。编辑器只要实现一次 ACP,就能接所有 ACP agent;反之亦然——把过去 N 个编辑器 × M 个 agent 的私有集成,压成一套标准。本仓库是协议的类型定义(Rust 结构体 + JSON Schema 生成器),不是运行时。
1. 这是什么(零基础也能懂)
一句话定义。 ACP(Agent Client Protocol)是一套基于 JSON-RPC 2.0 的线缆协议,标准化「代码编辑器」与「编码 agent」之间的通信。
它要解决的痛点。 AI 编码 agent 和编辑器天然要紧耦合,但互通不是默认的:
- 每出一个新 agent,每个编辑器都要为它写一份私有集成。
- 每个 agent 要想被用上,得去实现一堆编辑器各自的私有 API。
- 用户被锁死:选了某个 agent,就只能用它支持的那几个界面。
ACP 用「一套标准」打破这点——思路完全类比 LSP(Language Server Protocol,微软为「编辑器 ↔ 语言服务器」定的标准)。这一点项目自己也明说了,见 docs/get-started/introduction.mdx:17。
一句话类比。
LSP 让「一个语言服务器」服务「所有编辑器」;ACP 让「一个编码 agent」服务「所有编辑器」。ACP 就是「agent 界的 LSP」。
典型场景(白话走一遍)。 你在 Zed 里写代码,想让一个 AI agent 帮你改一个大项目:
- 编辑器把 agent 作为子进程拉起来,双方通过 stdin/stdout 用 JSON-RPC 对话(
docs/get-started/architecture.mdx:18)。 - 你输入一句「帮我把这个函数改成异步的」。
- agent 一边思考一边流式把「我在想什么/我要调哪个工具/改了哪个文件」推回编辑器,实时显示。
- agent 要改文件、跑命令这类敏感操作前,反向问编辑器:「准许吗?」——你点「允许」它才动手。
- 这一轮结束,agent 回一个「停止原因」(正常结束 / 触顶 / 被取消…)。
它长什么样(最小线缆示例)。 一条最关键的消息——用户发一句 prompt(agent.rs:3263 PromptRequest):
{
"jsonrpc": "2.0",
"id": 7,
"method": "session/prompt",
"params": {
"sessionId": "sess-abc",
"prompt": [{ "type": "text", "text": "把 foo 改成 async" }]
}
}
agent 处理途中往回推的流式更新(client.rs:50 SessionNotification,无 id 故是 notification):
{
"jsonrpc": "2.0",
"method": "sessionUpdate",
"params": {
"sessionId": "sess-abc",
"update": { "sessionUpdate": "agent_message_chunk",
"content": { "type": "text", "text": "好的,我来改" } }
}
}
注意
method用的是协议线缆名session/prompt、sessionUpdate,字段是camelCase;Rust 侧的类型名是PromptRequest、SessionNotification——本仓库就是把这层映射用强类型固定下来。
本节不碰底层。下一层我们看「大盘怎么转」。
2. 顶层全景(它大概怎么转)
两个角色,一条管道
ACP 里只有两个角色,沟通是双向的——不是简单的「客户端请求 / 服务端响应」:
- Client(客户端) = 代码编辑器 / IDE。它持有本地文件、终端、MCP 配置,掌握 UI 和用户授权。
- Agent(代理) = 那个用 LLM 自主改代码的程序。
关键认知:两边都能发起请求。agent 不只是被动应答——它会反过来请编辑器读写文件、跑终端、问用户要权限。
一个连接(通常 stdin/stdout),可并发多个 session
┌──────────────────────────────────────────────────────────────┐
│ │
│ Client (编辑器) Agent (LLM 程序) │
│ ┌───────────┐ ──── initialize ───────▶ ┌──────────────┐ │
│ │ UI / 文件 │ ──── session/new ──────▶ │ 会话上下文 │ │
│ │ 终端 / MCP │ ──── session/prompt ───▶ │ + LLM 循环 │ │
│ │ 用户授 权 │ │ │ │
│ │ │ ◀── sessionUpdate(流) ── │ (流式吐内容) │ │
│ │ │ ◀── fs/read · terminal ─ │ (反向请求) │ │
│ │ │ ◀── request_permission ─ │ │ │
│ │ │ ──── (用户的选择) ──────▶ │ │ │
│ └───────────┘ ◀── PromptResponse ────── └──────────────┘ │
│ (带 stop_reason) │
└──────────────────────────────────────────────────────────────┘
怎么读这张图:横向箭头是 JSON-RPC 消息;向右是 Client→Agent 的方法(agent 侧实现),向左是 Agent→Client 的方法(client 侧实现)和流式通知。一个连接可承载多个并发 session(
architecture.mdx:20)。