跳转至

OpenClaw ACP 实战指南:从踩坑到全通

作者

飞马 | 2026-04-23

今天花了几个小时验证和调试 OpenClaw 的 ACP(Agent Control Protocol)功能,把 Codex 和 Claude Code 的 ACP 调用全部跑通了。过程中踩了不少坑,这篇记录核心发现。

ACP 是什么

ACP 是 OpenClaw 调用外部 coding agent(Codex、Claude Code、Copilot 等)的统一协议。相比直接 exec 运行 CLI,ACP 提供结构化通信、自动回调、session 管理等能力。

调用方式:

{
  "runtime": "acp",
  "agentId": "codex",
  "mode": "run",
  "task": "你的任务描述",
  "cwd": "/workspace/project-dir",
  "runTimeoutSeconds": 900
}

踩坑 1:heartbeat.target 未配置导致回调不投递

问题

exec background=true 完成后,agent 生成了回复,但 Discord 上看不到。

根因

heartbeat.target 默认是 "none",导致两层阻断:

  1. Prompt 层:生成的 prompt 是 "Handle the result internally. Do not relay it to the user"
  2. 路由层OriginatingChannel 为空,reply 无处投递

解法

openclaw config set agents.defaults.heartbeat.target last

设成 "last" 后,completion wake 会路由到最后交互的 channel。不会串频道——exec completion 自带 deliveryContext,优先使用发起时的 channel。

踩坑 2:Claude Code ACP 进程不退出

问题

通过 ACP 调用 Claude Code 后,claudeclaude-agent-acp 进程不退出,累积僵尸进程。Codex 没有这个问题。

根因

两个原因叠加:

  1. npm exec 包装层claude-agent-acp 没有本地安装时,acpx 通过 npm exec 启动,产生三层进程树(npm → claude-agent-acp → claude)。child.kill() 只杀了 npm 进程,内层变成孤儿。
  2. oneshot close 缺陷manager.core.tsrunTurn() 调用 runtime.close() 时没传 discardPersistentState,导致不发 session/close ACP 消息,adapter 的 teardown 不触发。

Codex 没问题是因为 codex-acp 是单进程,检测到 stdin 断开后自行退出。

解法

全局安装 claude-agent-acp,让 acpx 走 installed 路径而不是 npm exec 包装:

npm install -g @agentclientprotocol/claude-agent-acp

踩坑 3:subagent 里 background exec 回调丢失

问题

在 subagent 里用 exec background=true,exec 完成后回调丢失。

根因

subagent 是短生命周期 session。background exec 完成时,subagent session 已经不存在了,回调无处投递。

正确做法

场景 做法
Interactive session exec background=true 或 ACP spawn,异步
Subagent 同步 exec(不加 background),等完成后返回

subagent 里也没有 sessions_spawn

ACP spawn 工具在 subagent 环境中不可用(未注入),所以从机制上就阻止了嵌套 spawn。

踩坑 4:ACP 权限需要显式配置

问题

ACP 调用的 agent 默认只有读权限(approve-reads),写文件、执行命令会被拦截。

解法

openclaw config set plugins.entries.acpx.config.permissionMode approve-all

需要重启 gateway 生效。

超时策略

ACP 和 exec 调用 coding agent 时,超时最少 15 分钟起步。很多时候没法预估复杂度,给少了等于白跑。

任务类型 超时
一般任务 15 min (900s)
复杂编码 / 调研 30 min (1800s)

被超时杀掉 = 完全浪费

宁可多给时间。A killed run is a wasted run.

配置清单

最终让 ACP 全通的配置:

# 1. heartbeat 回调投递
openclaw config set agents.defaults.heartbeat.target last

# 2. exec 成功无输出也通知
openclaw config set tools.exec.notifyOnExitEmptySuccess true

# 3. ACP 全权限
openclaw config set plugins.entries.acpx.config.permissionMode approve-all

# 4. 安装 claude-agent-acp 避免 npm exec 包装
npm install -g @agentclientprotocol/claude-agent-acp

# 5. 重启 gateway
openclaw gateway restart