










Agent Client Protocol(ACP)是一个标准化通信协议,用于规范代码编辑器和集成开发环境(IDE)与编码智能体(Coding Agents)之间的交互。该协议同时支持本地和远程使用场景。
AI 编码智能体(Coding Agents)与代码编辑器 / IDE 之间虽然联系紧密,但互操作性却并非默认标准。
目前,每个编辑器都需要为它想支持的每一个智能体开发自定义集成;而每个智能体也必须实现针对不同编辑器的专有 API,才能触达用户。这导致了一系列问题:
ACP(Agent Client Protocol)正是为了解决这些问题而设计。它提供了一个标准化协议,用于规范编码智能体与编辑器之间的通信,类似于 Language Server Protocol (LSP) 当年标准化语言服务器集成的方式。只要智能体实现了 ACP,就能与任何支持 ACP 的编辑器无缝协作;只要编辑器支持 ACP,就能立即接入整个 ACP 生态中的所有兼容智能体。这种解耦设计让智能体和编辑器双方都能独立快速创新,同时赋予开发者真正的自由——可以根据自身工作流选择最适合的工具,而不再受集成限制。
ACP 的核心设计理念是:用户主要在代码编辑器中工作,并希望能够随时调用智能体来协助完成特定任务。
ACP 同时支持本地和远程两种部署场景:
目前,对远程智能体的完整支持仍在积极开发中。我们正在与多家智能体平台密切合作,以确保协议能够满足云托管和远程部署场景的特定需求。ACP 在可能的情况下会复用 MCP(Model Context Protocol)中已定义的 JSON 表示,同时新增了一些专为智能体编码体验设计的自定义类型,例如显示代码差异(diffs)。用户可读文本的默认格式为 Markdown,这既提供了足够的格式灵活性来呈现丰富的排版,又避免了要求代码编辑器必须具备 HTML 渲染能力。
Agent Client Protocol(ACP)定义了一套标准接口,用于实现 AI 智能体(AI Agents)与客户端应用(主要是代码编辑器)之间的通信。ACP 的架构设计注重灵活性、可扩展性以及平台无关性,能够适应不同的开发环境和集成需求。
ACP 的架构遵循以下几项核心原则:
当用户尝试连接到一个智能体时,代码编辑器会按需启动该智能体的子进程,所有通信均通过标准输入/输出(stdin/stdout)进行。每个连接支持多个并发会话(Sessions),这意味着用户可以同时进行多条思考路径(multiple trains of thought),实现并行处理多个任务或对话。

ACP 大量采用 JSON-RPC 通知(Notifications) 机制,允许智能体以实时流式(streaming) 的方式向编辑器界面推送更新。这使得用户能够即时看到智能体的思考过程、代码生成进度或执行结果,从而提供更加流畅和响应迅速的交互体验。
此外,ACP 还充分利用了 JSON-RPC 的双向请求能力,让智能体能够主动向代码编辑器发起请求。例如,当智能体需要执行某个工具调用(Tool Call)时,可以向编辑器请求相应的权限(如读取或修改本地文件),从而实现更安全、可控的协作流程。
这种通知与请求相结合的设计,既保证了高效的实时更新,又保留了必要的用户控制权,让 AI 智能体与编辑器的协作更加自然、灵活且可靠。
在实际使用中,代码编辑器通常已配置了用户自定义的 MCP 服务器(Model Context Protocol Servers)。当用户向智能体发送提示词(Prompt)时,编辑器会将这些 MCP 服务器的配置信息一并转发给智能体。这使得智能体能够直接连接并访问这些 MCP 服务器,而无需经过编辑器作为中间代理。这种设计带来了显著优势:
通过这种配置传递机制,ACP 实现了编辑器、智能体与 MCP 服务器之间的高效协同,进一步增强了 AI 编码智能体的实际生产力。

代码编辑器自身也可能希望向智能体提供基于 MCP 的工具和服务。
为了避免在同一个通信通道上同时运行 MCP 和 ACP 协议带来的复杂性,ACP 推荐采用以下优雅的设计:
编辑器可以将自己作为一个 MCP 服务器,并把其配置信息传递给智能体。这样,智能体就可以像连接其他 MCP 服务器一样,直接与编辑器提供的 MCP 服务进行交互。
由于部分智能体可能仅支持通过 stdio(标准输入输出) 来访问 MCP,代码编辑器可以提供一个轻量级的代理(Proxy),负责将智能体的 MCP 请求通过隧道(Tunnel)转发回编辑器自身进行处理。
这种方式具有以下显著优势:
通过这一机制,代码编辑器不仅能消费外部 MCP 服务,还能主动将自身能力暴露给 AI 智能体,实现真正的双向赋能。

Agent Client Protocol(ACP)兼容智能体列表
以下智能体已实现 Agent Client Protocol(ACP),可以与任何支持 ACP 的代码编辑器客户端无缝协作:
Clients, Frameworks, Connectors 与相关工具
以下项目直接实现了 Agent Client Protocol(ACP),或提供了将 ACP 智能体连接到其他环境的能力,同时也涵盖了支持相邻编码智能体工作流的相关工具。
这些项目共同构成了 ACP 生态的重要组成部分,帮助开发者更轻松地集成和使用标准化智能体协议。
ACP 采用 子进程(Subprocess)模型 进行通信。
客户端(可以是你的应用程序,也可以是 Zed、VS Code 等代码编辑器)会将 AI 智能体作为子进程启动,并通过 标准输入/输出(stdin/stdout) 使用 JSON-RPC 消息进行双向通信。
整个交互过程分为三个主要阶段:
<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(); } }
Agent Client Protocol(ACP)是一个标准化协议,旨在打破 AI 编码智能体与代码编辑器之间的集成壁垒。
通过 JSON-RPC + 子进程模型,ACP 实现了智能体与编辑器的解耦:一次实现,即可多端兼容。它支持实时流式响应、MCP 配置传递,并提供 Hooks 与 TurnSpec 等机制,提升交互体验。
ACP 的核心目标是让开发者自由选择最佳编辑器与最强智能体,彻底告别重复集成与工具锁定,推动 AI 编程生态走向开放与互联。
这篇博客就和大家分享到这里,如果大家在研究学习的过程当中有什么问题,可以加群进行讨论或发送邮件给我,我会尽我所能为您解答,与君共勉!
另外,博主出新书了《Hadoop与Spark大数据全景解析》、同时已出版的《深入理解Hive》、《Kafka并不难学》和《Hadoop大数据挖掘从入门到进阶实战》也可以和新书配套使用,喜欢的朋友或同学, 可以在公告栏那里点击购买链接购买博主的书进行学习,在此感谢大家的支持。关注下面公众号,根据提示,可免费获取书籍的教学视频。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。