生成模型:Claude Opus 4.6 (anthropic/claude-opus-4-6) Token 消耗:输入 ~320k tokens,输出 ~6k tokens(本节)
随着 AI Agent 生态的快速扩展,不同 Agent 系统之间的互操作成为关键需求。ACP(Agent Communication Protocol,代理通信协议)应运而生——它定义了一套标准的 Agent 间通信协议,允许 IDE、编辑器和其他客户端以统一的方式与 AI Agent 交互。OpenClaw 通过 src/acp/ 模块实现了 ACP 协议的服务端适配,将其作为连接外部客户端(如 IDE 插件)的桥梁。
衍生解释:Agent Communication Protocol (ACP) ACP 是一种开放的 Agent 通信标准,类似于 LSP(Language Server Protocol)之于编程语言工具链的角色。LSP 让任何编辑器都能复用同一个语言服务器的能力(代码补全、跳转定义等),ACP 则让任何客户端都能与 AI Agent 进行标准化的交互——创建会话、发送提示、接收流式响应、管理工具调用等。ACP 使用 JSON-RPC 风格的 NDJSON(Newline-Delimited JSON)作为传输格式,通过 stdio 管道通信。
32.1.1 ACP SDK 依赖
OpenClaw 的 ACP 实现基于 @agentclientprotocol/sdk 包,该 SDK 提供了协议的核心类型和连接管理:
import {
AgentSideConnection, // Agent 端连接(服务端)
ClientSideConnection, // 客户端连接
ndJsonStream, // NDJSON 流传输
PROTOCOL_VERSION, // 协议版本号
type Agent, // Agent 接口
type PromptRequest, // 提示请求
type PromptResponse, // 提示响应
type SessionNotification, // 会话通知
// ...
} from "@agentclientprotocol/sdk";
SDK 提供的关键抽象:
将 stdin/stdout 封装为 NDJSON 双向流
32.1.2 ACP 服务端架构
OpenClaw 的 ACP 服务端由三层组成:
serveAcpGateway() 是 ACP 服务端的入口函数:
注意 stdio 方向的处理:ACP 协议中,Agent 通过 stdout 发送消息给客户端,通过 stdin 接收来自客户端的消息——因此 input = stdout、output = stdin 的赋值是正确的(从流的角度,写入 stdout 是 Agent 的输出,读取 stdin 是 Agent 的输入)。
ACP 服务端通过 openclaw acp 命令启动,支持以下参数:
每个 ACP Agent 需要声明自己的身份信息:
32.1.3 翻译层:AcpGatewayAgent
AcpGatewayAgent 是整个 ACP 实现的核心——它实现了 ACP 的 Agent 接口,将 ACP 协议的请求翻译为 OpenClaw Gateway 的 RPC 调用,并将 Gateway 的事件流翻译回 ACP 的会话通知。
初始化响应声明了 Agent 的能力集合。当前实现支持图像和嵌入上下文,但不支持音频和 MCP 服务器集成。
ACP 的会话与 OpenClaw 的会话之间需要映射:
会话键的解析支持多种方式:
通过标签:sessionLabel → 调用 sessions.resolve RPC 按标签查找
通过键:sessionKey → 直接使用或验证存在性
ACP 会话存储(AcpSessionStore)是一个简单的内存 Map,维护 sessionId → AcpSession 的映射,以及 runId → sessionId 的反向索引。
提示处理的关键设计:
工作目录前缀:默认在用户消息前添加 [Working directory: /path/to/project],让 Agent 知道用户的工作上下文
幂等键:使用 runId(UUID)作为 idempotencyKey,防止重复处理
Promise 桥接:将 Gateway 的事件驱动响应转换为 Promise 风格的同步返回
Gateway 返回的事件需要翻译为 ACP 的会话更新通知:
事件翻译的两个核心映射:
流式文本增量(差分计算:fullText - sentSoFar)
PromptResponse(cancelled)
增量文本的处理值得注意:Gateway 的 delta 事件发送的是累积全文(非增量),ACP 翻译层通过 sentTextLength 计数器追踪已发送的字符数,只发送新增部分。这种设计的优势是支持乱序和重传——即使错过一个 delta 事件,后续的完整文本也能自我纠正。
inferToolKind() 根据工具名称推断其 ACP 工具类型:
这是一种启发式分类——通过关键词匹配将 OpenClaw 丰富的工具名称映射到 ACP 定义的有限工具类别中。
client.ts 提供了 ACP 客户端的参考实现,用于从命令行与 ACP Agent 交互:
客户端通过 stdio 与 ACP 服务端通信:
交互式模式(runAcpClientInteractive)提供了一个简单的 REPL 界面:
客户端接收的会话更新通知被翻译为人类可读的输出:
ACP 服务端在会话创建时推送可用的斜杠命令列表:
这些命令与 OpenClaw 的聊天命令系统(第 25 章)一致,但通过 ACP 协议暴露给外部客户端,使 IDE 插件等工具能够提供命令补全和快捷操作。
ACP 协议的 _meta 字段用于传递扩展信息。meta.ts 提供了类型安全的读取工具:
多键名查找设计使得同一配置可以通过不同的键名传递。例如,readString(meta, ["sessionKey", "session", "key"]) 接受三种键名——这提高了与不同客户端实现的兼容性。
ACP 是 Agent 间通信的标准协议,类似于 LSP 之于语言工具链,通过 NDJSON over stdio 进行通信。
三层架构:ACP 客户端 ↔ AcpGatewayAgent(翻译层)↔ OpenClaw Gateway,翻译层负责协议转换。
AcpGatewayAgent 实现了 ACP 的 Agent 接口,将 prompt/newSession/cancel 等请求翻译为 Gateway 的 chat.send/sessions.resolve/chat.abort RPC。
事件翻译 将 Gateway 的 chat.delta/agent.tool 事件转换为 ACP 的 agent_message_chunk/tool_call 通知,增量文本通过差分计算避免重复发送。
会话映射 支持通过键、标签或自动生成三种方式建立 ACP 会话与 OpenClaw 会话的对应关系。
工具类型推断 使用启发式关键词匹配将 OpenClaw 工具名映射到 ACP 标准类别。
命令暴露 将 25+ 个斜杠命令通过 ACP 协议暴露给外部客户端,支持 IDE 插件的命令补全。