写给机器的操作手册:机器可读规约长什么样

传统的需求文档是一种沟通工具。它的读者是人类,目的是在产品经理和程序员之间建立共识。因此它可以使用自然语言叙述,可以省略"显而易见"的细节,可以用"参考现有实现"这样的指代。人类读者会用自己的知识和经验补全这些省略和指代。

给 Agent 写的规约是一种操作手册。它的读者是一个没有任何先验知识的执行者。它必须自包含:所有相关的约束、边界条件和完成定义都需要显式写出。它必须可验证:每一条验收标准都应该能转化为一个测试用例。如果你无法为一条验收标准写出测试,这条标准本身就太模糊,需要回到需求阶段重新明确。

一个最小的机器可读规约应该包含以下结构:

task_id: FEAT-123
context: ["/docs/arch.md#payments", "/tickets/9876"]
inputs:
  - name: amount
    type: decimal
invariants:
  - amount > 0
acceptance_criteria:
  - "支付成功后在账单页出现一条金额=amount、状态=success的记录"
  - "失败时返回可本地化的错误码,未写入账单"
non_goals:
  - "不处理分期与退款"

每个字段都有明确的工程作用。

task_id 将规约与项目管理系统关联,使变更可追溯。context 指向 Agent 需要阅读的相关文档和代码,限定它的信息范围。inputsinvariants 定义输入空间和约束条件,告诉 Agent 哪些是合法输入、哪些边界需要防御。acceptance_criteria 是最关键的部分:它定义了"完成"意味着什么。每条标准都应该具体到可以直接生成测试断言。non_goals 明确划定了范围的边界,防止 Agent 过度发挥。

这个结构可以根据项目需要扩展。有些团队会增加 dependencies(依赖的其他模块)、risk_level(风险等级,影响后续的审查流程)、examples(输入输出的具体示例)等字段。但核心原则保持一致:自包含、可验证、边界明确。

验收标准的写法值得特别强调。比较这两种写法:

模糊版本:"系统应该正确处理支付失败的情况。"

清晰版本:"当支付网关返回错误码 4xx 时,系统返回对应的本地化错误消息,不创建账单记录,不扣减用户余额。当支付网关超时(>30s)时,系统将交易标记为 pending,启动异步查询,5 分钟内未确认则自动取消并通知用户。"

模糊版本给了 Agent 巨大的决策空间:什么算"支付失败"?什么算"正确处理"?Agent 会做出某种选择,但这个选择是否符合你的意图,取决于运气。清晰版本将决策空间压缩到接近零:每种情况的预期行为都被明确定义,可以直接转化为测试用例。

将验收标准当作评估函数来写。如果一条标准读完之后,你和另一个工程师可能对"是否满足"给出不同答案,这条标准就需要继续拆分和明确。

results matching ""

    No results matching ""