太长不看:
- 不要指望 agent 一口气吃下一个复杂工作流。
- 把流程拆成多个单向、短上下文、规则明确的子流程,稳定性会明显提高。
- 有环流程不是不能做,但一定要显式限制循环次数和停止条件。
最近已经不满足于 agentic coding 了,沉迷于使用 coding agent 做自动化。
像 CC(Claude Code) 这样的工具,不仅仅是优秀的编码助手,在“听从指令”这件事上也很擅长,很适合接手固定、复杂、又重复的流程化工作。
这里有个非常重要的小提示:不要指望 agent 能一口气搭建好非常复杂的工作流。
虽然 agent 的知识面很广,但是它的注意力是有限的。除非你能给出非常具体的规则条件,精确到每一个容易跑偏的小细节,否则它的注意力很容易被转移,工作流就会跑偏。
在用 coding agent 做开发自动化时,可能会遇到这些问题:
- 流程一长就开始跑偏
- 一旦需要反复回滚、重试、验收,结果就越来越不稳定
- prompt 越写越长,但效果并没有变好
我的经验是,把复杂工作流拆成一个一个简单流程,先把简单流程稳定实现,再把整个流程串起来,成功率会高很多。
把频繁的UI交互流程做成自动化
上周我试着把 CC 应用到软件开发业务的工作流中,搭一套跟自己业务相关的 AI 自动化工作流。
软件团队人手不够,需求、测试、开发、验收全靠自己(纯纯一人公司了),有很多繁琐的流程化操作不得不去面对。
需求暂且不说,测试要负责“找问题”:跑场景、抓指标、提issue、复测验收。研发要负责“解问题”:复现、修复、单元测试、回归测试。
即便只是使用最简单的 gitlab 来维护项目,像“维护issue”这类工作,也需要大量重复性的键鼠交互操作。
所以,第一个自动化就拿它开刀。
把工作流的目标抽象成一条条规则
我这里说的自动化不涉及像 Github Action 这样的第三方 App,简单利用 skills/hooks 这样的原生机制就能制作很好用的自动化流程。
像 CC 这样的 agent 都具备自动构建 skills 的能力(skill-creator),你只需要把需求转化成它能看懂的 prompt 告诉它就行,它能自动完成转化。
当然,这样生成的自动化是否好用,完全取决于 user prompt 的质量高低。我强烈建议用 markdown 这种格式化的语言去写 prompt,并把自动化工作流用规则的形式明确表达出来。
比如,可以模仿 skills 的通用模板,按照Objective, In-Scope, Out-of-Scope, Rules等标题去归纳、整理 prompt。
这样做的目的是让 agent 集中注意力,让它在你关注的所有流程细节上深入挖掘,避免工作流“跑偏”。
拿测试的需求举例,我希望 agent 能抓取、分析数据日志,从日志中提取性能指标并跟 benchmark 做对比,将不符合预期的 case 都在 GitLab 上用 issue 的形式整理出来。整个工作流是单向线性的,输入端是测试场景,输出端是 GitLab issues。
这个时候,prompt 里至少要显式写清楚这几类规则:
- 不同测试分别看什么指标
- 日志结构长什么样,关键字段在哪里
- benchmark 是什么,超过多少算异常
- issue 要用什么标题、正文结构和标签
如果当前工作流只是更大流程中的一个子流程,那还要额外考虑“给下游喂什么数据”。
比如,如果后续还有一个“自动修复 issue”或者“自动验收 issue”的子流程要接这个输出,那么在定义 issue 模板时,就应该提前把后续流程需要的信息也写进去(即便当前流程本身不需要这些信息),比如:
- 测试数据源
- 异常指标
- 日志片段
- 预期行为
很多时候,工作流不稳定,不是因为 agent 不够聪明,而是因为上游输出的信息对下游来说不够用。
拿我做的这件事举例,可以把一个无环工作流抽象成下面这种样子:
| 项目 | 内容 |
|---|---|
| Input | 测试场景、日志文件、benchmark 配置 |
| Rules | 指标提取规则、阈值定义、issue 模板 |
| Steps | 解析日志 -> 提取指标 -> 对比 benchmark -> 生成 issue |
| Output | 一组结构一致的 GitLab issues |
| Stop Condition | 当前批次所有 case 都已完成分析 |
prompt 可以按照这种格式去写:
# Objective
分析测试日志,找出异常 case,并生成 GitLab issue。
# Input
- 测试场景列表
- 日志目录
- benchmark 配置文件
# Rules
- 每种场景使用对应的指标集合
- 仅当指标超过阈值时创建 issue
- issue 标题格式固定
- issue 正文必须包含场景、指标、阈值、日志证据、复现建议
# Out-of-Scope
- 不负责修复问题
- 不负责回归测试
# Stop Condition
- 所有输入场景均完成处理
这样的 prompt 格式可以帮助 agent 更好的理解和完成工作流。
单向无环的工作流远比有环的工作流稳定
在实践中发现,越简单的工作流越容易实现,越不容易出错。
这也很符合工程设计的哲学:越稳定的系统,其内部设计往往越简单。
什么是“单向无环”的工作流?所有的步骤只允许向前执行一次。这样的工作流往往是简单的。
“有环”的工作流就是不符合这一特征的流程,即流程可能会“回头”。比如,对于某些有验收标准的工作,很难一次性完成,就需要构造“验收 -> 不通过 -> 修改 -> 再验收”的环状流程。
我自己的感受是,这两类工作流的差异非常大:
| 对比项 | 无环工作流 | 有环工作流 |
|---|---|---|
| 步骤方向 | 只向前走一次 | 会回头、会重试 |
| context 压力 | 低 | 高 |
| 规则复杂度 | 相对简单 | 通常更高 |
| 失败模式 | 某一步失败即停止 | 容易反复迭代后越来越偏 |
| 是否适合先自动化 | 很适合 | 适合拆小后再自动化 |
有环流程最麻烦的地方,不是“多了一步”,而是它会持续消耗 context。
当 agent 在同一个上下文里反复经历“判断 -> 修改 -> 再判断 -> 再修改”这类循环时,约束条件会逐渐松动,局部目标会逐渐覆盖全局目标,最后就开始出现一些很熟悉的症状:
- 忘记最初的验收标准
- 只盯着眼前报错,忽略更高层的约束
- 输出格式越来越飘
- 修着修着,把原本已经正确的东西也改坏了
这也是为什么我越来越倾向于把工作流做成能在单个 context 内闭环完成的小任务。
不是因为有环流程完全不可做,而是因为它对 agent 的记忆稳定性要求更高,而这恰恰是今天的 coding agent 最不稳定的一环。
所以,对于有环工作流,我现在的默认策略很简单:
- 能拆成多个无环子流程,就先拆
- 实在拆不掉,也必须限制最大循环次数
- 每轮循环都要重新声明验收标准
- 到达上限后,宁可中断交给人,也不要让它无节制地继续转
这样做当然有副作用。最直接的副作用就是:有些任务可能因为迭代次数不够,最终没能达到验收条件,工作流会提前中断。
但在工程上,这通常是个更好的失败方式。因为**“可控地失败”往往比“失控地继续”更容易被接受**。
一言以蔽之,简单、单向、无环的工作流,通常比复杂、有环、持续自我回写的工作流更稳定。