找回密码
 立即注册
首页 业界区 业界 Agent Client Protocol 全景解析

Agent Client Protocol 全景解析

全叶农 前天 20:05
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
  1.     org.springaicommunity    claude-code-sdk    1.0.0-SNAPSHOT
复制代码
简单问题代码示例如下:
  1. import org.springaicommunity.claude.agent.sdk.Query;// Simplest usage - one lineString answer = Query.text("What is 2+2?");System.out.println(answer);  // "4"
复制代码
简单问题增加参数:
  1. 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);
复制代码
获取返回的元数据:
  1. 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());
复制代码
流式问答:
  1. for (Message msg : Query.query("Explain recursion")) {    if (msg instanceof AssistantMessage am) {        am.getTextContent().ifPresent(System.out::print);    }}// Or with Stream APIQuery.stream("Explain recursion")    .filter(msg -> msg instanceof AssistantMessage)    .forEach(msg -> System.out.println(msg));
复制代码
工厂适配模式:
  1. // Sync client with fluent buildertry (ClaudeSyncClient client = ClaudeClient.sync()        .workingDirectory(Path.of("."))        .model("claude-sonnet-4-20250514")        .systemPrompt("You are helpful")        .timeout(Duration.ofMinutes(5))        .build()) {    // Use client}// Async clientClaudeAsyncClient client = ClaudeClient.async()    .workingDirectory(Path.of("."))    .permissionMode(PermissionMode.BYPASS_PERMISSIONS)    .build();
复制代码
多轮对话:
  1. 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 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:
  1. 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 commandshookRegistry.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 resultshookRegistry.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:
  1. 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 serverMcpServerConfig sdkServer = McpServerConfig.sdk(myMcpServer);try (ClaudeSyncClient client = ClaudeClient.sync()        .workingDirectory(Path.of("."))        .mcpServer("filesystem", npmServer)        .mcpServer("custom", sdkServer)        .build()) {    // MCP tools available to Claude}
复制代码
文本响应:
  1. ClaudeAsyncClient client = ClaudeClient.async()    .workingDirectory(Path.of("."))    .permissionMode(PermissionMode.BYPASS_PERMISSIONS)    .build();// Simple text responseclient.connect("Hello!").text()    .doOnSuccess(System.out::println)    .subscribe();  // Non-blocking
复制代码
多轮对话:
  1. // Elegant multi-turn via flatMapclient.connect("My favorite color is blue.").text()    .flatMap(r1 -> client.query("What is my favorite color?").text())    .doOnSuccess(System.out::println)  // "blue"    .subscribe();
复制代码
流式:
  1. // Stream text as it arrivesclient.query("Explain recursion").textStream()    .doOnNext(System.out::print)    .subscribe();
复制代码
访问全部信息:
  1. // Access all message types for metadataclient.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:
  1. import org.springframework.web.bind.annotation.*;import org.springframework.http.MediaType;import reactor.core.publisher.Flux;@RestControllerpublic 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 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大数据挖掘从入门到进阶实战》也可以和新书配套使用,喜欢的朋友或同学, 可以在公告栏那里点击购买链接购买博主的书进行学习,在此感谢大家的支持。关注下面公众号,根据提示,可免费获取书籍的教学视频。

公众号:




作者:哥不是小萝莉 [关于我][犒赏]

出处:http://www.cnblogs.com/smartloli/

转载请注明出处,谢谢合作!


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册