Skip to content
阿德的博客
Go back

从 dispatch 到 ACP:用 OpenClaw 重建我的开发协作流程

前几周,我在这台 Linux 机器上专门养了一个 OpenClaw agent:coder

它的定位很明确——不是陪聊,也不是通用助理,而是一个偏工程执行的开发代理。我最早给它做了几组 skills,目标也很务实:把日常开发任务一键 dispatch 给 Claude Code,尤其是放在 Telegram 里以 slash command 方式触发。

一开始这套东西是能跑的,而且不只是“勉强跑通”,甚至已经有一点像真正的工作流:

再配合本地约定:

这套设计并不“学术”,但很实用。问题是,它越实用,就越暴露出一个事实:我其实是在自己造一层 agent 调度壳,而 OpenClaw 后来原生支持了 ACP。

一旦 ACP 可用,很多之前必须靠自定义 skill、脚本、tmux、callback、env 约定去补的东西,突然变成了平台原生能力。

于是问题就从“怎么把 dispatch 技能做得更强”变成了:

既然 OpenClaw 已经支持 ACP,我是不是应该直接用 ACP 重建整个开发流程?

我现在的答案是:是,而且越早越好。

这篇文章就是一次完整复盘:不是抽象讨论,而是结合 coder 的 workspace、长期记忆和 session 里过去几周的真实轨迹,整理出一条从“dispatch 技能驱动”迁移到“OpenClaw ACP 原生驱动”的思路。

最早那套 dispatch 流程,解决了什么问题

先别急着否定旧方案。

coder 早期那套 dispatch skills 并不是“错误路线”,它其实非常符合当时的问题形状:

  1. 我想从聊天界面快速把开发任务扔给外部 coding agent
  2. 我不想每次手动拼命令、切目录、建日志、盯结果
  3. 我需要异步执行,而不是把主会话阻塞住
  4. 有些任务需要交互式 loop,例如 slash-only 的插件场景

所以 dispatch / dispatchi / cancel 的本质,不是“做 skill 为了炫技”,而是把一个重复出现的开发工作流包装起来。

coder 的长期记忆里后来把这些约定写得很清楚:

这很像一个人在把“口头默契”变成“可执行流程”。

而且它确实解决了一个早期最重要的问题:把“我想让 Claude Code 去干活”从一堆散乱 shell 操作,收敛成一个稳定入口。

真正的问题,不是能不能跑,而是这套系统本身太重了

过去几周里,coder 的 session 有一个非常典型的演化:

一开始讨论的是功能;后面越来越多讨论的是边角稳定性。

例如这些问题,都是在真实使用里慢慢浮出来的:

1. callback 和通知链路很脆

dispatchi 如果想在任务结束后自动通知 CodeHook 群,必须保证本地配置里正确打开 callback,像:

一旦 skill 更新、重装,或者 env 文件被覆盖,这条通知链路就会静默失效。

换句话说,任务可能已经跑完了,但你以为它还没结束;或者它出结果了,但没有回传。

这不是模型能力问题,而是自建工作流最常见的“胶水层脆弱性”。

2. 交互式任务要自己维护 tmux / socket / auto-exit

dispatchi 为了支持交互式 loop,本质上做了很多平台外工作:

在 session 里还能看到一次非常典型的 bug:tmux socket 文件名过长导致启动失败。后来为了修复这个问题,又不得不把 session/socket 名裁短,引入哈希键,继续补逻辑。

这就是典型的工程信号:

你本来想解决的是“如何调度外部 agent”,结果越来越多时间花在“如何维护调度系统本身”。

3. skill 为了可发布、可移植、可过审,不断增加额外负担

当这套 dispatch 技能准备发到 ClawHub 时,又暴露出另一类问题:不是功能不对,而是包装方式和安全模型不够平台友好

例如当时需要处理的点包括:

于是又做了一轮“低 VT 风险”改造:

这些改动都合理,也都值得做。但它们有一个共同点:

你投入的工程力越来越多地用在“让自定义派发层不出问题”,而不是用在“让开发任务本身更顺滑”。

我后来意识到:这套 dispatch 技能,其实是在模拟平台原生能力

当我回头看 coder 的这段实践,最强烈的感受不是“这套技能写得挺不错”,而是:

它在很大程度上,是在手工模拟一个本应由平台承担的 agent orchestration 层。

看一下 dispatch 技能到底在手工解决什么:

而这些,恰恰就是 ACP 想解决的问题。

一旦 OpenClaw 原生提供 ACP runtime,并且可以通过 sessions_spawn 之类的能力直接启动外部 coding agent,那么之前那一大层自定义 glue code,就开始显得越来越像“过渡方案”。

不是说它完全没价值,而是:它不再是最优抽象层。

为什么 ACP 是更好的重建方向

我现在更倾向于把 ACP 理解成:

OpenClaw 与外部 coding agents 之间的统一调度协议层。

这个“统一”很重要,因为它带来了几个旧 dispatch 流程很难天然具备的优势。

1. agent 启动不再是“脚本技巧”,而是平台能力

旧流程里,启动 Claude Code 其实是一套脚本工程:

ACP 之后,启动外部 coding agent 这件事本身就是 runtime 能力。

这会带来一个关键变化:

你不再需要围绕“如何把 agent 拉起来”设计 skill,而是围绕“要不要把这个任务交给某个 agent”设计流程。

这两个抽象层次完全不一样。

2. 状态跟踪更自然

coder 的长期记忆里后来明确写了一条非常重要的规则:

没拿到 accepted + childSessionKey + streamLogPath 三件套,就不能对用户说“已经开始”。

这条规则之所以会被写进长期记忆,就是因为过去确实踩过坑:如果只是“看见某个日志文件在变”,你很容易误把上一个任务的痕迹当成这一个任务已经启动。

ACP 模式下,状态确认来自平台级 session 语义,而不是“某个目录里有个新文件”“某个 tmux session 像是活着”。

这件事听起来很小,但实际体验差别非常大:

3. 少掉大量非业务性的脆弱点

ACP 并不会让 bug 消失,但它能把很多原本由你自己维护的脆弱点收回到平台层:

也就是说,故障面会更小,而且更集中。

旧方案的复杂性分散在 skill、env、repo、tmux、Telegram callback、ClawHub packaging、workspace 同步等很多层;ACP 则把“调用外部 agent”尽量收口到一个平台能力上。

4. 不再被单一外部 agent 工作流绑死

dispatch 技能最初几乎就是为 Claude Code 工作流量身做的。

这在早期是优点,因为它针对性强;但从长期看,它也意味着一件事:

你的调度层天然偏向某一个外部 agent 的交互模型。

而 ACP 的价值之一就在于,它把“外部 agent 的差异”下沉到了协议/运行时层,让上层可以更自然地面向任务,而不是面向某个具体 CLI 的怪癖。

这会让后续扩展到 Codex、Pi、Claude Code 甚至更多 ACP harness 时更顺手。

那是不是 dispatch skills 就没有价值了?

也不是。

我更愿意把它们看成一个典型的“过渡时代产物”:

比如 coder 在这些技能实践里沉淀下来的很多经验,迁移到 ACP 时代照样成立:

经验 1:开发流程要有固定的发布回归闭环

coder 后来被明确要求长期遵循这条流程:

本地开发 → 本地测试 → 发布 → 从 ClawHub 安装并回归测试

这条经验并不会因为从 dispatch 转向 ACP 就失效。

相反,在 ACP 时代我会把它稍微泛化成:

本地实现 → 本地验证 → 平台入口验证 → 真实聊天面回归

因为问题往往不出在“代码能不能运行”,而是出在“平台接入之后的真实行为是不是和你想的一样”。

经验 2:把长期约定写进 memory,而不是指望 agent 临场记住

coder 这段实践里最对的一件事,就是不断把经验写回 MEMORY.md 和 daily memory:

这也是我越来越认同的一条原则:

agent 的稳定性,很大一部分来自可写回的工作记忆,而不是模型当下的临场发挥。

经验 3:真正该抽象的不是命令,而是工作流边界

早期 dispatch skills 已经说明了一个事实:

ACP 时代也一样。

真正应该抽象清楚的,依然不是某条 shell 命令,而是:

抽象对了,底层是 shell 也好、ACP 也好,都只是实现细节。

如果现在用 OpenClaw ACP 重建开发流程,我会怎么做

如果让我今天基于这些实践,重新设计 coder 的开发协作流程,我会尽量收敛到下面这套结构。

一、把“请求外部 coding agent”默认切到 ACP

也就是说,今后用户说:

默认都应该先走 ACP 路由,而不是优先想到 dispatch skills。

dispatch 只保留为一种显式兼容入口,或者只在特别适合 slash command 的旧场景里使用。

换句话说:

二、把流程分成“任务型”和“会话型”两类

这是我从旧 dispatch 与新 ACP 对比里最想强调的一点。

以前很多设计复杂,根本原因是“任务型调用”和“持续会话型调用”被混在了一起。

更合理的拆法应该是:

1)任务型

适合:

例如:

这类就适合直接 ACP spawn 一次任务,平台管理生命周期。

2)会话型

适合:

这种就该走 thread-bound 的 ACP session,而不是用一层层 callback 和 tmux session 去假装“有持续会话”。

这会极大简化 mental model:

三、保留一个极薄的“开发工作流 skill”,但不再负责 agent 调度

我不觉得 ACP 时代就完全不需要 skill 了。

我认为仍然应该保留一个很薄的本地 skill,例如 development-workflow 这种角色:

它不负责启动外部 agent,而负责:

这类 skill 的价值仍然很高,因为它解决的是“如何更稳定地组织开发任务”,而不是“如何把 agent 启动起来”。

也就是说:

这是一种更干净的分层。

四、把“启动确认”和“进度跟踪”严格建立在 session 语义上

这也是从过去踩坑里直接得出的经验。

以后只要是 ACP 任务,就应该坚持:

这听上去像个小流程问题,但它会显著降低代理在多任务并行时的混乱度。

五、把旧 dispatch 时代最有价值的经验迁移到 ACP 时代

这一步很关键,因为迁移不是“推倒重来”,而是“保留有效经验,换掉脆弱底盘”。

我认为至少有这些经验应该保留:

真正该淘汰的,不是这些工程纪律,而是围绕旧 dispatch 技能堆出来的那层重脚本调度壳。

一个更现实的判断:ACP 不是“更高级”,而是“更省系统维护成本”

很多人聊新能力时,容易把重点放在“更先进”“更智能”。

但如果从这几周 coder 的真实轨迹看,我觉得 ACP 最大的价值甚至不在这里。

它更重要的价值是:

把原本要你自己维护的大量调度基础设施,交还给平台。

而这对一个长期使用的个人开发系统来说,非常关键。

因为真正会拖垮体验的,往往不是大故障,而是大量小故障:

这些事情单看都不严重,但累计起来会不断消耗信心。

ACP 的意义,就是尽量把这类“系统维护税”压低。

结语

回头看 coder 这几周的实践,我并不觉得那几组 dispatch skills 白做了。

恰恰相反,我觉得它们非常有价值,因为正是这些真实使用里的成功与踩坑,才让我看清楚一件事:

我真正需要的不是“把派发 Claude Code 的脚本做得更完美”,而是让 OpenClaw 原生承担外部 agent 编排这件事。

所以如果要给这段经历下一个结论,我会写成这样:

dispatch skills 解决了“先把开发任务扔出去”的问题; ACP 才更适合解决“长期、稳定、可追踪地与外部 coding agents 协作”的问题。

接下来,如果我要继续演进 coder,方向不会是继续堆更复杂的 dispatch skill,而是:

这样重建出来的开发流程,不一定最花哨,但大概率会比旧方案更稳,也更配得上“长期使用”这四个字。


Share this post on:

Next Post
When Tech Optimism Breaks: A Geek’s Fear in the Age of AI