返回文章归档

文章详情

acpx 高级用法:输出格式控制与复杂 Workflow 构建

从 JSON 输出、超时与重试、降级策略,到扇出、链式、评审循环三种工作流模式,聊聊 acpx 在复杂编排里的实战经验。

系列:acpx 实战 OpenClawacpx

acpx 入门其实不难:建个 session、发个 prompt、拿到结果,十分钟就能跑起来。

真正开始见水平的,是你把它放进复杂工作流之后。 这时候问题就不再是“能不能调用 agent”,而变成:

  • 输出怎么给脚本消费?
  • 超时了怎么办?
  • 失败要不要重试?
  • 哪些步骤适合并行,哪些必须串行?
  • 什么时候该 push,什么时候不该轮询?

也就是说,acpx 的高级用法,不在于记住更多命令,而在于你是否把它当成一个可编排的系统组件,而不是一个“会说话的命令行工具”。

这篇文章就集中讲四件事:

  1. 如何控制输出格式,尤其是 JSON/NDJSON 的消费方式
  2. 复杂流程里如何处理超时、重试和降级
  3. 三种常见 workflow 模式:扇出、链式、评审循环
  4. 为什么我更推荐 push-based,而不是到处写轮询

一、输出格式控制:先想清楚你的消费者是谁

很多人第一次用 acpx,会把它当成终端里的聊天输出工具。但一旦要接脚本、自动化、日志处理系统,输出格式就不只是“好不好看”,而是“好不好接”。

acpx 支持三种核心输出格式:

  • text
  • json
  • quiet

1. text:给人看,适合交互式观察

默认的 text 输出最适合在终端里盯着执行过程看。 它会给你比较友好的流式信息,包括进度、工具状态和最终结果。

这很适合这些场景:

  • 本地手工调试
  • 想知道 agent 正在做什么
  • 需要边看边决定下一步

但如果你的下游是脚本,text 通常就不够稳了。因为人类喜欢“有点弹性”的文本,程序不喜欢。

2. quiet:只要最终答案,不要过程噪音

如果你只是想拿最终文本,quiet 很顺手:

acpx --format quiet exec '用三句话总结当前项目定位'

它特别适合:

  • shell 脚本拼接
  • 快速生成摘要
  • 把最终文案传给下一个步骤

但要注意,quiet 的代价是你几乎放弃了中间状态。 一旦要调错,信息量就不够。

3. json:真正进入自动化世界的入口

我自己最喜欢的还是 json

acpx --format json codex exec '审查当前分支改动并输出风险摘要'

json 实际上是 NDJSON 事件流,每一行是一个独立 JSON 事件。这种格式的好处非常明确:

  • 可流式消费
  • 可按事件类型过滤
  • 适合管道处理
  • 既能拿过程,也能拿结果

比如你可以这样筛工具调用:

acpx --format json codex exec 'review changed files' \
  | jq -r 'select(.type=="tool_call") | [.status, .title] | @tsv'

一个关键建议:不要试图“正则解析 text 输出”

这是我最想强调的一点。

如果你已经进入自动化或编排场景,请直接用 json,别去拿 text 输出做脆弱解析。

原因很简单:

  • 文本人类可读,不代表机器稳定可读
  • 一旦输出文案变化,正则就碎
  • 调试时你以为是 agent 出错,实际是解析器先炸了

所以先问自己一句:

这一步输出是给人看,还是给程序接?

给人看,用 text。 给程序接,用 json。 只要最终文本,用 quiet

这一步想清楚,后面会省很多事。

二、JSON 输出怎么设计消费逻辑?

光有 JSON 不够,关键是你怎么消费。

我更推荐一种“事件驱动”的思路,而不是“等全量结束再整体处理”。

1. 按事件类型分层处理

例如你可以把流里的事件粗分成:

  • 中间进度事件
  • 工具调用事件
  • 错误事件
  • 最终完成事件

这样脚本就能做更清楚的决策:

  • 看到中间进度就更新日志
  • 看到工具调用就记录审计轨迹
  • 看到错误事件就触发重试或降级
  • 看到完成事件就取最终结果

2. 保留原始事件日志,不要只保留最终文本

这是我踩过坑之后最认同的一条。

如果你只保留最终结果,一旦流程出了问题,后面几乎没法复盘。反过来,如果你把 NDJSON 原样存下来,调试体验会好很多。

尤其是在复杂流水线里,原始事件日志能帮你回答很多关键问题:

  • 超时前卡在哪个阶段
  • 请求过哪些工具
  • 哪一步失败最多
  • 是否有权限请求被拒绝

3. 结构化输出不等于“把所有内容都塞成 JSON 字符串”

有些人会让 agent 自己再输出一层 JSON,然后外面再包 NDJSON 事件。不是不能做,但要克制。

更好的做法通常是:

  • 外层由 acpx 负责事件流结构
  • 内层只在真正需要结构化业务结果时,再要求 agent 输出稳定 JSON

别把每一步都设计成“JSON 里套 JSON 再套 markdown”。 那种系统看起来高级,实际维护时会很烦。

三、错误处理:复杂 Workflow 拼的不是快乐,是恢复能力

只要工作流够长,失败就不是意外,而是常态。 所以 acpx 的高级用法里,错误处理比“跑通一次”更重要。

我会重点看三类策略:超时、重试、降级。

1. 超时:先承认有些任务不该无限等

acpx 支持 --timeout <seconds>,这在复杂流程里非常重要。

例如:

acpx --timeout 180 codex exec '生成当前仓库的发布说明草稿'

为什么超时要显式设? 因为很多工作流失败,不是完全报错,而是长时间卡住。没有超时的系统,最容易把整个流水线拖死。

2. 重试:不是所有失败都值得原样重来

重试当然有用,但别搞成无脑 while true。

我更推荐按失败类型分类:

适合重试的:

  • 暂时性连接问题
  • 偶发超时
  • 依赖服务短暂不可用

不适合直接重试的:

  • 权限被拒绝
  • prompt 本身有歧义
  • 输入上下文缺失
  • 逻辑型错误导致的稳定失败

也就是说,重试应该是对暂态问题的恢复手段,不是对设计问题的遮羞布。

3. 降级:系统别只会成功或死亡

我非常看重降级策略。

比如一个完整流程原本希望:

  1. research
  2. draft
  3. review
  4. publish

但如果 review 阶段超时了,系统是不是只能整条失败? 不一定。

你可以设计成:

  • review 成功 → 正常发布
  • review 失败但 draft 成功 → 标记“待人工复核”,先保存草稿
  • research 失败 → 直接终止,因为后续输入不可靠

这就是降级的价值:

不要把系统设计成“全对才有产出”。

真实工作流更好的目标,通常是“尽量产出可用中间结果”。

四、三种常见 Workflow 模式

我自己在用 acpx 时,最常见的是三类模式:扇出、链式、评审循环。

模式一:扇出(Fan-out)

适合把一个大问题拆成多个独立子问题,同时处理。

例如你要写一篇大文章,可以并行开几个 research session:

  • 一个查协议能力
  • 一个查权限模型
  • 一个查 session/queue 机制

最后再汇总。

它适合:

  • 多主题研究
  • 多模块并行分析
  • 多候选方案比较

它的优点是快,缺点是后面一定要做归并,不然你只是得到了三堆材料。

模式二:链式(Chaining)

这是最稳的一种。

前一步输出,成为后一步输入,比如:

  1. research 输出提纲
  2. writing 根据提纲写初稿
  3. review 根据初稿提问题
  4. publish 根据定稿落盘

这种方式速度未必最快,但最容易控制质量和责任边界。

如果你刚开始搭复杂工作流,我建议先把链式做好,再考虑更花的模式。

模式三:评审循环(Review loop)

这是我最常用也最容易失控的一种。

流程通常是:

  1. writer 产出草稿
  2. reviewer 提意见
  3. writer 根据意见改稿
  4. reviewer 再检查

这个模式特别适合:

  • 文案润色
  • 技术文档修订
  • 代码 patch review
  • 风险审查

但它最大的坑也很明显: 如果你不设停止条件,它会一直转。

所以评审循环一定要有边界,比如:

  • 最多两轮
  • 只处理高优先级问题
  • 当剩余问题低于阈值时结束

别把“反复优化”误写成“无限循环”。

五、Push-based vs 轮询:我为什么更讨厌后者

这部分是实战里最容易踩坑的。

很多人写自动化时,第一反应是轮询:

  • 每隔几秒查一次状态
  • 看看有没有完成
  • 没完成就再查

这在简单系统里能凑合,但在 Agent 编排里,轮询通常很烦:

  • 浪费资源
  • 延迟大
  • 日志碎
  • 出现竞态条件
  • 很容易把“处理中”和“已失败未上报”搞混

我更偏向 push-based

  • 流式输出就流式消费
  • 有事件就处理
  • 有结果就推进下一步
  • 阶段完成时再触发后续动作

acpx 的 NDJSON 流本身就很适合这种风格,因为它不是要你反复“去问一遍”,而是在执行过程中持续把状态推出来。

轮询最常见的几个坑

1. 过于频繁

几百毫秒一次地查状态,看似积极,实际只是制造噪音。

2. 状态定义不清

“running”“queued”“done”“cancelled”“failed”这些状态如果脚本层没处理清楚,轮询逻辑很容易写出鬼故事。

3. 误把“没有新消息”当成“系统挂了”

有些长任务只是暂时没输出,不代表死了。轮询系统往往很容易误判。

4. 恢复逻辑越来越复杂

你会发现最后不是在做编排,而是在写半套状态机。

如果能直接基于事件流推进,就别没事给自己加一个轮询层。

六、一个更稳的复杂 Workflow 思路

如果让我给一个比较稳的高级用法建议,大概会是这样:

1. 默认链式,必要时局部扇出

不要一上来就全并行。大多数系统真正需要的是清晰,不是表面速度。

2. 给每个阶段明确输入、输出、超时和降级策略

例如:

  • research:输入主题,输出提纲,超时 5 分钟,失败则终止
  • writing:输入提纲,输出初稿,超时 10 分钟,失败则保留半成品
  • review:输入初稿,输出问题列表,超时 3 分钟,失败则转人工
  • publish:输入定稿,输出文件路径,失败则回滚或保留待发状态

3. 机器消费一律优先 json

别在自动化里硬啃 text

4. 尽量保留事件日志

这一步在系统还小的时候看不出价值,等你出第三次线上怪问题时就会感激自己。

5. 让主 Agent 收口

复杂流程跑完后,不要把原始事件流直接甩给人看。 最好由主 Agent 做最后的总结、解释和人工决策承接。

七、结语:高级用法的重点,不是更复杂,而是更可恢复

很多人说“高级用法”,容易想到更多参数、更多模式、更多并发。 但我对 acpx 的理解是:

真正高级的,不是把工作流堆得更复杂,而是让它在复杂时仍然有边界、有日志、有恢复能力。

输出格式控制,让你分清人和程序的消费方式; 超时、重试和降级,让系统不会一碰就碎; 扇出、链式、评审循环,让任务拆分更贴近真实协作; push-based 的思路,则帮你少踩很多轮询带来的烂坑。

说到底,acpx 真正适合的不是“演示型自动化”,而是要长期跑、反复跑、出问题还能排查的工作流。

这也是我越来越喜欢它的原因: 它不是把 Agent 包装得更神奇, 而是让 Agent workflow 终于有了点工程系统该有的样子。

移动端目录

目录

  1. 一、输出格式控制:先想清楚你的消费者是谁
  2. 1. text:给人看,适合交互式观察
  3. 2. quiet:只要最终答案,不要过程噪音
  4. 3. json:真正进入自动化世界的入口
  5. 一个关键建议:不要试图“正则解析 text 输出”
  6. 二、JSON 输出怎么设计消费逻辑?
  7. 1. 按事件类型分层处理
  8. 2. 保留原始事件日志,不要只保留最终文本
  9. 3. 结构化输出不等于“把所有内容都塞成 JSON 字符串”
  10. 三、错误处理:复杂 Workflow 拼的不是快乐,是恢复能力
  11. 1. 超时:先承认有些任务不该无限等
  12. 2. 重试:不是所有失败都值得原样重来
  13. 适合重试的:
  14. 不适合直接重试的:
  15. 3. 降级:系统别只会成功或死亡
  16. 四、三种常见 Workflow 模式
  17. 模式一:扇出(Fan-out)
  18. 模式二:链式(Chaining)
  19. 模式三:评审循环(Review loop)
  20. 五、Push-based vs 轮询:我为什么更讨厌后者
  21. 轮询最常见的几个坑
  22. 1. 过于频繁
  23. 2. 状态定义不清
  24. 3. 误把“没有新消息”当成“系统挂了”
  25. 4. 恢复逻辑越来越复杂
  26. 六、一个更稳的复杂 Workflow 思路
  27. 1. 默认链式,必要时局部扇出
  28. 2. 给每个阶段明确输入、输出、超时和降级策略
  29. 3. 机器消费一律优先 json
  30. 4. 尽量保留事件日志
  31. 5. 让主 Agent 收口
  32. 七、结语:高级用法的重点,不是更复杂,而是更可恢复

系列阅读

acpx 实战

10 分钟
acpx 高级用法:输出格式控制与复杂 Workflow 构建

从 JSON 输出、超时与重试、降级策略,到扇出、链式、评审循环三种工作流模式,聊聊 acpx 在复杂编排里的实战经验。