Agent Client Protocol 全景解析

1.概述

Agent Client Protocol(ACP)是一个标准化通信协议,用于规范代码编辑器和集成开发环境(IDE)与编码智能体(Coding Agents)之间的交互。该协议同时支持本地和远程使用场景。

2.内容

2.1 为什么需要 ACP?

AI 编码智能体(Coding Agents)与代码编辑器 / IDE 之间虽然联系紧密,但互操作性却并非默认标准。

目前,每个编辑器都需要为它想支持的每一个智能体开发自定义集成;而每个智能体也必须实现针对不同编辑器的专有 API,才能触达用户。这导致了一系列问题:

  • 集成成本高:每新增一个智能体与编辑器的组合,都需要进行大量定制开发;
  • 兼容性有限:单个智能体通常只能支持少数几种编辑器;
  • 开发者锁定:开发者一旦选择某个智能体,往往就被迫接受其支持的有限界面和功能。

ACP(Agent Client Protocol)正是为了解决这些问题而设计。它提供了一个标准化协议,用于规范编码智能体与编辑器之间的通信,类似于 Language Server Protocol (LSP) 当年标准化语言服务器集成的方式。只要智能体实现了 ACP,就能与任何支持 ACP 的编辑器无缝协作;只要编辑器支持 ACP,就能立即接入整个 ACP 生态中的所有兼容智能体。这种解耦设计让智能体和编辑器双方都能独立快速创新,同时赋予开发者真正的自由------可以根据自身工作流选择最适合的工具,而不再受集成限制。

ACP 的核心设计理念是:用户主要在代码编辑器中工作,并希望能够随时调用智能体来协助完成特定任务。

ACP 同时支持本地和远程两种部署场景:

  • 本地智能体:作为代码编辑器的子进程运行,通过标准输入输出(stdio)使用 JSON-RPC 进行通信;
  • 远程智能体:可部署在云端或独立基础设施上,通过 HTTP 或 WebSocket 进行通信。

目前,对远程智能体的完整支持仍在积极开发中。我们正在与多家智能体平台密切合作,以确保协议能够满足云托管和远程部署场景的特定需求。ACP 在可能的情况下会复用 MCP(Model Context Protocol)中已定义的 JSON 表示,同时新增了一些专为智能体编码体验设计的自定义类型,例如显示代码差异(diffs)。用户可读文本的默认格式为 Markdown,这既提供了足够的格式灵活性来呈现丰富的排版,又避免了要求代码编辑器必须具备 HTML 渲染能力。

2.2 架构设计

Agent Client Protocol(ACP)定义了一套标准接口,用于实现 AI 智能体(AI Agents)与客户端应用(主要是代码编辑器)之间的通信。ACP 的架构设计注重灵活性、可扩展性以及平台无关性,能够适应不同的开发环境和集成需求。

2.2.1 设计理念

ACP 的架构遵循以下几项核心原则:

  • MCP 友好:协议基于 JSON-RPC 构建,并尽可能复用 MCP(Model Context Protocol)中已定义的数据类型。这样,集成方无需为常见数据类型重新设计另一套表示方式,显著降低了集成成本。
  • 以用户体验为核心(UX-first):协议专注于解决与 AI 智能体交互时的用户体验挑战。它提供了足够的灵活性,能够清晰地呈现智能体的意图和操作过程,同时避免引入不必要的抽象复杂度。
  • 可信赖:ACP 适用于用户在代码编辑器中与自己信任的 AI 模型进行交互的场景。用户仍可完全控制智能体的工具调用(Tool Calls),而代码编辑器则负责为智能体提供对本地文件和 MCP 服务器的安全访问权限。

2.2.2 连接与启动流程

当用户尝试连接到一个智能体时,代码编辑器会按需启动该智能体的子进程,所有通信均通过标准输入/输出(stdin/stdout)进行。每个连接支持多个并发会话(Sessions),这意味着用户可以同时进行多条思考路径(multiple trains of thought),实现并行处理多个任务或对话。

ACP 大量采用 JSON-RPC 通知(Notifications) 机制,允许智能体以实时流式(streaming) 的方式向编辑器界面推送更新。这使得用户能够即时看到智能体的思考过程、代码生成进度或执行结果,从而提供更加流畅和响应迅速的交互体验。

此外,ACP 还充分利用了 JSON-RPC 的双向请求能力,让智能体能够主动向代码编辑器发起请求。例如,当智能体需要执行某个工具调用(Tool Call)时,可以向编辑器请求相应的权限(如读取或修改本地文件),从而实现更安全、可控的协作流程。

这种通知与请求相结合的设计,既保证了高效的实时更新,又保留了必要的用户控制权,让 AI 智能体与编辑器的协作更加自然、灵活且可靠。

2.2.3 MCP

在实际使用中,代码编辑器通常已配置了用户自定义的 MCP 服务器(Model Context Protocol Servers)。当用户向智能体发送提示词(Prompt)时,编辑器会将这些 MCP 服务器的配置信息一并转发给智能体。这使得智能体能够直接连接并访问这些 MCP 服务器,而无需经过编辑器作为中间代理。这种设计带来了显著优势:

  • 智能体可以更高效地读取项目上下文、代码库结构、文档等丰富信息;
  • 减少了数据在编辑器与智能体之间多次转发的开销,提升整体响应速度;
  • 让智能体能够像"原生集成"一样,充分利用用户已配置的外部知识源和工具。

通过这种配置传递机制,ACP 实现了编辑器、智能体与 MCP 服务器之间的高效协同,进一步增强了 AI 编码智能体的实际生产力。

代码编辑器自身也可能希望向智能体提供基于 MCP 的工具和服务。

为了避免在同一个通信通道上同时运行 MCP 和 ACP 协议带来的复杂性,ACP 推荐采用以下优雅的设计:

编辑器可以将自己作为一个 MCP 服务器,并把其配置信息传递给智能体。这样,智能体就可以像连接其他 MCP 服务器一样,直接与编辑器提供的 MCP 服务进行交互。

由于部分智能体可能仅支持通过 stdio(标准输入输出) 来访问 MCP,代码编辑器可以提供一个轻量级的代理(Proxy),负责将智能体的 MCP 请求通过隧道(Tunnel)转发回编辑器自身进行处理。

这种方式具有以下显著优势:

  • 协议职责清晰,MCP 负责工具调用与上下文访问,ACP 专注于智能体与编辑器的核心交互;
  • 避免了协议冲突和 socket 复用带来的技术复杂性;
  • 保持了极高的灵活性,既支持功能强大的编辑器原生工具,又兼容仅支持 stdio 的智能体实现;
  • 为未来扩展提供了良好的基础。

通过这一机制,代码编辑器不仅能消费外部 MCP 服务,还能主动将自身能力暴露给 AI 智能体,实现真正的双向赋能。

2.3 Agent

Agent Client Protocol(ACP)兼容智能体列表

以下智能体已实现 Agent Client Protocol(ACP),可以与任何支持 ACP 的代码编辑器客户端无缝协作:

  • AgentPool
  • Augment Code
  • AutoDev
  • Blackbox AI
  • Claude Agent (via Zed's SDK adapter)
  • Cline
  • Codex CLI (via Zed's adapter)
  • Code Assistant
  • Cursor
  • Docker's cagent
  • fast-agent
  • Factory Droid
  • fount
  • Gemini CLI
  • GitHub Copilot (in public preview)
  • Goose
  • Junie by JetBrains
  • Kimi CLI
  • Kiro CLI
  • Minion Code
  • Mistral Vibe
  • OpenClaw
  • OpenCode
  • OpenHands
  • Pi (via pi-acp adapter)
  • Qoder CLI
  • Qwen Code
  • Stakpak
  • VT Code

2.4 Clients

Clients, Frameworks, Connectors 与相关工具

以下项目直接实现了 Agent Client Protocol(ACP),或提供了将 ACP 智能体连接到其他环境的能力,同时也涵盖了支持相邻编码智能体工作流的相关工具。

这些项目共同构成了 ACP 生态的重要组成部分,帮助开发者更轻松地集成和使用标准化智能体协议。

2.4.1 编辑器和IDE

  • Chrome ACP (Chrome extension / PWA)
  • Emacs via agent-shell.el
  • JetBrains
  • neovim
    • through the CodeCompanion plugin
    • through the carlos-algms/agentic.nvim plugin
    • through the yetone/avante.nvim plugin
  • Obsidian --- through the Agent Client plugin
  • Unity Agent Client (Unity editor)
  • Visual Studio Code --- through the ACP Client extension
  • Zed

2.4.2 客户端和apps

  • ACP UI
  • acpx (CLI)
  • gemini-cli-desktop
  • Agent Studio
  • AionUi
  • aizen
  • DeepChat
  • fabriqa.ai
  • Harnss
  • iflow-cli
  • Lody
  • Minion Mind --- through the Agent Client plugin
  • Mitto
  • Nori CLI
  • Ngent
  • RayClaw
  • RLM Code
  • Sidequery (coming soon)
  • Tidewave
  • Toad
  • Web Browser with AI SDK (powered by @mcpc/acp-ai-provider)

3.ACP Java SDK

ACP 采用 子进程(Subprocess)模型 进行通信。

客户端(可以是你的应用程序,也可以是 Zed、VS Code 等代码编辑器)会将 AI 智能体作为子进程启动,并通过 标准输入/输出(stdin/stdout) 使用 JSON-RPC 消息进行双向通信。

整个交互过程分为三个主要阶段:

  • 初始化阶段(Initialize):客户端与智能体交换协议版本号和各自支持的能力(Capabilities),完成握手协商,确保双方兼容。
  • 会话阶段(Session):客户端创建一个会话,并向智能体提供工作目录(Working Directory)等上下文信息,为后续交互建立环境基础。
  • 提示与响应阶段(Prompt):客户端向智能体发送用户提示词(Prompt)或其他消息,智能体则以流式(Streaming) 方式返回响应、代码生成结果、思考过程或工具调用请求等。

3.1 Claude Code Maven

复制代码
<dependency>
    <groupId>org.springaicommunity</groupId>
    <artifactId>claude-code-sdk</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>

简单问题代码示例如下:

复制代码
import org.springaicommunity.claude.agent.sdk.Query;

// Simplest usage - one line
String answer = Query.text("What is 2+2?");
System.out.println(answer);  // "4"

简单问题增加参数:

复制代码
import org.springaicommunity.claude.agent.sdk.Query;
import org.springaicommunity.claude.agent.sdk.QueryOptions;
import java.time.Duration;

QueryOptions options = QueryOptions.builder()
    .model("claude-sonnet-4-20250514")
    .appendSystemPrompt("Be concise")
    .timeout(Duration.ofMinutes(5))
    .build();

String response = Query.text("Explain Java", options);
System.out.println(response);

获取返回的元数据:

复制代码
import org.springaicommunity.claude.agent.sdk.Query;
import org.springaicommunity.claude.agent.sdk.types.QueryResult;

QueryResult result = Query.execute("Write a haiku about Java");

System.out.println(result.text().orElse(""));
System.out.println("Cost: $" + result.metadata().cost().calculateTotal());
System.out.println("Duration: " + result.metadata().getDuration().toMillis() + "ms");
System.out.println("Model: " + result.metadata().model());

流式问答:

复制代码
for (Message msg : Query.query("Explain recursion")) {
    if (msg instanceof AssistantMessage am) {
        am.getTextContent().ifPresent(System.out::print);
    }
}

// Or with Stream API
Query.stream("Explain recursion")
    .filter(msg -> msg instanceof AssistantMessage)
    .forEach(msg -> System.out.println(msg));

工厂适配模式:

复制代码
// Sync client with fluent builder
try (ClaudeSyncClient client = ClaudeClient.sync()
        .workingDirectory(Path.of("."))
        .model("claude-sonnet-4-20250514")
        .systemPrompt("You are helpful")
        .timeout(Duration.ofMinutes(5))
        .build()) {
    // Use client
}

// Async client
ClaudeAsyncClient client = ClaudeClient.async()
    .workingDirectory(Path.of("."))
    .permissionMode(PermissionMode.BYPASS_PERMISSIONS)
    .build();

多轮对话:

复制代码
import org.springaicommunity.claude.agent.sdk.ClaudeClient;
import org.springaicommunity.claude.agent.sdk.ClaudeSyncClient;
import org.springaicommunity.claude.agent.sdk.parsing.ParsedMessage;
import org.springaicommunity.claude.agent.sdk.types.AssistantMessage;
import java.util.Iterator;

try (ClaudeSyncClient client = ClaudeClient.sync()
        .workingDirectory(Path.of("."))
        .build()) {

    // First turn
    client.connect("My favorite color is blue. Remember this.");
    Iterator<ParsedMessage> response = client.receiveResponse();
    while (response.hasNext()) {
        ParsedMessage msg = response.next();
        if (msg.isRegularMessage() && msg.asMessage() instanceof AssistantMessage am) {
            am.getTextContent().ifPresent(System.out::println);
        }
    }

    // Second turn - Claude remembers context
    client.query("What is my favorite color?");
    response = client.receiveResponse();
    while (response.hasNext()) {
        ParsedMessage msg = response.next();
        if (msg.isRegularMessage() && msg.asMessage() instanceof AssistantMessage am) {
            am.getTextContent().ifPresent(System.out::println);  // "blue"
        }
    }
}

使用Hooks:

复制代码
import org.springaicommunity.claude.agent.sdk.hooks.HookRegistry;
import org.springaicommunity.claude.agent.sdk.hooks.HookInput;
import org.springaicommunity.claude.agent.sdk.hooks.HookOutput;

HookRegistry hookRegistry = new HookRegistry();

// Block dangerous commands
hookRegistry.registerPreToolUse("Bash", input -> {
    if (input instanceof HookInput.PreToolUseInput preToolUse) {
        String cmd = preToolUse.getArgument("command", String.class).orElse("");
        if (cmd.contains("rm -rf")) {
            return HookOutput.block("Dangerous command blocked");
        }
    }
    return HookOutput.allow();
});

// Log all tool results
hookRegistry.registerPostToolUse(input -> {
    if (input instanceof HookInput.PostToolUseInput postToolUse) {
        System.out.println("Tool completed: " + postToolUse.toolName());
    }
    return HookOutput.allow();
});

try (ClaudeSyncClient client = ClaudeClient.sync()
        .workingDirectory(Path.of("."))
        .permissionMode(PermissionMode.DEFAULT)
        .hookRegistry(hookRegistry)
        .build()) {
    // Hooks intercept tool calls
}

使用MCP:

复制代码
import org.springaicommunity.claude.agent.sdk.mcp.McpServerConfig;

// External MCP server (subprocess)
McpServerConfig npmServer = McpServerConfig.command("npx")
    .args("-y", "@anthropic/mcp-server-filesystem")
    .env("HOME", System.getProperty("user.home"))
    .build();

// In-process SDK MCP server
McpServerConfig sdkServer = McpServerConfig.sdk(myMcpServer);

try (ClaudeSyncClient client = ClaudeClient.sync()
        .workingDirectory(Path.of("."))
        .mcpServer("filesystem", npmServer)
        .mcpServer("custom", sdkServer)
        .build()) {
    // MCP tools available to Claude
}

文本响应:

复制代码
ClaudeAsyncClient client = ClaudeClient.async()
    .workingDirectory(Path.of("."))
    .permissionMode(PermissionMode.BYPASS_PERMISSIONS)
    .build();

// Simple text response
client.connect("Hello!").text()
    .doOnSuccess(System.out::println)
    .subscribe();  // Non-blocking

多轮对话:

复制代码
// Elegant multi-turn via flatMap
client.connect("My favorite color is blue.").text()
    .flatMap(r1 -> client.query("What is my favorite color?").text())
    .doOnSuccess(System.out::println)  // "blue"
    .subscribe();

流式:

复制代码
// Stream text as it arrives
client.query("Explain recursion").textStream()
    .doOnNext(System.out::print)
    .subscribe();

访问全部信息:

复制代码
// Access all message types for metadata
client.query("List files").messages()
    .doOnNext(msg -> {
        if (msg instanceof AssistantMessage am) {
            am.text().ifPresent(System.out::println);
        } else if (msg instanceof ResultMessage rm) {
            System.out.printf("Cost: $%.6f%n", rm.totalCostUsd());
        }
    })
    .subscribe();

使用SSE:

复制代码
import org.springframework.web.bind.annotation.*;
import org.springframework.http.MediaType;
import reactor.core.publisher.Flux;

@RestController
public class ChatController {
    private final ClaudeAsyncClient client;

    public ChatController() {
        this.client = ClaudeClient.async()
            .workingDirectory(Path.of("."))
            .permissionMode(PermissionMode.BYPASS_PERMISSIONS)
            .build();
    }

    @GetMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> chat(@RequestParam String message) {
        return client.query(message).textStream();
    }
}

4.总结

Agent Client Protocol(ACP)是一个标准化协议,旨在打破 AI 编码智能体与代码编辑器之间的集成壁垒。

通过 JSON-RPC + 子进程模型,ACP 实现了智能体与编辑器的解耦:一次实现,即可多端兼容。它支持实时流式响应、MCP 配置传递,并提供 Hooks 与 TurnSpec 等机制,提升交互体验。

ACP 的核心目标是让开发者自由选择最佳编辑器与最强智能体,彻底告别重复集成与工具锁定,推动 AI 编程生态走向开放与互联。

5.结束语

这篇博客就和大家分享到这里,如果大家在研究学习的过程当中有什么问题,可以加群进行讨论或发送邮件给我,我会尽我所能为您解答,与君共勉!

另外,博主出新书了《Hadoop与Spark大数据全景解析》、同时已出版的《深入理解Hive》、《Kafka并不难学》和《Hadoop大数据挖掘从入门到进阶实战》也可以和新书配套使用,喜欢的朋友或同学, 可以在公告栏那里点击购买链接购买博主的书进行学习,在此感谢大家的支持。关注下面公众号,根据提示,可免费获取书籍的教学视频。

相关推荐
小白跃升坊5 小时前
Codex 增强部署:基于 Codex++ 接入 DeepSeek
ai·ai编程·codex·deepseek·ai coding·codex++
AlfredZhao5 小时前
GPT 省钱,不是别用最新模型,而是别浪费缓存
gpt·ai
doiito8 小时前
【Agent Harness】Gliding Horse 本体论系统设计:给 AI Agent 装上“语义大脑”
ai·rust·架构设计·系统设计·ai agent
小七-七牛开发者14 小时前
周一上线 | SpaceX 收购 Cursor、支付宝进入 AI 时代、DeepSeek 完成 500 亿元融资
ai·agent·token·glm·智谱·claudecode·ai coding·周一上线
doiito1 天前
【Agent Harness】为什么我把 JSON‑LD “编译成 DAG” 后,整个 Agent 平台立刻聪明了
ai·rust·架构设计·系统设计·ai agent
xiezhr2 天前
折腾半小时,终于让AI 能直接帮我写飞书文档了
ai·飞书·ai agent·飞书cli·飞书文档
岳小哥AI2 天前
Claude Fable和Claude Mythos 5同时发布:注意力机制下愈加强大的AI大模型
ai·ai基础
Artech2 天前
[MAF预定义的AIContextProvider-04]Mem0Provider——长期记忆基于的云端解决方案
ai·agent·maf·aicontextprovider·chathistorymemoryprovider·mem0provider
哥不是小萝莉2 天前
一文读懂 OpenAI Codex 源码的原理、架构与未来
ai
AlfredZhao2 天前
AI 编程工作总结:从体验问题到模块能力建设
ai·codex