32.1 ACP 协议概述

生成模型: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 提供的关键抽象:

类型
角色
说明

AgentSideConnection

服务端

Agent 侧的连接管理,接收客户端请求

ClientSideConnection

客户端

客户端侧的连接管理,发送请求给 Agent

ndJsonStream

传输层

将 stdin/stdout 封装为 NDJSON 双向流

Agent

接口

Agent 必须实现的方法集合

32.1.2 ACP 服务端架构

OpenClaw 的 ACP 服务端由三层组成:

服务端启动

serveAcpGateway() 是 ACP 服务端的入口函数:

注意 stdio 方向的处理:ACP 协议中,Agent 通过 stdout 发送消息给客户端,通过 stdin 接收来自客户端的消息——因此 input = stdoutoutput = stdin 的赋值是正确的(从流的角度,写入 stdout 是 Agent 的输出,读取 stdin 是 Agent 的输入)。

命令行参数

ACP 服务端通过 openclaw acp 命令启动,支持以下参数:

ACP Agent 信息

每个 ACP Agent 需要声明自己的身份信息:

32.1.3 翻译层:AcpGatewayAgent

AcpGatewayAgent 是整个 ACP 实现的核心——它实现了 ACP 的 Agent 接口,将 ACP 协议的请求翻译为 OpenClaw Gateway 的 RPC 调用,并将 Gateway 的事件流翻译回 ACP 的会话通知。

协议初始化

初始化响应声明了 Agent 的能力集合。当前实现支持图像和嵌入上下文,但不支持音频和 MCP 服务器集成。

会话管理

ACP 的会话与 OpenClaw 的会话之间需要映射:

会话键的解析支持多种方式:

  1. 通过标签sessionLabel → 调用 sessions.resolve RPC 按标签查找

  2. 通过键sessionKey → 直接使用或验证存在性

  3. 回退:生成 acp:{uuid} 格式的新键

ACP 会话存储(AcpSessionStore)是一个简单的内存 Map,维护 sessionId → AcpSession 的映射,以及 runId → sessionId 的反向索引。

提示处理

提示处理的关键设计:

  • 工作目录前缀:默认在用户消息前添加 [Working directory: /path/to/project],让 Agent 知道用户的工作上下文

  • 幂等键:使用 runId(UUID)作为 idempotencyKey,防止重复处理

  • Promise 桥接:将 Gateway 的事件驱动响应转换为 Promise 风格的同步返回

事件翻译

Gateway 返回的事件需要翻译为 ACP 的会话更新通知:

事件翻译的两个核心映射:

Gateway 事件
ACP 通知
说明

chat.delta

agent_message_chunk

流式文本增量(差分计算:fullText - sentSoFar

chat.final

PromptResponse(end_turn)

提示完成

chat.aborted

PromptResponse(cancelled)

被用户取消

chat.error

PromptResponse(refusal)

Agent 拒绝或错误

agent.tool.start

tool_call

工具调用开始

agent.tool.result

tool_call_update

工具调用完成/失败

增量文本的处理值得注意:Gateway 的 delta 事件发送的是累积全文(非增量),ACP 翻译层通过 sentTextLength 计数器追踪已发送的字符数,只发送新增部分。这种设计的优势是支持乱序和重传——即使错过一个 delta 事件,后续的完整文本也能自我纠正。

工具类型推断

inferToolKind() 根据工具名称推断其 ACP 工具类型:

这是一种启发式分类——通过关键词匹配将 OpenClaw 丰富的工具名称映射到 ACP 定义的有限工具类别中。

32.1.4 ACP 客户端

client.ts 提供了 ACP 客户端的参考实现,用于从命令行与 ACP Agent 交互:

客户端通过 stdio 与 ACP 服务端通信:

交互式模式(runAcpClientInteractive)提供了一个简单的 REPL 界面:

会话更新处理

客户端接收的会话更新通知被翻译为人类可读的输出:

32.1.5 可用命令

ACP 服务端在会话创建时推送可用的斜杠命令列表:

这些命令与 OpenClaw 的聊天命令系统(第 25 章)一致,但通过 ACP 协议暴露给外部客户端,使 IDE 插件等工具能够提供命令补全和快捷操作。

32.1.6 元数据辅助函数

ACP 协议的 _meta 字段用于传递扩展信息。meta.ts 提供了类型安全的读取工具:

多键名查找设计使得同一配置可以通过不同的键名传递。例如,readString(meta, ["sessionKey", "session", "key"]) 接受三种键名——这提高了与不同客户端实现的兼容性。


本节小结

  1. ACP 是 Agent 间通信的标准协议,类似于 LSP 之于语言工具链,通过 NDJSON over stdio 进行通信。

  2. 三层架构:ACP 客户端 ↔ AcpGatewayAgent(翻译层)↔ OpenClaw Gateway,翻译层负责协议转换。

  3. AcpGatewayAgent 实现了 ACP 的 Agent 接口,将 prompt/newSession/cancel 等请求翻译为 Gateway 的 chat.send/sessions.resolve/chat.abort RPC。

  4. 事件翻译 将 Gateway 的 chat.delta/agent.tool 事件转换为 ACP 的 agent_message_chunk/tool_call 通知,增量文本通过差分计算避免重复发送。

  5. 会话映射 支持通过键、标签或自动生成三种方式建立 ACP 会话与 OpenClaw 会话的对应关系。

  6. 工具类型推断 使用启发式关键词匹配将 OpenClaw 工具名映射到 ACP 标准类别。

  7. 命令暴露 将 25+ 个斜杠命令通过 ACP 协议暴露给外部客户端,支持 IDE 插件的命令补全。

Last updated