为什么我开始用 YAML 约束 AI 的执行步骤
摘要:很多 AI 任务失败,不是因为它不会做,而是因为它执行顺序错了。配置类和权限类任务尤其如此。YAML 的价值不在“更规范”,而在“把执行过程变成可状态推进、可失败恢复、可熔断阻断的状态机”。
我后来发现,有一类任务特别适合做成结构化契约:
配置类和权限类操作。
包括但不限于:
- 查询配置
- 权限配置
- 路由配置
- 表头配置
- 菜单关联配置
这类任务有一个共同特点:
- 步骤很固定
- 输入输出明确
- 出错成本高
- 一旦失败,低能力智能体特别容易乱试
所以我后来基本不再让 AI 自由发挥处理这类任务,而是尽量把它们做成 YAML 执行契约。
配置类任务最怕的,不是复杂,而是跳步骤
这类任务真正的问题,不是逻辑难,而是流程不能乱。
比如一个看起来很简单的修改动作,正常顺序应该是:
- 找到目标对象
- 查旧值
- 预览变更
- 确认
- 提交修改
- 打标签 / 同步 / 记录结果
如果交给低能力智能体,它却很容易变成:
- 没查旧值直接改
- 没预览 diff 就提交
- 修改失败后直接重试
- 同步失败后继续乱试
- 甚至调错工具
所以我后来意识到,这类任务最重要的不是“会不会改”,而是:
会不会按顺序改。
YAML 的意义,不是格式化,而是状态化
很多人第一次听到“把执行流程做成 YAML”,会觉得这只是把自然语言写得更结构化一点。
但我真正看重的是另一点:
YAML 可以把开放任务收束成状态机。
比如一份执行契约里,我会写:
steps:
- query-current
- preview-diff
- confirm
- modify
- sync再给每一步加状态:
status: pending | running | done | failed | blocked | skipped这样 AI 的任务就不再是“理解一整段复杂流程”,而是:
- 找到当前
pending - 执行
- 回写状态
- 遇到
blocked停止
这会大幅降低乱序执行和重复执行的概率。
YAML 最大的价值,是放规则,而不是放说明
真正让我觉得 YAML 特别值的一点是:
它特别适合放白名单、禁用项和重试策略。
例如:
allowedTools:
- toolA
- toolB
forbiddenTools:
- toolX或者:
retryPolicy:
network:
maxAttempts: 2
wrongTool:
action: block这比在提示词里写一句“请不要调用 toolX”有效得多。
因为 YAML 不是建议,它是契约。
结构化契约真正解决的是“失败后从哪继续”
低能力智能体还有一个很明显的问题:
失败后,它通常不知道应该从哪一步重新开始。
如果没有状态,它就会从头开始。可从头开始意味着:
- 重复调用
- 重复改动
- 重复同步
- 重复制造噪音
而有了状态:
- step: query-current
status: done
- step: preview-diff
status: done
- step: modify
status: failed那下一次就很明确了:不是从头再来,而是从 modify 这一步继续,或者直接被阻断。
这才是“可恢复执行”。
schema + template + instance 才是完整结构
如果直接让每个需求手写一大段 YAML,其实也会增加负担。
我更推荐三层结构:
schema
定义字段和规则。
template
定义标准执行模板。
instance
在具体需求里填入本次真实参数。
这样可以做到:
- 上层规则统一
- 具体操作又能落地
- 新需求不用每次重新发明格式
不是所有任务都要 YAML 化
我也不是主张一切都 YAML 化。
我更倾向于这个判断:
适合 YAML 的任务
- 步骤固定
- 状态清晰
- 输入输出明确
- 失败成本高
- 容易误调工具
不适合 YAML 的任务
- 开放式设计讨论
- 复杂代码重构
- 强依赖上下文创造力的问题
- 需要大量临场判断的问题
所以 YAML 不是为了替代思考,而是为了约束那些本来就不该靠自由发挥完成的任务。
最后一句
我开始用 YAML 约束 AI 的执行步骤,不是为了把事情写得更复杂。
相反,是为了让复杂度从“隐含在 AI 脑子里”,变成“显式写在契约里”。
这样一来,执行才真正变成:
- 可读
- 可追踪
- 可恢复
- 可熔断
- 可审查
对工程系统来说,这比“它看起来挺聪明”重要得多。