
当开发团队把大模型接入测试流程之后最容易遇到的一个问题不是“模型能不能写代码”而是“模型能不能理解一套测试基础设施并在这个基础上做优化”。为了稳定评估这种能力我基于 HarnessOpt-Bench 的思路整理了一份完整的实操笔记内容包括测试索具Test Harness优化场景拆解、评测维度设计、轻量评测框架实现以及一个可复现的测试夹具优化示例。本文既适合想了解 LLM 评估体系的读者也适合准备把大模型接入测试基础设施的工程团队。在开始之前先明确一下本文的讨论范围。我们不会去讨论怎么训练一个大模型也不会做复杂的分布式评测平台。重点放在“如何构造一个评测任务”“如何编写评测框架”“如何让不同 LLM 在统一的 Harness 优化场景下接受打分”。代码以 Python 3.10 为例尽量做到完整可运行、思路可复用。1. 背景与核心概念1.1 什么是 Test HarnessTest Harness 通常翻译为“测试执行框架”或“测试索具”但在实际工程里它指的并不是 pytest、JUnit 这种测试框架本身而是“为了让测试能够运行起来而搭建的一套脚手架系统”。举个例子一个完整的 Test Harness 通常包含测试环境初始化逻辑例如准备数据库、创建临时目录、设置环境变量。测试夹具Fixture例如 Mock 对象、桩数据、网络请求模拟。断言和验证逻辑例如字段比对、异常断言、输出快照比对。构建和运行入口例如 CI 里的启动脚本、超时控制、并发策略。测试数据管理例如 Excel、CSV、数据库种子数据。很多项目对业务代码的重视程度很高但对这套“脚手架代码”往往缺乏维护。这导致了一个典型现象业务功能明明没变测试却因为环境初始化顺序不对、Mock 数据过期、断言过于脆弱而频繁失败。Harness 优化目标就是把这一层基础设施变得更稳定、更快、更容易排查。从代码量上看Harness 代码可能只占项目总代码量的 10% 左右但它们直接影响 CI 的成功率和开发者的提交效率。这也是为什么“优化 Harness”作为独立任务值得被单独研究和评估。1.2 为什么需要评估 LLM 的 Harness 优化能力传统上我们用代码生成类基准例如 HumanEval、MBPP来评估大模型的编程能力。这类基准的侧重点是“根据自然语言需求从零编写一个函数”。但真实开发场景里更多时候我们需要的是“在既有代码基础上做修改”现有测试脚本有 bug需要定位并修复。测试用例运行时间过长需要优化执行顺序。Mock 数据不完整需要补充边界条件。断言不严谨导致假阳性或假阴性。需要把硬编码的配置参数改成从环境变量读取。这些任务和“从零写一个函数”差异很大。它们要求模型不仅理解单点代码还要理解测试项目结构、理解运行日志、理解失败上下文并做出最小幅度的变更。HarnessOpt-Bench 这类基准的出现本质上是为了填补“LLM 在测试基础设施优化任务上的能力评测空白”。从工程角度来看评估 LLM 的 Harness 优化能力还有一层现实价值它直接决定了大模型能否在现有 CI 流程中承担“自动化测试维护者”的角色。如果模型只能生成零散代码却无法处理项目上下文那接入 CI 后反而会增加人工审查成本。1.3 HarnessOpt-Bench 的定位与价值HarnessOpt-Bench 是一个面向 LLM 的评测基准核心任务是让模型在一个给定的测试仓库快照中完成各类 Harness 优化操作并用统一指标体系打分。它对比的是“模型输出的修改是否真的提升了 Harness 质量”。这种评测思路的价值在于三点任务粒度更接近真实工程。模型面对的不是一个函数描述而是一套包含多文件的测试项目。评估指标更全面。不只看代码能不能运行还看修改后的测试是否稳定、是否最小化变更、是否引入额外风险。可扩展性强。只要任务集足够丰富就可以覆盖“测试用例生成、断言优化、性能优化、可观测性增强”等多个维度的模型能力。对于测试开发工程师而言即使不直接使用 HarnessOpt-Bench 本身它的评测思想和任务设计方式也能应用到团队内部的模型选型和 prompt 调优中。2. 评测能力维度与任务设计2.1 把 Harness 优化拆解为能力维度要对 LLM 做评测首先得把“Harness 优化”这个模糊的目标拆成可观测的能力维度。参考 HarnessOpt-Bench 的设计思路我认为至少应该包括六个维度。第一个维度是“测试用例生成”。模型需要根据功能描述或缺陷报告生成新的测试用例覆盖正常路径、边界条件和异常场景。第二个维度是“断言质量改进”。模型需要判断现有断言是否足够严格是否存在只验证了“不报错”却没有验证“行为正确”的问题并且给出修改后的断言。第三个维度是“环境与配置修复”。模型需要识别测试代码中的硬编码路径、过期依赖、环境变量缺失等问题并修复它们。第四个维度是“执行稳定性提升”。模型需要处理 flaky test 的典型原因比如未等待异步任务完成、随机数未固定、共享状态未被清理等。第五个维度是“失败信息可观测性”。模型需要在测试失败时补充更多上下文让开发者不用打开日志就能知道哪里出了问题。第六个维度是“运行效率优化”。模型需要识别不必要的 sleep、重复初始化、串行执行导致的耗时并给出并行化或缓存方案。这六个维度并不互相排斥。一个完整的 Harness 优化任务往往需要模型同时具备多个维度的能力。2.2 任务输入输出格式HarnessOpt-Bench 的一大特点是输入信息更接近真实环境。以我实现的轻量版本为例每个评测任务的输入包含四个部分repo_snapshot仓库文件快照通常是测试项目中的关键文件列表。instruction自然语言描述说明当前 Harness 存在什么问题期望模型做什么。test_command验证用的测试命令评测系统会用它来运行修改后的代码。context额外的上下文信息例如失败日志、错误堆栈、相关生产代码片段。模型输出则要求是一个“修改方案”一般包含修改文件列表和补丁内容。为了避免模型自由发挥难以自动打分任务设计阶段最好要求输出结构化格式。{ task_id: harness_opt_001, repo_snapshot: { tests/test_user_service.py: 代码内容..., tests/conftest.py: 代码内容..., src/user_service.py: 代码内容... }, instruction: test_user_service.py 中 test_create_user 用例存在随机失败问题请定位原因并修复。不要修改 src 目录下的业务代码。, test_command: pytest tests/test_user_service.py -x -q, context: { latest_failure_log: tests/test_user_service.py:12: assert User(nametom) User(nametom), hint: 问题可能与 conftest.py 中的共享数据库 fixture 有关 } }{ task_id: harness_opt_001, model_output: { summary: 将 conftest.py 中的共享 fixture 改为 function 作用域并在每个测试用例结束后清理数据库记录。, modified_files: { tests/conftest.py: 补丁内容或完整文件内容... } } }在实际评测中我们通常要求模型输出“完整修改后的文件内容”而不是统一 diff 格式因为这样更容易通过直接覆盖文件的方式做自动化验证也能减少 patch 合不上的问题。2.3 评测指标设计评测指标不能只看“测试是否通过”。Harness 优化任务里一个模型可能通过禁用测试、删除断言、硬编码返回值等方式让测试“看起来通过”但这不是优化而是破坏。基于这个考虑我的评测方案包含五个子指标指标说明打分方式功能正确性修改后的测试是否全部通过运行 test_command通过计 1失败计 0断言有效性断言是否覆盖了真实业务行为通过变异测试抽查算子级语义判断最小变更是否只修改了必要的文件统计修改文件与指令相关性匹配安全性是否删除已有测试或跳过重要校验扫描输出中的 skip、pass、删除注释可观测性失败信息是否补充了有效上下文关键词和日志结构规则匹配这五个指标里功能正确性是硬性条件其余指标可以做成加权打分。需要提醒的是自动打分很难做到完全准确尤其是“断言有效性”这一项。我的经验是先用自动化规则初筛再留下一部分样本做人工抽审这样既保证效率又保证可信度。3. 环境准备与项目结构3.1 运行环境说明这里的运行环境分为两个层面评测代码运行环境以及被评测的测试项目运行环境。评测代码运行环境建议使用 Python 3.10因为我们需要使用较新的类型注解和异步特性。被评测的测试项目环境则取决于任务集通常使用 pytest 作为测试框架并在 Docker 容器中执行保证测试不会污染宿主机环境。如果你是在本地做小规模验证可以直接使用虚拟环境。但一旦进入多人协作或大规模自动评测强烈建议把“模型调用”和“测试执行”分离模型调用服务部署在一台机器测试执行放在独立的临时目录或容器中。这样做有两个好处第一评测过程不会因为测试代码意外删除文件而影响宿主环境第二测试执行并发度高时不会拖垮模型调用服务。3.2 项目结构我实现了一个轻量评测框架结构如下harness_opt_bench/ ├── data/ │ └── tasks/ │ ├── harness_opt_001/ │ │ ├── task.json │ │ ├── repo/ │ │ │ ├── tests/ │ │ │ │ ├── test_user_service.py │ │ │ │ └── conftest.py │ │ │ └── src/ │ │ │ └── user_service.py │ │ └── expected_score.json │ └── harness_opt_002/ ├── src/ │ ├── __init__.py │ ├── task.py │ ├── runner.py │ ├── evaluator.py │ └── utils.py ├── configs/ │ └── eval_config.yaml ├── outputs/ │ ├── model_outputs/ │ └── eval_reports/ ├── requirements.txt └── run_eval.py每个任务目录下包含 task.json、repo 快照和 expected_score.json。repo 目录模拟一个最小测试项目expected_score.json 记录该任务的人工打分参考值用于评估自动评分的准确性。3.3 依赖文件requirements.txt 内容如下。这里刻意没有锁定太细的版本因为 LLM 调用接口和网络环境差异较大建议按实际环境安装。requests2.31.0 pydantic2.5.0 pyyaml6.0 pytest7.4.0 rich13.7.0如果项目后续要做更复杂的质量评估可以增加tree-sitter做代码结构解析但初版不建议引入复杂度会明显上升。3.4 配置文件配置文件使用 YAML方便扩展和修改。# configs/eval_config.yaml eval: task_dir: data/tasks output_dir: outputs time_out_seconds: 120 concurrency: 4 model: provider: openai_compatible base_url: ${MODEL_BASE_URL} api_key_env: MODEL_API_KEY model_name: ${MODEL_NAME} temperature: 0.2 max_tokens: 4096 score: use_rule_based: true run_ground_truth: false human_review_sample_size: 5providers 字段中的 openai_compatible 表示我们直接请求一个兼容 OpenAI Chat Completions 协议的接口。这样无论是使用官方 API还是使用本地部署的推理服务代码都不需要改动只需要修改 base_url 和 api_key。4. 构建一个轻量评测框架这一节我们来实现评测框架的核心部分。目标不是做一个功能完善的商业化平台而是把最核心的“加载任务 - 调用模型 - 应用修改 - 运行测试 - 给分”这条链路跑通。4.1 任务加载模块task.py 负责从 data/tasks 目录读取任务配置。每个任务包含一个 task.json 文件以及对应的 repo 快照目录。# src/task.py import json from pathlib import Path from typing import Dict, Any, List class EvalTask: def __init__(self, task_id: str, task_dir: Path): self.task_id task_id self.task_dir task_dir self.config self._load_config() def _load_config(self) - Dict[str, Any]: config_path self.task_dir / task.json with open(config_path, r, encodingutf-8) as f: return json.load(f) property def instruction(self) - str: return self.config.get(instruction, ) property def test_command(self) - str: return self.config.get(test_command, ) property def repo_files(self) - Dict[str, str]: result {} repo_root self.task_dir / repo for file_path in repo_root.rglob(*): if file_path.is_file(): rel_path file_path.relative_to(repo_root).as_posix() result[rel_path] file_path.read_text(encodingutf-8) return result def apply_model_output(self, modified_files: Dict[str, str]) - None: # 将模型的修改写入一个可执行的临时目录 temp_root self.task_dir / _run temp_root.mkdir(exist_okTrue, parentsTrue) for rel_path, content in modified_files.items(): target temp_root / rel_path target.parent.mkdir(exist_okTrue, parentsTrue) target.write_text(content, encodingutf-8) class TaskRepository: def __init__(self, task_dir: str): self.task_dir Path(task_dir) def list_tasks(self) - List[EvalTask]: tasks [] for child in sorted(self.task_dir.iterdir()): if child.is_dir() and (child / task.json).exists(): tasks.append(EvalTask(child.name, child)) return tasks这里有一个关键设计模型输出的修改不会覆盖原始 repo 目录而是写入_run临时目录。这样做的目的是保护原始评测任务方便重复执行。4.2 模型调用与执行器runner.py 负责调用 LLM 接口并把输出解析成结构化格式。为了让代码具有一定的模型无关性我这里使用 requests 直接请求兼容 OpenAI 的 Chat Completions 接口。# src/runner.py import json import os from typing import Dict, Any import requests class LLMRunner: def __init__(self, config: Dict[str, Any]): self.base_url config[base_url] self.api_key os.environ.get(config[api_key_env], EMPTY) self.model_name config[model_name] self.temperature config.get(temperature, 0.2) self.max_tokens config.get(max_tokens, 4096) def run(self, system_prompt: str, user_prompt: str) - str: payload { model: self.model_name, messages: [ {role: system, content: system_prompt}, {role: user, content: user_prompt}, ], temperature: self.temperature, max_tokens: self.max_tokens, } headers { Authorization: fBearer {self.api_key}, Content-Type: application/json, } resp requests.post( f{self.base_url}/chat/completions, headersheaders, jsonpayload, timeout120, ) resp.raise_for_status() data resp.json() return data[choices][0][message][content] def run_and_parse(self, system_prompt: str, user_prompt: str) - Dict[str, Any]: raw_output self.run(system_prompt, user_prompt) # 这里要求模型输出 JSON 代码块便于解析 json_str extract_json(raw_output) return json.loads(json_str)需要说明的是extract_json是解析模型输出中 JSON 代码块的工具函数实际场景里模型的输出可能包含多余说明文字。你可以用正则抽取第一个 json 代码块也可以直接传入原始输出并用容错解析。核心原则是prompt 设计阶段就要告诉模型输出规范而不是等模型输出后再想办法解析。4.3 评测执行流程与打分evaluator.py 负责执行测试命令并对模型输出做多维打分。# src/evaluator.py import subprocess from pathlib import Path from typing import Dict, Any class Evaluator: def __init__(self, timeout: int 120): self.timeout timeout def run_pytest(self, task_dir: Path) - Dict[str, Any]: run_dir task_dir / _run if not run_dir.exists(): return {passed: False, output: run dir not exists} proc subprocess.run( [pytest, -x, -q, .], cwdrun_dir, capture_outputTrue, textTrue, timeoutself.timeout, ) return { passed: proc.returncode 0, return_code: proc.returncode, stdout: proc.stdout, stderr: proc.stderr, } def score(self, task, model_output: Dict[str, Any]) - Dict[str, Any]: modified_files model_output.get(modified_files, {}) task.apply_model_output(modified_files) result self.run_pytest(task.task_dir) # 指标1功能正确性 correctness 1.0 if result[passed] else 0.0 # 指标2最小变更只统计与指令相关的文件 target_files set(task.config.get(target_files, [])) modified_keys set(modified_files.keys()) relevance len(modified_keys target_files) / max(len(target_files), 1) # 指标3安全性扫描是否删除了测试方法或跳过断言 safety 1.0 for content in modified_files.values(): for line in content.splitlines(): stripped line.strip() if stripped.startswith(pytest.mark.skip): safety - 0.3 if stripped.startswith(def test_): continue return { task_id: task.task_id, correctness: correctness, minimal_change: relevance, safety: max(safety, 0.0), raw_output: result[stdout], }这个打分器是初版实现有很多可以深化的地方。比如功能正确性可以拆成“原有测试通过率”和“新增测试通过率”安全性检查也可以引入语义层面的判断。但作为基准评测流程这个版本已经能稳定区分“模型是否真的解决了问题”。4.4 主入口与运行验证run_eval.py 把所有模块串起来完成一次完整的评测循环。# run_eval.py import argparse import json from pathlib import Path import yaml from src.task import TaskRepository from src.runner import LLMRunner from src.evaluator import Evaluator def build_prompts(task) - str: system_prompt ( 你是一名测试基础设施优化工程师。 你需要根据给出的仓库代码和失败上下文对测试 Harness 进行最小修改。 只允许修改 tests 目录下的文件不允许修改 src 下的业务代码。 输出必须为 JSON 格式包含 summary 和 modified_files 两个字段。 ) user_prompt f任务说明\n{task.instruction}\n\n user_prompt 仓库文件内容\njson\n user_prompt json.dumps(task.repo_files, ensure_asciiFalse, indent2) user_prompt \n\n return system_prompt, user_prompt def main(): parser argparse.ArgumentParser() parser.add_argument(--config, defaultconfigs/eval_config.yaml) args parser.parse_args() with open(args.config, r, encodingutf-8) as f: config yaml.safe_load(f) repo TaskRepository(config[eval][task_dir]) tasks repo.list_tasks() runner LLMRunner(config[model]) evaluator Evaluator(timeoutconfig[eval][time_out_seconds]) report_list [] for task in tasks: system_prompt, user_prompt build_prompts(task) model_output runner.run_and_parse(system_prompt, user_prompt) score evaluator.score(task, model_output) report_list.append(score) output_path Path(config[eval][output_dir]) / report.json output_path.parent.mkdir(exist_okTrue, parentsTrue) output_path.write_text( json.dumps(report_list, ensure_asciiFalse, indent2), encodingutf-8, ) print(json.dumps(report_list, ensure_asciiFalse, indent2)) if __name__ __main__: main()运行方式export MODEL_BASE_URLhttps://your-llm-endpoint export MODEL_API_KEYyour-api-key export MODEL_NAMEyour-model-name python run_eval.py --config configs/eval_config.yaml预期运行结果会输出每个任务的 task_id、correctness、minimal_change、safety 字段。这个结果就是后续做模型对比分析的基础数据。5. 实战示例用 LLM 优化一个测试夹具为了让上面的流程更直观这里用一个具体而微的场景来做演示。假设我们的测试项目里存在一个经典的 flaky test 问题每个测试用例前都有一段等待代码但等待时间不够稳定导致测试在 CI 高峰期经常失败。5.1 原始测试代码项目路径暂且记作demo_project/tests/里面有两个文件。# tests/test_order_service.py import time import pytest from order_service import create_order def test_create_order_valid(): time.sleep(2) order create_order(user_idu123, product_idp456, quantity1) assert order.status CREATED def test_create_order_invalid_product(): time.sleep(2) with pytest.raises(ValueError): create_order(user_idu123, product_idnot_exist, quantity1)# tests/conftest.py import pytest from order_service import OrderRepository pytest.fixture def order_repo(): repo OrderRepository() repo.reset() yield repo问题分析使用time.sleep(2)等待服务就绪属于典型的硬编码等待无法保证等待目标是 ready 状态。order_repo是 function 作用域但repo.reset()只发生在 fixture 开始时测试结束后的状态清理并不明确。如果业务接口是有状态的test_create_order_valid执行后留下的订单可能影响后续测试。这种情况非常适合让 LLM 来优化。优化目标是提高稳定性同时不改变测试语义。5.2 面向该问题的 Prompt 设计下面给出一个可以在评测框架中使用的通用 prompt 模板。实际使用中可以把仓库文件内容直接填充到 prompt 中。你是一名测试基础设施优化工程师。请根据下面给出的仓库文件和问题描述对测试代码进行最小修改。 问题描述 tests/test_order_service.py 中的测试存在 flaky 问题原因是使用 time.sleep(2) 等待服务就绪。请移除不稳定的固定等待改为轮询等待指定条件满足。同时检查 tests/conftest.py 中的 fixture 是否存在状态污染问题如有则一并修复。 约束 1. 只能修改 tests 目录下的文件。 2. 不能修改 src 目录下的业务代码。 3. 不能删除或跳过任何测试用例。 4. 输出必须为 JSON 格式 { summary: 对本次修改的简要说明, modified_files: { tests/test_order_service.py: 完整文件内容, tests/conftest.py: 完整文件内容 } }这里的关键是“约束”部分。如果没有明确约束LLM 很容易选择跳过测试或者把断言改弱——这在自动评测中会被判为安全性不合格。5.3 预期输出与修复效果一个合理的模型输出大概是下面的样子# tests/test_order_service.py import pytest from order_service import create_order def wait_for_service_ready(timeout: float 5.0, interval: float 0.1) - None: import time from order_service import is_service_ready deadline time.time() timeout while time.time() deadline: if is_service_ready(): return time.sleep(interval) raise RuntimeError(order service not ready within timeout) def test_create_order_valid(): wait_for_service_ready() order create_order(user_idu123, product_idp456, quantity1) assert order.status CREATED def test_create_order_invalid_product(): wait_for_service_ready() with pytest.raises(ValueError): create_order(user_idu123, product_idnot_exist, quantity1)# tests/conftest.py import pytest from order_service import OrderRepository, delete_order_by_user pytest.fixture def order_repo(): repo OrderRepository() repo.reset() yield repo repo.cleanup()这个修复方案有两个明显改进第一固定time.sleep(2)变成了带超时的轮询等待稳定性更好第二fixture 增加了 teardown 清理逻辑避免测试间的状态污染。当我们在评测框架中运行这个输出时pytest tests/test_order_service.py -x -q应该能够通过。如果业务服务没有提供is_service_ready和cleanup这样的接口模型给出的方案可能会不同此时需要结合项目实际情况打分而不能机械地要求输出必须完全一致。5.4 如何在真实项目中验证在真实项目中验证 LLM 修改的效果不能只跑一次测试。我建议至少做三个层面的验证第一层是单次运行确认修改后的代码能通过当前测试。第二层是重复运行比如连续执行测试 10 次观察是否还有随机失败。第三层是回归测试也就是运行与当前测试相关的相邻测试模块确认修改没有破坏其他用例。pytest tests/test_order_service.py -q --count10 pytest tests/ -q这里的--count需要安装 pytest-repeat 插件如果没有安装可以用一个简单的 for 循环代替for i in $(seq 1 10); do pytest tests/test_order_service.py -q || echo failed at $i; done不要小看这一步。LLM 生成的“看似合理”的修复很多时候只是碰巧在当前机器的当前网络条件下通过换一个环境就又会失败。只有重复运行和回归测试才能真正评估修复质量。6. 常见问题与排查思路在搭建 HarnessOpt-Bench 评测流程和实际运行 LLM 优化测试 Harness 的过程中有一些问题是反复出现的。下面以表格形式给出问题现象、可能原因和解决思路。问题现象常见原因解决思路模型输出不是合法 JSONprompt 未强调输出格式在 prompt 中给出 JSON 示例并要求只输出代码块模型修改了 src 目录业务代码约束条件不明确在 system prompt 中反复强调目录边界并在评分时加入约束校验测试运行后仍然 flaky模型只修了表面逻辑没有处理根本原因增加重复运行测试评分连续 10 次通过才判定稳定性合格并发评测时模型接口限流评测并发数设置过高降低 concurrency并在 runner 中加入指数退避重试逻辑不同模型输出分数波动大模型温度设置过高调低 temperature推荐 0.1 到 0.3 之间正式评测固定 seed模型跳过测试或删除断言模型为了通过评测选择了捷径在评分逻辑中扫描跳过标记和断言删除行为安全性指标置零修改后的测试在本地通过但在 CI 失败本地环境与 CI 环境差异统一使用容器环境运行测试固定 Python 版本和依赖版本评测成本过高每个任务都调用高价大模型先用小型模型做初筛再由大模型处理困难任务或对历史输出做缓存这里还想补充一个经常被问到的问题LLM 框架和 ComfyUI 这类工具是否必须在同一台电脑上运行事实上这取决于工具架构。ComfyUI 是本地图形化工作流工具它和 LLM 推理服务之间并没有强制绑定关系。如果你只是想在 ComfyUI 里调用 LLM 能力常见做法是让 ComfyUI 访问一个独立的 LLM API 服务这个服务可以在同一台机器上也可以部署在其他服务器。在 Harness 优化评测场景里我更推荐把“模型推理”和“测试执行”分离到不同环境推理服务放在 GPU 机器或云端 API测试执行放在临时 Docker 容器中。这样既隔离风险也能让两者按需独立扩展。7. 最佳实践与工程建议7.1 评测环境的隔离与安全让 LLM 直接修改测试代码并执行本质上是“让模型生成的代码在本机运行”。如果模型不具备安全意识或者受到恶意 prompt 诱导可能会生成删库、上传文件、恶意网络请求等内容。因此运行时隔离是硬性要求不是可选项。我建议的隔离方案有三个层次第一层是操作系统级隔离使用 Docker 容器运行测试禁止挂载宿主机的敏感目录。第二层是网络级隔离在容器内通过防火墙或代理限制外网访问只保留必要的包下载源。第三层是权限隔离使用非 root 用户运行测试进程测试目录也只给予最小写权限。即使你的评测任务完全来自可信数据集也应该默认遵守这个安全策略。因为评测系统本身可能成为攻击者的目标一旦漏洞被利用影响范围会很大。7.2 从“跑通评测”到“可复现评测”对于基准测试来说可复现性非常重要。同一个模型在同一天评测两次结果不能相差太大否则后续的模型选型就没有参考价值。为了保证可复现性我有几个建议prompt 模板要有版本号任何修改都必须生成新版本避免结果无法对比。模型推理参数需要固定尤其是 temperature、top_p、max_tokens。测试运行环境需要固定推荐使用固定版本的 Python 镜像以及 requirements 锁定文件。每次评测结果要保存原始输出包括模型 raw_output、运行日志、评分明细而不是只保存最终得分。对随机性强的模型最好多次采样取中位数而不是只跑一次。在实际评测中我曾经遇到过一次“同一模型同一任务上午通过、下午失败”的情况。排查后发现原因是模型服务端做了负载均衡在不同时刻命中不同的推理实例导致输出不稳定。后来我在评测环境中固定了模型实例并增加了结果一致性检查问题才得到解决。# configs/eval_config.yaml 中添加可复现性配置 reproducibility: prompt_version: v20250201 temperature: 0.2 top_p: 0.9 sample_times: 3 metric: median7.3 成本控制与去重策略LLM 评测的成本是团队经常忽略的部分。评测任务数量多的时候调用费用会快速增长。有几种控制方式值得参考第一任务去重。多个任务的 repo_snapshot 可能包含相同的代码段可以在生成请求前做内容哈希去重复用上一次的评测结果。第二分级模型策略。先用轻量模型跑一遍全量任务把得分低的任务挑出来再用强模型重跑这样可以在保持整体质量的情况下节约成本。第三输出缓存。模型输出可以按 “task_id prompt_version model_name temperature” 作为缓存键保存到本地或 Redis。重复评测时如果命中缓存直接读取结果。# src/utils.py 中的简化缓存示例 import hashlib import json from pathlib import Path class OutputCache: def __init__(self, cache_dir: str outputs/_cache): self.cache_dir Path(cache_dir) self.cache_dir.mkdir(exist_okTrue, parentsTrue) def key(self, task_id: str, prompt_version: str, model_name: str) - str: raw f{task_id}|{prompt_version}|{model_name} return hashlib.sha256(raw.encode(utf-8)).hexdigest() def get(self, task_id: str, prompt_version: str, model_name: str): path self.cache_dir / f{self.key(task_id, prompt_version, model_name)}.json if path.exists(): return json.loads(path.read_text(encodingutf-8)) return None def set(self, task_id: str, prompt_version: str, model_name: str, output): path self.cache_dir / f{self.key(task_id, prompt_version, model_name)}.json path.write_text(json.dumps(output, ensure_asciiFalse, indent2), encodingutf-8)7.4 指标要能反映真实工程价值在做评估时不要过度依赖“测试通过率”这一个指标。通过率很容易被模型钻空子比如删掉测试、跳过初始化、把断言改成恒真表达式。要真正衡量 Harness 优化能力的提升需要关注更贴近工程价值的指标失败信息修复耗时原本需要开发者看 10 分钟日志才能定位的问题优化后是否能 1 分钟内定位。无效测试占比优化后测试套件里是否有更少“测了等于没测”的用例。执行时间变化优化后测试套件整体耗时是否下降。维护负担后续新增测试时Harness 相关代码是否更容易扩展。这些指标在自动评分中很难完全量化但它们应该是评测基准设计时的“北极星”。自动打分只能提供初筛最终判断还是要结合人工抽审。7.5 框架扩展方向如果后续想把 HarnessOpt-Bench 应用到更大范围或者做成团队内部的持续评测平台可以考虑以下扩展方向接入更多任务类型例如性能优化类任务、可观测性增强类任务、代码重构类任务。接入代码静态分析工具利用 tree-sitter 或 AST 来判断断言强度。引入模型间对比给每个任务生成模型 A 和模型 B 的输出做胜率统计。增加人工反馈接口将人工对模型输出的评分反馈给评测系统持续校正自动评分规则。这些扩展不需要推翻现有框架只需要在任务模型、评分模块和结果展示层做增量开发。核心的“任务加载 - 模型调用 - 测试执行 - 打分”流程可以保持不变。8. 总结与下一步学习路线这篇文章从 HarnessOpt-Bench 的评测思路出发完整梳理了“LLM 在测试 Harness 优化场景下如何被评估”这一问题的解决方案。我们首先拆解了 Test Harness 优化的能力维度明确了“测试用例生成、断言质量改进、环境配置修复、执行稳定性提升、失败信息可观测性、运行效率优化”六个方向然后实现了一个包含任务加载、LLM 调用、测试执行和评分四个模块的轻量评测框架最后通过一个时间等待优化案例演示了如何让 LLM 在真实测试代码上做最小修改并通过重复运行和回归测试验证修改质量。如果你打算深入这个方向下一步可以从三个层面继续学习第一个层面是评测数据本身。可以参考 HarnessOpt-Bench 的任务设计思路自己收集真实项目中的 flaky test、配置问题和断言缺陷构建一个小规模评测集。不需要一开始就追求数量20 到 30 个高质量任务就能支撑初步的模型选型。第二个层面是评分质量。当前我们使用的基于规则的评分只能覆盖浅层语义要提升评分的可信度可以引入代码静态分析、变异测试和人工抽审机制。第三个层面是工程化集成。当你已经有了一批稳定的评测任务就可以把评测框架接入到 CI 流水线中让每个候选模型在合入前自动跑一轮 Harness 优化能力测试作为模型发布的准入条件之一。在实际项目中最值得优先关注的风险仍然是运行环境隔离和输出结果可复现。LLM 的评测很容易因为环境差异、温度参数、并发时序等问题产生不稳定结果。先把这两条基础打好再增加更多复杂的评估能力评测结果才有长期参考价值。