公司动态

LLM优化Harness:从代码生成到系统化工程能力评估

📅 2026/8/29 19:58:09
LLM优化Harness:从代码生成到系统化工程能力评估
让大模型去优化一套持续集成脚本是最近我经常被问到的一件事。听起来很理想把一段运行缓慢、依赖混乱的测试框架交给 LLM让它自己读代码、找瓶颈、改配置、重跑测试最后再给你一份优化报告。但实际跑过几次就会发现问题模型经常给出一个看起来逻辑自洽、一执行就崩的补丁。它并不是不会写代码而是缺少一种面向“系统外围控制层”的优化能力知道改哪里、为什么改、改了之后如何证明不会破坏别的东西。HarnessOpt-Bench 这个基准想评估的正好是这件事——LLM 在 Harness Optimization 上的真实水平。这里的 Harness 不是马具而是工程里那些“包裹在核心逻辑之外、负责让系统跑得更顺”的层测试脚手架、构建流水线、Agent 执行环境、数据回放框架都可以叫 harness。优化一个 harness意味着在存在约束条件的情况下调整结构、配置或流程让某个指标变好同时不破坏原有能力。这个任务看起来只是改代码实际上是对 LLM 的系统理解、调试能力和工程判断的综合检验。1. Harness Optimization 到底在优化什么1.1 一个场景让 LLM 优化构建脚本结果线上全崩假设你有一个项目CI 流程每次构建需要十分钟。你找了一个当前主流的大模型把构建脚本、项目目录结构、运行日志一股脑喂给它要求是“把整体构建时间压缩到三分钟以内”然后让模型给出修改后的方案。模型很快给出了一份新脚本把原来串行的单元测试改成并行缓存了依赖目录删掉了几个看起来很冗余的初始化步骤。单看补丁每一步都有道理。但放到完整环境里跑一遍问题出现了并行测试共用同一个临时数据库产生写入冲突依赖目录缓存键忽略了 Python 版本差异换一台机器就失效删掉的“冗余步骤”其实负责生成动态配置文件后面测试和打包环节都需要它。这种时刻你很难说是模型能力不够因为它确实理解了构建脚本的大部分逻辑。更准确地说它缺乏对“整个 harness 是一个闭环系统”的认知局部优化必须放在全局依赖和运行环境里验证否则就是拆东墙补西墙。这个是 Harness Optimization 和普通代码生成的本质区别。普通代码生成的任务边界通常是明确的输入是需求输出是函数或模块验证方式是独立的单元测试。而 harness 优化任务的边界是模糊的优化目标由你定义约束分散在环境、时序、资源、权限和依赖里验证方式是“整个系统是否还能稳定跑通”。模型需要具备系统思考能力而不只是代码改写能力。1.2 Harness 的三种常见形态如果把 Harness 按工程用途分类我通常会分成三类每一类的优化重点都不一样。Harness 类型典型例子优化目标常见约束测试骨架pytest fixture、测试容器、mock 数据生成器测试覆盖率提升、执行时间下降数据隔离、并发安全、环境可重复构建发布链路CI 流水线、打包脚本、多阶段构建配置构建速度、产物大小、发布成功率依赖缓存、平台差异、步骤顺序Agent 运行框架LLM Agent 的上下文组装、工具调用封装、交互循环任务完成率、Token 成本、稳定性上下文长度、工具权限、错误恢复这三类共性很强它们都不是业务主逻辑而是业务主逻辑的“外围支撑系统”。优化的价值恰恰在这个“外围”里因为重复劳动、性能瓶颈和运行不稳定大多发生在这些胶水层。但正因为它们不是主逻辑出问题时不会立刻抛出一个清晰的函数报错而是表现为“整体变慢”“偶尔失败”“换环境就挂”。1.3 为什么这是比“代码生成”更难的任务如果只用传统代码生成基准来评估一个模型比如“根据描述写一个排序函数”“实现一个 REST 接口”模型可以做得很好。原因是这些任务有标准输入、标准输出、标准测试模型可以通过大规模语料学习到正确答案。但 harness 优化任务没有单一正确答案。相同目标你可以通过改配置、加缓存、改并发、重构依赖、重写脚本来实现不同方案对可维护性、可移植性、安全性的影响也完全不同。模型不仅要生成一个能跑的方案还要能回答“为什么这个方案比原来好”“在什么环境下成立”“如果资源缩减一半是否依然安全”。这种评估很难用简单的“对不对”来打分需要动态执行整个流程观察多个指标甚至要做多次重复实验来排除随机性。所以 HarnessOpt-Bench 这类基准出现的意义不在于给 LLM 的代码能力再排一次名而在于把评估从“能不能生成代码”推进到“能不能在复杂系统里完成受约束的改进”。2. HarnessOpt-Bench 想要测出的能力图谱2.1 任务结构输入、输出、验证闭环如果让我从工程视角来拆解 HarnessOpt-Bench我会认为它的一个标准评测任务至少包含这几部分任务说明用自然语言描述当前 harness 存在的问题和期望目标比如“构建时间从 10 分钟降到 3 分钟不能减少测试用例”。代码仓库快照一份可运行的完整项目包含被优化的 harness 代码、依赖清单、环境配置和测试脚本。外部约束例如只能修改哪些文件、运行资源上限、不允许网络访问、容器镜像固定。评估脚本能够在隔离环境里自动执行优化后的 harness测量关键指标并验证原有功能没有回归。模型的输出不是一段文字而是针对代码仓库的修改补丁或者是新的配置内容。评测系统拿到输出后会应用补丁、执行流水线、采集指标、和基线做对比得到最终分数。这里最关键的是“验证闭环”。如果模型只是输出一段“看起来会更快”的代码而评测系统无法把它真正跑起来那么这个输出就没有任何价值。Harness 优化比普通代码生成更依赖环境反馈模型必须看到一次真实的执行结果才能判断自己的修改方向是否正确评测系统也只有通过真实执行才能判断模型是否具备“迭代式调试”的能力。2.2 评估维度四个不是“过不过”的指标单一指标很难衡量 harness 优化能力。目前我看到比较合理的评测体系不会只看最终优化率而是从四个维度来拆解。维度说明为什么重要正确性修改后功能是否保持不变原有测试是否通过优化不能以牺牲功能为代价优化率目标指标的实际提升幅度如构建时间、内存占用这是任务的核心目标稳定性多次运行结果是否一致是否存在偶发失败稳定性差的优化不适合生产环境成本与复杂度修改的代码量、是否引入新依赖、可读性是否下降工程上必须考虑长期维护成本正确性是第一道门。一个补丁如果让 30% 的测试用例失败哪怕运行时间缩短了 90%也是失败的。优化率是第二个维度但要注意“统计显著性”。一次跑得快可能是因为缓存命中、负载低或者随机种子变化必须多次重复取中位数或均值。稳定性往往被低估有些优化会让流水线在理想环境里跑得飞快但稍微遇到并发冲突或网络延迟就失败。最后是成本复杂度模型如果为了 5% 的提速把整个脚本改成 800 行的抽象工程那对团队来说不一定是收益可能是负资产。2.3 动态评测为什么比静态评测可靠在 HarnessOpt-Bench 的设计讨论里有一个争论点是只分析模型产出的补丁代码还是真正执行补丁后的系统。我强烈倾向“动态执行”。静态评测可以快速、低成本地判断改动了哪些文件、调用了哪些函数、是否符合某种代码模式但它无法回答“系统是否真的更快”以及“是否引入了隐性错误”。比如模型把某个测试函数从类中移出去了静态分析可能看不出任何问题但动态执行时会发现该函数依赖类初始化时创建的 shared fixture导致运行报错。动态评测的问题在于成本高、环境复杂、容易有安全隐患。但 harness 优化本身就是一项工程活动离开执行环境谈优化效果没有任何意义。可靠的基准设计应当默认所有修改都必须在隔离容器中跑一遍并对比基线。这既提高了评估可信度也能把模型的工作流从“一次性生成”逼向“假设—验证—修正”的循环。3. 手把手设计一个 Harness 优化评测任务这一节不讨论 HarnessOpt-Bench 官方的具体实现因为那需要等数据集和代码库正式发布后再落地。我更想分享的是如果我们要在自己团队里做一次小规模的“LLM 优化 Harness”评估要怎么设计才能得到有价值的结论。3.1 选一个可控的测试 Harness 样例不要一上来就拿完整业务系统。建议选一个 2000 到 5000 行的小型开源项目它自带测试框架和构建脚本有明确的性能问题但不至于复杂到模型无法理解。我自己的选型标准有三个必须能本地运行所有依赖都能通过 pip 或 npm 安装不需要特殊硬件或外部服务。有可重复的基线指标执行同样的命令得到相对稳定的时间或资源数据。有回归测试即使没有完整的 CI也至少要有一套pytest或unittest能验证功能是否被破坏。一个常见的样例是有一个 Python CLI 工具它的测试套件使用了 fixture 构建大型临时文件导致测试耗时很长。优化目标是“让测试时间减少 40%且不能跳过任何测试”。这个任务足够具体模型需要理解 fixture 的作用域、临时文件的生命周期、测试之间的依赖关系然后决定是否把某些 fixture 改为 session 级、使用临时目录还是改用内存对象。3.2 定义优化目标和基线在写评测脚本之前先要把“好”定义清楚。比如目标可以写成输入现有仓库测试命令pytest -q。优化目标pytest 执行时间降低 40%。约束test/目录下测试用例数量不能减少不允许跳过任何测试不能修改被测源代码只能修改测试配置和 fixture。环境固定 Python 版本和依赖版本固定容器镜像。然后先在原仓库上跑 5 次pytest -q记录耗时取中位数作为基线。这一步很重要如果基线本身不稳定后续任何优化数据都不可信。3.3 编写自动评测脚本评测脚本的核心流程是应用模型补丁 → 执行目标命令 → 采集指标 → 回归检查。一个简单的结构是这样import subprocess import time import statistics import os from pathlib import Path REPO_DIR Path(./sample_project) def apply_patch(patch_text): # 实际场景里要校验补丁来源避免注入 patch_path REPO_DIR / model.patch patch_path.write_text(patch_text) subprocess.run(fcd {REPO_DIR} git apply model.patch, shellTrue, checkTrue) def run_pytest(): start time.perf_counter() result subprocess.run( cd sample_project pytest -q, shellTrue, capture_outputTrue, textTrue ) elapsed time.perf_counter() - start return result, elapsed def evaluate(patch_text): apply_patch(patch_text) timings [] results [] for _ in range(5): result, elapsed run_pytest() timings.append(elapsed) results.append(result) # 检查全部通过 all_pass all(r.returncode 0 for r in results) median_time statistics.median(timings) return { median_time: median_time, all_tests_pass: all_pass, has_regression: not all_pass }这个脚本只是一个演示结构。真实评测要比这复杂因为要处理 git 回滚、依赖安装、输出日志、超时控制、资源限制甚至每个任务都要独立的容器。但核心思想不变让模型输出补丁用真实执行来做裁判用多次采样消除随机影响。3.4 先小样本跑通再扩展在把所有模型都纳入评测之前建议先用 3 到 5 个任务做小样本试跑。原因有两点评测脚本本身可能是错的。比如没有清理缓存、没有重置数据库、多个并行任务干扰了全局端口这些都会导致评测结果失真。模型输出格式会不统一。有的模型会同时输出说明和补丁有的只输出最终文件内容有的给出的补丁无法直接应用。评测流程必须对这些情况做出明确处理。小样本跑通后要检查三件事补丁是否成功应用、评测结果是否稳定、失败任务能不能定位到具体原因。如果你发现某个模型的补丁总是把整个测试目录删掉那不是模型笨而是评测缺少“最大修改范围”约束。要在评测系统里增加安全策略比如只允许修改test/和pytest.ini其他路径一律拒绝。4. LLM 在 Harness 优化上的典型翻车点即使有了评测框架识别模型的失败模式仍然很有价值。因为失败模式能直接告诉我们一个模型是在真正优化还是在“看起来合理地碰运气”。4.1 只看局部不看全局模型经常会抓住一个明显的瓶颈比如某个函数特别慢于是花费大量精力去重写它却没有意识到这个函数被调用的上下文才决定了瓶颈是否成立。在 harness 优化里一个典型的案例是测试 fixture 里发现每次测试都重新构建一个数据库模型决定把数据库构建改成全局复用。从单个函数看确实减少了重复计算但如果两个测试用例依赖不同的初始数据全局复用就会导致测试串台。这类问题的根因是模型缺乏“依赖图”分析能力。人类工程师遇到这种情况会先看 fixture 的 scope看测试之间的数据隔离要求再决定是否能把初始化上提。模型如果只看局部代码不看调用链路很容易做出表面合理、实际破坏性的改动。4.2 不会验证把“疑似优化”当成结果当你问模型“怎么证明这个补丁更快”时很多模型会回答“我检查了逻辑应该会更快”。但在 Harness 优化里“应该会更快”等于没说。真正的证明只有一条在相同环境下跑优化前后各十次对比分布。评测过程中我见过不少失败案例模型把缓存目录从/tmp改到项目目录下理由是“读本地缓存更快”。但它没有验证缓存是否真的被命中结果新缓存目录的权限有问题每次都绕过了缓存构建时间反而更长。如果模型有一套自己的验证习惯比如修改后主动运行一次前后对比这类问题是可以自己发现的。可惜很多模型倾向于直接生成结论而不是通过工具来验证。4.3 参数与环境的边界感缺失Harness 优化离不开环境参数并发数、超时时间、缓存 Key、临时目录、环境变量。模型经常为了优化某个指标把参数硬编码到极限。例如把测试并行数从 4 调到 CPU 核心数但没考虑测试进程的内存占用把缓存保留时间调到 30 天但没考虑磁盘空间把网络请求超时从 30 秒降到 3 秒导致在弱网环境下大量失败。这些参数在开发机上是合理的到了 CI 环境就是灾难。这说明模型的训练数据里包含很多“看起来正确”的工程实践但缺少“在给定资源约束下做权衡”的推理能力。评测任务里如果加上资源上限、系统版本等约束低水平模型和强模型之间的差距会被迅速拉开。4.4 缺乏回归意识优化 harness 时最容易犯的错误是只顾着让目标指标变好忽略了原有一切必须继续工作。这个“回归意识”看起来基础但对很多模型来说很难。我在测试里让模型优化构建脚本模型为了提速把生成 API 文档的步骤从build阶段挪到release阶段。版本发布是变快了但开发环境的本地预览不再更新文档导致其他同事的调试流程被破坏。模型没有做“是否有人依赖这个步骤产物”的检查。好的优化方案应该保留原有功能同时让整体更高效。如果做不到这一点至少要在输出里明确标注“这个优化会改变哪些行为”方便人工决策。5. 从基准到能力如何把评测结果变成工程判断5.1 分数高的模型不一定适合你的项目HarnessOptimization 评测分数可以反映模型在处理这类任务时的综合能力但不能直接等同于“某个模型适合我们的仓库”。评测任务通常经过简化仓库大小可控、优化目标清晰、约束明确、环境固定。真实项目里代码仓库可能由几十个服务组成优化目标可能是“让模型在降低延迟的同时提高准确率”甚至约束条件本身都在业务讨论中不断变化。基础模型在 benchmark 里的表现只能说明它在理想化场景下的上限不说明它在混乱现实中的下限。一个合理的判断顺序是先用 HarnessOpt-Bench 这类评测在同等条件下筛选模型排除结果明显偏弱的。再从剩余模型中选 2 到 3 个在自己的一个真实小型项目上做模拟优化。最后根据输出质量、调试成本、交互体验综合决定是否长期使用。5.2 评测治理版本、容器、随机性、可复现不管你是要复现 HarnessOpt-Bench还是自建评测都要注意评测本身的工程治理。否则你得到的不是一个结论而是一堆无法复现的日志。有几件事必须提前做锁定环境版本Python、Node、GPU 驱动、CUDA、依赖库都要用固定的requirements.txt或锁文件。每次从干净状态开始缓存目录、临时文件、环境变量都要重置避免上一次运行残留影响下一次结果。隔离执行强烈建议所有模型生成的补丁都在容器里执行不要直接在工作区里跑。模型输出是不可信的补丁可能删除文件、修改权限、执行任意命令。多次采样取中位数构建和测试耗时都有噪声单独一次结果不能说明问题。通常至少跑 5 次条件允许可以跑 10 次。记录日志和产物每一次评测都要保留补丁、命令输出、指标数据、版本信息便于事后定位分析和对比。如果忽略这些治理项评测结果很容易出现“同一个补丁上一次跑 100 秒这一次跑 200 秒”的情况。你不能把这个差异归咎于模型能力而要先检查环境是否存在热缓存、网络波动或资源争抢。5.3 在真实项目里引入 Harness 优化评估的建议如果你希望自己的团队项目也能借鉴 HarnessOpt-Bench 的思路我建议不要一开始就做全自动评估而是先把工作流拆成三阶段。第一阶段是“人工协助模式”让 LLM 给出优化建议由工程师审查、修改、验证重点观察模型的建议是否具备全局视野和可执行性。第二阶段是“半自动验证模式”把人工改好的补丁交给自动脚本执行跑出优化前后的对比数据看模型建议和实际结果之间的偏差。第三阶段是“受限自动评估模式”在隔离容器里让模型直接生成补丁由脚本应用并执行但限制只能在指定目录下修改且需要人工审批后才能跑。这个过程能让团队一步步积累评测数据理解模型的强项和短板而不是突然上线一个全自动机器人然后被错误的补丁折腾到崩溃。5.4 不适合用 HarnessOpt-Bench 的场景任何基准都有边界HarnessOpt-Bench 也不例外。至少以下几类场景用它来评估模型意义不大纯业务算法调优比如优化 RAG 检索的召回率、提升推荐模型的排序效果这属于模型或算法层面的调优不是 harness 优化。完全黑盒的第三方系统如果系统没有任何测试入口无法本地运行也没有日志模型无法形成“假设—验证”闭环评测也就无从谈起。需要大量私密数据的场景如果 harness 优化必须访问内部数据和权限不适合做自动化评估除非你有完善的权限隔离方案。对稳定性极其敏感的生产核心链路即使模型给出漂亮的数据人工审批依然是必须的自动化边界。评估的作用是辅助决策而不是替代工程判断。模型在 Harness 优化上的表现再亮眼最后把关的还是对系统真正理解的人。6. 把 Harness 优化能力看作新的工程素养回到开头的问题为什么让 LLM 优化一个构建脚本结果会全崩因为我们过去评估 LLM 的标准是“能不能答对”而 Harness 优化要求的标准是“能不能在真实系统里把它做出来、验证出来、保持住”。HarnessOpt-Bench 这类基准把评估重心从单点能力移到了系统化的工程操作这是一个更务实的信号。对普通开发者来说这意味着我们和模型的协作方式正在变化。以前我们要求模型写出一个函数现在我们要求模型理解一套流程在约束下做出更改并且提供验证过程。模型的“调试能力”“环境感知”“回归意识”会变得越来越重要。未来真正稀缺的能力不是谁能让模型生成更多代码而是谁能设计出合理的任务边界和评测闭环让模型在可控范围内持续优化那些繁琐、易错、重复的 harness 层。所以当你下次再想让 LLM 帮你优化什么脚本时不要只看它输出的补丁漂不漂亮。先让它讲清楚三件事改了什么、为什么不会破坏别的东西、用什么证据证明结果成立。如果它答不上来不妨把 HarnessOpt-Bench 的思路拿过来先跑一次基线再做一次对比实验。这比盲目信任一次生成结果要可靠得多。