最佳实践
何时用哪种步骤、如何写 idempotent、模块化、性能与成本调优 —— 工程化工作流的集体经验。
这一篇是"踩过的坑"汇总。写过 10 条以上工作流就能感同身受;没写过就先存着,碰到了翻回来看。
一、如何写一条"能上生产"的工作流
从模板起步
哪怕你的场景看起来很独特,240+ 个模板里总有一条"拆一半、改一半"能用的。从模板起步省掉大量从零搭骨架的时间。
从模板实例化 是大多数用户的第一步。
先做"最蠢版本",再做"聪明版本"
新工作流第一版:
- 变量写死默认值
- condition 都不加,全部都跑
- 用平台统一的 LLM Key,不折腾 BYOK
- 不挂 cron,手动跑
跑通后再逐个"精细化":变量化、分支、BYOK、cron、审批。这样每一步出问题都好定位。
每次改都先 dry-run
改了东西 → dry-run 看 DAG 结构和变量流 → 再真跑。dry-run 零成本,不要跳。
二、步骤类型的选择
优先级从上到下,遇到选择困难挑排得靠上的那个:
code— 能用确定性逻辑就别用 LLM。快、便宜、可测试。classifier— 需要 LLM 但输出是一个类别时用;不要用 single 让 Agent 自由发挥。single— 大部分"摘要 / 抽取 / 改写"任务。sub_workflow— 同一段逻辑在多个 workflow 里复用,或单 workflow > 15 个 step。group_chat— 任务需要多个视角互相讨论时用;一个 Agent 能独立完成的用 single。agent_based— 任务有很强分支特征,每个分支都需要 LLM 判断派到哪里。state_machine— 有明确的状态转移,譬如多轮交互 / 工单生命周期。manual_approval— 影响线上 / 花钱 / 对外的步骤前都要加。
反模式:全部丢给 agent_based
把所有事情交给 orchestrator 动态派发,看起来灵活,实际是"让 LLM 做系统设计"—— 不可复现、难调试、token 成本高。agent_based 的 worker 数要清晰、少于 5 个。
三、变量与数据流
大字段先 extract 再传
上游 step 返回 100KB JSON 时,不要直接塞给下游 task。用 extract 把真正需要的字段挑出来:
yaml
- id: fetch_data
type: code
code: |
// 返回一个很大的 JSON
return await heavyFetch();
extract:
user_count: $.data.stats.total_users
top_3: $.data.items[:3].name用 | default(...) 兜底
引用可能为空的变量(被 condition 跳过的 step 的输出)时,加 default:
yaml
- id: summarize
type: single
agent: writer
condition: "length({{steps.classify.categories}} | default([])) > 0"
task: "{{steps.classify.output | default('无内容可摘要')}}"condition 分支 vs on_failure
不要混用:
- condition 控制"正常情况下走不走这一步"—— 跳过 = SKIPPED(不算失败)
- on_failure 是"出错后的补偿动作"—— 发通知 / 降级到备用数据源
把 on_failure 当 try-catch 用,但不要把它当正常分支。业务正常逻辑用 condition。
四、Agent 与模型
tool_set 越小越好
默认 preset 给的工具多数 step 用不上。裁到 2–3 个 —— 成功率上升、token 消耗下降。
模型按任务挑
- 推理 / 代码审阅 → Claude Opus 4 / GPT-5 / DeepSeek-Reasoning
- 短摘要 / 分类 → Haiku / GPT-4.1-mini / DeepSeek-V3.5
- 中文写作 → Claude Sonnet / Kimi K2
- 长上下文(32K+)→ Kimi K2 / Claude 200K
temperature 按任务挑
- 0.0 – 0.3 —— 推理 / 分类 / 抽取(要稳定)
- 0.4 – 0.7 —— 摘要 / 改写(平衡)
- 0.7 – 0.9 —— 创意写作 / 头脑风暴(要发散)
五、idempotent 与自动续跑
纯数据管道的 step 都加 idempotent: true —— 服务重启后可续跑。含副作用(发消息 / 下单)的 step 不要加。
详见 自动续跑。
六、拆分与模块化
- 一个 workflow 超过 15 个 step —— 该拆。
- 同一段 3–5 步逻辑在另一个 workflow 里也要用 —— 该做成模块(sub_workflow)。
- 模块发布后,删 input / 改类型都是破坏兼容,要升 MAJOR 版本。
七、成本控制
- 先 dry-run — 已说过,白跑一次真执行浪费的钱最多,这条最省。
- 分类用便宜模型 — classifier 十有八九不需要 Opus / GPT-5。
- 并发有上限 — 批处理用 sub_workflow + max_parallel 控制并发,别让 TPM 打爆。
- 缓存 RAG index — 同一语料每次都 re-embedding 很贵,把结果持久化到产物。
- 绑预算告警 — 在通知设置里加"单 execution cost > $1"或"当日累计 > $50"告警。
八、安全与合规
- 永远不把 key 写进 YAML —— 用凭据中心。
- code step 的 credentials: 列表要显式 —— 不给 step 它用不上的凭据。
- 付款 / 对外通讯 / 写客户数据库前都加 manual_approval。
- 涉及用户数据的 workflow 考虑开启 审批人列表,让合规团队进 approvers。
- Webhook 用的 API Key(以及兼容模式的 signing secret)定期轮换。
九、测试与上线流程
- 新 workflow 先在测试工作流页 dry-run。
- code step 的脚本单独在本地 node / python 里跑一次看输出。
- Agent 行为用断点调试器 + 小样本跑 10 次看稳定性。
- 调度上线前用"立即触发一次"验证时区 / 参数预设。
十、协作与版本
- 重要改动前先"导出 YAML"本地备份 —— 哪怕版本历史兜底,一份本地副本更踏实。
- 多人编辑:一个人拿锁、改完保存、释放锁,再下一个人拿。并行改请拆成子工作流。
- 大版本变更前和团队同步 —— 别人可能正在依赖你的模块。
十一、监控与告警
- 关键 workflow 的 execution.failed 绑 Slack / 飞书通知 —— 失败了第一时间知道。
- 定期查看数据看板 —— 哪条 workflow 最贵 / 最慢 / 最常失败?优化从它开始。
- 每月看一次审计日志 —— 权限有没有异常 / 凭据被谁用过。
十二、我做完一条工作流的 checklist
- dry-run 通过
- 真跑一次成功
- 每个 step 的 idempotent / retry 策略已确认
- 对外副作用前有 manual_approval 或 condition 明确控制
- 所有凭据都从凭据中心解析,YAML 里没有 plaintext key
- cron / webhook 绑好并确认"下次触发时间"
- 失败通知配好(至少把 execution.failed 推到 Slack)
- YAML 导出一份到 git 做异地备份