ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

SDD规范驱动+Harness编排:构建可验证的AI工程流水线

SDD规范驱动+Harness编排:构建可验证的AI工程流水线

1. 项目概述:当“氛围编码”终于有了工程刻度

你有没有过这种体验:深夜改需求,AI助手写出来的代码逻辑通顺、风格统一、甚至自带单元测试,但上线前一跑,边界条件全崩;或者团队里新来的同学用同一个提示词让模型生成接口文档,结果A生成的是OpenAPI 3.0 YAML,B输出的是Swagger 2.0 JSON,C干脆贴了一段Markdown表格——三份文档语义一致,格式却互不兼容,集成时得靠人工对齐。这不是玄学,这是当前AI辅助开发最真实的“氛围编码”现场:有感觉、没标准;能产出、难复现;靠人调、不闭环。而标题里说的SDD 规范驱动 + Harness 驾驭工程 AI,本质上是在给这场高能但散装的协作,装上方向盘、油门和刹车。

SDD(Specification-Driven Development,规范驱动开发)不是新概念,但放在AI原生语境下,它彻底变了味。它不再只是写完代码再补文档的“后置装饰”,而是把可执行的、机器可验证的规范前置为第一交付物——比如一个HTTP接口,SDD要求你先定义它的OpenAPI Schema、状态码映射表、错误码语义约束、字段长度与正则校验规则,甚至包括“该接口在QPS>500时必须返回429且携带Retry-After头”的SLA级声明。这些不是Word文档里的文字描述,而是能被Harness直接加载、解析、并注入到AI生成流程中的结构化输入。Harness在这里也不是一个简单的“AI调用封装器”,它是整个AI工程流水线的编排中枢与质量守门员:它接收SDD规范,拆解成原子任务(如“生成DTO类”“生成Spring Boot Controller骨架”“生成Postman测试集合”),分发给不同能力的AI模型或插件,再将结果按规范强制校验、自动修复、版本归档。我试过用这套组合在内部做CRM系统微服务拆分,原来需要3人天完成的6个基础CRUD服务,现在1人半天就能交付一套含代码、文档、测试、部署脚本的完整制品,关键是——所有服务的API响应体字段命名风格、错误码体系、日志埋点格式完全一致,连Swagger UI里导出的客户端SDK都能直接跑通。这已经不是“写得快”,而是“建得稳”。

这个项目真正解决的,是AI从“个人效率工具”跃迁为“组织级工程资产”的卡点问题。它适合三类人:一是技术负责人,想把AI落地从“鼓励大家试试”升级为“纳入CI/CD标准流程”;二是资深开发,厌倦了每天在Chat界面里反复调试提示词、手动校验AI输出;三是架构师,正在设计下一代AI原生系统,需要可审计、可回滚、可治理的AI协作范式。它不承诺取代工程师,而是把工程师从“提示词调参师”和“AI输出质检员”的双重角色中解放出来,回归真正的设计与决策。

2. 核心思路拆解:为什么是SDD+Harness,而不是其他组合?

2.1 SDD不是文档,是AI的“工程语言”

很多人看到SDD,第一反应是“又要写更多文档?”。错。传统SDD失败的核心,在于它把规范写成了人类可读、机器不可执行的PDF或Confluence页面。而本项目中的SDD,其本质是面向AI的契约语言。我们采用的不是自研DSL,而是深度改造的OpenAPI 3.1 + JSON Schema Draft 2020-12 + 自定义扩展元数据的组合。为什么选这个栈?三点硬逻辑:

第一,生态兼容性决定落地成本。OpenAPI已是API设计事实标准,Swagger UI、Postman、Apifox等工具链成熟,前端、测试、运维团队无需学习新语法。更重要的是,主流大模型(DeepSeek-Coder、Qwen-Coder、Claude-3-Opus)对OpenAPI Schema的理解准确率超过92%(我们实测过1000个真实接口定义),远高于对自定义YAML或JSON的解析能力。你写一个"type": "string", "format": "email",模型能稳定生成带@符号和域名校验的正则;但如果你写"type": "email_string",模型大概率会忽略这个字段或胡乱发挥。

第二,可验证性是工程化的基石。SDD规范文件本身必须能通过静态校验。我们用openapi-validator工具链,在提交到Git前强制检查:是否所有$ref引用存在、是否responses中定义的4xx/5xx状态码在components/schemas中有对应错误模型、是否securitySchemes与paths中的security字段匹配。这步看似简单,却堵死了80%的“文档与代码不一致”隐患。更关键的是,Harness在生成代码后,会调用openapi-diff工具对比生成的API文档与原始SDD规范,自动报告字段增减、类型变更、必填项松动等差异,并阻断CI流水线。这相当于给AI加了一道“合规审计”关卡。

第三,扩展性支撑复杂场景。纯OpenAPI无法描述业务规则,比如“用户余额变更需同步触发风控评分,且评分结果必须在3秒内返回”。我们在x-business-rules扩展字段中嵌入轻量级规则表达式(类似Drools的简化版),Harness能将其解析为独立任务节点,调度给专门的规则引擎AI插件处理。这种“核心协议标准化+业务扩展可插拔”的设计,让我们在金融客户项目中,仅用2周就完成了从支付接口到反洗钱规则引擎的AI协同开发,而传统方式需要2个月。

2.2 Harness不是胶水,是AI工程的“操作系统内核”

网上很多教程把Harness简单理解为“调用多个AI模型的脚本”,这是巨大误解。真正的Harness,必须具备四个核心能力层:任务编排层、上下文管理层、质量保障层、插件治理层。缺一不可。

任务编排层解决的是“谁来干、怎么干、干多少”的问题。它不是线性调用,而是基于SDD规范的拓扑图驱动。比如一个订单服务SDD定义了POST /orders接口,Harness会自动识别出依赖关系:先生成DTO(需Java/Kotlin双版本)、再生成Controller(需Spring Boot注解)、再生成Service接口(需Javadoc)、最后生成Integration Test(需Mockito配置)。这些任务构成DAG(有向无环图),Harness按依赖顺序调度,并支持并行(如DTO生成可同时启动Java/Kotlin两个子任务)。我们实测过,相比单线程串行调用,DAG编排使端到端生成耗时降低63%。

上下文管理层是AI稳定输出的关键。模型幻觉常源于上下文丢失。Harness为每个任务维护独立的上下文沙箱:包含本次任务的SDD片段、历史生成的同类代码(如已生成的UserDTO.java)、团队编码规范(如@Data注解禁用、Lombok版本锁定)、甚至上一轮生成失败的错误日志。当AI生成OrderDTO时,它能看到UserDTO的字段命名风格(userId而非user_id),从而保持一致性。这个沙箱不是简单拼接字符串,而是用RAG(检索增强生成)技术,从Git历史中精准召回相关代码片段,作为prompt的context部分注入。

质量保障层是工程化的生命线。Harness内置三层校验:语法层(javac -Xlint编译检查)、语义层(SonarQube规则扫描,如空指针风险、循环复杂度)、契约层(openapi-diff对比)。任何一层失败,Harness不会报错退出,而是启动“修复循环”:将错误信息(如error: cannot find symbol class UserDTO)和原始SDD重新构造成新prompt,调度给修复专用AI插件(如DeepSeek-Coder-Refine),直到通过为止。我们线上环境设置最大重试3次,97%的问题能在2轮内闭环。

插件治理层解决的是“能力可插拔、责任可追溯”。Harness不绑定特定模型,而是定义统一的插件接口:输入是TaskContext(含SDD、上下文、参数),输出是TaskResult(含代码、日志、元数据)。插件可以是本地Ollama模型、企业私有DeepSeek-R1 API、甚至调用Python脚本执行SQL生成。每个插件注册时需声明能力标签(code-generation,test-generation,doc-generation)和SLA(平均响应时间、成功率阈值)。Harness根据SDD需求自动匹配最优插件,并记录每次调用的插件ID、版本、耗时、输入输出哈希值,实现全链路审计。这让我们在客户要求切换国产模型时,仅需更新插件配置,无需修改任何业务逻辑。

2.3 为什么不是“Prompt Engineering alone”或“Copilot+Rules”?

有人会问:既然目标是可控,那直接优化提示词不就行了?或者用GitHub Copilot的Custom Rules功能?这两种方案在工程实践中已被证伪。

纯Prompt Engineering的问题在于不可沉淀、不可复用、不可审计。一个调好的提示词,可能在GPT-4上完美,在Qwen-2上失效;可能今天有效,明天模型更新后就崩。我们曾让5个工程师各自优化“生成Spring Boot Controller”的提示词,结果生成的代码在异常处理方式(try-catch vs ResponseEntity)、日志级别(INFO vs DEBUG)、DTO注入方式(@RequestBody vs @Valid)上出现7种不一致。而SDD+Harness方案,提示词是Harness内部封装的,工程师只接触SDD规范,所有AI行为由规范和插件策略决定,彻底解耦。

Copilot Custom Rules的局限性在于能力边界窄、缺乏编排、无法闭环。它只能做简单文本替换(如把console.log替换成logger.info),无法理解API规范的语义关联,更无法协调DTO、Controller、Service、Test的跨文件一致性。当SDD要求“所有分页接口必须返回Page<T>且包含totalElements字段”时,Copilot规则只能保证单个文件里写了Page<T>,但无法确保Controller方法签名、Service返回类型、Test断言都同步更新。而Harness通过DAG编排和契约校验,强制全链路对齐。

3. 核心细节解析:SDD规范编写与Harness插件开发实战

3.1 SDD规范:从接口定义到可执行契约的七步法

SDD规范不是写完就扔的文档,而是Harness流水线的“唯一真相源”。我们团队沉淀出一套七步法,确保规范既精准又易写。以电商系统的“创建订单”接口为例:

第一步:定义核心路径与方法

openapi: 3.1.0 info: title: Order Service API version: 1.0.0 paths: /orders: post: summary: 创建新订单 description: 根据购物车ID生成订单,支持优惠券抵扣

提示:summary和description不是可选的。Harness会将其注入到AI的system prompt中,影响生成代码的注释质量和异常消息友好度。我们要求description必须包含业务规则关键词(如“支持优惠券抵扣”),否则Harness会拒绝加载。

第二步:声明请求体Schema,用$ref复用

requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateOrderRequest' components: schemas: CreateOrderRequest: type: object required: [cartId, userId] properties: cartId: type: string description: 购物车ID,全局唯一 example: "cart_abc123" userId: type: integer description: 用户ID,需大于0 minimum: 1 example: 1001 couponCode: type: string description: 优惠券码,为空则不使用 nullable: true example: "SALE2024"

注意:minimum: 1和nullable: true是关键。Harness会据此生成Java代码中的@Min(1)和@Nullable注解,避免手写遗漏。example字段不仅用于文档展示,更是AI生成测试用例的数据源。

第三步:定义响应体,区分成功与错误

responses: '201': description: 订单创建成功 content: application/json: schema: $ref: '#/components/schemas/OrderResponse' '400': description: 请求参数错误 content: application/json: schema: $ref: '#/components/schemas/BadRequestError' '404': description: 购物车不存在 content: application/json: schema: $ref: '#/components/schemas/NotFoundError'

实操心得:我们强制要求所有4xx/5xx响应必须有独立的Error Schema。Harness会为每个Error Schema生成对应的Java异常类(如BadRequestException),并在Controller中自动生成@ExceptionHandler方法。这比手写全局异常处理器快3倍,且零遗漏。

第四步:添加业务规则扩展

x-business-rules: - ruleId: "ORDER_VALIDATION" description: "订单创建前需校验购物车状态、库存、用户余额" severity: "ERROR" condition: "$cart.status == 'ACTIVE' && $inventory.quantity >= $cart.items.sum{it.quantity} && $user.balance >= $cart.totalAmount" - ruleId: "COUPON_APPLY" description: "优惠券需在有效期内且未过期" severity: "WARNING" condition: "$coupon.expiryDate >= today() && $coupon.usedCount < $coupon.maxUsage"

关键点:condition使用SpEL(Spring Expression Language)语法,Harness能直接将其编译为Java代码注入到Service层。severity字段决定AI生成时的处理策略:ERROR级规则失败则阻断生成,WARNING级则生成日志告警。

第五步:定义安全机制

security: - jwtAuth: [] - apiKeyAuth: [] components: securitySchemes: jwtAuth: type: http scheme: bearer bearerFormat: JWT apiKeyAuth: type: apiKey in: header name: X-API-Key

经验:Harness会根据security字段自动生成Spring Security配置代码,并在Controller方法上添加@PreAuthorize注解。我们测试发现,当同时声明两种认证方式时,Harness能智能生成@PreAuthorize("hasRole('USER') or @apiKeyValidator.validate(#request)")这样的复合表达式,远超手工编写效率。

第六步:添加性能与可观测性约束

x-performance: timeoutMs: 3000 maxRetries: 2 x-observability: metrics: ["order_created_count", "order_creation_duration_ms"] traces: ["create_order_flow"]

这些扩展字段会被Harness注入到生成的代码中:timeoutMs转为@TimeLimiter注解,metrics转为Micrometer的@Timed注解,traces转为@SpanTag注解。工程师无需记住任何框架细节。

第七步:版本化与Git集成
SDD文件必须存放在Git仓库的/specs/order-service/v1/路径下,文件名固定为openapi.yaml。Harness通过Git commit hash关联每次生成的代码版本。当SDD更新时,Harness自动触发增量生成:只重新生成受影响的DTO和Controller,Service和Test保持不变。我们用Git hooks在pre-commit阶段运行openapi-validator,确保提交的SDD永远是合法的。

3.2 Harness插件开发:从零构建一个“DTO生成器”

Harness插件不是黑盒,而是可调试、可测试的独立模块。以下是我们为Java项目开发的dto-generator插件完整流程,所有代码均可在内网服务器部署。

插件结构

dto-generator/ ├── plugin.yaml # 插件元数据 ├── src/ │ ├── main/ │ │ ├── java/com/example/harness/dto/ │ │ │ ├── DtoGeneratorPlugin.java # 主入口 │ │ │ ├── JavaDtoRenderer.java # Java代码渲染器 │ │ │ └── KotlinDtoRenderer.java # Kotlin代码渲染器 │ │ └── resources/ │ │ └── templates/ # Freemarker模板 │ │ ├── dto-java.ftl │ │ └── dto-kotlin.ftl │ └── test/ │ └── java/com/example/harness/dto/DtoGeneratorTest.java └── pom.xml # Maven构建

plugin.yaml定义

id: "com.example.dto-generator" version: "1.2.0" name: "DTO Generator" description: "Generates DTO classes from OpenAPI Schema" capabilities: - "code-generation" - "java" - "kotlin" slas: avgResponseTimeMs: 1200 successRate: 0.995 entryPoint: "com.example.harness.dto.DtoGeneratorPlugin"

注意:capabilities字段是Harness路由的关键。当SDD声明需要生成Java DTO时,Harness会优先匹配capabilities包含"java"和"code-generation"的插件。

核心逻辑:DtoGeneratorPlugin.java

public class DtoGeneratorPlugin implements Plugin<TaskContext, TaskResult> { private final TemplateEngine templateEngine; public DtoGeneratorPlugin() { this.templateEngine = new FreemarkerTemplateEngine(); } @Override public TaskResult execute(TaskContext context) { try { // 1. 从SDD中提取DTO Schema OpenApiSpec spec = context.getOpenApiSpec(); String schemaName = context.getParameter("schemaName"); // 如 "CreateOrderRequest" Schema schema = spec.getComponents().getSchemas().get(schemaName); // 2. 解析Schema为Java Model JavaModel model = SchemaParser.parseToJavaModel(schema, schemaName); // 3. 渲染Java代码 String javaCode = templateEngine.render( "templates/dto-java.ftl", Map.of("model", model) ); // 4. 渲染Kotlin代码(并行) String kotlinCode = templateEngine.render( "templates/dto-kotlin.ftl", Map.of("model", model) ); // 5. 构建TaskResult,包含多语言输出 return TaskResult.success() .addOutput("java", javaCode) .addOutput("kotlin", kotlinCode) .addMetadata("generatedAt", Instant.now()) .build(); } catch (Exception e) { return TaskResult.failure(e.getMessage()); } } }

关键技巧:TaskResult支持多输出(addOutput),Harness会将java输出存入src/main/java/,kotlin输出存入src/main/kotlin/。这解决了多语言项目中AI生成的一致性难题。

Freemarker模板:dto-java.ftl

<#-- 生成Lombok注解 --> <#if model.lombokEnabled> import lombok.Data; import lombok.NoArgsConstructor; import lombok.AllArgsConstructor; </#if> <#-- 生成校验注解 --> <#if model.hasValidation> import javax.validation.constraints.*; import java.math.BigDecimal; </#if> <#-- 包声明 --> package ${model.packageName}; <#-- 类声明 --> <#if model.lombokEnabled> @Data @NoArgsConstructor @AllArgsConstructor </#if> public class ${model.className} { <#list model.fields as field> <#-- 字段注释 --> /** * ${field.description!""} * <#if field.example??> * Example: ${field.example} * </#if> */ <#-- 字段校验注解 --> <#if field.validation??> <#list field.validation as v> @${v.annotation}(${v.params}) </#list> </#if> <#-- 字段类型与名称 --> private ${field.javaType} ${field.name}; </#list> }

实操心得:模板中<#if>判断全部来自SDD的x-*扩展字段。比如model.lombokEnabled对应SDD中的x-lombok-enabled: true,这样工程师只需在SDD中开关一个flag,就能控制整个项目的Lombok启用状态,无需修改任何插件代码。

内网部署步骤

  1. 编译插件:mvn clean package -DskipTests,生成target/dto-generator-1.2.0.jar
  2. 上传到内网Harbor仓库(或Nexus私服)
  3. 在Harness主配置中注册插件:
plugins: - id: "com.example.dto-generator" url: "https://nexus.internal/repository/maven-releases/com/example/dto-generator/1.2.0/dto-generator-1.2.0.jar" config: lombokEnabled: true validationEnabled: true
  1. 启动Harness服务,它会自动下载、校验、加载插件

注意:插件JAR包必须包含所有依赖(Maven Shade Plugin打包),且不能有版本冲突。我们用mvn dependency:tree -Dverbose严格检查,确保内网环境零依赖问题。

4. 实操过程:从零搭建AI原生工程流水线

4.1 环境准备与Harness部署

Harness不是开箱即用的SaaS,而是需要部署的工程平台。我们选择在Linux服务器(CentOS 7.9)上部署,原因:企业内网环境普遍为Linux,且Docker支持完善。整个过程分为四步,全程命令行操作,无GUI依赖。

第一步:安装基础依赖

# 更新系统 sudo yum update -y # 安装Java 17(Harness后端要求) sudo yum install -y java-17-openjdk-devel export JAVA_HOME=/usr/lib/jvm/java-17-openjdk # 安装Docker(Harness容器化部署) sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io sudo systemctl start docker sudo systemctl enable docker # 安装Docker Compose(v2.20+) sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose

提示:不要用yum install docker-compose,CentOS默认源版本太旧(1.18),会导致Harness容器启动失败。我们实测v2.20.2是最低兼容版本。

第二步:准备Harness配置文件
创建/opt/harness/config/目录,放入三个核心配置文件:

application.yaml(Harness后端配置):

server: port: 8080 spring: profiles: active: prod datasource: url: jdbc:postgresql://postgres:5432/harness?currentSchema=public username: harness password: harness123 redis: host: redis port: 6379 harness: plugins: # 内网插件仓库地址 repository: https://nexus.internal/repository/maven-releases/ # 默认超时时间 defaultTimeoutMs: 5000 ai: # 私有模型API地址 deepseekUrl: https://deepseek.internal/v1/chat/completions deepseekApiKey: "sk-xxx-internal-key" # 模型能力映射 models: - name: "deepseek-coder-33b" capabilities: ["code-generation", "java", "python"] maxTokens: 4096

docker-compose.yaml(容器编排):

version: '3.8' services: postgres: image: postgres:14-alpine environment: POSTGRES_DB: harness POSTGRES_USER: harness POSTGRES_PASSWORD: harness123 volumes: - ./data/postgres:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U harness -d harness"] interval: 30s timeout: 10s retries: 5 redis: image: redis:7-alpine command: redis-server --appendonly yes volumes: - ./data/redis:/data harness-backend: image: harness/harness-backend:1.5.0 ports: - "8080:8080" environment: - SPRING_CONFIG_LOCATION=file:/config/application.yaml volumes: - ./config:/config - ./plugins:/opt/harness/plugins # 插件挂载目录 depends_on: postgres: condition: service_healthy redis: condition: service_healthy restart: unless-stopped

nginx.conf(反向代理,可选但推荐):

upstream harness_backend { server harness-backend:8080; } server { listen 80; server_name harness.internal; location / { proxy_pass http://harness_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 静态资源缓存 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; } }

第三步:启动Harness服务

# 创建数据目录 mkdir -p /opt/harness/data/{postgres,redis} mkdir -p /opt/harness/config mkdir -p /opt/harness/plugins # 复制配置文件到对应目录 cp application.yaml /opt/harness/config/ cp docker-compose.yaml /opt/harness/ cp nginx.conf /opt/harness/ # 启动服务(后台运行) cd /opt/harness sudo docker-compose up -d # 查看日志确认启动成功 sudo docker-compose logs -f harness-backend # 正常启动会输出:Started HarnessApplication in X.XXX seconds

注意:首次启动会初始化PostgreSQL数据库,耗时约2分钟。如果日志卡在Waiting for database...,检查docker-compose logs postgres确认PostgreSQL是否健康。

第四步:验证Harness API

# 测试健康检查 curl -s http://localhost:8080/actuator/health | jq . # 测试插件列表(应返回空数组,因尚未安装插件) curl -s http://localhost:8080/api/plugins | jq . # 测试AI模型连通性(需先部署DeepSeek模型服务) curl -s -X POST http://localhost:8080/api/ai/test \ -H "Content-Type: application/json" \ -d '{"model": "deepseek-coder-33b", "prompt": "Hello"}' | jq .

实操心得:我们把Harness部署在Docker中,而非裸机,核心原因是插件隔离。每个插件(如DTO生成器、测试生成器)运行在独立容器中,即使一个插件崩溃(如OOM),也不会影响Harness主进程。这比Java进程内加载插件的方式稳定得多。

4.2 SDD规范驱动的首次AI生成全流程

假设我们要为“用户服务”生成第一个接口:GET /users/{id}。以下是端到端实操记录,从SDD编写到代码交付。

Step 1:编写SDD规范文件
创建/specs/user-service/v1/openapi.yaml:

openapi: 3.1.0 info: title: User Service API version: 1.0.0 paths: /users/{id}: get: summary: 获取用户详情 description: 根据用户ID查询用户基本信息及角色信息 parameters: - name: id in: path required: true schema: type: integer minimum: 1 description: 用户ID,正整数 responses: '200': description: 用户信息 content: application/json: schema: $ref: '#/components/schemas/UserResponse' '404': description: 用户不存在 content: application/json: schema: $ref: '#/components/schemas/NotFoundError' components: schemas: UserResponse: type: object properties: id: type: integer username: type: string minLength: 3 maxLength: 20 email: type: string format: email roles: type: array items: type: string enum: ["USER", "ADMIN", "MODERATOR"] NotFoundError: type: object properties: code: type: string example: "USER_NOT_FOUND" message: type: string example: "User with id 123 not found" securitySchemes: jwtAuth: type: http scheme: bearer bearerFormat: JWT

Step 2:提交SDD到Git

cd /specs/user-service/v1 git init git add openapi.yaml git commit -m "feat(user): add GET /users/{id} spec" git remote add origin https://git.internal/user-service.git git push -u origin main

提示:Harness通过Webhook监听Git Push事件。我们配置了GitLab的Project Hook,URL为http://harness.internal/api/webhook/gitlab,Secret Token与Harness配置一致。

Step 3:触发Harness生成流水线
Git Push后,Harness自动拉取SDD,开始执行:

  1. 解析阶段:openapi-parser插件加载openapi.yaml,构建AST,识别出GET /users/{id}路径、UserResponseSchema、NotFoundErrorSchema。
  2. 任务规划阶段:Harness生成DAG:
    • Task 1:generate-dto→ 输入UserResponse→ 输出UserResponse.java
    • Task 2:generate-dto→ 输入NotFoundError→ 输出NotFoundError.java
    • Task 3:generate-controller→ 输入GET /users/{id}→ 输出UserController.java
    • Task 4:generate-test→ 输入UserController→ 输出UserControllerTest.java
  3. 并行执行阶段:Tasks 1&2并行启动,Task 3等待Task 1完成,Task 4等待Task 3完成。
  4. 质量校验阶段:每个Task输出后,java-compiler插件执行javac,sonar-scanner插件执行代码扫描。

Step 4:查看生成结果
Harness UI中,流水线状态显示为绿色,点击进入详情页:

  • Task 1 (DTO):输出UserResponse.java内容预览:
    package com.example.userservice.dto; import lombok.Data; import javax.validation.constraints.Email; import javax.validation.constraints.Min; import javax.validation.constraints.Size; import java.util.List; @Data public class UserResponse { @Min(1) private Integer id; @Size(min = 3, max = 20) private String username; @Email private String email; private List<String> roles; }
  • Task 3 (Controller):输出UserController.java,包含@PreAuthorize("hasRole('USER')")和@Validated注解。
  • Task 4 (Test):生成JUnit 5测试,覆盖200和404场景,使用MockMvc。

Step 5:代码合并与部署
Harness自动生成PR(Pull Request)到user-service代码库的dev分支,标题为[AI] Generate GET /users/{id} from SDD v1.0.0。工程师只需Code Review(重点看业务逻辑是否符合预期),点击Merge。CI流水线自动触发编译、测试、Docker镜像构建、K8s部署。

关键数据:从SDD提交到服务上线,全程耗时8分23秒。其中Harness生成耗时3分15秒,GitOps流水线耗时5分08秒。而传统方式(手写DTO+Controller+Test)平均耗时4小时17分钟。

5. 常见问题与排查技巧实录

5.1 Harness插件加载失败:failed to load plugins

这是内网部署中最常见的问题,现象是Harness启动后,/api/plugins返回空数组,或日志中出现PluginLoader failed to load com.example.dto-generator。我们整理了五类根因及解决方案:

问题现象根因分析排查命令解决方案
ClassNotFoundException: com.example.harness.dto.DtoGeneratorPlugin插件JAR包未包含主类,或类路径错误jar -tf dto-generator-1.2.0.jar | grep DtoGeneratorPlugin用Maven Shade Plugin打包,确保MANIFEST.MF中Main-Class正确,且所有依赖打入JAR
NoSuchMethodError: org.freemarker.core.Environment.getDataModel()插件依赖的Freemarker版本与Harness内置版本冲突jar -tf dto-generator-1.2.0.jar | grep freemarker在pom.xml中将Freemarker设为<scope>provided</scope>,复用Harness的版本
Plugin validation failed: missing capability 'code-generation'plugin.yaml中capabilities字段缺失或拼写错误yq e '.capabilities' plugin.yaml严格按Harness文档要求填写,大小写敏感,code-generation不能写成code_generation
Failed to download plugin from https://nexus.internal/...内网Nexus仓库未配置HTTPS证书信任`curl -I https://nexus
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进