这两年圈内聊 AI Coding 的动静特别大。真正的分水岭其实不在“模型能不能写代码”而在“你敢不敢把一段由大模型生成的代码交给构建体系正式跑”。单点对话生成一个函数已经是家常便饭但从需求、设计、编码到提交一个能合入的改动中间还隔着排错、review、接口适配、回归验证这些环节每一步都会把裸奔式的 AI 输出打回原形。这不是模型不够强而是流程缺少约束。我最近在梳理一套把“智能体”嵌进研发管线的内部框架名字就叫 Agentic Harness Workflow。它不是让你绑定某个固定的商业方案而是一整套把 AI Coding 从“临时对话生成”升级成“结构可管理、过程可干预、回归可复用”的工程化流水线方法。这篇文章我把它完整拆开讲设计思路、最小配置、易碎点以及排错映射适合独立开发者也适合那些已经在用 AI 改代码、但总觉得集成环节不可控的小团队。1. 为什么 AI Coding 需要工程化1.1 从一次性对话到可复用流水线的转变刚开始接触 AI 编码工具的人通常是被“一句提示词生成一段能跑的代码”这个瞬间打动的。你会觉得写代码的门槛被铲平了把需求描述清楚回车代码就出来了。但用到第三个项目你一定会发现生成的代码能跑但离“能被工程接纳”还有很大一段距离。能跑只是单点成立能被接纳则意味着它要过编译、过单测、过风格检查、过评审意见、过其它模块的接口约定。也就是从那个节点开始我意识到问题不在“生成”而在“组织”。一个模型在一个回合里可以生成一百行高质量代码但它没法天然保证这一百行代码是放在正确的位置、遵循了正确的边界、没有被无关需求污染。这就像你找一位很厉害的自由撰稿人约稿他给你一篇文字干净的文章但你还要配图、排版、校对、对照标题重新调整结构最后才能发布。稿件质量高不高是一回事稿件能不能进入发布流水线又是另一回事。所以工程化的第一个目标不是追求单次生成的正确率而是给每次生成安一个“轨道”。让模型在轨道里分段工作每段都有输入、输出、校验标准。轨道本身不产生代码但它决定了代码如何被论证、被检查、被合入。把 AI Coding 变成工程化流程我理解的核心就是把“不可复现的灵光一现”变成“可重复执行的工序”。1.2 直接让模型“裸奔”的四个症状如果你现在只是打开 IDE 里的 AI 对话窗口把整个项目路径拖进去然后说“帮我把这个 bug 修了”你会反复撞上下面四类问题。第一探索无边界。模型在对话里可以“看到”几乎所有的文件它可以提任何改法没有谁能拦住它越过模块边界。短对话里你还能靠人肉盯住换来换去之后它到底改了几个文件夹、动了哪些被其它功能依赖的公共函数你完全没底。无边界探索的直接后果就是改动范围失控。我见过一次改一个“登录超时提示”的小需求模型顺手重构了共用的认证中间件导致三个业务模块一起翻车。第二上下文不可信。项目一大模型的上下文窗口必然被塞满。它不知道哪些信息是过时的哪些文件是废弃的哪些配置是历史遗留它只能基于你能喂给它的文件做判断。于是它经常给出一个逻辑自洽、但跟真实代码库脱节的方案。第三不可复验。对话型 AI 的操作过程是随机的你无法把“上一轮成功修好某个 bug 的完整操作”录制下来下一次以相同输入重放。没有录制的过程就不可能进回归体系。昨天它能跑通今天同样的描述跑出另一套改法这对工程来说是致命的。第四无门禁。模型生成完一段代码自己在对话里说“已经完成”没有构建没有测试没有人工审批节点。代码质量好不好全靠它在文本世界里的自我评判。这种东西直接进主干分支迟早要出事。这四个症状指向同一个结论AI 编码不是没有生产力而是缺少机制来约束生产力。Harness 的价值就是把“探索、决策、执行、验证”从模型的黑盒行为里拆出来放到一套开发者可以定义、可以观察、可以打断的流程框架里。2. Harness 工作流的整体设计思路2.1 五大核心概念Agent、Task、Tool、Gate、HarnessHarness 这个词最早出现在工程领域本意是一套把被测对象固定住、再提供输入和测量手段的夹具。测试领域里的 test harness 很常见它不执行被测系统的核心逻辑却决定了测试能不能稳定、重复、可控地发生。借用到 AI Coding 里Harness 就是这个“夹具壳”模型是壳里的执行者而壳本身承担编排、约束、检查、底账。在我搭的框架里一共有五个概念级组件。Agent 是执行体负责完成某一类工作比如“分析代码影响面”“生成单元测试”“重构某个函数”。它由模型能力加提示策略共同构成你可以把 Agent 理解为一种特定技能的执行者。Task 是工作单元描述一次具体要做的事。Task 要有明确的输入、输出、验收标准。比如“找出订单模块里所有未处理的空指针风险”这是一个 Task而“把项目代码优化一下”不是 Task它太含糊了。Tool 是 Agent 可使用的工具集合比如读取文件、运行测试、搜索符号、执行静态检查。工具是 Agent 与真实代码库交互的唯一通道。没有工具Agent 就只能凭空输出代码片段有了工具它才能拿到真实的测试结果、编译反馈和代码结构信息而不是靠猜。Gate 是门禁节点也是 Harness 区别于普通对话的重中之重。Gate 会停顿下来执行一个校验逻辑通过则继续不通过则打回。它可以是自动化的比如必须跑过单测也可以是人力的比如“必须由开发者确认改动范围没有越界”。Gate 本质上让流程从“一条道冲到黑”变成“分阶段验收”。Harness 本身则是把这些组件穿起来的编排层。它定义哪些 Agent 在什么阶段可以运行、以什么顺序运行、哪些工具可以被调用、哪些 Gate 必须通过。一个 Harness 工作流就是一张有向图节点是 Task/Agent边是依赖关系Gate 嵌在关键路径上。2.2 为什么需要一层“约束壳”而不是一个提示词模板很多人会问这些规则我写成一段很长的系统提示词塞给模型不就行了吗为什么要单独做一层框架出来提示词模板确实能起到一定的引导作用但它有两个致命短板。提示词没有强制力。你在提示词里写“不要修改无关文件”模型在生成过程中仍然可能越界。它没有在真实文件系统上执行命令的能力边界也没有一个机制在越界之后被拦截。而 Harness 可以通过工具白名单控制 Agent 能触达的路径非白名单操作直接拒绝这比提示词里的“请遵守”可靠一个量级。提示词不可编排。工作流里最关键的不是让模型“做得对”而是让它在多个阶段之间建立依赖关系先做影响分析再做编码再跑测试再评审。这些阶段需要真实的外部状态来推进比如前一个阶段的产物要落盘、后一个阶段要读取。一个纯提示词无法承载这种状态流转它只是一次性的上下文输入。所以我的经验是把约束写进代码和配置把策略写进提示词。约束是硬性的策略是软性的。模型可以在策略空间里自由发挥但它绝对碰不破约束壳。这就是 Harness 真正的意义不是把模型关进笼子而是给笼子装上仪表盘和安全阀让笼子里的模型能安全地高速运转。2.3 工作流与单次调用的本质差异单次调用是“输入一句话输出一段代码”。工作流是“输入一个目标输出一个经过多级验证的变更产物”。从用户感受上看前者像是一次即时聊天后者像是一条生产线。生产线上的每个工位都有自己的输入要求和质检标准工件流过所有工位之后才成为成品。单次调用如果类比就像是让一位全能技师在没图纸、没质检、没工具台账的情况下现场给你手工敲一台机器出来。天才技师可能做出来好东西但没法保证每次都能做出来也没法保证做出来的东西能通过验收。从可观测性上看工作流里的每一步都留下了痕迹哪个 Agent 跑了什么 Task、调用了哪些工具、Gate 校验输出了什么结论。这些痕迹可以复盘可以重放可以作为下一次任务的参考。单次调用只有一段对话记录而且还是不可稳定复现的。从风险控制上看工作流允许你在任意 Gate 位置暂停、回退、人工干预。你可以看每个阶段的产物再决定是否继续。单次调用一旦生成了代码你要么全盘接受要么全盘拒绝中间几乎没有管理空间。3. 核心细节解析与实操要点3.1 任务拆分把长流程切成可验证的小步把需求拆成 Task 是 Harness 工作流里最考验功力的一步。拆得好模型每一步都有明确边界处理起来快且准拆得不好每个 Task 都还是一个大型项目的缩影模型照样会迷失。我的拆分原则是三条。第一每个 Task 要有独立的验收标准。不能光说“优化性能”要说“将订单查询接口在千条数据下的 P95 响应时间降到 200ms 以内”。第二每个 Task 的产物形态要明确。是代码改动、是分析报告、还是测试用例产物越具体后面的 Gate 越好设计。第三Task 之间的依赖要尽量单向。A 任务的输出是 B 任务的输入避免两个 Task 循环依赖否则模型在两个状态之间反复横跳很难收敛。举个实际例子。一个需求是“在批量下载场景里增加并发限流”。我不会把它拆成一个 Task而是拆成影响分析 Task找出下载执行链路里所有相关函数和入口、设计 Task给出限流策略和参数建议、编码 Task在指定文件范围内实现限流逻辑、验证 Task编写或更新单测并跑通全部相关测试用例。这一步拆完每个 Agent 面对的问题域一下子缩小了模型不再需要同时处理“理解整个系统 设计算法 写代码 自测”四件事而是每次只处理一件事。3.2 工具接入与上下文管理Harness 环境里Agent 不能直接翻文件系统它必须通过 Tool 层访问项目资源。Tool 层的设计有两个关键点。第一个关键点是工具粒度。工具不要太粗也不要太细。太粗的工具比如“执行任意 shell 命令”这等于让 Agent 在服务器上裸奔安全性和可控性都很差。太细的工具比如“打开第 3 行并返回字符”信息密度太低模型得来回调用很多次才能积累足够的上下文。折中的做法是把工具设计成领域原子操作读取指定路径文件、搜索符号定义、查找引用、运行某个具体测试文件、执行静态检查报告、查看最近 git 提交差异。每个工具干一件明确的事组合起来却能覆盖大多数开发场景。第二个关键点是上下文节流。我在框架里做了一个分层读取策略Agent 需要了解代码库时先通过“目录结构读取 搜索符号引用”建立起宏观认知再按需读取具体文件内容。这比把整个项目一次性塞进上下文要省得多也更接近人类的阅读习惯。配合上我还会把每次读取的结果做摘要萃取控制进入模型上下文的信息量。上下文不是越大越好而是越相关越好。喂进去十个文件七个别无用模型会把噪音也当成事实来用结果常常是生成了一个看起来考虑周全、实际上基于错误前提的方案。3.3 Gate 门控人类审批点和自动校验点Gate 的分类方式我一般按两个维度一个是校验主体人还是程序一个是校验时机阶段入口还是阶段出口。自动校验点最常用的任务是语法编译通过、风格规范检查、单测通过、数据流安全扫描。这类校验一旦写进 Harness就变成了模型代码合入前的硬门槛。模型可以用任意风格写代码但跑不过静态检查它就卡住无法进入下一个阶段。这种硬门槛比任何提示词都有效。人工审批点则是用在那些无法自动化判断的环节上。比如影响范围评估模型分析出某个改动会影响三个模块但这个影响能不能被接受只有开发者知道。再比如架构一致性模型提出的方案符合局部目标是否符合整体技术架构需要人来拍板。我刚搭 Harness 的时候Gate 放得特别少觉得麻烦。后来有一次编码 Agent 在“修复缓存过期问题”的任务里把缓存键的生成规则从“模块前缀 业务键”改成了“全局业务键”单测确实全过了但线上数据被新旧两套键值混着读写过了两天才被监控发现。那次之后我才彻底认清凡是能影响全局的节点都必须放 Gate宁多勿缺。3.4 闭环验证不验不合并一条完整的工作流必须以“验证”结束不能以“代码生成”结束。很多 AI Coding 事故的本质是模型把“写完代码”当成了“改完 Bug”。但工程系统里写完代码只是起点验证才是终点。闭环验证要做三层。第一层是最小验证编译和新增用例跑通证明代码本身没写崩。第二层是关联验证找出这个模块的消费者跑一遍相关模块的测试或者做一次接口兼容性检查。比如你改了内部工具函数的签名就要把所有调用它的地方都拉出来测一遍。第三层是环境验证如有条件在临时的干净分支上重建构建并跑关键路径用例。这一步不一定要每次全量做但对关键模块的变更一定要做。我在设计 Harness 时把“验证”作为一个独立阶段和前序编码阶段隔着一个 Gate。前序阶段产出的代码只有通过了第一层验证才能进入第二层否则打回给编码 Agent 重新处理。这种“打回”机制特别重要因为模型自己不会主动发现代码编译不过。有了这一层闭环模型生成的代码质量会以肉眼可见的速度提升因为它在流程里被迫反复检查自己。4. 实操过程与核心环节实现4.1 一个最小可用的 Harness 工作流定义接下来是这套框架里最值得拿走的干货一个最小可用的工作流定义。我先给你一个非常朴素的 JSON 结构它能跑通“需求到 PR”的全流程又不至于让你一上来就被复杂的配置吓退。{ workflow: feature_dev, stages: [ { name: impact_analysis, agent: code_analyzer, tools: [list_files, read_file, search_symbol, find_references], input: 需求描述{requirement}\n项目根路径{repo_path}, output: 影响分析报告.md, gate: { type: human, description: 确认分析报告覆盖所有相关模块且没有遗漏边界 } }, { name: code_generation, agent: code_writer, tools: [read_file, write_file, search_symbol, find_references, git_diff], input: 影响分析报告.md\n需求描述{requirement}, output: 代码变更文件列表, gate: { type: auto, commands: [npm run lint, npm run build] } }, { name: test_generation, agent: test_writer, tools: [read_file, write_file, run_test], input: 代码变更文件列表, output: 测试变更文件列表, gate: { type: auto, commands: [npm run test -- --changedSinceorigin/main] } }, { name: human_review, agent: none, tools: [], input: test_generation 的全部产物, output: 评审结论, gate: { type: human, description: 开发者人工 Review通过后进入 PR 提交 } } ] }这个配置的核心逻辑是需求先进入影响分析产出报告后由人审批影响范围确认了才允许编码 Agent 出手代码生成后自动化跑 lint 和 build测试 Agent 补测试跑回归最后交给人工 Review。每一步都是上一阶段的 Gate 通过之后才推进。4.2 关键 Runner 逻辑拆解配置只是静态描述真正让工作流转起来的是 Runner也就是执行引擎。Runner 做的事情可以简化成一个循环取节点、解析输入、唤起 Agent、收集产物、执行 Gate、决定下一步。def run_workflow(workflow, context): current workflow[stages][0] while current: context.log(进入阶段 current[name]) # 1. 解析输入 inputs resolve_inputs(current[input], context) # 2. 如果这个阶段有 Agent就让 Agent 执行 if current.get(agent) and current[agent] ! none: result call_agent(current[agent], inputs, current[tools]) save_outputs(current[output], result, context) else: # 比如人工 Review 阶段只需要把产物收集给用户 collect_outputs(current[output], context) # 3. 执行 Gate gate current.get(gate) if gate[type] auto: for cmd in gate[commands]: success run_shell(cmd) if not success: context.log(自动门禁未通过 cmd) return blocked elif gate[type] human: wait_for_approval(current[name], gate[description], context) # 4. 推进到下一个阶段 current next_stage(workflow, current) return completed这段伪代码看起来简单但它把工程化最关键的两个行为固定下来了第一Agent 的每一步都必须经过 Gate 检查失败就停第二每个阶段的产物都会落盘保存形成可追踪的工作流底账。Runner 里还有一个隐含机制任何一步失败了可以选择“打回上一阶段”而不是直接全部重跑。打回时要把失败信息整理成结构化摘要连同 Gate 输出一起作为输入喂给上一个 Agent让它针对性修改。这个回环机制比整条重跑要高效得多。4.3 配置一个真实任务从需求到合入纸上谈兵再多不如跟着走一遍。以我手上一个模拟项目 X 为例这个项目是一个订单管理系统最近接到一个需求批量发货接口需要加上超时取消机制超过 30 分钟未确认的发货单自动标记为失败。第一步把需求文本放进 impact_analysis 阶段。这是最有可能出彩也最容易翻车的一步。这个项目的代码库交接不全遗留模块多导致代码分析 Agent 一开始给出的影响范围只有“批量发货接口”和“订单状态枚举”。我按下暂停手动补上了“任务调度模块”和“发货确认回调函数”两个搜查入口然后让人工审批通过。没有这一层人工 Gate编码 Agent 后面只会在接口本体上修修补补真正的超时调度问题根本没被覆盖。第二步进入 code_generation。因为前置分析报告指定了明确的文件范围和约束这个阶段的产出质量明显比直接对话式生成要高。它不是凭记忆猜结构而是基于 read_file 和 find_references 拿到的真实引用关系动手。生成的代码里有一个小瑕疵超时任务在异常场景下没有重试机制。我在评审时抓了出来要求补充异常处理路径后重新跑自动 Gate。第三步test_generation 阶段的 Agent 比起我人工写测试要省力得多但它很容易只补“快乐路径”用例。我给这个 Agent 的提示里固定加了一条硬要求必须包含超时边界值测试分别验证 29 分钟、30 分钟、31 分钟三个场景。这个经验是我在落地框架前踩过一次坑得出的模型天然倾向于写“预期成功”用例边界和异常路径需要以规则形式强制。最后是人工评审。机器人产出的代码可以帮我们节省大量时间但“是否要维护这个拆单状态、是否要对发失败做补偿提醒”这类业务规则还是要人来拍板。整个流程走下来一个需要跨 5 个文件、牵涉 2 个遗留模块的改动从需求到可合入的 PR大约用了 2 个小时。直接对话式生成的话这个需求我评估至少要半天还得提心吊胆过 review。4.4 团队协作时加什么这套框架单机用着已经够爽但一旦进入团队协作有几个东西是必须补上的。第一个是状态可见性。团队里其他人可能会在你的工作流跑挂的时候问“现在卡在哪”。这时候 Runner 的每个阶段落盘记录就派上用场了。我在内部做了一个简单的看板展示每个工作流实例当前停在哪个节点、上次 Gate 失败的原因是什么、相关产物在哪里。没有这个看板Harness 就像自己的黑盒工程化就失去了意义。第二个是评审角色分离。人工 Gate 的审批人不能是写提示词定义工作流的人。我也遇到过这种尴尬代码生成 Agent 是自己配置的影响分析报告也是自己确认的到了人工评审阶段就会下意识放松标准。所以团队落地时我会建议把 impact_analysis 的人工 Gate 和 code_generation 后的人工 Review 分给两个人承担。第三个是产物沉淀。每次工作流跑完的影响分析报告、测试用例、失败原因摘要都应该被归档。这些历史数据是后续 Agent 的“记忆库”。下次遇到类似需求新的影响分析 Agent 可以直接检索到旧报告显著提升分析的准确性。5. 常见问题与排查技巧实录5.1 高频失败模式速查表几乎每一个刚开始用这套工作流的团队都会先在一批同样的坑里打转。我把最高频的失败模式整理成了一张速查表。现象通常出现在工作流早期阶段表现为 Agent 产出与预期不符根因初始化阶段配置了过多无用上下文模型把后台垃圾信息当成依据编码 Agent 生成了不在指定文件列表范围内的改动工具层缺少变更范围检查或者是 Gate 只校验了编译没校验 diff 范围测试 Agent 写了大量断言但跑一个挂一个测试 Agent 没有先读取被测模块的真实接口签名它只是凭教程经验在写工作流卡在自动 Gate 上反复重试很可能 Gate 命令本身存在环境依赖比如依赖未安装、路径不对影响分析报告看起来面面俱到却漏了核心调用链分析 Agent 的工具集缺了 find_references它只能靠文本搜索猜测调用关系人流审批点形同虚设审批者面对的信息过载三个小时的工作流产物堆在一起没人能逐个看完这类问题都有一个共性张冠李戴地把模型当成了全能专家。实际上模型的能力上限在很大程度上取决于你为它搭的工具链和上下文它只是整个系统里最容易被替换的执行核心。工具缺失比提示词写得差更致命。5.2 三个大概率要踩的坑第一个坑是我自己在落地时踩得最深的上下文污染。有一段时间为了保证编码 Agent 有足够信息我把需求文档、设计文档、架构图、测试计划全部塞进系统提示词。结果是模型在生成代码时“太全面”为了迎合大量文档写出了一套过度设计的实现原本 100 行能解决的问题写了 400 行。后来我把上下文策略改成“按需拉取”只有影响分析阶段才读全量文档编码阶段只读它真正要改的文件和相关测试问题立刻缓解。第二个坑是自动 Gate 的“环境脆弱性”。我刚开始把 npm run build 做成 Gate 命令但没注意构建脚本依赖了一个本地环境变量。工作流在别人的机器上跑全部失败我自己机器上跑却一切正常。排查了半天发现是 Gate 命令本身不干净不是模型代码的问题。教训是 Gate 命令必须保证可隔离执行要么用容器化环境要么把环境依赖显式写进配置否则 Gate 会成为整个流程最不稳定的节点。第三个坑是打回机制的反馈信息太粗。我第一次做测试失败打回时只是把测试日志原文返给编码 Agent。结果模型看得一头雾水因为它不知道失败发生在哪段代码、是逻辑错误还是环境问题。后来我把失败摘要结构化哪条用例失败、预期值是什么、实际值是什么、对应哪个函数、改动发生在哪个文件。模型拿到这份结构化反馈之后修复成功率明显上升。给模型的信息质量直接影响它下一步的行动质量和人类协作没有本质区别。5.3 实际操作中的排查顺序如果你的工作流跑挂了别急着怀疑模型能力先按这条顺序查一遍。先看 Gate 输出。Gate 是工作流里最硬的事实它说卡了就一定有一个客观原因。如果 Gate 是 build 失败先手动跑一遍 Gate 命令判断是不是环境问题。如果命令能过但工作流里过不了那问题在 Runner 的调用方式。再看产物落盘。每个阶段是否生成了预期的输出文件文件内容是否完整。产物是 Agent 思考的痕迹如果影响分析报告本身就是自相矛盾的那后续所有阶段都会跟着错。再看工具调用日志。Agent 有没有调用过 find_references有没有查看过相关的调用链如果它在没有调用关系工具的情况下直接写代码那它一定是在靠猜。这个问题的根子不在 Agent而在你的工具配置。最后才考虑调提示词。大多数时候问题不在提示词而在工具、门禁和上下文这三座地基。地基稳了提示词简单直接效果也不差。6. 最后再聊聊这套框架的定位从我个人落地这套框架的体会来说Agentic Harness Workflow 最讨喜的地方是它没有把模型当成“更快的程序员”而是把它当成一个必须纳入工程制度的执行单元。模型负责在给定边界内快速试错、生成和自检开发者负责定义边界、设计门禁和做最终决策。人机之间的权责被画得非常清楚这也让我在推进时不再有那么强的失控感。如果你只是偶尔用 AI 生成几个脚本那这套框架确实有点重。但凡是把 AI Coding 用在生产项目、核心模块或者多人协作的代码库里我都建议至少给自己搭一个最小版本的 Harness一个影响分析阶段、一个编码阶段、一个自动检查门禁、一个最终人工审批。不要一步到位搞大而全先把这四个节点跑通把产物记录留下来再一点一点往里加工具和校验。我自己的下一步计划是给这套工作流加上“失败案例自动归档”的能力每次 Gate 打回之后把原因分类存起来积累成一份专属这个代码库的避坑清单。这样一来同样的问题模型只会踩一次。这个方向很有意思等实现得再成熟一点我再专门写一篇出来。
阅读完成 · 觉得有帮助?