作者系统梳理了spec-driven development加loop engineering的组合方法论,解释了为何上下文窗口是易失内存,各种agentic方法论本质都是对抗这一限制。
来源:dev.to · AI 第 1/3 部分
上次我写了我用来交付支付基础设施的三技能工作流,以及当代码不再是瓶颈后瓶颈转移到了哪里。
AI 智能体工程不是凭感觉编程:我用来交付分布式系统的三技能循环
我认为有必要回答一个在讨论工作流时经常被问到的问题:"为什么采用这种方法?"这个领域现在有十几种命名方法,其中一些在 GitHub 上的星标数量比我整个公司的客户数量还多,而我选择这种特定组合是有特定原因的。
所以这篇文章是我希望刚开始时能有的综述。我会先诚实地走遍这片领域,包括我拒绝的部分。然后我会告诉你为什么我最终选择了规范驱动开发加循环工程,以及每一半实际上在做什么。
以下是让我看清这片领域的透镜。
上下文窗口是易失性存储器。它们会填满、会压缩、会丢失线索。每个会话都会结束并带走它的理解。因此每一种智能体方法论,每一个,无论其作者是否这样描述,都是在回答一个问题:
真相在智能体运行之间栖息于何处?
就这样。这就是整个分类学。按照方法论将持久状态停放在哪里分类,它们之间的差异就不再是营销话术而是架构设计。
让我们逐一走过它们。
真相存在于对话中。你描述,你得到代码,你肉眼检查,你继续。
我在第一部分已经讲过这部分,所以不会再争论。我只想说,对于尖峰研究、一次性脚本和探索不熟悉的 API,它仍然是最正确的工具,而它的定义特性是没有任何东西能存活于会话之外。当上下文压缩时,你的意图也随之压缩。
它在地图上的位置:原点。其他一切都是为弥补这一方法所丢失的东西而设计的策略。
真相存在于组装好的上下文中:AGENTS.md、CLAUDE.md、仓库约定、检索策略、为智能体导航设计的文件布局。
这是一门确保智能体在运行开始时读取的内容能够正确定向它的学科。现在有了真正的研究,关于面向文件的原生智能体系统的结构化上下文工程的大量工作,以及"测试夹具工程"这一新兴方向——它研究的是模型周围的脚手架而非模型本身。
我不认为上下文工程是一种竞争方法。我认为它是一种基质。其他列表上的每种方法都在做上下文工程,无论它是否承认,规范是上下文,任务列表是上下文,测试失败是上下文。明确谈论它的人只是对机制更加诚实而已。
我的看法:必要但不充分。一个完美设计的上下文仍然不会告诉你该构建什么,或者如何知道它是否有效。
真相存在于规范产物中,它比每个会话都长寿。
这是迄今为止最大的集群,值得精确定义,因为"SDD"现在至少命名了四种有实质差异的事物。共同线索是:结构化规范(通常是 Markdown,有时是机器可读的)成为权威来源,实现、测试和文档都从中派生,而不是事后编写的文档。
变体主要在它们施加多少仪式感以及将规范推向字面源代码的程度。
四阶段工作流:指定、计划、任务、实现。每个规范都继承自项目范围的"宪法",其中编码了持久规则、技术栈、约定、不可协商事项。GitHub 的分发使其成为该类别中星标最高的选项。
优点:最小仪式感、技术栈无关、宪法这个想法非常出色。缺点:针对绿地项目和合理规模的变更进行了优化;小型编辑与会话结构相冲突。
专为修改而非净新工作而构建,使用增量标记 ADDED、MODIFIED、REMOVED,因此变更提案描述的是什么发生了变化而非重述整个世界。
如果你的现实是一个成熟代码库,其中每个任务都是一次修订,这是列表中最诚实的模型。这也是运行成本最低的。
极致选项:十几个专业智能体角色,分析师、项目经理、架构师、Scrum Master、开发者、QA,沿着镜像完整 SDLC 的管道向下传递产物。
我想对 BMAD 保持公正,因为它确实令人印象深刻,而且为已经习惯 PRD 和冲刺故事teams 解决了一个真正的问题。但我发现最具说服力的批评是结构性的:角色管道的好坏取决于其最弱的交接点。当架构师做了一个项目经理从未记录过的假设时,Scrum Master 忠实地将其传播到故事中,开发者以完全自信实现它。你在 QA 或生产环境中发现它。角色越多意味着交接面越大,而交接失败是一种棘手的调试类别,因为每个智能体个体的行为都是合理的。
成本也不容小觑。一家咨询公司报告称 BMAD 运行每次工作流平均消耗低万级别 token,每位开发者每月前沿模型账单在高几百到低几千美元之间。你的情况会有很大差异,但这不是一个可以四舍五入的错误。
AWS Kiro 是一个完整的 IDE,从头内置了规范工作流,而非在其上叠加。各种"智能体开发环境"平台也是如此,它们围绕共享的活规范协调多个智能体。
权衡是明确的:以进入某人的环境为代价获得更紧密的集成。如果你的团队工具已经固定,这是一个真正的成本;如果还没有,这是一个真正的好处。
激进立场:规范是主要产物,代码是构建输出。编辑规范,重新生成。人们联想到的类比是 Terraform 或 SQL 查询规划器——你写意图,系统产生计划。
我发现这个方向正确但实践上为时过早,我会回来解释原因。
真相存在于磁盘上:任务列表、每个任务的规范、日志和 git 历史。
Geoffrey Huntley 在 2025 年中期以 Ralph Wiggum 的名字命名了这种方法,基于这样一个理论:任何单次迭代都是一次普通智能体运行,可能会有轻微偏差,而循环通过持久性和稳定的真相来源而非一个精妙的提示来获胜。最小形式简单得近乎冒犯——一个 bash while 循环,不断重新调用非交互式智能体,直到待办事项列表耗尽。
使其工作的洞见是人们错过的那个:每次迭代都会获得一个全新的上下文。单个长会话会积累疲劳,窗口会填满,压缩会丢弃细节,模型会丢失线索。一系列短会话从磁盘上的文件重新定向会保持敏锐。进度不在对话中;它在已提交的代码中、任务文件中,以及下次迭代启动时读取的日志中。
现在有了很多实现:用于可视化的 TUI、一个 Vercel Labs 包装器,它循环直到 verifyCompletion 函数通过,以及在测试门控 SDLC 内跨依赖排序待办事项运行 Ralph 的企业级报告。
关键问题,而且是一个大问题:规范 Ralph 以 --yolo 模式运行。完全权限、无确认。这要求真正的沙箱化,而且这意味着这种技术在其纯粹形式下无法用于任何糟糕迭代可以转移资金或删除表的场景。
但请注意 Ralph 实际是什么。它不是结构化开发的替代品,而是你已经拥有的结构的执行引擎。它的文档本身就说明了这一点。这个区别实际上很重要。
这种方法已经获得了认真的学术关注,在 EASE 2026 上发表了关于多智能体代码生成的 TDD 治理的研究,以及像 TDFlow 这样围绕测试驱动循环构建智能体工作流的系统。激励论证是每个分布式系统人员都会认出的:LLM 是非确定性的,相同提示产生不同输出,在多智能体设置中一个小逻辑错误会传播到整个工作流。自动化护栏不是奢侈品。
研究还发现,测试用例通过作为可执行规范来减少歧义,这与 SDD 对散文规范的主张相同,只是从不同方向得出。
它的薄弱之处:测试能完美地指定行为,却无法指定架构。测试套件无法告诉你某个模块不应该知道另一个模块的存在,无法告诉你这条队列是至少一次语义,也无法告诉你某个约束为什么会存在。测试是验证层,不是意图层。
真相存在于编排器的任务图和共享内存中。
Anthropic 的 2026 年智能体编码趋势报告描述了这种形态:一个编排器并行协调多个专业化的智能体,每个智能体拥有独立的上下文,结果被综合为统一的输出,这与单智能体工作流(通过一个上下文窗口顺序处理)形成对比。
Addy Osmani 的分层模型是我发现的最实用的实践框架:
指挥者层,子智能体在同一个会话内。不需要额外工具。你的上下文窗口大小就是上限。
本地编排层,多个智能体在隔离的 git worktree 中运行,带有仪表盘和合并控制。在大约 3-10 个智能体处理你熟悉的代码库时表现最佳。
云端异步层,分配任务、合上笔记本、回来时已经有一个 pull request 在等着你。
诚实的反面:生产级编排是一个需要多个季度才能完成的工程努力,可观测性工具无法开箱即用地处理非确定性流程,而且 Thoughtworks 的技术雷达一直在标记着随 AI 辅助开发规模扩大而累积的认知债务——这是我第一部分中提到的评审瓶颈的組織版本。
我的观点:编排是一种执行策略,不是方法论。它回答的是"同时运行多少个",而不是"朝着什么目标"。
真正重要的五个维度
剥掉各种 branding,我认为你在以下五个维度上做选择:
可重新推导性是我在纸上会画三遍下划线的那一个。大多数评估 SDD 的团队问的是:这份规格说明是否是好文档。这是错误的问题,而且这个问题会让你得到一份没人维护的规格说明。
以下是我的真实推理过程,与其说是在挑选赢家,不如说是在注意到其中两个类别在回答不同的问题,因此可以组合。
规格作为锚点,而锚点让你能重新推导
我最关心的属性是能够实现再生成的持久性。
当我拥有一份编写完善的 PRD 时,我持有的不是对已构建内容的描述。我是持有着生成工作的那个东西。这给了我三个我不会放弃的能力:
第一,我可以在同一个需求上迭代很多次。不是"修改代码",而是修改需求,让下游的一切随之跟进。变更的单元上移了一级。
第二,我可以扇出。一个产物生成多个任务。PRD 是源头;issues 是派生出来的;实现又是从那些 issues 派生出来的。这是一棵有单一根节点的树,我控制着根节点,而不是一堆需要协调的聊天会话。
第三,也是说服我的那一个:我可以丢弃实现。当一个智能体在第四个切片上脱轨了——因为它发明了一个没人写下来的假设——我不是去调试智能体的推理,也不是把代码奶回来。我去到那份文档,修复假设,然后重新生成。完全重新生成。需要多少次就重新生成多少次。
心态上的转变:实现变成了可丢弃的,而规格说明变成了资产。这与我曾经受训的关系相反,在那种关系里代码是你保护的东西,而文档是你懒得维护的东西。
注意这是规格作为源代码的论点,但我故意只采纳了其中一部分。我不接受"规格编译成代码,你永远不需要看输出"。在支付领域,我必须能够阅读、拥有并对待交付的东西负责。我接受的是那个更弱但更有用的主张:规格是工作重新推导的来源。代码保持可审查和可拥有的状态。它只是不再被当作珍贵的东西了。
循环是锚点被修正的方式
以下是 spec-driven development 做不到的事:保证规格说明是正确的。
规格说明是一个假设。它是一个好的假设,它经过了澄清问题和人工审查,但它是在与实际系统接触之前编写的,我的规格说明经常以我无法预测的方式出错。单独的规格驱动开发,加上没有反馈机制,就是带有更好工具的瀑布开发。同样的失败模式,只是更快。
这就是循环工程存在的意义,我想精确地说明我从中学到了什么。不是 --yolo 式的自主权。我从中提取了结构性的洞察:
每次迭代使用全新上下文,胜过一次漫长的衰退会话
状态在磁盘上、任务文件、日志、git 历史,是记忆层,不是聊天层
明确的停止条件,这样循环在收到信号时结束,而不是靠猜测
验证委托到循环内部,这样智能体在交给我之前先找到自己的错误
应用在规格之上,循环不再是蛮力,而变成了更有用的东西:一种使规格假设失效并将修正推向上游的机制。验证在第二个切片上失败,背后的假设是错的,PRD 被编辑了,第三到第七个切片在智能体接触它们之前就重新推导了。
这就是我在第一部分描述的级联。它之所以有效,是因为两部分都存在。
用控制理论来表述,因为这就是它
对于任何构建过分布式系统的人来说,这个框架会立即落地:
spec ────────▶ SETPOINT (what "correct" means)
│
▼
agent ────────▶ ACTUATOR (does the thing)
│
▼
loop ────────▶ FEEDBACK (measures the gap, corrects)
│
└──────▶ error signal updates the SETPOINT
when the setpoint was the problem
没有循环的规格是开环控制。推算导航。在现实偏离你的模型之前没问题,然后你会很晚才发现。
没有规格的循环是一个没有设定点的控制器。它会可靠地、持续地、愉快地收敛到某个东西,只是不一定是你想要的那个。或者它会振荡。
两者都有就是带定义目标和误差信号的闭环控制,误差信号可以修正目标本身。
这不是一个新想法。这是工程中最古老的想法,应用在一个新的执行器上。这大概就是为什么我比那些感觉上更"新"的方法更信任它的原因。
方法论不是球队。你不需要选一个然后穿上它的球衣:
从 Spec Kit 那里,宪法这个想法。每个规格都继承的持久项目级规则,这样我就不用在每个 PRD 中重复陈述不可协商的事项。
从 OpenSpec 那里,delta 思维。我大部分工作是修订,不是创作,描述变更的规格胜过重新陈述整个世界的规格。
从 TDD governance 那里,测试作为循环的真实依据。属性测试和契约测试使得智能体的自我修正有意义,而不是自我感觉良好。
从编排那里,由依赖图限定的并行化,以及 worktree 隔离。作为循环下的执行策略,而不是作为循环本身。
从安全研究那里,这是我最喜欢的一个。有工作在研究"宪章式"SDD,它将不可协商的安全约束嵌入规格层,这些约束来自 CWE/MITRE Top 25 和监管框架,这样生成的代码通过构造满足它们,而不是通过检查。如果你读了第一部分,你就会知道为什么这对我很有意义。这就是合规瓶颈,在唯一能廉价解决的地方解决了:上游,在 artifact 中。
BMAD,那个交接面。在一个静默传播的错误假设意味着重复扣款的领域,我想要更少的智能体间边界,不是更多。还有 token 账单。
Canonical Ralph,我采纳了模式但去掉了 --yolo。在资金流动路径上的人工门槛是不可协商的,这与纯粹形式不兼容。
Kiro 和平台层,对于一个棕地支付代码库,我不打算迁移环境。对其他人来说这是一个不错的权衡,但不适合我。
TDD governance 作为一个完整方法论,拒绝,因为测试无法承载架构意图。但对这个持保留态度;我会在结尾再次提到它,而且我对它的立场已经改变了。
我宁愿自己说出来,也不愿被人问到。
我对这些工具找到的最严谨的比较指出了两件让任何 SDD 拥护者都应该 pause 的事情。第一:对于微不足道的变更,SDD 何时增加价值而不是带来开销,这确实不清楚——更重的框架是杀鸡用牛刀。第二,更尖锐的:与模型驱动开发的历史类比,后者在 2000 年代做出了结构上类似的承诺,却没有在真实软件的生命周期中存活下来。
我认为反驳者的观点有一定道理:MDD 失败的部分原因在于生成步骤过于僵硬,抽象层次泄漏严重——你得到的是无法修改的代码,而模型无法表达真实系统。LLM 生成的实现是可读的、可编辑的、地道的,规范是纯文本。这是截然不同的失败面。
但我也不执于此。诚实的版本是:Stack Overflow 的数据一直在告诉我们,采用率不是问题,大多数开发者都在使用这些工具,但信任其输出的却少得多。这份列表上的每一种方法论都是对如何弥合这一差距的一次押注。我的也是。
我想在这里谨慎一点,因为"视情况而定"是人们没深入思考某件事时说的话。我认真想过,但仍然视情况而定,原因有两点,值得分开说。
第一个原因是你的约束条件确实和我不同。爆炸半径、棕地与绿地、团队规模、监管姿态、有多少工作是修订性的。这些都是真实的输入,它们指向不同的答案。
但还有一个更软的输入,我认为它被过于轻易地Dismiss了:你的实现偏好是一个真实的工程约束,而不是性格怪癖。一个你在第三周就放弃的方法论具有负价值——你付出了搭建成本,却没有获得任何复利。如果一个七角色管道让你想合上笔记本,那就是数据。你不会持续进行的仪式比你从未采用的仪式更糟糕。
第二个原因是,地面在移动,而且移动得很快。不只是工具链,还有模型。它们在方法论设计所关心的方面各不相同:指令遵循能力、在长上下文下优雅降级的程度、当规范模糊时是提问还是假设、以及它们各自的典型失败模式是什么。
这就引出了关于整份 field guide 的一个令人不安的观察:
我们称为方法论的很大一部分,实际上是给特定模型的错误纠正挂了个好听的名字。其中一些实践的存在是为了弥补特定一代模型的特定失败模式。当模型改变时,这种补偿可能变得不必要,或者不够充分。
所以,把上面的一切——包括我的在内——当作一张快照来对待。换模型时重新调整。注意你的哪些习惯是承重的,哪些是疤痕组织。
这里我要少一些犹豫。我不认为存在完美的方法论。但我确实认为一个非常好的方法论的形状现在已经清晰了,而且它不在这份列表的任何单一选项中。
它是由三层构成,每层做三件真正不同的事,彼此之间没有重叠:
早些时候在这篇文章中,我把控制循环画成了两个组件。这是不完整的,而且是故意的,因为我想要在这里呈现出来。完整的图景:
spec ────────▶ SETPOINT what "correct" means
│
▼
agent ────────▶ ACTUATOR does the thing
│
▼
tests ────────▶ SENSOR measures reality, honestly
│
▼
loop ────────▶ CONTROLLER computes the error, acts on it
│
└───────▶ and when the error is in the SETPOINT
itself, corrects upstream
添加 sensor 不是装饰点缀,这是我之前搞错的部分。一个反馈循环如果 sensor 不可信,比没有循环更糟糕,因为它会以机器的速度自信地、持续地、稳定地收敛到错误的方向。这正是一个智能体从与生成代码相同的误解中编写自己的测试时的失败模式。它测量,它与自身一致,它继续前进。
这就是为什么我把 TDD 治理从"我借来的组件"提升到了平等层。规范驱动的开发给了循环一个收敛目标。测试治理给了它一个收敛依据。去掉任何一个,第三个就会停止工作。
如果三层是骨架,那么各个框架就变成了零件箱,而不是相互竞争的宗教。
去采购之前有两个警告。
每一层现在都是一个你需要保持真实的制品。组合有复利的维护成本,混合体的失败模式是一份不再描述系统的规范,阻塞信任它的智能体。只有在你愿意维护的情况下才采用某一层。
不要把组合和累积混为一谈。把六个框架绑在一起得到的是它们仪式的并集和它们收益的交集。关键是从中各取一个能做其他东西做不到的事的东西,而且要能说清楚那个工作是什么。
所以,四个问题,它们是关于组合而非选择的:
是修订还是创建?→ 增量规范与阶段结构规范。
你付出错误的代价是多少?→ 决定你需要多少 sensor 以及人类关卡放在哪里。
重新推导还是仅做记录?→ 如果你永远不会从制品重新生成,你就是在维护文档,而它会像文档一直以来的那样腐烂。
你能实际持续多少仪式预算?→ 诚实地回答,不是愿景式地回答。
一旦看到这三层,显而易见的动作就是不再把它们当作三个并发运行的方法论,而是当作一个具有单一控制流的策略来对待。意图、验证和纠正在一个系统中作为一等公民的阶段,而不是三种你在手动保持同步的实践。
这就是我一直在做的事情。它是一个混合体,在锚点处由规范驱动,在关卡处由测试治理,在纠正步骤由循环驱动,而有趣的问题出现在接缝处:sensor 如何从规范中派生而不继承其盲点,以及当循环断定 setpoint 本身错了时究竟会发生什么。
这是下一篇文章的内容。
与此同时:如果你正在运行一个我没有覆盖的组合,特别是如果你已经让角色管道方法在大规模下工作了,因为我很想被证明是错的,告诉我哪里出了问题,哪里站住了。
这是关于智能体工程的系列文章的第二部分。