1. 从 Vibe Coding 到生产可用:一个 Coding Agent 调优项目的完整复盘
Vibe Coding 这个词从 2025 年初开始火起来,到 2026 年已经从一个“让 AI 随便写写”的玩具概念,演变成了不少团队内部真实使用的开发范式。但真正在生产环境里跑过 Coding Agent 的人都知道,从“能跑”到“好用”之间,隔着一条巨大的鸿沟。这条鸿沟不是模型能力不够,而是 Harness 工程做得不到位。
我所在的团队从 2025 年下半年开始,在一个内部研发效能平台上落地了一套基于 Coding Agent 的自动化编码辅助系统。整个系统的核心目标很明确:让 Agent 能够理解项目上下文、自主完成中等复杂度的编码任务、并且在人工 review 之前就把大部分低级错误消灭掉。听起来很美好,但实际调优过程中踩的坑,足够写一本小册子。
这篇文章不讲概念科普,也不讲“AI 将如何改变编程”这种大而空的话题。我只做一件事:把我们在 Harness 层做效果调优的完整过程拆开,告诉你哪些参数真正影响 Agent 的输出质量、哪些设计决策会让 Agent 从“智障”变成“靠谱同事”、以及那些文档里不会写的实操细节。如果你正在做 Coding Agent 的落地,或者正在被 Agent 的“最后一公里”问题折磨,这篇内容应该能帮你省下不少试错时间。
2. Harness 到底是什么:Coding Agent 的能力放大器
2.1 Harness 和 Agent 的本质区别
很多人会把 Harness 和 Agent 混为一谈,觉得都是“让 AI 干活”的东西。但实际做工程的人必须把这两个概念分清楚,因为它们的职责边界完全不同。
Agent 是决策主体。它负责理解任务、规划步骤、选择工具、生成代码、判断结果。Agent 的能力上限由底层模型决定,这部分你很难通过工程手段大幅改变。
Harness 是执行框架。它负责给 Agent 提供上下文、管理工具调用、控制执行流程、处理错误恢复、约束输出格式。Harness 做得好不好,直接决定了 Agent 的实际表现能发挥出模型能力的百分之多少。
打个比方:Agent 是一个刚入职的聪明新人,Harness 是他手里的 IDE、文档、代码规范、CI 流程和 mentor 的 review 意见。新人再聪明,如果给他的工具是坏的、文档是过期的、规范是不存在的,他产出的代码质量一定惨不忍睹。
我们内部做过一个对比实验:同一个模型,在粗糙 Harness 和精细调优 Harness 下,完成同一个中等复杂度重构任务的成功率分别是 34% 和 78%。模型没变,变的只是 Harness 层的上下文组织方式、工具调用策略和错误处理逻辑。
2.2 为什么 Harness 工程是 Vibe Coding 的“最后一公里”
Vibe Coding 的核心体验是“你说意图,Agent 写代码”。在 demo 阶段,这种体验很惊艳。但到了生产环境,问题就暴露了:
- Agent 写的代码不符合项目规范,变量命名随意、目录结构混乱
- Agent 不理解项目的历史决策,重复造轮子或者引入不兼容的依赖
- Agent 在遇到编译错误时反复尝试同样的错误修复方式,陷入死循环
- Agent 生成的代码缺少必要的边界处理和错误捕获
- Agent 无法感知项目的测试覆盖要求,写完代码就跑
这些问题没有一个能靠“换个更强的模型”解决。它们全部属于 Harness 层的工程问题。Harness 需要负责把项目规范、历史上下文、工具使用约束、错误恢复策略、质量门禁这些东西全部编排好,让 Agent 在一个“有护栏的环境”里工作。
这就是为什么我说 Harness 是 Vibe Coding 的最后一公里。模型能力已经足够强了,但如果没有一套好的 Harness 工程,Agent 的产出永远停留在“能跑但不敢用”的阶段。
2.3 我们的 Harness 架构选型思路
在架构设计阶段,我们评估了三种方案:
| 方案 | 核心思路 | 优势 | 劣势 |
|---|---|---|---|
| 轻量级 Harness | 只做上下文注入和工具调用转发 | 实现简单、调试方便 | 无法处理复杂任务流、错误恢复能力弱 |
| 全托管 Harness | 平台方提供完整 Agent 运行时 | 开箱即用、维护成本低 | 定制能力受限、无法深度集成内部工具链 |
| 自建 Harness | 完全自主控制上下文、工具、流程 | 深度定制、可针对业务调优 | 工程量大、需要持续迭代 |
我们最终选择了自建 Harness 为主、参考开源 Harness 工程实践为辅的路线。核心原因是我们的项目有大量内部特有的工具链和规范,全托管方案无法满足集成需求。同时我们借鉴了一些开源 Harness 项目的设计思路,比如工具注册机制、上下文窗口管理策略、多轮对话的状态保持方式等。
这个选型决策背后的逻辑是:Harness 层的核心竞争力不在于“有没有”,而在于“贴不贴”。贴得越紧,Agent 的表现越好。通用方案能解决 60% 的问题,剩下 40% 必须靠自建。
3. 上下文工程:让 Agent 真正“看懂”项目
3.1 上下文注入的层次化设计
Agent 表现差,十有八九是上下文给得不对。我们最初的做法很简单:把当前文件内容 + 用户指令塞进 prompt,然后让 Agent 生成代码。结果就是 Agent 经常写出“局部正确但全局冲突”的代码。
后来我们设计了一套层次化的上下文注入策略,把上下文分成四个层次:
第一层:项目级上下文。包括项目技术栈、目录结构说明、核心依赖版本、代码规范摘要。这部分内容是相对静态的,每次会话开始时注入一次,占用约 800-1200 token。
第二层:模块级上下文。包括当前任务涉及的模块的接口定义、数据模型、关键类型声明。这部分内容根据任务范围动态选取,占用约 1500-2500 token。
第三层:文件级上下文。包括当前编辑文件的完整内容、相邻文件的导入关系、该文件的测试文件摘要。这部分是 Agent 最直接的工作区域,占用约 2000-4000 token。
第四层:任务级上下文。包括用户的具体指令、历史对话摘要、当前遇到的错误信息、之前尝试过的修复方案。这部分是动态变化的,占用约 500-1500 token。
四层加起来,总上下文控制在 6000-9000 token 之间。这个数字不是拍脑袋定的,而是我们通过 A/B 测试找到的平衡点。上下文太少,Agent 缺乏必要信息;上下文太多,Agent 的注意力被稀释,关键信息反而被淹没。
3.2 上下文压缩与摘要策略
项目大了之后,上下文窗口永远不够用。我们试过几种压缩策略:
- 滑动窗口:只保留最近 N 轮对话。简单但容易丢失关键历史信息。
- 关键信息提取:用一个小模型对历史对话做摘要,只保留决策相关的信息。效果好但增加延迟。
- 结构化状态保持:把对话中的关键状态(如已修改的文件列表、已确认的接口变更、待解决的问题)用结构化格式维护,不依赖原始对话历史。
我们最终采用的是结构化状态保持为主、关键信息提取为辅的方案。具体做法是:Harness 维护一个任务状态对象,记录当前任务的进度、已完成的步骤、待解决的问题、已知的约束条件。每次调用 Agent 时,把这个状态对象序列化后注入上下文,而不是把全部历史对话塞进去。
这个方案的好处是上下文利用率极高,而且状态对象可以被多个 Agent 调用共享。缺点是 Harness 需要维护状态的一致性,实现复杂度更高。
3.3 实操心得:上下文注入的常见坑
注意:上下文注入不是越多越好。我们曾经把整个项目的 README 和所有相关文档都塞进去,结果 Agent 的表现反而下降了 15%。原因是大量无关信息干扰了 Agent 对核心任务的注意力。
几个实操中总结的要点:
- 上下文中的代码示例要精选,不要把所有相似代码都放进去。Agent 会倾向于模仿它看到的第一个示例。
- 接口定义要完整,但实现细节可以省略。Agent 需要知道“能调用什么”,不需要知道“内部怎么实现”。
- 错误信息要保留原始格式,不要做二次加工。Agent 对原始错误信息的理解能力远强于人工摘要。
- 上下文中的注释要精简。过长的注释会占用宝贵 token,而且 Agent 可能会把注释内容当作指令执行。
4. 工具调用调优:从“能用”到“好用”的关键一跃
4.1 工具注册与描述优化
Harness 给 Agent 提供的工具,描述方式直接决定了 Agent 会不会用、用得对不对。我们最初给工具写的描述很技术化,比如“执行 shell 命令并返回输出”。结果 Agent 经常在不该用 shell 的时候用 shell,或者用了 shell 但参数格式不对。
后来我们把工具描述改成了“意图导向”的写法:
- 旧描述:“执行 shell 命令并返回输出”
- 新描述:“在项目根目录下运行构建、测试或 lint 命令。适用于验证代码改动是否正确。不要用于文件读写操作。”
新描述明确了使用场景和禁用场景,Agent 的误用率下降了 60% 以上。
我们还给每个工具加了“使用示例”字段,用 2-3 个典型调用示例告诉 Agent 正确的参数格式。这个改动看起来很小,但效果非常明显。Agent 不再需要猜测参数格式,直接模仿示例即可。
4.2 工具调用链的编排策略
单个工具调用好解决,难的是多个工具调用的编排。Agent 经常出现的问题是:调用工具 A 拿到结果后,不知道下一步该调用工具 B 还是工具 C,或者反复调用同一个工具期望得到不同结果。
我们在 Harness 层做了一个“工具调用图”的设计。具体来说,Harness 维护一个状态机,根据当前任务状态和上一步工具调用的结果,动态推荐下一步应该调用的工具集合。Agent 仍然有最终决策权,但 Harness 会通过上下文注入的方式给出建议。
比如,当 Agent 完成代码修改后,Harness 会自动在上下文中注入:“建议下一步运行测试验证改动。可用工具:run_tests、run_lint、check_types。”这样 Agent 就不容易忘记验证步骤,也不会在验证工具之间反复横跳。
4.3 工具返回结果的处理与截断
工具返回的结果往往很长,比如测试输出、编译日志、lint 报告。如果全部塞回上下文,很快就会撑爆窗口。我们的处理策略是:
- 成功结果:只保留摘要信息。比如测试通过,只返回“全部 47 个测试通过,耗时 12.3s”。
- 失败结果:保留关键错误信息 + 上下文。比如测试失败,返回失败的测试名称、错误类型、错误位置、相关代码片段。
- 警告结果:按类别聚合。比如 lint 警告,按规则类型分组,每组只展示前 3 个示例。
这个策略的核心逻辑是:Agent 需要的是“可操作的信息”,而不是“完整的信息”。把原始输出直接丢给 Agent,反而会增加它的认知负担。
4.4 工具调用失败的重试与降级
工具调用失败是常态,不是异常。网络抖动、命令超时、权限不足、资源竞争,各种原因都可能导致工具调用失败。Harness 必须有一套完整的失败处理策略。
我们的做法是三级处理:
第一级:自动重试。对于幂等的工具调用(如读取文件、查询状态),失败后自动重试 2 次,间隔 1 秒和 3 秒。
第二级:降级替代。对于非幂等的工具调用(如执行命令、修改文件),失败后不自动重试,而是把失败信息返回给 Agent,同时提供替代方案建议。比如“run_tests 失败,建议尝试 run_single_test 指定具体测试文件”。
第三级:人工介入。如果连续 3 次工具调用失败,或者失败原因涉及权限、环境配置等 Harness 无法自动处理的问题,暂停 Agent 执行,通知人工介入。
这套策略把工具调用失败导致的任务中断率从 23% 降到了 4% 左右。
5. 效果调优实录:那些真正影响输出质量的参数
5.1 温度与采样策略的实战选择
温度参数对 Coding Agent 的影响比想象中大。我们做过一组对比测试,同一个任务在不同温度下的表现:
| 温度 | 代码正确率 | 代码多样性 | 适合场景 |
|---|---|---|---|
| 0.0 | 82% | 极低 | 格式化、重构、bug 修复 |
| 0.2 | 78% | 低 | 常规功能开发 |
| 0.5 | 65% | 中 | 探索性任务、方案设计 |
| 0.8 | 48% | 高 | 创意性任务、原型生成 |
我们的策略是动态调整温度:根据任务类型自动选择温度值。重构和 bug 修复用 0.0,常规开发用 0.2,方案设计用 0.5。这个策略让整体任务成功率提升了 12%。
还有一个细节:top_p 参数我们固定在 0.95,不做动态调整。原因是 top_p 对代码生成的影响不如温度明显,而且调整 top_p 会引入额外的不可控因素。
5.2 最大输出长度的陷阱
最大输出长度(max_tokens)设置不当会导致两种问题:设置太小,Agent 的代码被截断,生成不完整的代码;设置太大,Agent 倾向于生成冗长的代码和过多的解释。
我们的经验值是:对于单文件修改任务,max_tokens 设置在 2000-3000 之间;对于多文件修改任务,设置在 4000-6000 之间。超过 6000 之后,Agent 的输出质量明显下降,而且更容易出现“为了凑长度而写废话”的情况。
还有一个技巧:在 prompt 中明确要求 Agent“只输出代码,不要解释”。这个简单的约束可以减少 30% 左右的无效输出。
5.3 系统提示词的迭代过程
系统提示词是 Harness 调优中最容易被低估的部分。我们前后迭代了 7 个版本的系统提示词,每个版本都针对上一版暴露的问题做修正。
第一版:简单粗暴,只写了“你是一个编程助手,帮助用户完成编码任务”。结果 Agent 经常越界,做用户没要求的事情。
第三版:加入了角色定义、任务边界、输出格式要求。Agent 的行为规范了很多,但遇到复杂任务时容易“想太多”,生成大量分析文字。
第五版:加入了“先思考再行动”的引导,要求 Agent 在调用工具前先输出简短的思考过程。这个改动让 Agent 的工具调用准确率提升了 25%。
第七版(当前版本):在第五版基础上,加入了错误处理指引、工具使用优先级、代码风格约束。同时把提示词长度从 1200 token 压缩到 800 token,去掉了所有冗余表述。
系统提示词的核心原则是:约束要具体,引导要明确,废话要删干净。
5.4 多轮对话中的状态管理
Coding Agent 的任务往往需要多轮对话才能完成。多轮对话最大的挑战是状态一致性:Agent 在第三轮忘记第一轮确认的接口定义,或者在第五轮推翻了第二轮的设计决策。
我们的解决方案是引入“任务状态快照”机制。每轮对话结束后,Harness 自动提取本轮的关键决策和状态变更,更新到任务状态对象中。下一轮对话开始时,把最新的状态对象注入上下文。
状态对象包含以下字段:
- 任务目标(一句话描述)
- 已完成步骤列表
- 待完成步骤列表
- 关键决策记录(如“选择使用 Repository 模式而非 Active Record”)
- 已知约束(如“不能引入新的第三方依赖”)
- 当前阻塞问题(如有)
这个机制让多轮对话的任务完成率从 51% 提升到了 79%。
6. 常见问题与排查技巧实录
6.1 Agent 反复犯同一个错误怎么办
这是最常见的问题。Agent 在修复一个编译错误时,反复尝试同样的修复方式,每次失败后稍微改一下参数再试,陷入死循环。
排查思路:检查 Harness 是否在上下文中保留了之前的失败尝试记录。如果 Agent 看不到自己之前试过什么,它就会重复尝试。
解决方法:在任务状态对象中增加“已尝试方案”列表,记录每次失败尝试的方案摘要和失败原因。每次调用 Agent 时,把这个列表注入上下文,并明确提示“以下方案已尝试且失败,请勿重复”。
6.2 Agent 生成的代码不符合项目规范
这个问题通常有两个原因:一是 Harness 没有把项目规范注入上下文;二是规范注入的方式不对,Agent 没有真正“理解”规范。
排查思路:检查上下文中是否有明确的代码规范说明,以及规范说明是否足够具体。比如“使用驼峰命名”这种规范太模糊,Agent 可能理解成“变量名用驼峰,文件名也用驼峰”。应该写成“变量和函数名使用驼峰命名,文件名使用短横线分隔”。
解决方法:把项目规范拆成“必须遵守”和“建议遵守”两类,在上下文中明确标注。同时提供正例和反例,让 Agent 有明确的参照。
6.3 工具调用超时导致任务中断
工具调用超时是 Harness 层必须处理的问题。我们的经验是:超时时间不能设得太短,否则正常的长耗时操作会被误杀;也不能设得太长,否则 Agent 会卡在某个工具调用上浪费大量时间。
我们的超时策略是分级的:
| 工具类型 | 超时时间 | 超时后处理 |
|---|---|---|
| 文件读写 | 5s | 重试 2 次 |
| 代码搜索 | 10s | 重试 1 次 |
| 编译构建 | 120s | 返回部分结果 + 提示 |
| 测试执行 | 180s | 返回部分结果 + 提示 |
| 网络请求 | 15s | 重试 2 次 |
超时后,Harness 会把超时信息返回给 Agent,并建议替代方案。比如编译超时,建议 Agent 先检查是否有语法错误,而不是直接重新编译。
6.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| Agent 输出截断 | max_tokens 太小 | 检查输出是否在句子中间截断 | 增大 max_tokens 或要求 Agent 精简输出 |
| Agent 忽略指令 | 指令在上下文中位置太靠前 | 检查指令是否被后续内容淹没 | 把关键指令放在上下文末尾 |
| Agent 调用不存在的工具 | 工具描述不清晰 | 检查工具注册列表和描述 | 完善工具描述,增加使用示例 |
| Agent 生成代码风格不一致 | 上下文中缺少风格示例 | 检查是否注入了代码风格规范 | 注入项目中的典型代码文件作为风格参考 |
| Agent 反复询问相同问题 | 状态管理失效 | 检查任务状态对象是否更新 | 修复状态快照机制,确保每轮更新 |
| Agent 执行危险操作 | 工具权限控制缺失 | 检查是否有危险工具未加限制 | 对危险工具增加确认机制或禁用 |
6.5 独家避坑技巧
注意:不要在系统提示词中写“尽可能”这样的模糊词汇。Agent 会把“尽可能”理解成“必须”,然后为了满足这个要求而做出过度设计。
几个从实际踩坑中总结的技巧:
- 工具描述中的“不要用于 XX 场景”比“适用于 XX 场景”更重要。Agent 的误用往往发生在边界场景。
- 上下文中的代码示例要标注来源和用途。否则 Agent 可能会把示例代码直接复制到不相关的场景中。
- 任务状态对象要定期清理。过期的状态信息会干扰 Agent 的判断,建议每完成一个子任务就清理一次。
- 系统提示词的长度控制在 800 token 以内。超过这个长度后,Agent 对提示词的遵循度明显下降。
- 多轮对话中,每轮都要重新注入关键约束。Agent 的“记忆”不可靠,不要假设它记得上一轮说过什么。
7. 调优效果与持续迭代
7.1 调优前后的关键指标对比
经过大约 3 个月的持续调优,我们的 Coding Agent 在内部研发效能平台上的表现有了明显提升。以下是一组关键指标的对比:
| 指标 | 调优前 | 调优后 | 提升幅度 |
|---|---|---|---|
| 任务完成率 | 34% | 78% | +129% |
| 代码一次通过率 | 41% | 72% | +76% |
| 平均任务耗时 | 8.2 min | 4.7 min | -43% |
| 人工介入率 | 67% | 22% | -67% |
| 工具调用失败率 | 23% | 4% | -83% |
| 多轮对话完成率 | 51% | 79% | +55% |
这些数字背后是大量的细节调优工作。每一个百分点的提升,都对应着某个具体问题的解决。
7.2 持续迭代的机制建设
调优不是一次性的工作,而是持续的过程。我们建立了一套持续迭代机制:
数据收集层:Harness 自动记录每次 Agent 调用的完整上下文、工具调用序列、最终结果、人工反馈。这些数据是后续调优的基础。
问题分类层:每周对失败案例做一次分类分析,把问题归入“上下文问题”“工具问题”“提示词问题”“模型能力问题”四个类别。前三个类别是 Harness 层可以解决的,第四个类别需要等待模型升级。
实验验证层:每个调优方案都要经过 A/B 测试验证。我们维护了一个实验平台,可以快速对比不同 Harness 配置下的 Agent 表现。
灰度发布层:调优方案先在 10% 的流量上灰度,观察 3 天无异常后再全量发布。
这套机制让我们的调优工作从“凭感觉改”变成了“数据驱动改”,效率提升非常明显。
7.3 后续可以继续深挖的方向
目前我们还在探索几个方向:
- 个性化 Harness:根据开发者的编码习惯和项目特点,自动调整 Harness 配置。比如对喜欢写详细注释的开发者,增加注释生成的权重。
- 跨项目知识迁移:把一个项目的调优经验迁移到另一个项目,减少重复调优的工作量。
- Agent 协作:让多个 Agent 分别负责不同模块,通过 Harness 协调它们的工作。这个方向还在早期探索阶段。
- 实时反馈闭环:把人工 review 的意见实时反馈给 Harness,让 Agent 在后续任务中自动规避同类问题。
这些方向都还在实验阶段,等有成熟结果后再单独分享。
8. 一些个人体会
做 Coding Agent 调优这件事,最大的感受是:模型能力是天花板,Harness 工程是地板。天花板很高,但如果你地板没铺好,永远够不到天花板。
我见过不少团队把精力全花在“换更强的模型”上,却忽略了 Harness 层的工程优化。结果就是模型升级了,Agent 的表现却没有明显提升。原因很简单:模型能力被 Harness 层的各种问题抵消了。
另一个体会是:调优工作要抓大放小。不要试图一次性解决所有问题,而是先解决影响面最大的那几个。我们的经验是,前 5 个问题的解决就能带来 60% 以上的效果提升。剩下的问题解决起来边际收益递减,可以放到后续迭代中慢慢处理。
最后分享一个实用建议:如果你刚开始做 Coding Agent 落地,不要一上来就追求“全自动”。先做“半自动”,让 Agent 在人工监督下工作,收集足够的失败案例后再逐步放开。这样既能保证生产安全,又能积累调优所需的数据。等 Harness 工程成熟到一定程度,再考虑全自动运行。