十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

AI工程化实践:基于Harness与Spec-Driven的智能编码框架

AI工程化实践:基于Harness与Spec-Driven的智能编码框架 1. 项目概述当AI成为你的新同事最近和团队里的几个技术骨干聊天大家不约而同地提到了同一个痛点项目迭代速度越来越快需求文档、代码评审、测试用例编写这些重复性高、逻辑性强的“体力活”占据了大量时间。我们尝试过让大模型帮忙写点代码片段但效果总是不尽如人意——生成的代码要么跑不起来要么和现有架构格格不入最后还得花更多时间去“擦屁股”。这让我开始思考AI Coding或者说让AI参与软件开发难道就只能停留在“玩具”阶段吗直到我们系统性地引入了Harness这套工程化实践情况才发生了根本性的转变。简单来说Harness不是某个具体的AI模型或工具而是一套包裹在AI Agent核心推理逻辑之外的基础设施层和工程方法论。它的核心目标不是替代开发者而是像给一位天赋异禀但缺乏经验的实习生AI Agent配齐了完善的开发环境、清晰的工作流程SOP和自动化的质检流水线让它能真正高效、可靠地为我们干活并融入持续交付Continuous Delivery体系。这背后的驱动力正是Spec-Driven Development规范驱动开发。我们不再给AI一个模糊的指令“写个登录API”而是提供一份机器可读、结构清晰的“任务规格说明书”。这份说明书定义了输入、输出、约束条件、验收标准甚至包括代码风格和依赖库版本。AI Agent在Harness的框架约束下基于这份Spec进行推理和代码生成其产出物能直接通过预置的流水线进行构建、测试和部署。这不仅仅是“让AI写代码”而是构建了一套人机协作的标准化生产流水线。接下来我将结合我们团队近半年的实战经验拆解如何搭建这套体系让你也能让AI成为团队里一位靠谱的“新同事”。2. 核心理念拆解Harness、Agent与SDLC的三角关系在深入实操之前必须厘清几个核心概念及其关系这是避免后续实践走入歧途的基础。很多人容易混淆Harness、AI Agent和LLM大语言模型把它们混为一谈。2.1 角色定位各司其职的黄金三角我们可以用一个汽车制造的比喻来理解LLM大语言模型像是拥有海量知识、理解力和创造力的“天才工程师大脑”。它知道物理原理、材料特性能构思出汽车的设计图。但它不知道工厂的流水线怎么运作也不知道拧螺丝该用多大的扭矩。AI Agent则是这位“天才工程师”本身。它拥有大脑LLM并且被赋予了目标比如“制造一辆车”。但如果放任不管它可能会用木头去造发动机或者把轮子装在车顶上。它缺乏在真实、复杂环境中的系统化执行能力。Harness就是现代化的汽车生产工厂、全套的工装夹具、严格的生产工艺手册和质量检测线。它不负责发明新的造车理论而是为“天才工程师”提供标准化的作业平台。工厂规定好了流水线顺序工作流夹具确保每个零件被安装在正确的位置环境与工具集成工艺手册定义了每一步的操作标准规范与约束质检线自动拦截不合格产品验证与测试。在软件开发的上下文中这三者的关系层级如下基础层LLM。提供最底层的代码生成、文本理解、逻辑推理能力。例如GPT-4、Claude 3、DeepSeek-Coder等。核心层AI Agent。它是一个具备自主性的软件实体其核心包含规划Planning拆解复杂任务为子任务。工具使用Tool Use调用外部API、执行命令、查询数据库。记忆Memory保留对话和任务上下文。执行Execution驱动整个任务流程。 Agent利用LLM的能力来完成这些环节的决策。基础设施层Harness。这是工程化的关键。它为Agent提供标准化环境统一的开发/运行时环境预装依赖。工作流引擎定义任务执行的标准步骤如解析Spec - 生成代码 - 运行单元测试 - 提交PR。规范与约束集成代码规范ESLint, Pylint、安全扫描SAST、架构守护规则。验证与反馈闭环自动运行测试将失败结果结构化地反馈给Agent驱动其迭代修正。核心认知Harness 的核心价值在于“约束下的创造力”。它通过工程化手段将AI不可控的“自由发挥”引导到可控、可预测、可集成的生产轨道上。2.2 Spec-Driven Development人机协作的契约传统开发中我们靠自然语言需求文档PRD和口头沟通来对齐。但对AI而言自然语言充满歧义。Spec-Driven Development 要求我们将需求转化为结构化、可验证的机器可读规范。一份好的AI Coding Spec通常包含以下部分任务描述Task清晰的目标如“实现一个用户注册的RESTful API端点”。输入/输出规范Input/Output Specification输入HTTP方法POST、路径/api/v1/register、请求体格式JSON Schema。输出成功响应201 Created 返回用户ID、错误响应400 Bad Request 验证错误详情。约束条件Constraints技术栈必须使用Spring Boot 3.x JPA 密码需用BCrypt加密。业务规则邮箱必须唯一用户名需3-20位字符。代码规范必须通过Checkstyle检查代码覆盖率需80%。验收条件Acceptance Criteria功能测试用例给定有效载荷应返回201和用户ID。集成测试注册后数据库中应存在对应记录密码为哈希值。负面测试重复邮箱注册应返回409 Conflict。上下文Context相关的已有代码片段、数据库表结构、API文档链接。Harness 会解析这份Spec并将其作为唯一真理源贯穿Agent的整个工作流程。Agent的每次代码生成和修改都必须以满足Spec中的所有条款为目标。2.3 与持续交付流水线的融合这是Harness工程化的终极体现。AI Agent不再是孤立运行的脚本其产出的代码需要无缝融入现有的CI/CD持续集成/持续部署流水线。我们的目标状态是触发开发者在任务管理平台如Jira创建一个标记为“AI-Implement”的任务并附上Spec。Harness调度Harness框架监听到新任务唤醒一个专用的AI Agent实例并将Spec和环境上下文注入。Agent执行Agent在Harness提供的沙箱环境中工作遵循工作流生成代码 - 运行本地预提交检查lint 单元测试- 提交代码到特性分支。CI流水线接管代码提交自动触发CI流水线如Jenkins GitLab CI运行更全面的集成测试、安全扫描、构建镜像。反馈与迭代如果CI失败Harness会捕获失败日志将其结构化后反馈给Agent。Agent分析错误自动生成修复代码并再次提交形成闭环。交付所有检查通过后自动创建PR等待人工评审合并。之后流程与常规CD流水线无异。这样AI生成的代码从诞生起就经历了与人工代码同等甚至更严格的质检确保了交付质量。3. 实战从零搭建你的第一个AI Coding Harness理论说再多不如动手一试。下面我将以一个具体的场景为例展示如何搭建一个最小可行MVP的Harness。我们选择Python技术栈因为它生态丰富易于演示。场景自动为给定的Python函数生成对应的单元测试用例。3.1 环境与工具选型我们不会从头造轮子而是基于优秀的开源框架进行搭建。核心组件如下AI Agent框架LangChain。它是目前构建AI应用最流行的框架之一提供了丰富的Agent、工具链和记忆模块。虽然性能开销稍大但其设计模式和生态完整性对于构建复杂Harness非常有帮助。核心LLMOpenAI GPT-4或Anthropic Claude 3。对于代码生成任务这两者是当前效果最好的。为降低成本也可以使用DeepSeek-Coder的开源模型通过Ollama或vLLM在本地部署。工作流与编排LangGraphLangChain的子库。它允许我们用图Graph的方式清晰地定义Agent的工作流比传统的线性链Chain更强大适合处理带有循环、条件分支的复杂任务。工具集成代码执行采用安全的沙箱环境如Docker容器或E2B的云原生沙箱。绝对禁止让Agent直接在本机或服务器上执行任意命令。版本控制通过GitPython库让Agent能操作Git仓库。代码静态检查集成pytest运行测试、coverage计算覆盖率、black格式化、flake8语法检查。规范定义使用Pydantic模型来定义结构化的Spec。这能确保Spec格式正确并方便序列化/反序列化。避坑指南在工具选型初期建议优先选择文档齐全、社区活跃的框架。LangChain虽然有时被诟病“抽象泄漏”但其快速原型能力无可比拟。切勿在项目初期就追求极致的性能或自定义快速验证流程的可行性更重要。3.2 定义结构化任务规范Spec首先我们用Pydantic定义一个机器可读的TestGenSpec。from pydantic import BaseModel, Field from typing import List, Optional class TestGenSpec(BaseModel): 生成单元测试的任务规范 task_id: str Field(..., description唯一任务标识) target_function_code: str Field(..., description需要被测试的Python函数源代码) target_function_name: str Field(..., description函数名) source_file_path: str Field(..., description目标函数所在源文件的路径用于上下文) # 约束条件 test_framework: str Field(defaultpytest, description测试框架默认为pytest) min_coverage_percentage: float Field(default80.0, ge0.0, le100.0, description要求达到的最低代码覆盖率百分比) required_imports: Optional[List[str]] Field(default_factorylist, description测试文件中必须包含的导入语句) # 验收标准 edge_cases: Optional[List[str]] Field(default_factorylist, description必须覆盖的边界用例描述如输入为空列表 参数为None) # 输出物 output_test_file_path: str Field(..., description生成的测试文件应存放的路径)这个Spec对象就是Harness与AI Agent之间的“合同”。它明确、无歧义地规定了输入、约束和输出要求。3.3 构建核心AI Agent接下来我们使用LangChain和LangGraph来构建一个具备规划、执行、自我验证能力的Agent。import os from typing import TypedDict, Annotated, Sequence import operator from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, SystemMessage from langgraph.graph import StateGraph, END from langgraph.checkpoint import MemorySaver # 1. 定义Agent的状态State class AgentState(TypedDict): Agent工作流的状态 spec: TestGenSpec # 输入的任务规范 messages: Annotated[Sequence, operator.add] # 与LLM的对话历史 generated_test_code: str # 生成的测试代码 validation_result: dict # 验证结果如{“tests_passed”: bool, “coverage”: float, “issues”: list} iteration_count: int # 迭代次数用于防止无限循环 # 2. 初始化LLM llm ChatOpenAI(modelgpt-4-turbo-preview, temperature0.1) # 低temperature保证输出稳定 # 3. 定义关键节点Nodes def analyze_spec_node(state: AgentState) - AgentState: 节点1分析Spec规划测试策略 system_prompt 你是一个资深的Python测试工程师。你的任务是根据给定的函数代码和规范规划如何编写全面的单元测试。 请思考需要测试哪些正常路径、边界条件和异常情况。 human_prompt f 这是需要测试的函数 python {state[spec].target_function_code} 这是任务规范 {state[spec].model_dump_json(indent2)} 请制定一个测试策略大纲。 response llm.invoke([SystemMessage(contentsystem_prompt), HumanMessage(contenthuman_prompt)]) state[messages].append(response) return state def generate_test_code_node(state: AgentState) - AgentState: 节点2根据策略和Spec生成测试代码 # 这里可以从messages中提取上一步的策略也可以直接让LLM基于全部上下文生成 prompt f 基于之前的分析和以下绝对必须遵守的规范为函数 {state[spec].target_function_name} 生成完整的pytest测试代码。 规范要求 1. 测试文件路径必须是{state[spec].output_test_file_path} 2. 必须包含这些导入{state[spec].required_imports} 3. 必须覆盖这些边界情况{state[spec].edge_cases} 4. 代码风格应简洁专业。 函数代码 python {state[spec].target_function_code} 只输出最终的Python测试代码不要有任何解释。 response llm.invoke([HumanMessage(contentprompt)]) generated_code response.content # 简单清理确保获取代码块内容 if python in generated_code: generated_code generated_code.split(python)[1].split()[0].strip() elif in generated_code: generated_code generated_code.split()[1].split()[0].strip() state[generated_test_code] generated_code state[messages].append(response) return state def validate_test_code_node(state: AgentState) - AgentState: 节点3在沙箱中执行生成的测试进行验证 # 这是关键我们将生成的代码和原函数代码写入临时目录 import tempfile import subprocess import json validation_result {tests_passed: False, coverage: 0.0, issues: []} with tempfile.TemporaryDirectory() as tmpdir: # 1. 写入源文件 source_path os.path.join(tmpdir, os.path.basename(state[spec].source_file_path)) # 这里简化处理实际需要从仓库中提取原文件这里我们假设只包含目标函数 with open(source_path, w) as f: f.write(state[spec].target_function_code) # 2. 写入生成的测试文件 test_path os.path.join(tmpdir, state[spec].output_test_file_path) os.makedirs(os.path.dirname(test_path), exist_okTrue) with open(test_path, w) as f: f.write(state[generated_test_code]) # 3. 在Docker沙箱中运行测试和覆盖率检查此处为简化示例实际应调用Docker API # 模拟一个验证过程 try: # 这里应该是实际的pytest和coverage命令执行 # 例如result subprocess.run([pytest, test_path, --cov, ...], capture_outputTrue, textTrue) # 解析result.stdout/result.returncode # 为演示我们假设第一次生成成功率70% state[iteration_count] 1 if state[iteration_count] 1: validation_result[tests_passed] True validation_result[coverage] 70.5 validation_result[issues] [边界条件‘输入负数’未覆盖] else: validation_result[tests_passed] True validation_result[coverage] 95.0 validation_result[issues] [] except Exception as e: validation_result[issues].append(f执行验证时发生错误{e}) state[validation_result] validation_result return state def decide_next_node(state: AgentState) - str: 条件判断边根据验证结果决定下一步是重试还是结束 if state[validation_result][tests_passed] and state[validation_result][coverage] state[spec].min_coverage_percentage: return success elif state[iteration_count] 3: # 最多重试3次 return failure else: return retry # 4. 构建工作流图Workflow Graph workflow StateGraph(AgentState) # 添加节点 workflow.add_node(analyze, analyze_spec_node) workflow.add_node(generate, generate_test_code_node) workflow.add_node(validate, validate_test_code_node) # 设置边连接 workflow.set_entry_point(analyze) workflow.add_edge(analyze, generate) workflow.add_edge(generate, validate) # 添加条件边 workflow.add_conditional_edges( validate, decide_next_node, { success: END, failure: END, # 可以连接到一个“人工介入”节点 retry: generate # 验证不通过返回“生成”节点重试 } ) # 5. 编译并持久化工作流 app workflow.compile(checkpointerMemorySaver())这个Agent工作流定义了一个清晰的循环分析 - 生成 - 验证 - 根据结果决定结束或重试。这正是Harness工程化的精髓将AI的创造力置于一个可度量、可反馈、可纠正的闭环系统中。3.4 集成到CI/CD流水线最后我们需要将这个Harness变成一个服务能被CI/CD流水线调用。一个简单的方式是将其封装为一个HTTP服务或命令行工具。# harness_service.py (简化版) from fastapi import FastAPI, BackgroundTasks from pydantic import BaseModel import asyncio from .agent_workflow import app as agent_app # 导入上面编译好的工作流 from .spec_models import TestGenSpec app FastAPI(titleAI TestGen Harness Service) class TaskRequest(BaseModel): spec: TestGenSpec app.post(/api/v1/generate-test) async def create_test_gen_task(request: TaskRequest, background_tasks: BackgroundTasks): 接收Spec异步启动AI Agent工作流 task_id request.spec.task_id # 初始化状态 initial_state AgentState( specrequest.spec, messages[], generated_test_code, validation_result{}, iteration_count0 ) # 在后台异步执行工作流 background_tasks.add_task(run_agent_workflow, task_id, initial_state) return {task_id: task_id, status: accepted, message: Task is being processed asynchronously.} async def run_agent_workflow(task_id: str, initial_state: AgentState): 实际运行Agent工作流的函数 config {configurable: {thread_id: task_id}} async for event in agent_app.astream(initial_state, configconfig): for node_name, node_value in event.items(): if node_name validate and node_value.get(validation_result): result node_value[validation_result] # 这里可以将结果更新到数据库或消息队列通知CI流水线 if result[tests_passed] and result[coverage] initial_state[spec].min_coverage_percentage: print(f[SUCCESS] Task {task_id} passed validation.) # 触发后续CI步骤如提交代码 elif initial_state[iteration_count] 3: print(f[FAILED] Task {task_id} failed after max retries.) # 触发告警通知人工介入在GitLab CI或GitHub Actions的配置文件中你可以这样调用这个服务# .gitlab-ci.yml 片段 ai_generate_test: stage: test script: - | # 1. 从当前变更中识别出需要测试的新函数可通过静态分析工具 # 2. 为每个函数构建Spec # 3. 调用Harness服务API curl -X POST ${HARNESS_SERVICE_URL}/api/v1/generate-test \ -H Content-Type: application/json \ -d $(generate_spec_for_function) # 4. Harness服务异步处理完成后会通过Webhook或更新状态文件通知CI # 5. CI流水线检测到测试文件生成后继续运行后续的集成测试、构建等步骤 rules: - changes: - src/**/*.py # 当Python源码变更时触发至此一个最小化的、具备自我验证和修复能力的AI Coding Harness就搭建完成了。它接收结构化的Spec驱动AI Agent生成代码并自动验证结果符合要求后才允许进入后续的交付流程。4. 进阶构建企业级Harness的关键考量上面的MVP演示了核心概念但要投入生产环境还需要考虑更多工程化细节。4.1 安全与隔离不容有失的底线让AI执行代码是最高风险的操作之一。必须建立多层防护网络隔离运行Agent和代码执行沙箱的环境必须处于独立、无外网访问权限的网络中。资源限制对沙箱容器严格限制CPU、内存、磁盘和运行时间防止恶意或错误代码耗尽资源。文件系统隔离使用只读文件系统挂载仅对必要的临时目录开放写权限。绝对禁止访问宿主机的敏感路径。命令白名单如果Agent需要执行Shell命令必须通过严格的工具抽象层仅暴露允许的命令如git clone,pytest,mvn compile而非直接提供Shell。内容安全扫描对AI生成的所有代码、文件在离开沙箱前进行静态安全扫描SAST检查是否有密钥硬编码、危险函数调用等。4.2 性能、成本与稳定性优化LLM调用优化缓存对相似的Spec和代码片段使用向量数据库缓存LLM的响应大幅降低成本和延迟。流式输出与超时控制设置合理的超时时间避免因LLM响应慢而阻塞整个流水线。降级策略当主要LLM如GPT-4服务不可用时能自动切换到备用模型如Claude Haiku或本地模型。Agent状态管理对于长时间运行的任务需要将Agent的状态记忆、中间结果持久化到数据库如Redis支持断点续跑。异步与队列Harness服务端应采用异步框架如FastAPI并将任务放入消息队列如RabbitMQ Celery实现请求的削峰填谷和任务的可追溯。4.3 监控、可观测性与持续改进没有度量就无法改进。必须建立完善的监控体系关键指标任务成功率首次生成通过率、最终通过率。迭代次数分布多少任务需要Agent自我修正修正多少次。耗时分析各阶段生成、验证的耗时。成本分析每个任务消耗的Token数、API调用费用。链路追踪为每个任务分配唯一ID记录完整的执行链路包括LLM的输入输出、工具调用记录、验证日志。这在排查问题时至关重要。反馈闭环建立机制让开发人员可以对AI生成的代码进行“好评/差评”标注。这些反馈数据可以用来微调提示词Prompt或作为评估不同LLM/Agent策略效果的依据。5. 避坑指南与最佳实践结合我们团队踩过的坑总结出以下几点血泪经验Spec的质量决定天花板垃圾进垃圾出。花时间设计好结构化的Spec模板并培训团队成员如何编写清晰的Spec这比优化任何Agent参数都重要。初期可以由资深开发审核Spec。从小处着手定义成功标准不要一开始就试图让AI开发整个微服务。从一个明确的、边界清晰的小任务开始比如“为这个Repository模式生成单元测试”、“为这个DTO生成OpenAPI Schema注解”。明确“成功”的定义如测试覆盖率90% lint检查通过并以此为标准衡量Harness的有效性。人始终在环Human-in-the-loop在完全信任AI之前必须设置人工评审环节。尤其是对于核心业务逻辑的代码生成AI提交的PR必须经过人工审核后才能合并。Harness的目标是提升效率而非取代人。版本化一切对Harness框架本身、使用的提示词模板、工具集配置、甚至LLM的版本都要进行严格的版本控制。任何变更都可能影响输出结果的可复现性。警惕“幻觉”与“妥协”AI可能会为了通过你设定的自动化测试如单元测试而“作弊”。例如它可能生成一个只针对测试用例返回固定值的函数而不是实现真正的逻辑。因此验证逻辑需要多层次不能只依赖单元测试还要结合集成测试、代码逻辑评审。团队文化与技能升级推行AI Coding Harness不仅是技术变革更是文化变革。需要让团队成员理解其价值从“写代码”转向“写Spec、审代码、设计流程”。培养团队的“AI工程化”思维。让AI高效、可靠地参与软件开发已不再是科幻。通过引入Harness这一工程化框架将Spec-Driven Development作为人机协作的契约并将AI Agent无缝集成到持续交付流水线中我们能够将AI的创造力规模化、规范化地转化为实际生产力。这条路充满挑战但回报也同样丰厚——它将开发者从重复劳动中解放出来更专注于架构设计、复杂问题解决和创新。
返回列表