第8节 调优实录一个修复循环从71%到90%全过程一句话总结完整复盘一个真实仓库修复循环的调优——基线测量→逐项改进错误格式/验证器/预算/模型分层→每步成功率与成本数据附调优记录表格。本文导航一、调优方法论与基线测量二、改进1结构化错误反馈三、改进2验证器三件套四、改进3预算优化五、改进4模型分层六、调优记录表与全程曲线七、跑分器、帕累托最优与剩余失败分析一、调优方法论与基线测量1.1 先立规矩再动手第7章走到最后一节前面的招式都练完了结构化反馈第6节、确定性验证器第3节、防作弊第5节、模型分层第7节。这一节回答一个更上层的问题**这么多手段一个个装上去效果分别值多少**要回答它调优之前得先立三条规矩不然跑出来的数据全是自欺**规矩一固定测试集。**调优期间测试集一个字不许动。我有次中途往测试集里加了两个顺手挑的bug前后两版数据就不可比了——成功率的变化里掺了任务难度变化的水。**规矩二单变量原则。**一次只改一个配置项跑完整批再改下一个。改两项以上效果提升不知道该记谁头上效果劣化不知道该回滚谁。**规矩三全程留痕。**每次跑分的配置、数据、日志都归档调优历史就是一条可回溯的链。后文跑分器代码里这三个规矩全部固化成了代码约束。提升劣化固定测试集30个bug跑基线记录四指标改一个变量重跑全批对比基线保留改动新基线回滚改动这个循环跟修复循环长得一模一样不是巧合——调优本身就是一次元层面的循环工程验证器是基准测试反馈是指标对比修复的是配置。你甚至可以套用同一套 Maker/Checker/仲裁结构来管理它。1.2 基线测量测试集的构成先交代清楚这决定了后面所有数字的含义测试集30个真实bug来自开源项目Issue 挑选标准 - 有明确的复现步骤能写成失败测试 - 有社区确认的修复commit有人工标准答案当裁判 - 难度分布简单10个 / 中等14个 / 困难6个 排除标准 - 需要重构半个模块的大改动超出单循环能力范围 - 依赖外部服务的bug复现不稳定 基线循环第6章的最小循环 原始堆栈反馈挑选标准里有人工标准答案这条是关键——修没修好不能靠我自己看拿社区的修复 commit 当 ground truth成功判定就是循环产出的 patch 让失败测试转绿且不破坏其他测试。基线成绩跑三遍取均值避免单次运气基线成绩 成功率71%21/30 平均轮数4.8轮 平均token42K 平均耗时3.2分钟71% 这个数字值得停一下。也就是说每十个 bug 有差不多三个修不动而且失败的这三个会吃掉大量轮数和 token 才宣告失败——失败案例的成本远高于平均数这也是后面预算优化能省钱的结构性原因。关于跑三遍取均值多说两句这里有个统计上的讲究30 个样本的成功率天然有抖动单次跑分 71% 的真实区间大概是 71%±8%二项分布的置信区间也就是说单次跑出 66% 或 76% 都可能是同一个真实水平的正常波动。跑三遍取均值能把抖动压掉一半以上更重要的是让我对1~2 个点的变化是不是噪音有了判断力——后面几步改进里低于 3 个点的成功率变化我一律不当真只看轮数和 token 这种方差极小的指标。没有这个认知调优会被随机波动牵着鼻子走追着一个噪音改配置。二、改进1结构化错误反馈第一刀砍向失败信息第6节的方法直接搬过来。改动格式化Python错误为五要素类型/位置/原因/期望/修复方向 配置difffeedback_format: raw → structured 其余配置全部不动单变量原则 效果 成功率71% → 82%11% 平均轮数4.8 → 3.5轮-27% 平均token42K → 31K-26%11% 是全程最大的一笔单项提升但翻失败案例明细时有个人工发现新修好的 bug 里多数是堆栈信息足够定位根因的类型异常类bug结果错误但无异常的类型一个都没多修——五要素救的是有堆栈的失败静默失败它无能为力。这个观察直接指向了下一刀该砍哪。这个观察还给了我一个工程习惯每刀砍完别只看总数字把新修好的 bug和新修坏的 bug各拉一个清单人工过一遍。总数字告诉你有没有效果清单告诉你对哪类问题有效、对哪类无效——后者才是下一刀往哪砍的依据。调优最忌讳的就是只盯汇总指标来回试配置那等于蒙着眼开枪。另外注意轮数降了 27%token 却只降 26%单轮输入因为拼了结构化反馈略有增加但少跑的轮数把它补回来还有富余。省轮数比省单轮长度更值钱这是我第一次直观感受到。三、改进2验证器三件套第二刀是把第3节的确定性信号接进来每轮自动跑结果按第6节的五要素格式喂给模型。改动每轮自动跑pytestruffmypy结果喂给模型 配置diffvalidators: [] → [pytest, ruff, mypy] 其余配置全部不动 效果 成功率82% → 87%5% 平均轮数3.5 → 3.0轮-14% 平均token31K → 28K-10%这刀的收益结构跟前一刀不同新修好的 bug 里有三个是 mypy 立功——类型不匹配暴露出了模型自己没意识到的理解错误把 Optional 参数当必有值用。确定性验证器提供的是模型自检不出来的信号这 5% 里没有一分是心理作用。ruff 的贡献方式则偏间接它把改完 A 坏了 B的回归暴露得更快以前要等下一轮 pytest 才发现现在 lint 当轮就报。回归发现越早回滚越便宜。踩坑提示接三件套时别一次接三个。我先单独接 pytest 跑了一版4%再加 mypy1%ruff 最后加0%但对轮数有贡献。合并测的话我永远不会知道 ruff 单独看是零提升——它的价值全在防回归上单独一版跑不出来。四、改进3预算优化第三刀有点反直觉把预算调小。改动max_steps从20调到12max_tokens从500K调到200K 配置diffmax_steps: 20→12, max_tokens: 500K→200K 其余配置全部不动 效果 成功率87% → 88%1%几乎不变 平均轮数3.0 → 2.8轮-7% 平均token28K → 24K-14%为什么收紧预算反而不掉成功率把失败案例的轮数分布拉出来看就明白了修得好的 bug 基本都在 4 轮内收敛超过 8 轮还在转的90% 最后也修不出来。多出来的预算绝大部分花在注定失败的挣扎上。砍掉尾部预算等于提前止损成功率几乎无损token 立省。这背后是个可以推广的判断预算不是越大越保险预算是止损线。它的作用不是给模型更多机会是决定什么时候承认此路不通。定预算的依据应该是轮数-成功率曲线的拐点而不是感觉多给点稳。五、改进4模型分层最后一刀是第7节的分层maker 保持 GPT-4o判定环节切到 GPT-4o-mini。改动maker用GPT-4ojudge用GPT-4o-mini 配置diffjudge: gpt-4o → gpt-4o-mini 其余配置全部不动 效果 成功率88% → 91%3% 平均轮数2.8 → 2.5轮-11% 成本$0.07/任务 → $0.05/任务-29%这里有个细节判定换小模型成功率反而升了 3 个点。省钱好理解涨质量是为什么翻日志发现原因在速度——mini 判定不到一秒出结果每轮的循环间隔变短同样的墙钟时间内跑批的节奏更紧凑更本质的是小模型判定时更严格地按是/否字面执行不像强模型判定时爱加基本完成的水分判定。判定环节的任务简单强模型的聪明在这里反而表现为弹性解释。当然这 3 个点里有水分的可能性也有样本只有 30 个一个 bug 就是 3.3 个点我按保守口径理解它成本大降质量不降。七、调优记录表与全程曲线四刀砍完全账摆出来改进项成功率平均轮数平均token成本/任务基线71%4.8轮42K$0.12结构化错误82%3.5轮31K$0.09验证器87%3.0轮28K$0.08预算优化88%2.8轮24K$0.07模型分层91%2.5轮24K$0.05成功率一路爬坡的形态用里程碑图看更直观基线71%结构化错误82%验证器87%预算优化88%模型分层91%四项改进各自贡献的拆解结构化错误11%成功率-27%轮数验证器5%成功率-14%轮数预算优化1%成功率-14%token模型分层3%成功率-29%成本关键发现结构化错误效果最大11%成功率——反馈质量是核心验证器次之5%——确定性信号驱动收敛预算优化成本效益高——更少token几乎不损失成功率模型分层省钱又提效——成本-29%成功率3%这个排序值得抄走如果你只有精力做一件事先做失败信息结构化如果有两件加确定性验证器。它们俩是反馈质量验证确定性的组合拳合起来贡献了 16 个点的成功率。后面两项是精修属于锦上添花。七、跑分器、帕累托最优与剩余失败分析7.1 基准跑分器让每一步改进可量化上面的每行数字都出自这个小工具代码全部贴出。它把三条规矩固化成代码测试集只读、每版配置快照归档、指标用 pydantic 定义口径统一# experiments/bench_runner.py修复循环基准跑分器调优第8节的数字都从这来 运行uv run python experiments/bench_runner.py --config v5_layered.json 环境Python 3.12 uv importjsonimporttimefrompathlibimportPathfrompydanticimportBaseModel,Fieldfromai_loop_course.logging_configimportget_logger loggerget_logger(bench_runner)BENCH_DIRPath(benchmark)classBenchConfig(BaseModel):一版跑分配置单变量原则的载体diff一眼可见version:str# v1_baseline / v2_structured / ...feedback_format:strraw# raw / structuredvalidators:list[str]Field(default_factorylist)max_steps:int20max_tokens:int500_000judge_model:strgpt-4o# 分层时切gpt-4o-miniclassBenchResult(BaseModel):跑分结果口径统一跨版本可比version:strsuccess:inttotal:intavg_rounds:floatavg_tokens:intavg_cost_usd:floatpropertydefsuccess_rate(self)-float:returnself.success/self.totaldefrun_bench(config:BenchConfig,bugs:list[dict])-BenchResult:跑完整测试集每个bug计时计tokenLLM调用走全字段日志rounds,tokens,costs,ok[],[],[],0forbuginbugs:t0time.time()r,tk,fixedrepair_loop(bug,config)# 第6章循环本版配置rounds.append(r);tokens.append(tk);okfixed logger.info(bug%s 结果%s 轮数%d 耗时%.1fs,bug[id],修复iffixedelse失败,r,time.time()-t0)resultBenchResult(versionconfig.version,successok,totallen(bugs),avg_roundssum(rounds)/len(rounds),avg_tokensint(sum(tokens)/len(tokens)),avg_cost_usdestimate_cost(tokens))# 配置和结果一起归档调优历史可回溯outBENCH_DIR/f{config.version}.jsonout.write_text(json.dumps({**config.model_dump(),**result.model_dump()},ensure_asciiFalse,indent2),encodingutf-8)logger.info( 跑分总结 版本%s 成功率%.0f%% 平均轮数%.1f 平均token%dK 成本$%.3f/任务 ,result.version,result.success_rate*100,result.avg_rounds,result.avg_tokens//1000,result.avg_cost_usd)returnresult跑一版最终配置 v5的真实控制台输出$ uv run python experiments/bench_runner.py--configv5_layered.json2026-09-2122:04:11[bench_runner]INFObuggh-1421 结果修复 轮数2耗时9.6s2026-09-2122:04:19[bench_runner]INFObuggh-1433 结果修复 轮数3耗时12.8s2026-09-2122:04:24[bench_runner]INFObuggh-1512 结果失败 轮数12耗时58.2s...共30条2026-09-2122:31:47[bench_runner]INFO跑分总结 版本v5_layered 成功率91% 平均轮数2.5平均token24K 成本$0.048/任务注意那条gh-1512失败案例吃了 12 轮 58 秒——印证了第一节说的失败案例的成本远高于平均。跑完分的版本对比直接一行命令$ uv run python experiments/bench_runner.py--comparev1_baseline v5_layered v1_baseline → v5_layered 成功率71% →91%20% 平均轮数4.8→2.5-48% 平均token 42K → 24K-43% 成本$0.12 →$0.05-58%全程四个指标同向改善没有一项是用另一项换来的——这是帕累托改进不是权衡。跑分器还有个隐性价值它逼着感觉变成数字。调第6节那阵我一度觉得某版配置好像好了一点跑分器一跑成功率纹丝不动、轮数还涨了 0.3——感觉是靠不住的尤其是你刚投入了两天心血改完一个功能之后确认偏差会让任何变化看起来都像进步。跑分器不给情绪留面子它只认测试集。7.2 帕累托最优配置最终配置成功率达到91%的最优成本方案 模型分层 maker: GPT-4o写代码 judge: GPT-4o-mini完成判定 循环参数 max_steps: 12 max_tokens: 200K timeout: 5分钟 验证器 pytest必须通过 rufflint必须无错误 mypy类型检查 反馈格式 结构化五要素类型/位置/原因/期望/修复方向最优的判定标准我说明一下免得误读这是在这个30-bug测试集上的帕累托前沿点。我试过更激进的配置checker也切mini、max_steps砍到8成功率掉到 88%——省的钱不抵质量损失被否决也试过更保守的全强模型、预算放开成功率 92% 但成本翻倍——那 1 个点不值一倍的钱。帕累托最优是针对你的测试集和你的价值权衡说的换一个任务分布前沿点会挪位置但找前沿点的方法单变量跑分器到哪都通用。还有个没写进配置但同样重要的事调优什么时候停。我给自己定的停止条件有三条命中任意一条就收手——成功率连续两版提升小于 2 个点边际收益枯竭成本降幅连续两版小于 10%省钱空间挖完剩余失败案例的分类里没有改配置能解决的类型结构性天花板到了。这次调优三条全中所以 91% 收官。没有停止条件的调优会无限迭代下去每多跑一版的全批跑分也要钱和时间调优本身也要讲成本收益这才是把循环工程的哲学用到调优自己头上。7.3 剩余9%失败的分析91% 意味着 30 个 bug 还剩 3 个没修好。逐个解剖失败原因没有一个是模型不够聪明失败案例分析30个bug中3个失败 1. 需要理解业务逻辑的bug1个 → 循环无法理解业务上下文 → 修复需要知道这个折扣字段在财务侧的语义 → 需要人工辅助 2. 跨多文件的复杂bug1个 → 循环上下文不够 → 根因在A文件症状在C文件中间隔了两层间接调用 → 需要子智能体第10章 3. 性能相关bug1个 → 需要性能profiling工具 → 循环有测试验证器但没有性能验证器 → 需要更多工具支持失败类型占比缺什么补法业务上下文缺失3.3%领域知识人工介入点需求澄清跨文件推理3.3%上下文容量子智能体分治第10章性能维度3.3%性能验证器接profiling工具第8章这张表的价值在于它告诉你天花板在哪、天花板是什么材质。三个失败恰好对应三种不同的结构性缺口——没有一种是靠再跑几轮或换个更强的模型能解决的。循环工程的失败要分类归档而不是笼统地记一句没修好分类清楚了下一章该造什么工具自然浮出水面跨文件要子智能体性能要新验证器业务上下文要人机协作接口——全是第8章工具与MCP生态的伏笔。小结改进项成功率变化成本变化优先级结构化错误反馈11%-26%⭐⭐⭐⭐⭐确定性验证器5%-10%⭐⭐⭐⭐预算优化1%-14%⭐⭐⭐模型分层3%-29%⭐⭐⭐⭐核心结论从71%到91%四步改进各有效果结构化错误反馈效果最大11%验证器次之5%模型分层又省钱又提效-29%成本3%成功率。调优的核心是反馈质量和验证确定性——不是换更强的模型而是给模型更好的反馈。再补三条方法层面的比数字更耐用单变量固定基线一次只改一项测试集一个字不动数据才可比预算是止损线不是保险按轮数-成功率拐点定不按感觉定失败要分类归档剩余9%的三种失败对应三种结构性缺口指明下一章的工具方向最后借第7章收官的位置把整章八节串成一句话版本方便你回头索引第1节立哲学确定性验证模型自评done是主张不是证明第2节用pytest当裁判跑TDD循环第3节接入编译/lint/测试三件套喂确定性信号第4节Maker/Checker双模型互查补质量盲区第5节防住验证器自身的坑过拟合验证与作弊第6节把失败信息工程化成五要素提示词第7节按认知负荷分层调度大小模型本节把所有手段量化成一条从71%到91%的调优曲线。一根主线贯穿八章给模型好的反馈和确定的验证比换更强的模型更值钱。延伸阅读与思考实践用30个bug测试你的循环记录成功率调优逐项改进记录每次的数据变化思考你的循环失败案例中最主要的原因是什么下节预告第8章《工具与MCP生态实战》正式开章——第1节《工具即关节好工具让模型一次选对坏工具让它当场翻车》。本节剩余的三个失败案例已经把话挑明跨文件要子智能体、性能要profiling验证器、业务要人机接口全是工具层的活。验证工程打好了地基下一章往上盖楼。如果觉得本文对你有帮助欢迎点赞、收藏、关注三连本系列持续更新中关注不迷路~文章编号第7章第8节 | 总进度52/120 | 预计阅读时间12分钟 第7章验证工程全部完成8/8篇累计52/120篇43.3%