拓冰建站拓冰建站
首页 / 资讯中心 / 正文

ACP协议:让AI Agent无缝进驻多种编辑器的公共接口

过去一年AI 编程工具重洗了很多人的开发工作流但团队协作时总会碰到一个尴尬同一套 AI 能力在 VS Code 里很顺手换到 Jupyter 就残废。问题不在某个工具做得差而在于 AI Agent 和编辑器之间没有一份公共协议。OpenHands 系列教程第六章第二节提到的 ACP 协议要解决的正是这件事。ACP 全称 Agent Client Protocol中文可以叫“智能体-客户端协议”。它不打算再造一个编辑器插件而是想把 AI Agent 和编辑器之间的交互方式标准化。我的核心判断是ACP 真正解决的不是“把 AI 塞进编辑器”而是让同一套 Agent 能力能被不同编辑器复用。它的价值在于可移植、可复用而不是某个单点功能。这篇文章会围绕这个判断把协议为什么存在、一次会话怎么跑、四种编辑器怎么接同一套协议、自己落地时会踩哪些坑以及协议化之后真正的长期意义讲清楚。1. 为什么AI要进编辑器必须先有一份协议1.1 没有协议的时候每家都在重复造轮子在没有 ACP 这类协议之前一个 AI 编程工具要进入编辑器基本只能靠深度绑定的插件。插件开发者需要调用编辑器官方的 API 去读文件、写文件、拿选中内容、弹出确认框、控制终端。听起来不复杂但每种编辑器的 API 都不一样编辑器内部的会话状态、未保存缓冲、文档变更事件、终端伪终端实现全都有各自的写法。如果只做一款编辑器成本还好。可一旦想覆盖多款编辑器问题就迅速放大同样的“读文件”逻辑要写好几遍“执行一条终端命令”要适配不同的终端架构权限弹窗要做成不同的 UI。每个插件团队都在用自己的方式重新实现一遍 Agent 和编辑器之间的通信管道。更麻烦的是Agent 能力升级时每个插件都要跟着改一遍。这其实是一种典型的重复劳动真正有价值的部分是 Agent 本身的规划、推理和工具调用能力而各家插件花大量精力维护的反而是编辑器和 Agent 之间那段“翻译层”。哪怕你用的是 vim 系编辑器只要接入方愿意实现适配理论上也能用上同一套 Agent 能力而不是被锁死在某个图形 IDE 里。但前提是得有一个人人都能遵守的公共接口。1.2 编辑器不是“文本输入框”而是有状态的宿主很多人会想AI 直接读写磁盘文件不就行了吗为什么要经过编辑器这么一层这是最容易误解的地方需要展开讲。编辑器不只是文件内容的镜子。你打开的文件可能还有未保存的修改你的光标位置、选区、折叠状态、diff 视图都是工作上下文终端里可能还挂着一个跑了一半的进程。如果 Agent 绕过编辑器直接改文件你的撤销栈、未保存状态、预览视图全部失效用户很难信任这样的工具。所以 Agent 要“进”编辑器本质上不是绕过编辑器而是成为编辑器里的一个受控操作方。它需要拿到文件内容、需要看到终端输出、需要请求用户同意某些危险操作然后把修改结果通过编辑器的 diff 和预览展示出来。这些能力必须由一个“宿主层”来提供而协议就是用来定义这个宿主层长什么样的。这里顺便回答一个常被混在一起的问题编译器和编辑器有什么区别编辑器负责和用户交互、展示内容、收集修改编译器负责把代码翻译成可执行程序。AI Agent 进编辑器进入的是一个交互层它可能还会通过终端调用编译器。编辑器、编译器、Agent 三者职责分开不应混为一谈。ACP 管的是 Agent 和编辑器之间的交互不是替你写好代码也不是替你编译运行。1.3 用LSP做类比从“语言智能”到“Agent智能”如果你写过代码一定听说过 LSPLanguage Server Protocol。它把 Java、Python、TypeScript 的语言服务从编辑器里抽离出来放到统一的 language server 里于是 VS Code、Neovim、Emacs 都能复用同一份语言智能。ACP 的思路和它非常相似把 Agent 的能力从具体编辑器里抽离出来用协议连接“Agent 服务”和“编辑器客户端”。但 ACP 比 LSP 更进一层。LSP 主要传输补全、诊断、跳转这类只读信息ACP 传输的是真正的动作——修改文件、执行命令、访问网络、操作 Notebook。动作有副作用所以协议必须额外处理权限申请、事件回传、会话生命周期、失败恢复。这也是为什么 ACP 不仅仅是一个“远程调用接口”而是一套事件驱动的交互协议。2. 一次ACP会话从握手到动作回放2.1 Agent与客户端两端各管一摊要理解 ACP先把两个角色分清楚。Agent 侧Provider负责接收用户目标调用大模型规划执行步骤向客户端请求动作。它不关心自己跑在什么编辑器里。客户端侧Client / Host运行在编辑器进程里提供编辑器的真实能力比如读取文件、写文件、执行终端命令、弹出权限确认框。它不关心 Agent 用的是什么模型。在不少实现里两端通过 WebSocket 连接消息格式接近 JSON-RPC。为什么不直接走本地函数调用因为协议的目标是解耦。Agent 可能跑在本地也可能跑在远程服务编辑器可能是一个桌面应用也可能是一个 Web 页面。基于消息的传输方式给部署方式留了很大弹性。一次会话的起点是握手。双方先互报“我会什么、我需要什么”。Agent 会声明自己支持哪些动作类型客户端会声明自己暴露了哪些宿主能力。举个常见场景某些轻量编辑器没有终端它就不会声明终端能力Agent 在规划时也只能绕开终端操作。这个能力协商很重要它决定了后面能做什么、不能做什么。2.2 会话生命周期握手之后进入会话运行阶段。一次会话可以很短比如“帮我把这段代码加注释”也可以很长比如“把整个项目从旧的构建方案迁移到新方案”。长任务场景下会话需要管理中间状态。Agent 每完成一步都会产生事件文件被改、终端输出更新、权限申请被批准或拒绝。这些事件合起来构成一个用户能逐步确认、随时打断的执行过程。这不是一次问答而是一个持续的双向对话。会话结束时需要明确的关闭流程释放终端、断开连接、清理临时资源。如果编辑器直接杀掉进程而不是正常关闭可能留下挂在后台的终端任务这也是后面要提到的坑。2.3 动作、事件和权限协议的核心消息可以分成两类动作请求ActionAgent 发给客户端请求执行某个操作。事件通知Event客户端发给 Agent反馈环境变化或操作结果。一个典型的文件修改动作示意结构大致如下{ type: action, action: file.edit, request_id: req_001, file_path: /workspace/docs/start.md, new_content: # 更新后的内容 }客户端收到后不一定直接落盘而是先判断权限。如果需要用户确认会先返回一个权限请求事件{ type: event, event: permission.request, request_id: req_001, message: Agent 想修改 /workspace/docs/start.md是否允许 }用户允许之后客户端才真正把修改应用到编辑器的缓冲区和磁盘用户拒绝Agent 会收到拒绝事件然后调整计划。这套“先申请、再执行、后反馈”的模型是 ACP 和普通 API 调用最明显的区别。注意上面是示意结构不是某个具体版本的标准字段。开始实操前必须去对应 SDK 和协议文档里确认字段名、消息类型和版本约定。2.4 权限模型是边界不是摆设刚开始尝试 ACP 的人很容易嫌权限弹窗烦AI 每改一个文件都要问一次效率太低。但换个角度看权限模型恰恰是这个协议能在真实项目里被信任的前提。没有权限控制的 Agent等于给一个自动执行代码的进程开了管理员权限。实际使用中权限可以按安全等级设计只读操作自动放行修改已知工作区文件可以放行或轻确认执行终端命令需要显式确认高危命令可以配置拒绝列表。不同客户端实现方式可能不同但核心原则一致Agent 的能力边界由用户和编辑器共同决定而不是 Agent 想做什么就做什么。先把这条理解透后面排障时会省很多事。3. 四种编辑器形态接入的是同一套协议3.1 四种编辑器到底差在哪教程标题里提到的“四种编辑器”我理解下来不是四个具体品牌而是四种典型的宿主形态。把它们放在一起看差异非常清楚宿主形态典型代表核心能力对Agent的期待桌面通用IDEVS Code 生态文件树、多标签、内置终端、diff 视图改完文件能弹 diff允许执行命令Notebook环境Jupytercell 执行、图文输出能执行 cell、拿回输出结果数据科学IDEPositron 类脚本编辑与 Notebook 执行融合既要改代码也要跑数据、看图表Web轻量编辑器在线 Markdown、代码片段工具轻量、通常没有本地终端以文件读写为主交互要简单当然具体适配了哪些编辑器、叫什么名字要以你实际安装时对应仓库的 README 和官方示例为准。上面这张表主要是帮助理解形态差异而不是一份已经落定的官方清单。这四种形态对“AI 进编辑器”的要求完全不一样。桌面 IDE 期待 Agent 改完文件能弹一个可视化 diffNotebook 期待 Agent 能执行某个 cell 并拿回输出结果Web 编辑器可能根本没有终端也不希望弹复杂的权限对话框。如果没有协议你要给四种形态各写一套集成有了协议你要做的是分别写一个适配层把协议动作翻译成各自编辑器的 API。Agent 侧只需要实现一套协议交互逻辑。这就是“让 AI 进驻四种编辑器”的核心前提。3.2 适配层协议和编辑器之间的翻译官适配层的职责很朴素接收协议消息调用编辑器 API再把结果转成协议事件回传。用一段非常示意性的接口来描述类似这样interface HostAdapter { readFile(path: string): Promisestring; editFile(path: string, content: string): Promiseboolean; runCommand(command: string): PromiseCommandResult; requestPermission(action: Action): PromisePermissionResult; }不同的编辑器只需要对同一个接口做不同实现。VS Code 的实现可能调用工作区 API 和 diff APIJupyter 的实现可能直接操作 kernel 执行 cellWeb 编辑器的实现可能只有 readFile 和 editFile没有 runCommand。对 Agent 而言它面对的是一个固定的协议接口而不是某个编辑器的私有 API。这也是协议最大的优势不是“功能更多”而是“接入成本可复用”。每新增一种编辑器形态团队只需要写一个适配层不需要把 Agent 的规划逻辑、上下文管理、模型调用再重写一遍。3.3 一条完整执行链路长什么样把前面的概念串起来一次用户请求在 ACP 架构里大概走这样一条链路用户在编辑器里输入需求“把 README 里的安装步骤改成新版命令。”编辑器里的客户端适配层读取当前文件和工作区信息打包成初始化上下文。适配层建立 ACP 会话把目标发给 Agent。Agent 规划后发出读取文件的动作请求。适配层读取文件内容返回给 Agent。Agent 生成新的安装步骤发出修改文件的动作请求。适配层判断是否需要权限确认弹出确认框。用户允许后适配层把修改应用到编辑器缓冲区和磁盘并通过 diff 视图展示。适配层回传成功事件Agent 接着检查是否还有其他步骤。任务结束Agent 关闭会话用户看到最终结果。这条链路里Agent 从头到尾不需要知道用户用的是 VS Code 还是 Jupyter。它只知道自己发出了“读文件”“改文件”这类动作请求剩下的事由客户端适配层解决。反过来客户端适配层也不需要关心 Agent 内部用什么模型、怎么规划。两端因为协议而解耦这才是 ACP 的关键价值。3.4 能力差异会决定体验上限协议统一了通信格式但不代表四种编辑器最终体验会完全一致。能力差异仍然存在而且会直接影响体验。Notebook 场景里Agent 的价值不只是改代码而是执行 cell、看输出、根据报错继续修正。如果客户端适配层没有实现 cell 执行动作Agent 就只能在文本层面改文件体验大打折扣。Web 编辑器如果只支持文件读写Agent 就无法执行命令复杂工程任务也就做不了。所以选型时要先问自己核心工作流需要哪些能力如果主要是写文档、改配置Web 编辑器和轻量适配层就够如果经常跑数据流水线就必须选支持 cell 执行和终端能力的宿主。4. 自己搭ACP环境时最容易踩的坑4.1 版本和SDK匹配问题ACP 本身是协议但实际开发中你接触到的往往是协议的具体实现Agent SDK、客户端扩展、插件、示例项目。这三者的版本如果不匹配最常见的结果是握手失败或者某些动作请求发过去没有响应。建议先从官方仓库的示例跑通不要自己从零搭。跑通之后再逐步替换成自己的模型配置和工作区。这样做的好处是你可以把“示例
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门