自动训练Harness而非LLM:跨模型与跨基准的Agent优化之道
发布时间:2026/9/4 20:07:18
分类:文化教育
浏览:1234

如果你维护过两个基于大模型的产品多少会遇到这种场景两个团队用同档次的基础模型一个把大量时间花在“换更强模型、做风格微调、刷评测分数”上另一个却整天围绕工具定义、交互流程、结果校验做文章。一段时间后前者在线上还是跌跌撞撞后者已经把线上任务的完成率稳定下来。这种差异并不是个例而是 LLM 应用开发正在发生的一次重心迁移。最近看到一条 HN 风格的公开分享标题很短观点却非常有代表性Auto-train the harness, not the LLM. cross-model, cross-benchmark gains。如果翻译成大白话意思是与其反复训练底层模型不如去自动训练“模型外面那层 harness架具/承托层”并且这种收益可以跨模型、跨评测数据集迁移。这篇文章想把这句标题背后的技术逻辑拆开讲清楚。读完你至少能回答三个问题harness 到底是什么为什么调整 harness 而不是训练 LLM反而可能赢得 cross-model 和 cross-benchmark 的收益如果你想亲手验证这个思路第一步应该做什么我会避开那种“因为新所以好”的模糊判断尽量把每个结论都落到你可以直接上手的工程方案上。1. 模型差距在缩小真正拉开交付差距的是 Harness过去两年LLM 应用开发者习惯把效果差异归因于模型。模型 A 比模型 B 强大家换模型就好。这个判断在“单轮问答、API 直连”阶段基本成立但在 Agent 任务中越来越不成立。Agent 任务和普通问答有一个本质差别任务成败往往不取决于一次生成的文本是否漂亮而取决于整个执行链路是否稳定。以代码修复为例模型可能给出一个看起来合理的补丁但它到底有没有通过测试靠模型自己是无法确认的。你需要在外部给模型提供执行测试、读取失败信息、第二轮修正的工具和环境。再以知识库问答为例模型生成的答案是否忠实于检索到的文档也需要外部验证模块做事实性核对。这些环节都不是模型参数的一部分而是工程系统的一部分。这套“把模型包起来、让它完成具体任务的工程层”在英文社区里被形象地称为 harness直译过来像是马的挽具、汽车的转向与制动系统。现在很多人在检索 deepseek harness、codex harness 这类关键词时真正想找的往往不是一个官方产品而是“如何为特定模型搭建可依赖的工具调用层、上下文编排层和评测层”。这类需求快速增多本身就是模型竞争格局变化的一个信号基础模型的“裸能力”并没有停止提升但模型之间的差距对最终交付结果的影响正在被外围系统稀释。如果你把模型想象成一台发动机harness 就是变速箱、刹车、方向盘和仪表盘。发动机的马力参数当然重要但一辆车开起来稳不稳、能不能精准过弯取决于整套底盘和车机系统的协同。这也能解释为什么同一个开源或商业模型在不同团队手里效果可以天差地别有人只把模型当 API 用有人则为它设计了完整的任务执行闭环。后者往往不是靠更玄学的 prompt 技巧而是靠更完整的 harness。对于一个正在预算有限团队里做 LLM 应用的人来说这个趋势有一个很实际的指导意义如果你的模型已经是当前主流的商用 API 或开源权重先不要急着把资源押在“继续调模型”上可以先用一个最小化的 harness 实验去观察外围环节变更是否能带来更稳定、更可预期的收益。2. 什么是 LLM Harness它不是 Agent但它决定了 Agent 的形态Harness 这个词在不同语境里含义会漂移。在模型评测领域它常指加载模型、跑数据集、计算指标的评测框架在 Agent 工程领域它则更接近“智能体的运行框架”。为了不在讨论中失焦我先把概念边界固定在一个更具体的定义上。LLM harness指以模型为执行内核、完成一个特定任务所需的全部外部机制包括任务指令构造、上下文组织、工具调用接口、记忆管理、行动循环、结果校验、输出解析与失败恢复。由这个定义可以自然推断Agent 是一层更高阶的抽象它利用 harness 提供的工具和循环自主规划并执行任务。换句话说Agent 解决的是“做什么”的问题harness 解决的是“如何稳定地做”的问题。不少开发者在刚接触时会把两者混为一谈以为“Agent 框架就是 harness”。实际上一个好的 harness 应当尽量不绑定具体 Agent 的思维流程它更像是一个可配置、可替换的运行底座。一个实用的 harness 通常由下面这些组件构成组件解决的问题常见错误做法Prompt 模板把任务目标稳定传达到模型所有任务共用一个万能模板上下文与检索把必要信息放进有限上下文让模型自行寻找分散的长文档Tools 定义让模型拥有调用外部动作的能力工具描述含糊模型频繁误用Memory 管理保留历史关键决策压缩噪声无限制累积历史导致上下文膨胀行动循环让模型能拆解步骤并持续执行一步出错就从头再来校验器验证模型输出的正确性完全信任单次生成结果输出解析把自然语言转成结构化的系统信号靠正则硬拆多种输出格式理解 harness 最简单的场景是“代码补丁执行”。如果不给模型接任何工具它只能生成一段代码然后等你人工去测试如果接上了一个可以执行测试并回传错误信息的工具模型的下一轮修正就有了依据。这种“模型生成 外部验证 策略修正”的剥壳设计就是 harness 在真实项目中最常见的形态。同样能反映 harness 重要性的还有输入格式问题。一些热搜词里反复出现“markdown 格式 llm 接收”和“用 llm 处理文档的现实问题场景”这些看似初级的问题实际操作中却往往是线上效果的最大变量。模型接收 markdown 文档时的截断策略、表格转成什么结构、代码块如何处理直接决定了后续工具和知识检索能不能准确复现。可以说一个团队对 harness 的重视程度往往会体现在这些细小但不简单的格式决策上。3. “训练 LLM”与“训练 Harness”不是替代而是分工变化标题中的“Auto-train the harness, not the LLM”容易让人理解为“以后不要微调模型、只需优化外壳”。这是一种错误理解。更准确的说法是当模型能力已经超过任务要求时微调带来的边际收益很小此时把资源转向 harness 的自动优化性价比更高。微调和 harness 优化解决的是不同层次的问题。微调改变的是模型的知识分布和生成风格属于“权重层修改”harness 优化改变的是模型完成任务所需要的上下文结构、工具编排和校验策略属于“系统层修改”。对大多数应用团队来说系统层修改的门槛更低、周期更短、风险更可控结果也更容易复现。对比维度可以这样看对比项Fine-tuning LLM微调Harness Auto-tuning自动调 harness优化对象模型权重模型外部机制与策略需要的数据成百上千条高质量样本成本较高少量开发集与清晰的可验证任务周期数天到数周几小时到几天失败风险训练不稳定、灾难性遗忘需要防御评测噪声、搜索爆炸可迁移性迁移到同系列模型才有意义工序级策略可跨模型复用举个例子。假设你希望模型输出更严格的 JSON 结构且业务有数百条数据要求模型遵循特定字段语义微调确实可行但多数场景下标准库函数调用加输出校验器就能解决不需要走训练流程。反过来如果你需要的是一种全新领域知识现有模型完全不了解而知识库检索也无法提供充分材料那微调就会比 harness 优化优先。在真实项目中真正稳健的推进顺序是先用一个简洁的人工 harness 跑通端到端流程保持模型不变逐步增加工具和验证器观测性能变化。等人工设计达到瓶颈后再考虑两类自动手段一类是自动搜索 harness 的离散结构比如是否使用自洽采样、是否启用代码验证器、工具调用失败后是否重试另一类是必要时做小规模微调去补齐模型在该任务上的基础能力短板。这也是为什么标题里强调“not the LLM”而不是“never the LLM”。它表达的是一个优先级判断既然模型能力已经相对充分就不要把每个团队都拖入训练模型的高成本战争中。先用 harness 挖出系统里最容易转化的收益是性价比更高的路径。4. Auto-train Harness 的机制Cross-Model 与 Cross-Benchmark 从何而来理解了 harness 之后一个很自然的问题会冒出来harness 明明包含一堆离散组件怎么做到“自动训练”这里的 train 明显借鉴了机器学习里“训练”的表达但本质上更像“配置搜索 策略优化”。核心思路是先把 harness 的各个可选项参数化再定义一个反馈信号最后用搜索或强化学习算法找到一组更优参数。它不修改模型权重但会把模型在多个任务上的平均效果当作优化目标。可以参数化的 harness 组件包括指令模板风格、few-shot 示例选择策略、工具候选集、工具调用的最大轮数、上下文摘要策略、是否需要 validator、validator 失败后是否进入 refine 流程。这些东西在传统工程里通常由开发者手写经验决定auto-train 则是把它们变成一个可搜索的离散空间。一个可行的反馈样例是在开发集上跑多轮评测用“任务完成率”作为信号如果任务具有可验证输出比如数学题有标准答案、代码任务能跑测试就可以用外部结果代替模型判断。这里真正容易踩坑的地方在于评测集不能参与搜索否则你只是在拟合单个榜单。为什么会有 cross-model 收益因为 harness 优化得到的很多成分是任务级策略而不是模型级技巧。比如“先生成多个候选答案再通过一致性投票选择结果”“测试不通过时读取报错再修正”等策略本质上不依赖某个模型的参数分布。把同一个 harness 配置从模型 A 换到模型 B只要模型具备执行指令和工具调用的基本能力大概率还能保留大部分收益。很多开源模型社区已经开始出现这种现象同一个工具层和验证层骨架稍作调整就能套到不同模型上说明跨模型迁移确实是存在的。为什么又会有 cross-benchmark 收益这要分两层看。第一层如果你用多个 benchmark 的混合反馈去搜 harness那么最后得到的配置自然会避开“只适配某一个榜”的过拟合。第二层harness 优化的一些常见措施比如验证器、自洽采样、错误反馈在很多不同评测集上都是通用的稳定的正面信号。它们不是某个数据集特有的玄学技巧而是让系统更可靠的一般性手段。但在乐观研判之外也要保持冷静。cross-benchmark 收益并不是天然成立的如果选择的几个 benchmark 本身高度相似或者存在共有的偏差那么被优化出来的 harness 很可能只是适应了这一类任务。要验证“泛化”就需要保留一个完全没参与搜索过程的评测集并且这个评测集和训练集的任务类型有足够差异。否则所谓跨基准提升只是另一种形式的“刷榜”。5. 动手实践一个最小的 Auto-train Harness 原型这一节我给出一套简化的原型代码用来演示 harness 自动搜索的基本流程。它是一个最小示例不是生产级框架但结构上能对应你将来接入真实模型和工具链时的关键部分。环境准备并不复杂建议使用 Python 3.10 以上版本本示例不依赖第三方库只使用标准库。真实场景中你只需要实现一个统一的模型调用函数让业务代码不必关心底层模型是商业 API、开源权重还是本地服务。先建立一个配置文件用来描述参与实验的模型和评测数据集# config/harness_demo.yaml models: - name: model_a backend: openai_compatible # 以你使用的实际网关为准 model_id: your-model-id temperature: 0.0 benchmarks: - name: math_dev file: data/math_dev.jsonl - name: reasoning_holdout file: data/reasoning_holdout.jsonl这里没有写死具体模型名是因为不同团队的网关、内网模型名和版本都不同。建议在 config 里统一维护让 harness 搜索代码不散落模型差异。下面是一个直接可运行的搜索示例它把 harness 策略建模为 4 个开关是否多候选投票、是否调用外部工具、是否做结果校验、校验失败后是否追问修正。核心代码放在auto_harness_demo.py# auto_harness_demo.py 最小 Auto-train Harness 示例 在简单的搜索空间里随机抽样用开发集上的可验证任务打分 输出一组效果最好的 harness 配置。 它刻意不绑定某个具体模型模型差异由 call_model 抽象掉。 from dataclasses import dataclass from typing import Callable, List, Optional import random # 模型调用协议传入 prompt返回 str。 # 真实使用时可以在内部封装 DeepSeek、OpenAI、本地权重等任意后端。 CallModel Callable[[str, float], str] dataclass class HarnessConfig: use_majority_vote: bool False use_tool_lookup: bool False use_verifier: bool False use_refine: bool False samples: int 1 def wrap_prompt(task: str, prompt_style: str) - str: 把题目包装成用于模型输入的 prompt。 if prompt_style step_by_step: return f请按步骤解决下面的问题\n{task}\n注意最终答案放在最后一行以 ANSWER 开头。 return f请解决下面的问题\n{task}\n最终答案放在最后一行以 ANSWER 开头。 def call_model_stub(prompt: str, temperature: float) - str: 桩函数真实项目中替换为对模型服务的调用。 这里返回一个固定答案只是为了让流程跑通。 return ANSWER42 def tool_lookup(task: str, answer: str) - str: 模拟外部工具查询根据任务和当前答案返回补充信息。 return 工具提示题目可能存在干扰项请复核关键数值。 def verifier(task: str, answer: str) - bool: 模拟校验器判断最终答案是否满足题目要求。 return ANSWER in answer and answer.split()[-1].strip().isdigit() def majority_vote(answers: List[str]) - str: 简单多数投票。生产环境建议把候选答案和置信度一起处理。 return max(set(answers), keyanswers.count) def run_task(task: str, cfg: HarnessConfig, call_model: CallModel) - str: 在某个 harness 配置下运行一次任务。 prompt wrap_prompt(task, step_by_step) # 分支1是否使用多次采样与多数投票 if cfg.use_majority_vote and cfg.samples 1: answers [call_model(prompt, 0.7) for _ in range(cfg.samples)] answer majority_vote(answers) else: answer call_model(prompt, 0.0) # 分支2是否启用外部工具补充信息 if cfg.use_tool_lookup: tool_info tool_lookup(task, answer) answer call_model(prompt \n tool_info, 0.0) # 分支3校验失败后是否进入修正流程 if cfg.use_verifier and not verifier(task, answer): if cfg.use_refine: refine_prompt ( f你刚才的答案没有通过校验请结合以下信息修正。\n f原题{task}\n旧答案{answer}\n f要求只输出新的最终答案。 ) answer call_model(refine_prompt, 0.0) return answer def load_tasks(path: str) - List[str]: 加载任务数据。这里以 JSONL 为例每行包含 question 字段。 import json tasks [] with open(path, r, encodingutf-8) as f: for line in f: obj json.loads(line) tasks.append(obj[question]) return tasks def evaluate_harness( cfg: HarnessConfig, tasks: List[str], expected: List[str], call_model: CallModel, ) - float: 在给定数据集上评估一个 harness 配置的准确率。 correct 0 for task, exp in zip(tasks, expected): pred run_task(task, cfg, call_model) if pred.strip().endswith(exp.strip()): correct 1 return correct / len(tasks) def random_config() - HarnessConfig: 随机生成一个 harness 配置用于探索搜索空间。 use_majority random.choice([False, True]) samples random.choice([1, 3, 5]) if use_majority else 1 return HarnessConfig( use_majority_voteuse_majority, use_tool_lookuprandom.choice([False, True]), use_verifierrandom.choice([False, True]), use_refinerandom.choice([False, True]), samplessamples, ) def auto_train_harness( train_tasks: List[str], train_expected: List[str], call_model: CallModel, search_steps: int 30, ) - HarnessConfig: 在开发集上做随机搜索返回效果最好的 harness 配置。 best_cfg None best_score -1.0 for _ in range(search_steps): cfg random_config() score evaluate_harness(cfg, train_tasks, train_expected, call_model) if score best_score: best_score score best_cfg cfg return best_cfg这个原型最关键的地方在于模型调用被抽象成CallModel校验器是外部函数工具查询并不依赖某个具体模型。所以一旦你在开发集上搜索到一组较好的配置理论上可以直接把call_model换成另一个模型观察这个配置能否保留收益。再看 shell 运行与验证方式。真实使用中先把 JSONL 数据准备好再执行python -c from auto_harness_demo import * tasks load_tasks(data/math_dev.jsonl) expected [l for l in open(data/math_dev_answers.txt).read().splitlines()] # 用随机搜索找到开发集上的最佳 harness best auto_train_harness(tasks, expected, call_model_stub, search_steps30) print(best harness:, best) # 固定该配置换到另一个评测数据集 另一个模型再做验证 holdout_tasks load_tasks(data/reasoning_holdout.jsonl) holdout_expected [l for l in open(data/reasoning_holdout_answers.txt).read().splitlines()] score evaluate_harness(best, holdout_tasks, holdout_expected, call_model_stub) print(holdout score:, score) 运行后预期输出至少包含一行最佳配置和一行留出集分数。在这个桩函数实现里模型始终返回固定答案所以数值本身没有意义有意义的是整套流程它能让你在接入真实模型后用同样结构跑出有效分数。如果你已经能通过一个 Python 函数调用目标模型接下来最值得做的实验是定义 3 个模型后端但保持同一个 harness 搜索循环分别记录开发集最佳配置然后观察这些配置在另一个保留评测数据集上的分数排序。这个操作能帮助你直观理解 cross-model 和 cross-benchmark 的含义。6. 验证实验设计如何区分真实收益与评测噪声很多团队第一次跑“auto-train harness”时会得到不错的开发集分数提升但换到测试集或线上场景后发现提升消失。这时候问题通常不在算法而在验证流程你被“评测噪声”骗了。首要原则是数据集隔离。搜索过程只能用开发集保留一个完全没有参与搜索的测试集用于最终报告。如果只有一个数据集建议至少切成三份开发集用于搜索验证集用于避免过拟合测试级只在最后使用一次。这个理念和传统机器学习的 train/valid/test 划分一致很多 Agent 开发者在引入 harness 优化后反而会忽略这条基本纪律。其次是多次重复。LLM 生成本身带有随机性如果你的搜索过程只在每个配置上跑一轮那么高分可能是运气而不是 harness 真的好。常见做法是在评估配置时调低温度或者对每个数据点多次采样取平均。如果资源有限可以采用最简单的方案同一个配置至少跑两次分数差异较大的配置重新评估。第三是跨模型验证不是额外项而是核心报告的一部分。当你搜索出最佳 harness 后应该在第二个模型上跑一遍如果同一个配置在多个模型上表现都不差才能宣称具备 cross-model 潜力。同样cross-benchmark 验证要求至少有一个基准没有参与搜索并且任务形态和开发集有差异。如果实验显示“最佳配置在测试集上不升反降”不要急着否定思路。可以先检查搜索步数是否太少、搜索空间是否恰好包含了对开发集过拟合的选项、验证器的信号是否本身不可靠。另一个常见失败原因是工具查询给模型增加了无关信息模型把提示中有额外内容当成了“标准答案的指示”。这种情况下可以尝试把工具返回内容从“直接注入模型”改成“影响后续校验逻辑”让模型不被干扰。最后记录日志时要保留每个任务级别的预测结果而不只是汇总准确率。这样当你怀疑“某个配置在某一类问题上更强”时可以回看日志逐条分析。很多看似玄学的现象追到原始样本后会发现只是验证器的判定逻辑写错了。7. 常见误区与排查方法下面整理几个我在类似工程中最常看到的问题以表格形式给出方便你遇到时对照处理。问题现象可能原因处理思路开发集分数提升测试集分数下降搜索过程发生过拟合严格执行开发集/测试集隔离减少搜索步数或增加任务多样性换模型后收益消失harness 策略绑定单模型风格检查 harness 中是否塞入了过多针对原模型的 prompt 技巧尽量保留可迁移的任务级策略搜索成本过高每个配置都跑全量数据集用更小的开发集做初筛把最佳少量配置放到更大验证集上复核结果不稳定LLM 采样随机性多次运行取均值记录方差降低搜索时的采样温度增加工具后效果反而变差工具返回信息被模型误读为指令把工具输出与任务指令区分必要时只在后续校验阶段使用工具结果自动搜索耗时太长尝试了过多无意义的配置组合先人工固定明显合理的组件只搜索小范围的策略开关一个额外提醒不要盲目相信热搜词里的“某某模型 harness”是现成官方解决方案。更多时候它们只是社区根据某类模型特性整理的外部工程方案。搜索这些关键词没有错但使用时要注意来源亲自判断它是否满足你的任务场景。如果是一个开源项目重点看它的评测方法、维护活跃度和许可证而不是只看 README 的效果表。在动手搭建 harness 时还要重视评测基准的“可信度”。如果你发现某个 benchmark 很容易通过外部工具作弊或者其评测脚本本身存在格式偏好就应该在报告中同时展示原始得分与修正后的得分否则会误导自己和团队。8. 工程化建议从实验到生产环境的安全与成本设计Auto-train harness 从实验走向生产不只是把搜索代码部署上线。它牵涉到稳定性、可观测性、权限与成本边界这些点有时比“算法得分”更容易决定项目成败。第一工具权限要最小化。harness 中真正危险的不是大模型而是被模型驱动的外部工具。模型一旦接上了文件删除、数据库写入、代码执行等工具权限边界必须收紧。在开始阶段建议先让模型只拥有只读工具比如读文件、查日志、检索代码所有写操作必须经过人工审批或明确的二次确认。不要把生产数据库的写权限直接交给 agent 工具即使只是测试也不要图省事。第二校验器要独立、可信、可回退。验证器的作用是防止模型输出直接进入业务链路。举例来说如果 Agent 负责生成数据库查询语句那么 SQL 校验器应当先做语法检查再在测试环境库上试跑最后才允许登上生产库。任何校验器的逻辑变更都应视为系统变更走代码评审流程。没有可靠校验器的 harness只会把错误从模型层转移到工程层。第三输入输出要保留可观测性。harness 的每个决策步骤都应该被记录模型请求时看到的上下文、工具返回的内容、校验器结论、以及模型在 refine 阶段看到的新信息。有一类检索热度很高的“LLM 知识库管理”需求比如用 AnythingLLM 管理知识库或者把团队文档整理成可检索的格式本质上都是为了让模型在每一步都能看到准确、完整的外部信息。可观测性做得到位这类知识库的问题也能更快排查出来。从团队经验沉淀看更推荐把 harness 的配置、评测集、工具说明文档作为代码库一样管理。不要把这些知识只放在聊天记录或个人笔记里。一个团队如果已经积累了大量“如何让模型处理 markdown 文献”“如何让工具返回格式更稳定”这类经验建议整理进统一的内部知识库或者以 llm 手册、运行手册的形式共享。这类经验不属于任何单一模型本质上就是团队自己的 harness 资产。成本层面也需要单独测算。harness 自动搜索会增加一定量的模型调用因为它需要在多个配置上反复跑数据集。比较稳妥的做法是限制搜索步数并且优先使用便宜的模型完成初筛再把最优配置放到更强但更贵的模型上验证。每一步调用都要有预算监控如果某个配置的调用量异常增长应该能在日志中直接看到是哪类任务导致的。在实际部署时换模型是一个很常见的优化动作。由于 harness 组件通常与模型解耦正确的切换方式是先把模型后端的call_model切换到新模型再在保留的评测集上重跑一遍已有 harness 配置。如果分数下降并不一定说明新模型弱更可能是旧 harness 中隐藏了一些只适用于旧模型的习惯。这只“壳”需要被重新检查而不是立即换回旧模型。9. 总结与接下来的探索方向回到标题那句话Auto-train the harness, not the LLM。它并不是要否定模型训练的价值而是给绝大多数没有自研基础模型能力的应用团队指出了一条更现实的路模型的边界暂时无法亲自改写时最值得优化的就是模型之外的整套执行系统。这篇文章的核心意图是把 harness 从模糊的流行词还原成一个可工程化的对象。它可以是 prompt 模板、工具集合、校验器、行动循环、评测配置也可以是一些看似琐碎的格式决策。现在社区里关于 harness engineering 的讨论越来越多很多团队已经验证了这类方法的稳定收益但这种收益来自系统的可靠性设计而不是某个“神奇技巧”。如果你打算继续深入我建议从一个小实验开始选择一个你手上已经能通过模型 API 完成的可验证任务准备一份 100 条左右的开发集和一份独立的测试集给 harness 选 4 到 6 个可配置开关然后照着第 5 节的演示跑一轮随机搜索。无论结果是提升还是无效你都比只读概念文章前进了更远的一步。因为有可复现的评测、可迁移的配置、可回看的数据你才能真正判断 auto-train harness 对你们项目的价值。把这个闭环构建好之后再去了解更复杂的搜索策略、校验器设计和跨模型迁移技巧也会顺畅得多。