需求不是功能清单,是任务合同
“上传资料、自动分析、生成报告、支持导出。”这类需求看起来完整,研发甚至可以据此做出一套顺畅的页面。但当系统真的开始处理任务,团队很快会遇到清单没有回答的问题:资料缺了一页怎么办,分析依据从哪里来,报告写到什么程度算完成,低把握时继续还是停,导出之后谁对结果负责。
功能清单描述系统拥有哪些部件,却没有定义这些部件怎样共同兑现一次任务。对于会检索、调用工具、等待外部事件并产生内容的 Agent,这个缺口尤其危险。
我更倾向于把需求写成任务合同。
任务合同锁住的是一次委托
任务合同不是更长的 PRD,也不是法律文件。它是产品、业务、设计、工程和测试对一次工作达成的共同约定。最少要说清:
- 谁发起,谁验收,谁承担最终决定;
- 本次要改变什么现实结果,范围到哪里为止;
- 必填输入、可选输入及各自来源;
- 输出给谁,以什么结构进入下一步;
- 可以使用哪些知识和工具,不能触碰哪些数据与动作;
- 什么证据代表完成,什么情况需要补充、审批或等待;
- 哪些失败必须明确结束,不能包装成“已完成”。
它的价值在于让同一句“做完了”只有一个可读回的含义。
为什么 Agent 更需要合同,而不是更多功能
传统页面通常由用户逐步操作,流程分支相对可见。Agent 会把多个步骤折叠成一次委托:理解目标、制定计划、查资料、调用工具、校验结果。用户看到的按钮更少,系统内部承担的不确定性却更多。
如果需求只写“AI 自动处理”,工程团队不得不替产品猜测:是否允许修改正式记录,工具失败能否重试,旧审批是否仍然有效,用户取消时在途动作怎么办。不同人会给出不同答案,最终每个模块都可能局部正确,整条任务却没人负责。
任务合同把这些猜测变成显式决定。它不是限制 Agent 能力,而是限定能力在什么条件下可以生效。
主流程要写状态,不写魔法
一个可执行的主流程,不应从“Agent 分析并输出结果”跳到完成。它要把关键对象和状态串起来。
以资料审查为例:系统先确认任务版本和资料范围;确定性检查处理格式、重复和权限;Agent 只在获准材料中寻找证据;缺资料时进入待补充,指出缺口;补充到达后只重跑受影响部分;形成候选结论后,由有权角色接受、修改或驳回;最终保存证据、差异和版本。
这里每一步都能回答五个问题:读了什么、做了什么决定、产生了什么状态、留下了什么证据、失败后去了哪里。这样的流程才有可能被测试。
停止条件属于需求正文
很多需求把停止条件留给开发兜底,结果系统只会两种状态:成功或报错。真实任务至少还有缺输入、等审批、外部结果未知、预算耗尽、用户取消和无法恢复等去向。
“停下”不是没有能力,而是一种产品能力。它保护用户不被假结论误导,也保护系统不在未知状态下继续制造副作用。
好的停止条件还要说明用户去向。缺输入时告诉他缺什么;等审批时展示影响和审批人;结果未知时允许查询与对账;预算耗尽时交付已完成部分和剩余缺口。只显示“发生错误”,等于把系统内部的不确定性重新扔给用户。
Prompt 不能替代任务合同
Prompt 可以描述上下文、目标、输出和语气,却无法独自承担权限、状态、版本、工具副作用和恢复。把所有规则塞进 Prompt,表面上集中,实际上把可验证的产品约束变成了一段容易漂移的自然语言。
任务合同应当位于 Prompt 之上。确定性规则进入系统控制,知识进入有版本的来源,工具使用受权限和状态门约束,Prompt 只承担适合语言模型的理解与生成部分。
这样做还有一个直接好处:当结果不好时,团队能判断问题出在任务边界、知识、工具、模型还是交互,而不是把所有 Bad Case 都变成“再改一句 Prompt”。
一份小而完整的需求
任务合同并不鼓励大而全。第一版反而应该只选择一种用户、一类高频任务、一组可治理资料、一个可观察的输出去向和一条真实失败路径。
最小不是页面最少,而是从触发到结果被使用,再到错误能被收集,链路完整。边界外的场景明确拒绝,比在清单里写“后续支持”更诚实。
评审时,沿一次真实任务走
评审需求时,不要按页面目录逐页翻。先确认用户、目标和非目标,再走一遍正常任务,然后故意拿走一项输入、制造一次工具超时、加入一个越权请求、让用户中途取消。每个分支都应该回到合同中的状态、责任和证据。
如果团队无法回答“现在到底算不算完成”,需求还没有准备好进入开发。功能可以在开发中增加,任务合同缺失却会让整个团队在同一条链上做出互相冲突的决定。
需求的本质不是告诉工程要做多少功能,而是约定我们准备替用户承担哪一段工作,以及用什么证据证明没有越界。