☰
Agent开发范式转型:从spec coding到意图驱动与验证驱动
2026/10/28 7:37:11 网站建设 项目流程

前几天帮一个团队梳理 Agent 开发流程,负责人很认真地跟我讲:他们第一步先把业务需求写成一份完整的 spec,字段、接口、边界条件全部列清楚,然后让 Agent 照着 spec 把代码写出来。听完我只问了一句:你的 Agent 在真实环境里跑了一周之后,被用户纠正过几次?他愣了一下,说好像还挺多次的。这就是 spec coding 这条路最典型的幻觉——你以为自己在给 Agent 传递需求,实际上只是在给一段静态文本做一次性的押注。我写这篇文章不是要否定规格文档本身,而是要说说为什么在 Agent 开发这个场景里,spec coding 已经从"可用的方法论"变成了"拖后腿的旧习惯",以及现在用意图驱动加验证驱动的方式,到底应该怎么落地。

如果你正在做 AI Agent 开发,或者打算转行做 Agent 方向,手里也囤了一堆"agent开发学习路线""agent开发教程"之类的东西,大概率会被灌入一个经典流程:理清楚业务需求、写规格、建模、再让模型生成代码。这套流程在传统软件工程里没问题,但放到 Agent 开发里,它恰恰是最容易翻车的一步。这篇文章适合所有想把 Agent 做成"能自我纠错、能应对真实需求漂移"的开发者,也适合那些还在纠结"为什么我的 Agent 明明照着 spec 写的,跑起来还是一团糟"的团队。

1. spec coding 曾经是对的:为什么"先写规格再写代码"会有市场

1.1 传统软件开发留下的惯性

先说清楚我指的 spec coding 是什么。它不是指写接口文档,也不是指写 PRD,而是指一种更深层的开发方式:在让大模型写代码之前,先穷尽式地把需求描述为机器可解析的规格——用户故事、验收条件、字段定义、接口签名、异常分支,全部落到文字上,然后让模型"照着这份规格把代码生成出来"。说白了,就是把大模型当成一个严格的函数,输入 spec,输出 code。

这个思路在传统软件开发里确实有市场,也经得起考验。你看传统的软件工程,无论是瀑布模型还是敏捷里的用户故事拆解,本质都是"先定义再实现"。因为人的认知带宽有限,代码评审、测试用例、维护成本都要求你尽可能早地冻结需求。就连外包行业也一样,一份合同如果没有清晰的规格,验收的时候就是互相扯皮。所以"先写清楚再动手"成了绝大多数程序员刻在骨子里的肌肉记忆,这套流程也被顺理成章地迁移到了 Agent 开发上。

我见过很多团队的早期尝试,都是从给 Agent 写 spec 开始的:定义好"用户输入什么,系统返回什么",定义好"当库存不足时应该报什么错",定义好"这个路由应该调用哪个 service"。在一开始,这套做法真的能跑通。因为那时候的 Agent 应用大多是窄场景、单步骤、可枚举的,比如一个表单校验器、一个根据关键词检索文档的工具、一个把 Markdown 转成 HTML 的脚本。任务边界清晰,失败模式有限,规格能把不确定性压到最低。

1.2 spec coding 在早期 Agent 时代的真实价值

还有一个现实问题:早期大模型的指令跟随能力没那么强,一个含糊的需求它可能给你生成完全跑不通的代码。Spec 在这里扮演的角色其实是"降噪器"。你把边界条件列得越细,模型越不容易自由发挥,也越容易被验证对错。这个阶段的核心诉求是"让生成结果稳定",而 spec 是当时唯一有效的稳定手段。

再加上团队协作上的便利。一个 Agent 项目如果参与的人多,总得有份文档同步认知,不然前端一个说法、后端一个说法,最后模型生成的接口谁也对接不上。Spec 在这里就是一个"对齐工具"。我记得有个朋友做内部知识库 Agent,他们团队就是靠 spec 把十几个检索接口的字段对齐的,没有 spec 的话,连 prompt 都写不下去。所以我要先把这个背景讲清楚:spec coding 不是从一开始就错,它在特定条件下确实解决过问题。

1.3 你依赖的 spec 其实是在跟编译器说话,而不是在跟 Agent 对话

但这里有个关键的认知陷阱:spec coding 的本质,是把 Agent 当成编译器来对待。传统编译器接收的是语法严格、语义确定的源代码,你给它一份精确到字节的规格,它就能给你一个确定性的输出。可 Agent 不是编译器,它是一个在环境中不断感知、推理、行动、再感知的循环体。它面对的不是"输入秒返回"的纯函数问题,而是"这个步骤做完之后下一步该做什么"的序贯决策问题。

你把一份 spec 丢给 Agent,就像给一个人发了一张十年前的地图,然后让他去一个每天都在拆迁的城市里送外卖。地图没错,城市也没错,错的是你把静态描述当成了动态现实的替代品。这个区别在传统开发里不明显,因为你交付的是一个程序,程序的行为在发布那一刻就固化了。但 Agent 交付的是一个持续运行的决策体,它在第一分钟、第一小时、第一周面对的世界完全不一样。用 spec 去框定它,本质上是在用一个旧时刻的快照,去约束一个不断流动的未来。

我第一次意识到这个问题,是在一个客服工单 Agent 上。当时我们的 spec 写得极其详细,甚至连用户骂人的时候应该怎么回复都有模板。结果上线第二天,一个用户提出了一个 spec 里完全没有覆盖到的诉求:他要求先把一个历史订单拆单,再把其中一个子订单改地址,然后还要用原订单的优惠券。这个路径在我们的规格表里不存在,Agent 当场就卡死了。它不是不会写代码,它是没有"面对意外路径继续推理"的机制。那一刻我才明白,spec coding 教会 Agent 的是"按图索骥",而真实世界教给我们的却是"图永远赶不上变化"。

2. 当 Agent 从"执行器"变成"协作者":spec 的粒度假设开始失效

2.1 任务不确定性的本质变化

为什么 spec 在 Agent 开发里越来越使不上劲?最根本的原因是任务不确定性的位置变了。在传统程序里,不确定性集中在需求层:需求想清楚之后,代码就是确定性的翻译。而在 Agent 开发里,不确定性分布在三层:需求层之外,还多了环境层和意图层。

环境层的不确定性,是 Agent 运行过程中工具返回的结果、用户输入的口语化表达、外部系统的状态随时在变。意图层的不确定性,是用户的真实目标往往只通过两三句模糊的话表达出来,Agent 必须追问、澄清、判断。这两个层面,都没有办法用静态 spec 提前穷举。你见过哪个 spec 能提前写出"第 37 次对话时用户会突然把话题从退款转到投诉物流"的?如果真有人写出来,那已经不是 spec 了,那是一份剧情脚本。

我在做 Agent 开发时有一个很强烈的体感:一份规格文档写得越长,Agent 面对新情况时的灵活性就越差。因为模型会把规格当成一个强约束,凡是规格之外的行为,它倾向于不执行。这就像给小孩立了太多规矩,结果小孩连基本的自主判断都丧失了。你真正想要的是一个"在约束范围内自由行动"的 Agent,而不是一个"在语义牢笼里做文字填空"的程序。

2.2 需求漂移与规格冻结的矛盾

还有个更现实的问题:业务需求本身就在漂移。传统软件工程里,我们可以通过"需求冻结"来保护开发周期,但 Agent 开发做不到,因为 Agent 往往直接面向最终用户,需求是长在真实对话里的。用户今天跟你说"帮我整理报销单",明天可能变成"帮我从报销单里找出超预算的项并给财务发提醒",后天又变成"每周五自动生成本周的报销异常报告"。这个演进过程如果每次都要先改 spec、评审 spec、再让 Agent 重读 spec,开发节奏根本跑不起来。

我可以拿一个真实的 Django 项目举例。我们当时做一个内部订单管理系统,打算用 Agent 辅助开发:让 Agent 先读 spec 生成 model 和 view。第一版 spec 写了字段、校验规则、接口路径,开发速度确实快,一天就生成了基本骨架。但第二天业务方就来了新需求:订单要加一个"取消原因分类",而且取消后的库存要回滚到上一个操作节点。按 spec 逻辑,我们得先改文档,再让 Agent 重新生成迁移脚本。结果 Agent 生成的迁移脚本直接删掉了两个原有字段,因为 spec 里没写这两个字段是否要保留。后来我把 spec 里的"字段定义"改成"必须通过的测试用例",让 Agent 自己去看现有代码、跑测试、再动手迁移,反而再没出过这种低级事故。

这个案例给我的启示是:Agent 开发里的需求不是被"冻结"的,而是被"验证"的。与其花三天把 spec 写得完美无缺,不如花三小时把验证路径搭好,然后让 Agent 在真实环境里不断试错。规格冻结只会让你延迟发现需求已经变了,而验证驱动能让你第一时间感知变化。

2.3 一份 200 行 spec 被 Agent 改掉 80% 的真实案例

去年我帮一个朋友看他的数据分析 Agent,他们团队走了完整的 spec coding 路线:PRD、接口矩阵、异常码表、级联流程图,洋洋洒洒两百行。结果怎么样?Agent 生成的代码第一版就跑不通,问题恰好出在 spec 最自信的地方——他们把"数据清洗规则"写死了,认为所有输入数据都必须符合"日期统一 YYYY-MM-DD,金额统一保留两位小数"的格式。实际数据里,日期有 2024.1.1、有 2024/01/01、还有"一月一号",金额有三位小数、有货币符号、还有千分位逗号。真实世界的数据根本没有按 spec 出牌。

后来他们换了一种方式:不再维护那份 200 行的 spec,而是把清洗规则写成一堆可执行的测试用例——"输入 '2024.1.1' 应该输出 '2024-01-01'"、"输入 '1,234.5元' 应该输出 '1234.50'"。每次 Agent 修改代码,就跑一遍测试集,挂了就带着报错信息回去改。改动最频繁的那一周,Agent 自己重写了 80% 的清洗逻辑,最后正确率从 61% 提到了 92%。那份 spec 的结局是被丢进了 archive 文件夹。

这个案例特别典型:spec 描述的是"你应该怎么做",测试用例描述的是"你要做到什么效果"。对于 Agent 这种"会自己想办法"的系统,后者远比前者重要。你把"怎么做"规定死了,Agent 的自由度没了;你把"做到什么效果"规定清楚,Agent 反而能在试错中找到更好的路径。

3. 决定落后与否的关键:Agent 的调试对象变了

3.1 旧模式:调试的是代码,spec 是"一次性需求文档"

传统开发里,程序员调试的是什么?调试的是代码。Spec 是需求文档,它只参与开发流程的起点,代码写完、测试一过,spec 基本就成了历史档案。后续维护、排查 bug,你读的是代码,不是 spec。就算代码和 spec 不一致,那也是改代码或者改 spec,但调试动作本身永远是围绕代码展开的。

到了 Agent 开发里,这个逻辑开始失灵。你的 Agent 跑出来的"代码",只是一条长链中的一个环节。真正需要你调试的是 Agent 的推理链路:它看到什么上下文、选择了哪个工具、基于什么依据做出了判断、路径走偏之后有没有自己绕回来。这些东西不是 spec 能描述的,也不是静态代码审查能覆盖的。我见过太多团队在 Agent 出了问题之后,第一反应是去翻 spec,"规格上明明写了应该先调用订单接口再调用库存接口"。但问题的根源根本不在调用顺序,而在 Agent 的上下文里根本没有足够的信息判断当前该调用哪个接口。

3.2 新模式:调试的是推理链和上下文,spec 缩成"动态约束集"

所以在 Agent 开发里,核心调试对象变了两样:推理链和上下文。

推理链指 Agent 从接收任务到最终输出的完整决策路径,你必须能随时查看它每一步的理由。这也是为什么现在主流框架都在做 trace、做观察面板的原因——没有 trace,Agent 出错了你连从哪下手都不知道。我自己的习惯是每一轮关键行动都让 Agent 输出一个"决策摘要":我为什么选这个工具、我看到了什么、下一步计划是什么。这样出了问题之后,我能像对着 X 光片一样,一眼看到是哪一步推理出了偏差。

上下文指 Agent 在决策时手里掌握的全部信息,包括系统提示、用户消息、工具返回、历史记录、临时备注。这里有个反直觉的点:给 Agent 的上下文不是越多越好。上下文一多,模型容易丢失关键信号,再加上 token 成本、响应延迟,实际效果往往比精简上下文还差。Spec 在新范式里的角色,其实应该从"每时每刻都必须遵守的完整画册"变成"只在关键决策点引用的一组动态约束"。比如"金额字段必须始终以分为单位存储""所有对外输出都必须经过脱敏检查",这类约束保留;但"清洗规则应该怎么写"这类实现细节,不再放进 spec,而是放进测试用例。

3.3 从"规格驱动"到"意图驱动 + 验证驱动"的新路径

那正确的路径是什么?我现在比较认可的思路是"意图驱动 + 验证驱动"的组合。

意图驱动不是说不要规格,而是把对"用户真实目标"的持续澄清作为开发的第一优先级。Agent 不能假设它第一次就理解了用户意图,它必须主动追问、确认、复述,并在后续对话中根据用户的反馈不断修正自己的理解。这个能力比"准确的接口返回值"更重要。你可以把意图理解想象成谈恋爱:你不能因为对方第一天答应了你,就认为以后每天都应该按照第一天的约定来生活。关系是动态维护的,意图也是。

验证驱动则是把"效果可测量"作为开发的第二优先级。你给 Agent 的每个行为变化,都配套一个可执行的验收机制。测试用例是最常见的一种,日志断言、工具返回检查、端到端演练也都算。核心原则是:Agent 每次改动之后,你能在几分钟内知道它改对了没有,而不是等到上线之后由用户来替你验收。

为了把这两条路径讲得更清楚,我做个对比表格:

开发维度spec coding(规格驱动)意图驱动 + 验证驱动
需求来源需求被提前穷尽并写进文档需求在交互中持续澄清和演化
交付物重心规格文档、接口定义可运行的 Agent、验证用例、trace 日志
变更处理先改文档再改代码先改验证逻辑再让 Agent 自我调整
出错调试对照 spec 查代码查看推理链、上下文、测试报错
不确定性容忍度低,依赖穷举高,依赖反馈循环
核心风险需求漂移、规则之外失能验证不全面、意图误判

我之前带过一个 Agent 开发的新人,她一开始特别执着于写 spec,每次改动需求都要先把文档更新一遍。我告诉她一个很简单的判断标准:你写的这段 spec,如果删掉之后 Agent 依然能靠测试用例跑对,那它就是在浪费体力;如果删掉之后 Agent 立刻跑错,那它才是真正的约束。从那以后她写的东西越来越少,但 Agent 的稳定性反而越来越高了。

4. 验证驱动开发在 Agent 场景里的落地做法:任务沙盒、测试回环与上下文压缩

4.1 把 spec 拆成任务沙盒而不是规格书

既然 spec coding 不再是主角,实际开发时第一步应该做什么?我的答案是"搭任务沙盒"。

任务沙盒可以理解为一个最小可运行的实验环境:一个临时的数据源、一组模拟的工具接口、一套可以随时触发的验证脚本,以及你自己写的 prompt 骨架。开发一个 Agent 功能时,第一步不是铺开文档,而是把这个沙盒跑起来,哪怕只能处理一个最最简单的场景。

举个例子,我要让 Agent 辅助开发一个 Django 订单模块。我不会先去写 100 行的接口规格,而是先把本地数据库跑起来,造几条假订单数据,然后给 Agent 一个非常简单的任务提示:

你是一个 Django 后端助手。当前仓库里已有一个简单的 Order 模型,字段包括 order_id、amount、status、created_at。你的任务是: 1. 检查现有 model 和 migration 状态; 2. 新增一个 pending_reason 字段,允许为空; 3. 写一个函数 get_pending_orders(),返回所有 status='pending' 的订单,且按创建时间升序排序; 4. 跑通 pytest 里的订单测试,测试文件在 tests/test_orders.py。 完成后用 git diff 输出你的改动摘要,并说明每个测试用例的通过情况。

注意这里我没有写字段长度、外键关系、排序方向这些实现细节,我只写了目标和验证方式。Agent 可以自己去看现有代码,自己决定怎么加字段、怎么处理迁移。然后我在沙盒里配套一个 pytest 文件,里面是几条行为断言:

def test_pending_reason_can_be_null(db): order = Order.objects.create(order_id="SO-001", amount=100.00, status="pending") assert order.pending_reason is None def test_get_pending_orders_sorted(old_order, new_order): orders = get_pending_orders() assert list(orders) == [old_order, new_order]

测试用例就是 Agent 的"导航系统"。它不需要知道路径,只需要知道终点。路径对不对,跑一遍测试就知道了。这样做的另一个好处是:Agent 改错了,测试报错信息会直接回流到它的上下文里,它自己就能迭代修复,不需要你扮演一个人工调试器。

4.2 测试回环:把断言焊进 Agent 的工作流

任务沙盒搭建好之后,第二个落地动作是设计"测试回环"。这个概念我目前用的是三步循环:

第一步,Agent 执行动作,生成代码或修改配置;第二步,自动运行相关测试和静态检查;第三步,把失败信息、日志、trace 原样塞回 Agent 的上下文,让它基于错误信息自我修复。然后循环,直到测试全部通过。

这套机制看似简单,但有一个关键细节容易忽略:你必须给 Agent 设置"回环次数上限",并且明确规定"超过上限后必须停下来向人类求助"。否则 Agent 会在同一个坑里无限打转,浪费 token 不说,还可能越改越乱。我见过很多团队踩这个坑,Agent 一句话不说,默默重试了 20 次,每次都是同样的错误。根源就是没有设置"放弃并报告"的条件。

测试回环里另一个实用技巧是"失败快照"。每次测试挂掉的时候,把当时的输入、上下文摘要、Agent 决策理由、报错输出存下来,作为这个 Agent 的"学习样本"。下次再遇到类似问题时,你可以把这些样本作为 few-shot 示例塞进上下文。这比在 spec 里写一万字"不要犯这个错误"有效得多。因为模型学习的是具体的失败模式,不是抽象的行为准则。

4.3 上下文管理:定期压缩比追加规格更重要

还有一个容易忽视的点:上下文管理。Agent 的对话历史和工具返回信息会不断堆积,如果你一直往上追加内容,最后模型会被淹没在噪声里。我的经验是给 Agent 设计一个"上下文压缩机制",目前最常用的有三种:

第一种是"结论沉淀法"。每一轮任务结束后,把最终验证过的结论(比如"orders 表新增的字段是 pending_reason,类型为 varchar(255)")写入一个摘要节点,旧的推理过程直接丢弃。第二种是"定期裁剪法"。超过 N 轮的历史消息,只保留最近的关键决策摘要和用户的原始诉求,其他全部删掉。第三种是"外部记忆法"。把需要长期保留的知识存到向量数据库或记录文件里,Agent 在需要时检索,而不是把全文放在上下文中。

这个操作的意义在于:spec coding 的思维是"文档越全越好,上下文越多越好",但实际跑 Agent 的时候,上下文质量远比数量重要。你想想,如果让一个人带着 50 本操作手册去做客服,他能全部记住吗?不能。正确的做法是把手册压缩成一页速查表,需要细节的时候再去查完整文档。

4.4 工具链选型与团队协作上的配套调整

在工具链上,我目前的推荐组合不会太花哨:代码仓库用 git,测试框架用 pytest(Python 生态)或 vitest(前端生态),Agent 编排框架选择你熟悉的那一种就行,重点是必须有 trace 能力。这里的核心不是"用什么框架",而是"能不能看到每一步的推理过程"。没有 trace 功能的 Agent 框架,用起来就像在没有仪表盘的飞机里开盲飞,团队里的工程师迟早会崩溃。

团队协作方式的调整同样重要。过去你们可能习惯用"文档评审"来推进项目,现在需要改成"测试评审 + 行为演示"。让 Agent 跑一遍关键流程,展示它处理的对话记录和决策理由,比读 50 行 spec 更能暴露问题。我在团队内部推行了一个规则:每个 Agent 功能必须有三个产出物——可见的行为演示、可重复的验证脚本、一段不超过 200 字的运行说明。超出 200 字的说明,往往意味着你的 Agent 链路设计得太复杂了。

5. 什么时候还在用 spec coding 也合理,什么时候必须转型

5.1 适合 spec coding 的保留场景与判断标准

写到这里,我不想制造一个"spec 一无是处"的错觉。在某些场景里,spec coding 依然是最高效的路径,而且我不认为它会被彻底淘汰。什么场景?我总结下来有三个特点:任务边界可枚举、验收标准可自动化、运行环境相对封闭。

典型的例子是"根据 OpenAPI 文档生成 SDK 客户端"。输入是一份规范明确的接口文档,输出是确定的客户端代码,验收标准就是编译通过 + 接口字段一一对应,这个场景用 spec 驱动,效率最高。再比如批量生成 CRUD 接口、根据数据库表结构生成 model 定义、按照设计稿生成固定布局的页面,这些都是"规格即是需求本身"的场景。你想让 Agent 做得越规范越好,越可预测越好,那就给它一份越精确的 spec 越好。

判断标准也很简单:如果你的任务在人与人之间交接时,只需要一份 excel 或 md 就能说清楚,那 spec coding 就还是最合适的。真正需要转型的,是那些"人与人之间交接都得聊半小时才能对齐"的任务——因为这种隐藏的不确定性,不是文档能承载的,必须靠交互和验证来消化。

5.2 团队协作方式的变化:从文档评审到小步验证

我观察到,从 spec coding 转型到意图驱动 + 验证驱动的团队,协作节奏会有一个明显变化。以前是一个大阶段的文档评审,后面跟着一个长周期的开发;现在是每天都有无数次"小步验证",每一个改动都立刻在沙盒里跑一遍。这种节奏对工程师的素质要求也在变化:你不再需要"能把需求翻译成规格的人",而是需要"能为 Agent 构建反馈回路的人"。

换句话说,你要从"写文档让 Agent 听你的",变成"设计验证让 Agent 自己纠错"。我记得有一次,我们一个功能上线前,业务方临时要求修改审核规则。放在以前,这意味着要改一份规格书、重新评审、重新开发,至少两三天。那次我们只改了三个测试用例,然后让 Agent 自己看着报错调整代码,两个小时后新版逻辑就部署到了测试环境。这个效率差,本质上不是大模型的进步,而是开发范式转变带来的红利。

5.3 判断团队 Agent 开发成熟度的三个信号

最后给三个信号,你可以拿来自检自己的团队是不是还在走 spec coding 的老路。

第一个信号:需求澄清是否占用了超过一半的交互时间。如果你的 Agent 在对话里只是机械执行指令,从不追问、从不复述、从不确认,那它在真实环境里多半会频繁出错。成熟的 Agent 应该花大量时间在"确认意图"上,而不是急着执行。

第二个信号:Agent 运行失败之后,你的第一反应是什么。如果第一反应是"改 spec,补充一条规则,然后再跑一遍",那说明你还是旧的调试心智。成熟的做法是去看 trace,看它在哪一步做了错误判断,然后调整上下文结构或验证条件,让 Agent 有能力自己修正决策路径。补规则是打地鼠,调链路才是治本。

第三个信号:你的团队还在不在一份 80 页的需求文档上做评审。如果还在,说明你潜意识里还是把 Agent 当成编译器,而不是协作者。真正成熟的团队,评审的是一堆测试用例和几条核心 trace,文档是支撑这些素材的注释,而不是发布的中心。

我个人的体感是,这个转型过程有点像是"从给孩子画好每一步的路线图,变成给他指南针、地图和他自己的脚"。Spec 依然可以在关键时刻提供方向,但你不可能用一张静态图纸,覆盖一条正在不断生长的河流。Agent 开发的价值不在于"生成符合规格的代码",而在于"构建一个能够面对意外、持续修正自己行为的新物种"。早点把重心从写规格移到搭验证环上,你的 Agent 会给你省下大量的兜底时间,这是我现在最深刻的体会。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询