Coding Agent生产级调优:Harness工程实战与最后一公里

发布时间:2026/10/3 5:29:10
Coding Agent生产级调优:Harness工程实战与最后一公里 1. 从“能跑”到“好用”之间隔着一条叫 Harness 的河Vibe Coding 这个词从去年火到现在很多人已经过了“哇AI 能写代码”的新鲜期。真正把 Coding Agent 塞进日常研发流程的人都会撞上同一堵墙Demo 里三分钟生成一个贪吃蛇很惊艳但让它在一个有十年历史、几十万行代码、依赖关系盘根错节的生产仓库里改一个真实需求它就开始胡言乱语——改错文件、漏掉边界、跑不通测试、把无关模块一起重构掉。问题往往不出在模型本身。你把同一个模型放进一个裸的对话框和放进一个精心设计的 Harness 里产出质量能差出一个数量级。Harness 这个词直译是“马具”“挽具”放在 Coding Agent 语境里它指的是包裹在模型外面那一整套工程化框架怎么给模型喂上下文、怎么约束它的动作空间、怎么验证它的输出、怎么在失败时回滚和重试。模型是马Harness 是缰绳、鞍具和跑道。马再壮没有合适的挽具也拉不动生产级的车。这篇实录讲的就是“最后一公里”的事。前面九十公里是选模型、搭环境、跑通第一个 Agent 循环网上教程一抓一大把。最后十公里是把一个能跑的 Coding Agent 调优到在生产环境里稳定交付——这才是真正卡住绝大多数团队的地方。我会围绕华为 CodeArts 体系下的生产级实践把 Harness 工程的核心思路、调优手段、踩过的坑尽可能掰开揉碎讲清楚。不管你现在用的是 Claude Code、DeepSeek Harness 还是自研的 Agent 框架这套调优逻辑都是通用的。适合谁看如果你已经能让 Agent 跑起来但产出质量忽高忽低、不敢让它碰核心代码、每次都要人工大改那这篇就是写给你的。如果你还在纠结怎么安装、怎么配 API Key也可以看但重点建议放在第二、三章的工程思路上那些才是决定成败的东西。2. Harness 工程到底是什么把模型关进一个“可验证的笼子”2.1 模型能力的天花板不等于系统能力的天花板先纠正一个特别普遍的认知偏差。很多人调优 Coding Agent 的第一反应是“换个更强的模型”。换模型有用但边际收益递减得很快。我做过一组对比同一个中等规模的重构任务用同一个模型只改 Harness 设计任务成功率从 40% 出头拉到了 85% 以上。模型没变变的只是它看到什么、能做什么、做完之后谁来验收。这背后的逻辑其实很朴素。大模型本质是一个“根据上下文预测下一个 token”的概率机器。它没有记忆没有真正的执行反馈也没有对代码库全局状态的理解。你给它一个模糊的指令它就给你一个模糊的、看起来合理的输出。Harness 的作用就是把这个概率机器约束到一个确定性的工程流程里把模糊变具体把开放变封闭把“看起来对”变成“验证过对”。打个比方。模型像一个极其聪明但完全没有工程纪律的实习生。你让他“优化一下这个模块”他可能真的去优化了也可能顺手把你不想动的地方也改了还可能改完不跑测试就说“搞定了”。Harness 就是给这个实习生配的导师加 CI 流水线任务拆解清楚、改动范围圈定、每步都有检查、交付前必须过测试。2.2 Harness 的四个核心职责把 Harness 拆开看它主要在干四件事这四件事构成了调优的四个抓手。第一是上下文供给。模型在每一步需要看到什么是整个仓库还是相关文件是原始代码还是带注释的摘要历史对话保留多少检索用什么策略这一块直接决定模型“知不知道自己在干什么”。上下文给少了模型瞎猜给多了关键信息被淹没还烧 token。第二是动作空间约束。模型能执行哪些操作只能读还是能写能跑终端命令吗能装依赖吗能改配置文件吗动作空间越大能力越强但失控风险也越高。生产环境里动作空间的设计是一门取舍的艺术。第三是输出验证。模型说改完了怎么知道真的改对了编译过了吗测试过了吗静态检查过了吗改动是否符合代码规范验证环节是 Harness 里最容易被忽视、却最影响最终质量的部分。第四是失败恢复。模型改错了怎么办是回滚重来还是带着错误信息让它自我修正重试几次每次重试给什么新信息这一块决定了 Agent 在长任务里的鲁棒性。2.3 为什么“最后一公里”这么难前面九十公里好走是因为任务简单、环境干净、容错率高。最后一公里难是因为生产环境的三个特性规模大、耦合深、后果重。规模大意味着上下文塞不下必须做检索和裁剪。耦合深意味着改 A 可能影响 B模型很难自己发现这种隐性依赖。后果重意味着不能试错一次错误的提交可能污染主干分支。这三条叠加起来就是为什么很多团队在 Demo 阶段信心满满一上生产就翻车。华为 CodeArts 这套体系的价值恰恰在于它把软件工程的既有能力——代码检索、依赖分析、CI/CD、代码检查——和 Agent 循环缝合在了一起。Agent 不是孤立地写代码而是在一个已经被工程化治理过的代码库里工作。这是它和裸用 Claude Code 最大的区别。3. 上下文供给调优让模型“看得准”比“看得多”重要3.1 全量塞入是新手最容易犯的错我见过太多团队的第一版 Harness就是把整个相关目录的文件内容拼起来塞进 prompt。结果呢模型要么被无关代码带偏要么在长上下文里“迷失中间”关键的那几行反而没注意到。更现实的问题是成本——一个中等仓库全量塞入单次调用轻松几十万 token跑几十轮下来账单能吓死人。正确的做法是分层检索加动态裁剪。第一层用符号索引函数名、类名、接口定义快速定位相关实体第二层用调用关系图扩展一跳或两跳的依赖第三层才把真正相关的代码片段按优先级拼进上下文。每一层都有预算上限超了就按相关性分数砍。这里有个实操细节相关性分数不能只看文本相似度。纯向量检索在代码场景里经常翻车因为代码的语义相似和文本相似是两回事。一个函数叫processOrder另一个叫handleTransaction文本上不相似但业务上可能强相关。所以检索要融合符号匹配、调用图距离、最近改动历史三个信号加权打分。3.2 上下文里必须有的“元信息”光给代码不够。模型还需要知道一些“元信息”才能做出正确判断。我在实践里固定会塞进上下文的几类信息任务描述的结构化版本不是一句自然语言而是拆成“目标、约束、验收标准、禁止改动范围”四段。代码库的约定命名规范、错误处理模式、日志格式、测试框架。这些约定如果不在上下文里模型就会按自己的习惯写产出风格和仓库格格不入。相关测试文件让模型知道这个模块是怎么被测试的它写出来的代码才更可能通过测试。最近的提交历史特别是相关文件的最近改动能帮模型理解这块代码正在往哪个方向演进。提示元信息不要一次性全塞。按任务类型动态组装。重构任务重点给约定和测试修 bug 任务重点给复现步骤和相关提交。3.3 上下文窗口的“预算管理”把上下文窗口当成一个有限预算来管理是调优的关键思维。我的经验分配大致是这样任务描述和约束占 10%核心相关代码占 40%依赖和调用方占 20%测试文件占 15%约定和历史占 10%留 5% 给模型自己的推理空间。这个比例不是死的但核心原则是永远给模型留出“思考的余地”。如果上下文塞到 95% 满模型几乎没有空间做推理输出质量会断崖式下跌。我实测过同样任务上下文占用 70% 和 95% 两种情况下前者的一次通过率明显更高。还有一个反直觉的点有时候删掉一些“看起来相关”的代码效果反而更好。因为那些代码会干扰模型的注意力。判断标准是——这段代码如果模型看不到它会不会做出错误决策如果不会那就别塞。4. 动作空间设计给 Agent 划出“能碰”和“不能碰”的红线4.1 动作分级从只读到全权限动作空间的设计本质是在能力和风险之间找平衡。我习惯把 Agent 的动作分成四级按任务风险逐级开放。级别允许动作适用场景风险L1 只读读文件、搜索、查符号代码理解、方案设计极低L2 受限写改指定文件、跑测试单文件 bug 修复低L3 扩展写改多文件、跑构建、装依赖功能开发、重构中L4 全权限改配置、操作分支、跑任意命令自动化流水线高生产环境里绝大多数任务应该跑在 L2 到 L3。L4 只在有完整回滚机制和人工审核的前提下开放。我见过有团队一上来就给 Agent 全权限结果它把 CI 配置文件改了整个流水线挂掉排查了半天才发现是 Agent 干的。4.2 文件级白名单比目录级更靠谱圈定改动范围时很多人用目录白名单。但目录粒度太粗一个目录里可能既有该改的也有不该碰的。更精细的做法是文件级白名单加符号级约束。具体来说任务开始时Harness 先根据任务描述和检索结果生成一个“预期改动文件列表”。Agent 只能改这个列表里的文件。如果它在执行过程中发现需要改列表外的文件必须显式请求扩展权限由 Harness 判断是否放行。这个机制能挡掉大量“顺手乱改”的情况。符号级约束更进一步允许改某个文件但只允许改指定的函数。这在维护老代码时特别有用——你只想让 Agent 修一个函数里的 bug不想它把整个文件重排一遍。4.3 终端命令的“沙箱化”让 Agent 跑终端命令是能力也是风险。我的做法是命令白名单加参数校验。只允许跑测试、构建、格式化、静态检查这几类命令且命令模板固定参数由 Harness 填充Agent 不能自由拼命令。比如跑测试Harness 提供的是一个run_test(module_name)的工具Agent 只能传模块名实际执行的命令由 Harness 组装。这样既给了 Agent 执行反馈的能力又杜绝了它跑出rm -rf这种灾难。注意即使有白名单也要在隔离环境里跑。容器、临时工作区、只读挂载这些基础设施该上就上。别指望白名单能挡住所有意外。4.4 动作空间的“渐进开放”策略一个很实用的技巧是渐进开放。任务开始时给最小权限随着任务推进和验证通过逐步放开。比如一个重构任务先让 Agent 在只读模式下出方案方案通过人工或自动审核后再开放写权限写完跑通测试后才允许它提交。这种策略的好处是风险被切成了小段每段都可控。坏处是流程变长需要 Harness 有状态管理能力。但对于生产环境的核心模块这点开销完全值得。5. 输出验证与失败恢复让 Agent 自己“照镜子”5.1 验证要分层不能只看“编译过了”编译通过只是最低标准。一个生产级的验证体系至少要有四层。第一层是语法与编译验证这是硬门槛不过直接打回。第二层是测试验证包括单元测试和相关的集成测试。第三层是静态检查代码规范、复杂度、潜在 bug 模式。第四层是语义验证这一层最难也最有价值——改动是否真的实现了任务目标而不只是“看起来像”。语义验证可以借助另一个模型来做让一个“审查者”Agent 对照任务描述检查改动。也可以借助测试覆盖率变化、接口契约检查等工程手段。华为 CodeArts 体系里这一层往往和代码检视流程结合把 Agent 的产出纳入既有的质量门禁。5.2 失败信息的“结构化回喂”Agent 失败后怎么把失败信息喂回去直接决定它能不能自我修正。最差的做法是把原始报错日志一股脑塞回去模型在几百行堆栈里根本找不到重点。好的做法是结构化回喂把失败信息拆成“失败类型、失败位置、期望值、实际值、相关代码片段”几个字段只把最相关的部分给模型。比如测试失败就告诉它哪个测试、哪一行断言、期望什么、实际什么再附上被测函数和测试函数。这样模型能快速定位问题。我实测过一个对比原始日志回喂模型二次修正成功率大概三成结构化回喂能到七成以上。差距非常明显。5.3 重试策略次数、退避、换路重试不是简单地“再来一次”。我的策略是有限次数加策略切换。第一次失败原样重试给结构化失败信息。第二次失败换一种上下文组织方式比如补充更多相关代码或换个检索策略。第三次失败换模型或换方案比如从“直接改”换成“先写测试再改”。三次还不行就交回人工并把整个失败过程记录下来作为后续调优的素材。重试次数不宜多。超过三次还在原地打转说明要么任务本身超出 Agent 能力要么 Harness 的某个环节有系统性问题继续重试只是烧钱。5.4 回滚机制改错了要能干净地退回去回滚是生产环境的底线。每次 Agent 开始改动前Harness 应该自动创建一个检查点——可以是 git stash、临时分支、或者文件快照。改动失败或验证不通过一键回滚到检查点环境干净如初。这里有个容易忽略的点回滚要包括副作用。Agent 可能装了依赖、生成了临时文件、改了环境变量。回滚时这些都要清理否则下次任务会在一个被污染的环境里跑问题很难复现。6. 实操调优全流程一个真实重构任务的拆解6.1 任务准备把模糊需求变成可执行规格假设任务是“优化订单模块的查询性能”。这句话直接丢给 Agent它大概率会给你一堆似是而非的改动。正确的做法是先把它变成可执行规格。我会拆成目标是把订单列表接口的 P99 延迟从 800ms 降到 300ms 以内约束是不能改变接口签名、不能引入新依赖、必须保持现有测试全绿验收标准是压测报告达标加所有测试通过禁止改动范围是订单写入逻辑和数据库 schema。这份规格本身就是 Harness 的一部分它让 Agent 知道边界在哪。规格的生成可以半自动——Harness 根据任务类型套模板人工补充关键约束。6.2 上下文组装检索加裁剪的实际操作规格定了接下来组装上下文。先用符号索引找到订单查询相关的入口函数再沿调用图往下找两跳得到候选文件集。然后按相关性打分排序取前若干名。同时把订单模块的测试文件、最近的性能相关提交、代码库的日志和错误处理约定一起打包。组装完检查一下 token 占用如果超过预算就按分数从低到高砍。砍的时候优先砍依赖方代码保留核心实现和测试。这一步的实操心得是宁可少给不要多给。模型缺信息会问或猜但信息过载会直接让它变笨。6.3 执行与验证一轮完整的 Agent 循环Agent 拿到上下文和规格开始工作。它先读代码、分析瓶颈然后提出改动方案。Harness 在方案阶段可以做一次拦截——如果方案明显偏离规格直接打回让它重想不用等到改完才发现方向错了。方案通过后Agent 在文件白名单内改动。改完Harness 自动跑测试和静态检查。如果失败结构化回喂进入重试。如果通过再跑一次性能压测对照验收标准。全部达标生成改动摘要进入人工审核或自动合并。这一轮循环里最耗时的往往不是模型推理而是验证环节。所以验证的并行化和缓存很重要。测试能并行跑的就并行静态检查结果能缓存的就缓存。6.4 效果度量怎么知道调优有没有用调优不能凭感觉。我固定跟踪几个指标一次通过率Agent 第一轮就通过验证的比例、平均重试次数、人工介入率需要人改的比例、单任务 token 成本、端到端耗时。这几个指标里一次通过率最能反映 Harness 的整体质量。它上去了其他指标通常都会跟着改善。我自己的经验是通过上下文和验证两块的调优一次通过率能从三成提到七成左右再往上就要靠更精细的动作空间设计和模型能力提升了。7. 常见问题与排查技巧实录7.1 Agent 改错文件、改超范围这是最高频的问题。排查顺序是先看文件白名单有没有生效再看上下文里有没有误导性的相关代码最后看任务规格里的禁止改动范围是否清晰。我遇到过一次Agent 反复去改一个无关的工具类。查下来发现是检索环节把那个工具类排到了前面因为它的名字和任务关键词有重叠。解决办法是在检索打分里加入“是否在预期改动范围内”这个信号把范围外的文件降权。7.2 测试跑不通但 Agent 说改好了这通常是验证环节缺失或验证结果没回喂。检查 Harness 有没有在 Agent 声称完成后强制跑测试以及测试失败信息有没有结构化地喂回去。另一个可能是 Agent 在沙箱里跑测试通过了但沙箱环境和真实环境有差异。这种情况要统一环境别让沙箱和真实环境两套配置。7.3 长任务跑到一半“失忆”长任务里 Agent 忘记前面的约束是上下文管理的问题。解决办法是关键约束在每个循环都重新注入不要指望模型记住几十轮前说的话。另外可以把任务拆成子任务每个子任务独立组装上下文减少对长历史的依赖。7.4 成本失控成本失控通常来自三个地方上下文过大、重试次数过多、验证环节重复跑。对策分别是收紧检索预算、设置重试上限、给验证结果加缓存。我还会给每个任务设一个 token 预算上限超了就中止并报警避免一个任务烧掉一天的额度。7.5 常见问题速查表现象可能原因排查方向改错文件白名单失效或检索误导检查白名单、检索打分改超范围规格约束不清补充禁止改动范围测试不过却说好了验证缺失或未回喂强制验证、结构化回喂长任务失忆上下文未重注入每轮重注入关键约束成本失控上下文大、重试多收紧预算、设重试上限产出风格不符约定未入上下文补充代码库约定7.6 几条踩坑换来的经验第一条别在调优初期就追求全自动。人工审核环节该保留就保留它既是质量兜底也是收集失败样本的渠道。等一次通过率稳定在高位再逐步减少人工介入。第二条失败样本比成功样本值钱。每次 Agent 失败都把完整的上下文、动作、验证结果存下来。攒够一批做分析能发现 Harness 的系统性短板比零散调参高效得多。第三条模型和 Harness 要匹配着调。换个模型Harness 的上下文预算、重试策略可能都要跟着变。别指望一套 Harness 打遍所有模型。第四条验证要快。验证慢会拖垮整个循环的吞吐。能并行的并行能缓存的缓存能增量的增量。验证速度上去了同样的时间能跑更多轮调优迭代也更快。8. 关于 Harness 工程的一点个人体会调了这么久 Coding Agent我最大的体会是决定生产级效果的从来不是模型有多聪明而是 Harness 有多克制。克制地给上下文克制地开权限克制地重试克制地相信模型的自我报告。每一次克制都是在用工程手段弥补模型的不确定性。Vibe Coding 的“最后一公里”说到底就是把“感觉能跑”变成“验证过能跑”。这条路没有捷径靠的是一轮轮真实任务的打磨靠的是把每次失败都变成 Harness 的一次改进。华为 CodeArts 这套体系给我的启发不是某个具体功能而是它把 Agent 放进了软件工程既有的质量框架里——检索、验证、门禁、回滚这些老东西配上新模型才是生产级的样子。如果你现在正卡在这一公里上我的建议是从验证环节先动手。把验证做扎实Agent 的产出质量会立刻上一个台阶后面的上下文和动作空间调优也有了可靠的反馈信号。至于模型选型、工具链搭建这些反而是相对好解决的。真正难的是那套让模型“不敢乱来、错了能发现、发现能修正”的工程机制那才是 Harness 的灵魂。