
Info 当执行不再稀缺时,软件研发的核心问题不再是“如何实现”,而是“如何让任务被系统准确表达”。 Spec 并不能解决这个问题,它只是一个开始。
我们已经可以用一句话生成代码。
但在真实项目中, 这件事往往不稳定,甚至不可复现。
问题并不在模型能力, 而在于我们如何表达任务。
如果从今天的工具能力出发,软件研发看起来已经进入了一个非常“顺滑”的阶段。
有 PRD,有设计稿,有接口定义,有代码上下文。 把这些信息整理成一份 spec,交给 AI,就可以生成代码。
很多团队已经开始这样尝试:
看起来,问题已经被解决了。
甚至进一步,会有人得出一个结论: 只要 spec 写得足够好,AI 就可以稳定完成研发任务。
但在真实项目中,事情并没有这么顺利。
同一份 spec,多次执行结果并不一致。 有些逻辑会遗漏,有些边界会处理不完整。 往往需要不断补充 prompt、反复调整表达,才能逐渐接近预期结果。
这时候,很容易把问题归因到:
但如果观察足够多的实际 case,会慢慢意识到: 问题并不在“AI 能不能写代码”, 而在“任务是否被稳定地表达出来”。
当 AI 还只是辅助工具时,这个问题并不明显。
因为人始终在“执行链路”中:
也就是说: 人,本身就是一个“补全表达”的系统。
但当执行开始逐步交给 Agent / 系统时,这个前提开始失效:
这时候,问题发生了转移: 执行能力不再是瓶颈, 表达能力开始成为瓶颈。
要理解这个变化,需要先把一个问题说清楚: Spec,本质上是什么?
Spec 在不同语境下含义并不完全一致。
在一些场景中,它指的是协议或标准(例如 API spec); 在软件研发中,它也可以指需求规格说明。
但在 AI Coding 的语境下,Spec 更常被用来指: 一种面向人和模型理解的任务描述方式。
在今天的实践中,Spec 也在发生变化。
像 spec-kit 这样的尝试,正在让 Spec 变得更加结构化, 并可以被 Agent 直接使用,从而参与执行过程。
也就是说,Spec 已经不再只是“文档”, 而是一种可以参与执行链路的表达形式。
但这里有一个关键区别: 参与执行,并不等于可以被系统直接执行。
它的设计目标,是约束任务的表达方式, 让人和 Agent 能在同一语境下理解,并通过解释过程引导执行任务。
但这也意味着:
而这在“人参与执行”的阶段没有问题。
但当执行者变成系统时,就会出现一个断层:
Spec 并不是为“系统执行”设计的。
也就是说,即便如此,Spec 仍然没有消除一个关键特征: 它依然允许解释空间的存在。

图1:Spec 需要解释才能执行,但无法被系统直接执行
当任务从“人参与执行”转向“系统执行”时,有三个变化会变得非常明显:
例如: “在订单列表页增加一个筛选条件”
对于人来说,这句话是可以被补全的:
但对于系统来说: 这是一段不完整的表达。
人可以结合:
去理解任务。
但系统需要的是: 显式提供的上下文。
人可以“感觉差不多了”。
但系统必须知道:
这三个变化,本质指向同一件事: 系统需要的不是“描述”,而是“可执行的表示”。
这里的“表示”,不是指某种具体格式(比如 JSON),而是一种更本质的东西: 一种可以被系统理解、执行,并且可验证的任务表达方式。
在实践中,一个“可执行的表示”通常需要具备三个最基本的要素:
当这些信息被补齐后,任务才开始具备一个重要特征: 它不再依赖“人来补全”,而可以被系统直接执行。
在我们的实践中,这种结构被进一步沉淀为: Task IR(任务中间表示)
这里有一个非常重要的观察。
在实际验证中,我们发现: 并不是所有任务,一开始都需要完整的 Task IR。
例如:
这些任务的特点是:
在这种情况下: 一句话 + Agent,就可以完成。
例如:
这类任务开始出现:
这时,仅靠自然语言就开始不稳定。
通常需要补充一些关键信息:
例如:
在这种情况下: 必须引入完整的 Task IR,才能保证执行稳定性。
这也带来一个更重要的结论: IR 不是一开始就存在的,而是在复杂度上升时逐渐显式化的。

图2:只有在“高复杂度 + 难表达”的场景下,Representation 才成为必要
在实践中,有一个看起来非常简单的需求:
在订单列表页中,新增一个筛选条件「待发货」,
点击后,仅展示状态为 waiting 的订单。
最开始,我们尝试用一种非常直接的方式来执行:
在订单列表页中新增一个筛选条件「待发货」,
点击后展示状态为 waiting 的订单。在单次执行时,结果看起来是“正确的”。
但当我们开始多次执行,或者在不同上下文下运行时,会逐渐出现一些不一致:
这些问题有一个共同特点: 代码“看起来大致正确”,但行为不稳定。
一开始,很容易把这些问题归因到模型或提示词。
但在对比多个 case 之后,会发现一个更本质的原因: 任务本身,并没有被完整表达出来。
在这个 case 中,原始描述中其实缺少了几类关键信息:
边界(scope)
约束(constraints)
完成标准(acceptance)
当这些信息没有被明确表达时: 系统只能“猜测”任务,而不是“执行”任务。
在后续的尝试中,我们没有一开始引入完整的 Task IR, 而是只补充了最关键的三类信息:
scope:
- 订单列表页筛选区域
- 使用现有筛选组件
constraints:
- 单选,不与其他筛选条件叠加
- 保持现有筛选逻辑不变
acceptance:
- 点击「待发货」后,仅展示 status=waiting 的订单
- 列表立即刷新
- 若结果为空,展示空状态组件当这些结构被补齐之后,结果开始变得明显不同:
这时会出现一个很直观的变化:
问题不再是“模型能不能写出来”, 而是“任务有没有被表达完整”。
这个 case 并不复杂,但它揭示了一件更普遍的事情:
即使是简单任务,一旦开始要求“稳定执行”, 就需要从“描述任务”,走向“表达任务”。
也正是在这样的过程中, Task IR 并不是一开始就被引入的, 而是随着问题的出现,被一点点“逼出来”的。
系统不会理解“差不多”,它只会执行“被明确表达的部分”。

图3:任务复杂度越高,执行方式越需要从 Prompt 走向 Representation
如果把这些变化放在一起看,会发现一条非常清晰的迁移路径。
过去的软件研发,是 Spec-Driven Development:
Spec → AI → Code
Spec 是核心输入,AI 负责执行。
而现在,系统开始走向另一种结构:
Input → Representation → Execution → Validation
但真正的变化,并不只是流程的增加。
而在于: Spec 不再是终点,而只是表示的一种投影。
换句话说:
Spec 的流行,是因为我们在用更好的方式“描述任务”; 但 Representation 的出现,是因为我们开始需要: 让系统真正执行任务。
RDD 并不是对 Spec 的增强, 而是将“描述任务”转变为“构建可执行结构”。
即使 Spec 变得更加结构化, 只要执行仍然依赖解释过程, 它就无法成为系统级的可执行结构。

图4:Spec 产生多种可能路径,而 Representation 将执行收敛为单一路径
当研发开始从 Spec 驱动走向表示驱动,会带来几件非常实际的变化:
不再是: “会不会写代码”
而是: “能不能把任务表达成系统可执行的结构”
从:
需求 → 开发 → 测试
变成:
理解 → 表示 → 执行 → 验证
所有这些能力,最终都依赖: 是否存在稳定的“表示层”
当执行者发生变化时,软件研发并不会只是“更快”。 它会开始改变结构。
过去,我们关注的是: 如何更高效地实现功能。
而现在,问题正在变成: 如何让任务被系统准确地表达。
Spec 解决的是“任务如何被理解与解释”。 但当系统开始执行时,我们需要的是另一种东西。 一种可以被表达、被执行、也可以被验证的结构。 当这种结构逐渐出现时,软件研发也开始从“被使用”,走向“被运行”。
Spec 描述任务,解决理解与解释问题; Representation 让任务成为系统的一部分,解决执行与验证问题。