在开发 Go Agent 框架 Covonaut 过程中,我实现了一个让 Agent 真正“入住”编辑器的协议——ACP(Agent Client Protocol)。
为什么需要 ACP 协议?官方将 ACP 类比为 LSP(Language Server Protocol),非常确切。当年 LSP 标准化了“编辑器与语言服务器的对话方式”,让编辑器不必为每种语言重复造轮子。ACP 想要解决的也是类似的问题,只不过对象换成了 Agent:把“编辑器如何与 Agent 对话”这件事标准化,达到“Agent 实现一次,任何兼容 ACP 协议的编辑器都能直接调用”的目的。
ACP 协议由 Zed 提出,核心设计理念是:Agent 是 Server,编辑器是 Client,Agent 作为编辑器的子进程启动,双方通过 JSON-RPC 通信。用户始终待在熟悉的编辑器里,需要时随时唤起 Agent,而不是切换到另一个专属界面。
Covonaut 的 ACP Server 实现Covonaut 的 ACP 模块本质上是一个运行在 stdio 上的 JSON-RPC 2.0 Server。交互流程可以分为三层:
握手层:编辑器发送 initialize 协商能力,再通过 authenticate 完成认证;会话层:支持 session/new 创建新会话,session/load / resume / fork / list 管理历史,session/prompt 下发任务,session/cancel 中止执行,还能在运行时通过 set_mode / set_model 动态切换模式与模型;持久化层:多会话可并存,元信息默认存储在 ~/.acp-agent/acp_sessions.json 中,重启后自动恢复。编辑器反向赋能 AgentACP 最值得关注的设计是编辑器反过来给 Agent 提供能力。Agent 在编辑器内工作时,文件系统、权限等本应由宿主把关的事,通过协议交回编辑器处理,而非 Agent 自行其是:
权限确认:当 Agent 要执行有风险的工具时,会反向发送 session/request_permission 请求,让用户选择 allow_once、allow_always或 reject_once。给危险操作加了一道安全闸门。文件读写(感知 Buffer):若客户端在初始化时声明了文件系统能力,Agent 的读写工具就不再直接操作磁盘,而是走 fs/read_text_file / fs/write_text_file。这就意味着它能读到编辑器里尚未保存的 buffer,真正实现“所见即所得”的协作。让 Agent 的行为可见当 session/prompt 触发 Agent 运行后,内部事件会被翻译成 session/update 通知推回编辑器。协议对更新类型做了细致区分:
消息增量:user_message_chunk / agent_message_chunk / agent_thought_chunk,分别对应用户输入、Agent 回复和思考过程;工具调用:tool_call / tool_call_update,每个调用都带有 kind(read/edit/execute/fetch 等)和一行可读标题,编辑器可据此渲染出 UI,而非暴露原始 JSON;状态更新:还包括 plan、available_commands_update、current_mode_update 等,为编辑器预留了丰富的展示空间。此外,ACP 复用了 MCP 的大量 JSON 结构,并补充了 Coding 场景特有的类型(如 diff 展示),用户可读文本默认使用 Markdown 格式。
小结把“编辑器如何调用 Agent”这一层标准化后,Agent 和编辑器就能各自独立演进,使用者也能自由选择趁手的工具组合。
让编辑器直接调用 Agent,Covonaut 中的 ACP 实践
在开发 Go Agent 框架 Covonaut 过程中,我实现了一个让 Agent 真正“入住”编辑器的协议——ACP
阅读:0
点赞:0