ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

规范先行,测试兜底:在存量代码中构建 AI Agent 系统

规范先行,测试兜底:在存量代码中构建 AI Agent 系统 SDD 划定什么是合法TDD 守住合法不被悄悄破坏。引言我们的指标问数产品一直在持续迭代。新功能要建立在旧代码之上每一次改动都得穿过已有的模块边界阻力并不小。项目早期靠的是 vibe coding功能出得很快。但版本迭代多了之后新旧代码越来越难融合代码逐渐失控下游配置会在不知不觉中失效往往要等到运行时报错才发现某个字段的默认值被人无意间改掉了或者某个 Agent 的装配逻辑经过几轮重构后早已偏离最初的设计。问题不在于人不够细心而在于缺少一套机制。存量代码这么大规模单靠经验和 code review 去维持稳定代价实在太高。为此我们引入了两套方法论SDD规范驱动开发和TDD测试驱动开发。本文想分享这段实践以及这两种方法是如何在 AI Agent 系统的迭代中相互咬合、彼此成就的。什么是 SDDSDD 的核心主张可以浓缩成一句话规范是唯一的真相代码只是规范的实现。在传统开发里代码才是真相。想知道某个接口接收什么参数、某个模块有哪些合法状态往往只能去读源码。文档跟不上变化、注释慢慢过时、口头约定被人遗忘——这些几乎是每个团队都躲不开的老问题。SDD 把这个顺序倒了过来先定义规范再动手写实现。规范不只是一份文档更是一套可执行的约束——它划定了什么合法、什么不合法并且由机器强制执行而不是寄望于人的自律。什么是 TDDTDD 的核心主张同样可以浓缩成一句测试要先于实现存在。它不是写完代码再补测试而是先写测试再写实现最后才重构。测试在这里不是质量保障的最后一道关卡而是一件设计工具——先把测试写出来会逼着你提前想清楚接口该长什么样、边界在哪里、异常路径怎么处理。写实现是为了让测试通过而不是反过来让测试去迁就实现。两者的关系SDD 和 TDD 不是彼此竞争的关系而是相互补位SDD 负责把规范定下来TDD 负责守住这份规范不被破坏。问题谁来回答什么是合法输入SDD — Schema 字段定义合法输入产生正确输出吗TDD — 测试断言验证默认值是什么SDD — 字段默认值声明默认值有没有被改坏TDD — 锁定默认值的测试接口契约是什么SDD — 类型签名与约束契约有没有被破坏TDD — 测试失败即报警SDD 定义合法TDD 保证合法不被破坏。二者缺一不可只有规范没有测试规范早晚会被悄悄破坏只有测试没有规范验证逻辑又会散落各处重复而且容易跑偏。实践一Agent 配置的 Schema 规范Agent 协作框架需要一套配置系统来描述一个 Team 由哪些 Agent 组成每个 Agent 又挂载了哪些技能和工具。我们没有一上来就写代码而是先把数据结构定义清楚。Schema 用声明的方式回答了所有关于什么是合法 Team 配置的问题Schema 本身就是文档Pydantic 本身就是验证器。任何不符合规范的配置在构造的那一刻就会立刻报错不用等到运行时才炸出来。实践二测试锁定默认值契约Schema 定好之后测试自然而然就跟了上来。我们为每个字段的默认值、每个必填项、每个边界条件都写了测试。乍一看这些测试未免太简单了不过是检查一下默认值。但它们的价值从来不在于发现 bug而在于把契约锁死。三个月后有人想改sandbox的默认值测试立刻报红。这不是坏事而是系统在提醒你你动的是一个有下游依赖的契约想清楚再改。实践三注册表的行为契约Agent 注册表负责管理所有 Team 定义要支持注册、查询、防重复。我们先写测试再写实现测试完整描述了注册表的行为契约——三个场景涵盖正常路径和两种异常路径测试就是活的 API 文档。这三个场景完整地告诉新成员注册表能做什么、不能做什么遇到错误时又会怎样反应。实践四Prompt 也能 SDDAI 系统有一个传统软件不会遇到的难题Prompt 承载着核心逻辑却没有类型系统来约束它。我们把 Agent 的行为规范写成 YAML用结构化格式把约束固定下来。YAML 是规范运行时是实现。规则要变只需要改 YAML代码可以完全不动。Prompt 三层架构三层分离的价值就在这里静态规则不用随每次请求重发可以共享缓存领域知识能按客户替换运行时注入的内容压到最少。要改意图判断规则只动 Layer 1要新增行业示例只动 Layer 2——都不需要碰代码。实践五生命周期管理的异常路径Session 生命周期管理是资源泄漏的高发地带。MCP 连接、临时目录、工具句柄任何一处没清理干净都是隐患。我们用 TDD 把异常路径也覆盖到了其中最关键的一条是MCP 连接关闭时抛出异常cleanup 不能因此中断其他资源必须继续释放。这种行为用自然语言说起来很轻巧但如果不写测试就没有任何机制能保证它真的存在也没法知道它哪天被悄悄改坏了。实践六新功能开发从红色测试开始TDD 最容易被误解的一点是很多人把它当成测试覆盖率工具功能写完了才回头补测试。这样写出来的测试永远是绿的——因为是对着已有实现写的只能描述现有行为管不住未来的行为。真正的 TDD 是从一个注定会失败的测试开始的。功能还没影子的时候先写一个测试声明它应该怎样工作跑起来看它报红然后再动手开发直到它变绿为止。方式测试何时写测试的作用补测试错误方式功能完成后描述已有行为永远绿色无约束力先写测试TDD功能开发前声明意图红色是目标实现服务于测试在我们的 Agent Hub 开发中每次新增一项能力第一步永远是先写一个描述它应该怎样工作的测试跑一遍看到红色再去开发。红色不是失败而是目标。这个习惯带来的最大改变其实是心态上的开发者不再问功能写完了吗而是问测试绿了吗。功能完成的标准从一件主观的事变成了客观的事。六条经验1. Schema 是最便宜的文档写 Pydantic Model 花的时间和写 dict 差不多换来的却是类型检查、自动文档、验证报错、IDE 补全。把 Schema 当成一笔投资而不是负担。2. 测试默认值不是多此一举默认值背后是一个设计决策。锁定它才能防止系统行为被无意中改变。默认值测试其实是在说这个值不是随便定的改之前先想清楚。3. 先写测试逼自己想清楚接口写测试的时候你站的是调用方的视角这个视角能更早暴露接口设计上的问题——比 code review 更早发现比调试更省成本。4. Prompt 规范化是 AI 系统的核心工程问题把 Prompt 写成 YAML、分层管理让不同层拥有不同的缓存和更新策略——这不是格式上的讲究而是实实在在的工程问题。5. 测试是活的契约不是死的文档测试会失败而一个失败的测试其实是在说有人正在改动一个受约束的东西。这是信号不是噪音。6. SDD 和 TDD 缺一不可只有 SDD规范虽然存在却没人知道它何时被破坏只有 TDD测试虽然覆盖到位验证逻辑却散落各处。两者结合起来规范才是唯一的真相测试则是全天候的自动巡逻。结语AI Agent 系统的复杂度不输给传统分布式系统还多了一层难处它的行为由 Prompt 定义而 Prompt 没有编译器。SDD 和 TDD 替代不了好的架构判断但它们能把我们到底达成了什么共识从人脑和会议记录里搬进代码仓库——变得可搜索、可执行、可验证。在存量代码中持续迭代这是我们认为最值得推广的一种工程习惯。本文基于真实项目经验代码示例来自生产代码库。
返回列表