CodeSpec:双重可执行规约驱动AI智能体长周期特性开发

CodeSpec:双重可执行规约驱动AI智能体长周期特性开发
1. 项目概述当代码规范“活”过来最近在跟几个做AI Agent和大型软件项目的朋友聊天大家普遍头疼一个问题需求文档写得再详细一旦进入长周期、多模块的“特性开发”Feature Development阶段文档和代码的脱节几乎是必然的。产品经理画的饼需求架构师做的蓝图设计最后到工程师手里经过几轮迭代和人员变动最初的意图早就面目全非了。更别提现在流行的“智能体驱动开发”Agentic Development你指望一个AI去理解上百页充满自然语言歧义的PRD产品需求文档然后写出符合预期的代码这简直是天方夜谭。这就是“CodeSpec: Dual Executable Specifications for Agentic Long-Horizon Feature Development”这个项目标题直击的痛点。它不是什么新框架而是一个核心的工程理念和方法论。简单说它主张为长周期特性开发创建“双重可执行规约”。听起来有点玄乎我把它拆开揉碎了讲。“可执行规约”Executable Specifications不是新概念在测试驱动开发TDD或行为驱动开发BDD里我们用类似Cucumber的Given-When-Then语法把需求写成可运行的测试。但CodeSpec强调“双重”Dual。我的理解是一重是面向“人”的、高层次的、描述业务逻辑和验收条件的规约另一重是面向“机器”特别是AI智能体的、低层次的、可直接驱动代码生成与验证的规约。两者同源、同步、可互相验证。而“Agentic Long-Horizon Feature Development”则是它的主战场。Agentic指的是开发过程由AI智能体如基于LLM的编码助手、自主测试Agent、代码审查Agent高度参与甚至主导。Long-Horizon指的是那些无法在一个短冲刺Sprint内完成需要拆分成多个子任务、跨越数周甚至数月并且各任务间存在复杂依赖和状态传递的特性开发。比如“为电商平台重构整个订单履约系统”或“在数据平台中实现一套全新的流式风控规则引擎”。传统的文档在这类场景下几乎失效。CodeSpec的理念就是为这个混乱的战场提供一套“活”的、可执行的宪法让所有参与者——无论是人类工程师还是AI智能体——都在同一套明确、无歧义、可验证的规则下协作。2. 核心理念拆解为什么需要“双重”规约要理解CodeSpec得先明白单一规约在长周期、智能体参与的开发中为什么不够用。2.1 传统文档的失效与智能体协作的鸿沟在纯人力开发时代我们靠会议、口口相传和不断修改的文档来对齐。虽然低效但人有模糊理解和上下文补全的能力。然而AI智能体目前严重缺乏这种“意会”的能力。你给AI一段自然语言描述“用户下单后检查库存如果充足则预占库存并通知仓库。” 这里面的坑太多了“检查库存”是查实时库存还是可售库存缓存策略是什么“预占库存”预占时长多久预占记录的结构是怎样的“通知仓库”通过什么渠道消息格式是什么是同步还是异步如果库存不足呢是返回错误还是进入等待队列一个人类工程师会去问或者根据既有系统惯例来决策。但一个AI智能体如果没有极其精确的输入它要么会卡住要么会生成一个看似合理但完全不符合你系统上下文的代码甚至引入安全漏洞。因此面向AI智能体的规约必须是机器可解析、无歧义、且包含完整上下文约束的。这远超过传统产品需求文档的范畴。2.2 “双重规约”的协同设计CodeSpec提出的“双重规约”正是为了桥接人类意图与机器执行之间的鸿沟。第一重人类可读/可写的业务规约 (Human-Centric Spec)这一层面向产品经理、架构师和工程师。它使用领域特定语言DSL或增强的自然语言描述特性的目标、业务价值、核心工作流、业务规则和验收标准。它的重点是“做什么”和“为什么”而不是“怎么做”。形式可能是结构化的YAML、Markdown表格或者一种自定义的DSL。示例简化Feature: 订单库存预占 Goal: 确保用户下单时商品库存得到可靠预留防止超卖。 Actors: 用户、库存服务、订单服务。 Main Flow: 1. 用户提交包含商品SKU和数量的订单。 2. 系统调用库存服务的 preempt 接口。 3. 库存服务校验实时库存 订单数量。 4. 若充足在inventory_holds表创建一条状态为RESERVED、有效期为30分钟的预占记录并返回成功。 5. 订单服务收到成功响应后创建状态为待支付的订单。 Business Rules: - 预占有效期(RESERVATION_TTL): 30分钟。 - 仅当订单支付成功后预占才转化为实际扣除。 - 预占到期或订单取消预占记录需释放库存回滚。 Acceptance Criteria: - AC1: 库存充足时下单成功生成预占记录。 - AC2: 库存不足时下单失败返回明确错误码 INSUFFICIENT_INVENTORY。 - AC3: 预占记录30分钟后自动过期库存恢复。这一层是人类团队对齐的基石。第二重机器可执行/可验证的工程规约 (Machine-Centric Spec)这一层是CodeSpec的精髓。它由第一层规约部分或全部转化而来为AI智能体提供精确的操作指令和验证标准。它更接近“怎么做”包括接口契约、数据模式、状态机、不变式约束甚至是可运行的测试用例。形式可能是OpenAPI规范、JSON Schema、状态机定义如XState的JSON、Prolog逻辑规则或直接就是一套单元测试的脚手架代码。与第一层的关联例如上面的“业务规则”会被编译成接口契约POST /inventory/preempt的请求/响应JSON Schema。数据模式inventory_holds表的SQL DDL或Prisma Schema。状态机订单和库存预占的状态流转图如RESERVED - CONFIRMED或RESERVED - RELEASED。不变式约束一条始终必须为真的逻辑规则如“sum(预占数量) sum(可用库存) 总库存”。可执行验收条件AC1-AC3会被转化为具体的集成测试代码框架。2.3 双重规约如何驱动智能体开发在一个理想的Agentic工作流中规划阶段主控智能体Orchestrator Agent读取第一重规约理解特性范围和目标。任务分解主控智能体根据规约中的工作流和规则将Long-Horizon特性分解为一系列具体的、可执行的子任务如“实现库存预占接口”、“设计预占记录表”、“编写预占过期定时任务”。分派与执行对于每个子任务主控智能体结合第二重规约中对应的精确约束如接口Schema、数据模型生成具体的开发指令分派给编码智能体Coder Agent。验证与集成编码智能体产出代码后验证智能体Tester Agent会直接运行第二重规约中对应的可执行验收条件测试用例验证代码是否符合所有规约。构建智能体Builder Agent则根据规约中的依赖关系执行集成和部署。整个过程中规约是唯一的事实来源。任何对需求的修改都首先更新第一重规约然后通过工具链可能是编译器、转换器同步更新第二重规约从而自动触发相关任务的重新规划、代码的重新生成或测试的重新运行。这形成了一个闭环的、基于规约的智能体开发流水线。3. 核心组件与实现路径要将CodeSpec从理念落地需要构建或集成一系列核心组件。这里我结合现有的工具链和可能的实现勾勒出一个可行的技术栈。3.1 规约定义语言与工具首先你需要一种方式来定义第一重规约。虽然可以用YAML或Markdown但为了更好的结构化和可转换性定义一个轻量级DSL是更专业的选择。自定义DSL示例你可以设计一个类似feature.spec的文件格式。feature 订单库存预占 { goal: 防止超卖确保库存一致性 actor User, InventoryService, OrderService flow 正常预占 { given User submits order with items when InventoryService.preempt is called then inventory_hold record created with status RESERVED and OrderService receives success response } rule 预占时效 { reservation_ttl: 30.minutes on_expiry: release_inventory } data InventoryHold { id: string sku: string quantity: integer status: enum(RESERVED, CONFIRMED, RELEASED) expires_at: datetime } accept 库存充足 { call InventoryService.preempt(skuA001, qty2) expect response.success true expect db.InventoryHold.count where statusRESERVED 1 } }工具选型你可以使用像ANTLR或Tree-sitter来为这个DSL编写语法解析器将其解析为抽象语法树AST。也可以基于现有的DSL框架如JetBrains MPS或Eclipse Xtext但后者可能过重。3.2 规约转换器与生成器这是连接“双重规约”的核心引擎。它需要将第一重规约的AST转换为各种第二重规约。转换目标API契约生成OpenAPI 3.0规范的YAML/JSON文件。你的DSL中的flow和rule可以转换为API路径、请求体和响应体的Schema。数据模型生成SQL DDL语句、Prisma Schema、或Python Pydantic/Go Struct定义。DSL中的data块直接对应于此。状态机定义生成XState或Spring State Machine的配置。DSL中data块内的status枚举和rule中的状态触发条件可用于此。测试脚手架生成Jest、Pytest或JUnit的测试文件框架将accept块转换为具体的测试用例函数包含基本的断言。实现方式为每个转换目标编写一个“生成器”Generator。这些生成器遍历DSL的AST根据不同的节点类型如flow节点、data节点、accept节点输出对应的代码或配置文本。这本质上是一个模板渲染的过程可以使用Jinja2、Handlebars等模板引擎。3.3 智能体集成接口为了让AI智能体理解并利用这些规约你需要提供规约的查询和解释接口。规约服务构建一个轻量级服务暴露以下能力GET /spec/features列出所有特性规约。GET /spec/features/{id}获取某个特性的完整双重规约表示例如一个包含人读和机读部分的JSON。POST /spec/validate接收一段代码或一个API设计验证其是否符合某个特性规约的约束。上下文注入在给编码智能体如ChatGPT API、Claude API的Prompt中结构化地插入相关规约。例如“你正在实现订单库存预占特性。请严格遵循以下规约业务目标防止超卖。接口契约POST /inventory/preempt请求体需符合Schema{“sku”: string, “quantity”: integer}。数据模型预占记录表inventory_holds必须包含字段id, sku, quantity, status, expires_at。关键业务规则预占有效期为30分钟(RESERVATION_TTL)。 请生成实现该接口的Go语言Gin框架代码。”3.4 版本控制与生命周期管理规约必须与代码一样进行版本控制Git。关键实践包括规约即代码将.spec文件放在项目根目录的specs/文件夹下与src/和tests/并列。规约变更触发CI当.spec文件发生变更时CI流水线如GitHub Actions应自动运行规约语法校验。重新生成所有第二重规约OpenAPI、测试脚手架等。运行所有基于规约生成的测试确保现有代码仍然符合旧的规约这是回归测试。可以可选地触发一个任务通知相关AI智能体或开发人员某个特性的规约已更新相关实现可能需要调整。4. 实战演练构建一个简单的CodeSpec原型理论说再多不如动手。我们来尝试为一个“用户账户激活邮件重发”功能构建一个最小可行的CodeSpec流程。4.1 第一步定义第一重规约我们创建一个specs/user_reactivation.spec文件Feature: 账户激活邮件重发 Goal: 允许未激活用户安全地重新请求激活邮件提升激活率。 Actor: UnactivatedUser, UserService, EmailService Flow: 用户请求重发激活邮件 Trigger: 未激活用户访问登录页点击“重发激活邮件”。 Steps: 1. 用户输入注册邮箱。 2. 系统验证邮箱是否存在且对应账户未激活。 3. 系统生成新的激活令牌带时效并使其旧令牌失效。 4. 系统发送包含新激活链接的邮件。 5. 用户收到邮件点击链接完成激活。 Business Rules: - 激活令牌有效期: 24小时。 - 同一邮箱1小时内最多请求3次重发。 - 新令牌生成后该邮箱所有旧的未使用激活令牌立即失效。 Data: User: - id (PK) - email (Unique) - is_active (Boolean) ActivationToken: - token (PK) - user_id (FK) - created_at - expires_at - is_used Acceptance Criteria: - AC1: 输入已激活用户的邮箱提示“账户已激活请直接登录”。 - AC2: 输入不存在的邮箱提示“邮箱未注册”但出于安全考虑UI提示与AC1相同“邮件已发送请查收”。 - AC3: 1小时内第4次请求同一邮箱返回错误“请求过于频繁请稍后再试”。 - AC4: 成功请求后旧的未过期令牌状态应标记为失效。4.2 第二步实现规约转换器关键环节我们写一个简单的Python脚本spec_compiler.py它读取上面的YAML并生成第二重规约。生成OpenAPI Schema片段# spec_compiler.py 部分代码 import yaml import json with open(specs/user_reactivation.spec.yaml, r) as f: spec yaml.safe_load(f) # 生成请求/响应Schema openapi_spec { paths: { /api/v1/user/resend-activation: { post: { summary: spec[Feature], requestBody: { required: True, content: { application/json: { schema: { type: object, properties: { email: {type: string, format: email} }, required: [email] } } } }, responses: { 200: {description: 成功无论邮箱是否存在统一返回此状态}, 429: {description: 请求过于频繁} } } } } } # 写入文件 with open(generated/openapi.json, w) as f: json.dump(openapi_spec, f, indent2)生成Prisma Schema片段prisma_schema model User { id String id default(cuid()) email String unique isActive Boolean default(false) tokens ActivationToken[] } model ActivationToken { token String id default(uuid()) userId String user User relation(fields: [userId], references: [id]) createdAt DateTime default(now()) expiresAt DateTime isUsed Boolean default(false) } with open(generated/prisma.schema, w) as f: f.write(prisma_schema)生成测试脚手架以Jest为例test_code describe(POST /api/v1/user/resend-activation, () { beforeEach(async () { // 清空测试数据库 }); it(AC1: should return generic success for already active user, async () { // 1. 创建一个 isActivetrue 的用户 // 2. 调用接口 // 3. 断言返回200且数据库没有新令牌生成 }); it(AC3: should return 429 on 4th request within an hour, async () { // 1. 创建一个未激活用户 // 2. 模拟3次请求可以mock时间 // 3. 发起第4次请求 // 4. 断言返回429 }); }); with open(generated/__tests__/reactivation.spec.js, w) as f: f.write(test_code)4.3 第三步集成AI智能体进行开发现在我们可以将生成的规约提供给AI。假设我们使用一个类似smol-developer的智能体框架。我们创建一个agent_prompt.md文件作为智能体的指令# 开发任务实现“账户激活邮件重发”API端点 ## 规约摘要 - **功能**允许未激活用户重新请求激活邮件。 - **关键约束** 1. 端点POST /api/v1/user/resend-activation 2. 请求体{ email: string } 3. 安全规则无论邮箱是否存在/是否激活前端均显示“邮件已发送”。后端需区分但不泄露信息。 4. 限流同一邮箱1小时内最多3次请求。 5. 令牌管理新令牌生成后使该用户所有旧未使用令牌失效。令牌有效期24小时。 ## 生成的工程规约你必须严格遵守 1. **API契约**详见 ./generated/openapi.json 2. **数据模型**详见 ./generated/prisma.schema。你将在 prisma/schema.prisma 中找到完整的模型定义。 3. **数据库**我们使用PostgreSQLPrisma ORM。 ## 你的任务 请使用Node.js (Express框架) 和 Prisma Client 实现这个API端点。 请将代码输出到 src/routes/userReactivate.js。 请确保实现所有业务规则和验收标准。然后我们将这个Prompt和生成的openapi.json、prisma.schema文件一起提交给一个强大的LLM如GPT-4、Claude 3。智能体生成的代码其接口形状、数据操作逻辑都将被严格约束在规约定义的范围内。4.4 第四步验证与闭环智能体生成代码后我们立即可以运行之前由规约转换器生成的测试脚手架reactivation.spec.js。这些测试就是第二重规约中“可执行”部分的具体化身。测试的通过与否直接验证了智能体产出的代码是否符合最初的业务规约。如果测试失败我们可以将错误信息反馈给智能体要求其修正。如果规约本身需要变更比如产品经理说“令牌有效期改成12小时”我们只需修改第一重的.spec.yaml文件重新运行转换器生成新的测试和API Schema智能体就能基于新的约束进行代码调整或重写。5. 挑战、心得与最佳实践在实际探索和概念验证中我总结出以下几个关键点和挑战。5.1 主要挑战与应对策略规约DSL的设计复杂度DSL设计得太简单表达能力不足设计得太复杂学习成本和工具链开发成本激增。心得从最小必要集合开始。最初只支持Feature、Flow、Rule、Data、Accept这几个核心元素。优先覆盖当前项目最痛的点比如API契约和基础数据模型。随着项目演进再逐步扩展DSL语法。可以借鉴Cucumber Gherkin或Azure DevOps的YAML Pipeline语法。规约与代码的同步性最怕规约更新了但生成的代码或测试没更新或者工程师直接改了代码但没更新规约导致两者不一致。心得将规约检查纳入CI/CD强制门禁。在PR合并前CI流水线不仅要跑测试还要跑一个“规约一致性检查”。这个检查可以包括a) 验证现有代码能否通过所有由规约生成的测试b) 使用静态分析工具检查代码中的API路径、数据模型是否与生成的OpenAPI/Prisma Schema匹配。不一致则阻塞合并。智能体的理解与遵从能力即使提供了精确规约当前LLM的能力仍可能“跑偏”或产生不符合上下文的代码。心得Prompt工程至关重要。不要简单地把规约扔给AI。要结构化、分层次地提供信息。先给目标再给约束最后给示例。在关键业务规则处使用“必须”、“禁止”、“确保”等强约束性词语。同时生成的代码必须经过严格的自动化测试这是最后的防线。5.2 CodeSpec适用的场景与团队CodeSpec不是银弹它引入了一定的前期设计和工具链成本。它最适合以下场景团队规模中大型团队特别是跨职能、异地协作的团队。项目类型核心业务逻辑复杂、生命周期长、需要长期维护的企业级应用或平台。技术栈正在或计划大量采用AI编码助手如GitHub Copilot、通义灵码进行日常开发并探索更自动化Agent工作流的团队。痛点深受需求误解、文档过时、接口不一致、回归测试困难等问题困扰的团队。对于小型、快速迭代的初创项目或者一次性脚本开发引入完整的CodeSpec可能过度设计。但即使在这些场景借鉴其“将需求转化为可执行约束”的思想用简单的脚本将Markdown需求自动转为测试用例也能带来巨大收益。5.3 从何处开始实践如果你对这个理念感兴趣我建议按以下路径逐步实施手动实践期在一个新特性开始前尝试用结构化的YAML或Markdown表格严格定义它的Flows、Rules、Data和Acceptance Criteria。然后手动根据这份文档去编写对应的接口测试如Postman Collection和数据库迁移脚本。感受一下“规约先行”带来的清晰感。工具辅助期编写一些简单的脚本将你定义的结构化规约YAML自动转换为API文档Swagger UI和基础的测试文件框架。这一步可以极大地提升效率。智能体集成期在编写代码时有意识地将规约的关键片段复制到AI编码助手的Prompt中观察其生成代码的准确率是否提升。尝试为某个简单特性像第4章那样构建一个从规约到Prompt再到代码生成的完整迷你流程。平台化建设期当团队认可其价值后可以考虑投资建设内部的CodeSpec平台包括DSL编辑器、转换引擎、规约仓库和与CI/CD、AI Agent平台的深度集成。最终CodeSpec的目标不是增加官僚流程而是通过精确的、可执行的“共同语言”消灭沟通中的模糊地带让人类和AI智能体能真正高效、可靠地协同工作攻克那些漫长而复杂的特性开发挑战。这条路还很长但起点就在于下一次写需求文档时多问自己一句“这个描述能直接变成测试用例吗”

最新新闻

日新闻

周新闻

月新闻