尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

LLM Harness工程与自进化闭环:从原理到最佳实践

LLM Harness工程与自进化闭环:从原理到最佳实践 在 LLM 应用里“模型换个 Harness 就变笨”不是错觉。Harness 决定了模型看到什么、按什么格式输出、能调用哪些工具、最终用什么标准被评价EverMind 这类自进化产品想解决的正是把这种容易受扰动的关系变成一套可持续改进的学习闭环。这篇文章会从 Harness 的本质出发拆解自进化引擎的组成再给出一个可运行的最小自进化 Harness 示例最后梳理换 Harness 后效果下滑的排查链路和落地生产的最佳实践。1. 先理解 Harness为什么模型换一套“马具”就变笨1.1 Harness 在 LLM 工程里到底指什么Harness 的英文原意是“马具、缆绳”。在 LLM 工程里它被借用来表示“模型外面的那层包装”。真正影响线上效果的往往不只是模型权重还有这层包装是否合理。一个完整的 Harness 至少包含这些部分系统提示词和用户提示模板。few-shot 示例也就是给模型的示范输入输出。工具或函数定义决定模型能调用哪些外部能力。输出格式约定要求模型返回 JSON、代码还是自然语言。输出解析逻辑负责把模型返回的文本变成结构化数据。外部反馈入口比如单元测试结果、用户点击行为、人工评分。如果把大模型比作发动机Harness 就是传动系统和仪表盘。同一台发动机装在不同的车上最终驾驶感受完全不同。模型权重没有变变的是“能力被暴露出来的程度”。在实际项目中Harness 经常以一份 prompt 文件、一组函数定义、一段解析代码的形式存在。问题在于很多团队把 Harness 当成“写一段提示词”这种小事换一个人就换一套写法结果模型表现忽上忽下。1.2 同一个模型不同 Harness为什么结果差异巨大大模型本质是条件概率模型输入分布一旦改变输出分布就会跟着改变。换 Harness 时以下任何一个因素变化都会导致结果明显变化系统提示词的表达方式。同样表达“你是客服助手”“直接判断意图”和“请先分析用户情绪再判断意图”会带来不同输出。few-shot 示例的数量、顺序和内容质量。示例放 1 条还是 5 条示例顺序颠倒效果都可能不同。输出格式的约束强度。要求“只输出 JSON”和“用自然语言回答最后给出意图”模型侧重点不同。工具定义的详细程度。函数名、参数说明、枚举值是否齐全影响模型是否敢调用工具。评估标准。评分规则改变时即使模型输出没变最终“好坏”结论也会改变。下面用表格展示一个典型的“同模型不同 Harness”表现差异数值为示意数据用于说明方向Harness 版本system prompt 简化程度few-shot 数量输出要求分类准确率示意解析失败率示意A详细包含任务边界3JSON92%1%B简短仅说明角色0自然语言78%5%C详细但示例噪声大5JSON83%3%这个结果说明模型“变笨”往往不是模型退化而是新的 Harness 没有把能力引导出来甚至主动引入了干扰信息。1.3 Harness Engineering 为什么会成为新话题最近大模型工具链里频繁出现 DeepSeek Harness、Codex Harness 这类叫法。它们本质上都在说同一件事把模型接入具体工程环境时外围控制逻辑需要被认真设计和版本化而不是随手写一段提示词。当模型的基础能力逐渐接近后应用效果的差距主要来自外围工程。Harness Engineering 可以理解为“围绕模型构建可控输入输出环境”的工程方法包括提示模板管理、工具调用协议、输出校验、评测回灌和自动改进。这也是自进化系统能成立的前提。如果 Harness 不可控、不可比较那“让 AI 越用越聪明”就只是一句口号。2. 自进化并不神秘核心是“生成-反馈-改进”的闭环2.1 自进化 AI 的定义和核心闭环自进化 AI 不是指模型自己修改权重而是指系统在运行过程中通过自动化的反馈回路不断优化自己的生成策略。这个策略可以是 prompt、few-shot 示例、工具定义也可以是最小规模的模型微调数据。一个完整的自进化闭环可以拆成五个环节Generator基于当前 Harness 生成任务输出。Evaluator用测试用例、规则、用户行为或外部评价模型对输出打分。Reflector分析失败样本总结改进方向。Updater把改进内容写回 Harness。Guardrail判断本次改进是否值得保留避免越改越差。闭环的特点是每一轮产生的新知识并不会丢而是沉淀到 Harness 里。这样模型即使还是同一个基础模型在特定任务上的“有效知识”却越来越多。2.2 Evolver 引擎可以拆分哪几个部分“自进化引擎”这个词可以用一张组件表来理解。无论产品叫 Evolver 还是 EverMind核心组件基本一致组件职责常见实现方向Generator用当前 Harness 产生候选输出大模型 API 调用、本地模型推理Evaluator判断输出好坏规则校验、单元测试、模型评分、人工标注Memory保存值得学习的样本示例库、向量库、失败样本缓冲Updater把改进写入 Harness动态修改 system prompt、追加 few-shot、调整工具 SchemaGuardrail防止回归和越权回归测试集、收益门槛、权限校验很多人把自进化理解为“模型自己反思一下就能变强”但工程上真正起作用的是 Evaluator 和 Guardrail。没有可靠评估改进方向就是随机的没有收益门槛系统会不断振荡甚至把原本正常的 Harness 改坏。2.3 EverMind 从研究到产品要解决什么问题研究环境里的自进化通常离线运行固定一个 benchmark反复迭代 Harness最后对比指标。这个流程相对干净因为数据稳定、评估标准固定、失败成本低。进入产品环境后问题完全不同输入是线上真实请求分布会随时间变化。每次调用都要付出模型成本和时间不能无限重试。改进可能对 8 成用户有效却伤害另外 2 成用户。线上系统需要日志、监控、回滚和权限控制不能直接用 Jupyter Notebook 跑。所以 EverMind 这类产品要把“研究证明可行的自进化”变成“生产可用的一键闭环”重点不是证明模型能自动变聪明而是让改进过程可控、结果可度量、回归可发现。维度研究环境产品环境数据固定 benchmark动态线上流量评估离线指标实时指标 回归测试迭代可接受慢速度低成本、低延迟风险失败只影响论文失败影响真实用户回滚重新跑一遍秒级回滚 灰度从研究走向产品最大的技术挑战不是“怎么让模型学习”而是“怎么在模型随时可能出错的情况下保证系统稳定”。3. 手写一个最小自进化 Harness 系统3.1 场景选择为什么用意图分类做示例为了把自进化闭环讲清楚这里选择一个容易自动评估的任务客服意图分类。输入是一句用户文本输出是意图标签比如“退款”“咨询”“投诉”。选择它的原因有三个评估容易。可以用一组带标准答案的测试集计算准确率。反馈明确。意图判断错了可以直接看到正确标签和模型输出差异。扩展性强。同样的闭环可以迁移到代码生成、内容审核、信息抽取等任务。系统结构包含Harness 定义、模型调用、输出解析、评估器、进化循环。下面的代码是教学骨架实际项目需要根据模型厂商、内部框架和部署方式调整。3.2 环境准备和依赖需要 Python 3.10 以上并安装两个基础依赖pip install openai python-dotenv在项目根目录创建.env文件LLM_API_KEY你的密钥 LLM_BASE_URLhttps://api.deepseek.com LLM_MODELdeepseek-chat不同厂商的 OpenAI 兼容端点地址可能不同落地前要先确认官方文档。代码统一通过环境变量读取避免把密钥写死在仓库里。3.3 定义 Harness 数据结构用 dataclass 描述 Harness把系统提示、few-shot 示例、温度和输出格式封装在一起。from dataclasses import dataclass, field from typing import List, Dict dataclass class Harness: system_prompt: str examples: List[Dict[str, str]] field(default_factorylist) temperature: float 0.2 def build_messages(self, user_input: str) - List[Dict[str, str]]: messages [{role: system, content: self.system_prompt}] for ex in self.examples: messages.append({role: user, content: ex[user]}) messages.append({role: assistant, content: ex[assistant]}) messages.append({role: user, content: user_input}) return messages这里的关键是build_messages。它把 Harness 的所有信息翻译成模型 API 要求的 message 列表。后续每次改动 Harness实际都是改动这里生成的一段上下文。3.4 实现模型调用和输出解析调用大模型时要求输出 JSON。为了兼容不同厂商不用强依赖response_format而是在系统提示中明确要求。import os import json import re from openai import OpenAI client OpenAI( api_keyos.getenv(LLM_API_KEY), base_urlos.getenv(LLM_BASE_URL, https://api.deepseek.com), ) def run_inference(harness: Harness, text: str) - str: messages harness.build_messages(text) response client.chat.completions.create( modelos.getenv(LLM_MODEL, deepseek-chat), messagesmessages, temperatureharness.temperature, max_tokens200, ) return response.choices[0].message.content def parse_intent(raw: str) - str: try: data json.loads(raw) return data.get(intent, ) except json.JSONDecodeError: match re.search(rintent\s*:\s*([^]), raw) return match.group(1) if match else def predict_intent(harness: Harness, text: str): raw run_inference(harness, text) return parse_intent(raw), rawparse_intent做了容错先尝试完整 JSON 解析失败后用正则提取。生产环境建议引入 JSON Schema 校验而不是只用正则兜底。3.5 实现评估器和失败样本收集评估器负责对 Harness 在固定测试集上的表现打分。这里使用准确率和解析失败率两个指标。import random def evaluate_harness(harness: Harness, dataset: List[Dict]) - dict: random.seed(42) correct 0 parse_fail 0 for item in dataset: pred, raw predict_intent(harness, item[text]) if not pred: parse_fail 1 if pred item[intent]: correct 1 n len(dataset) return { accuracy: correct / n, parse_fail_rate: parse_fail / n, size: n, } def get_failures(harness: Harness, dataset: List[Dict]) - List[Dict]: failures [] for item in dataset: pred, raw predict_intent(harness, item[text]) if pred ! item[intent]: failures.append({ text: item[text], expected: item[intent], prediction: pred, raw: raw, }) return failures评估集必须和训练集分开。如果拿训练样本既做改进又做评估系统会慢慢记住噪声而不是学会通用规律。3.6 实现进化循环用失败样本改进 Harness每一轮进化都走这样几条步骤在训练池上找失败样本。让一个“改进器”模型分析失败样本生成一条补充规则。生成候选 Harness并在独立测试集上评估。只有候选 Harness 的准确率更高、解析失败率没有明显变差时才接受。def make_improvement_prompt(failures: List[Dict]) - str: sample_text \n.join( f用户{f[text]}期望{f[expected]}模型预测{f[prediction]} for f in failures[:3] ) return f 你是自进化引擎的改进器。当前意图分类 Harness 在以下样本上识别错误 {sample_text} 请从这些错误中总结一条简短、通用、可执行的分类规则并输出 JSON。 JSON 格式{{rule: ...}} def parse_rule(raw: str) - str: try: data json.loads(raw) return data.get(rule, ) except json.JSONDecodeError: match re.search(rrule\s*:\s*([^]), raw) return match.group(1) if match else def improve_harness(harness: Harness, failures: List[Dict]) - Harness: prompt make_improvement_prompt(failures) response client.chat.completions.create( modelos.getenv(LLM_MODEL, deepseek-chat), messages[{role: user, content: prompt}], temperature0.1, ) rule parse_rule(response.choices[0].message.content) if not rule: return harness new_prompt harness.system_prompt \n补充规则 rule return Harness( system_promptnew_prompt, examplesharness.examples, temperatureharness.temperature, ) def evolve(harness: Harness, train_pool: List[Dict], testset: List[Dict], max_rounds: int 5): history [] for round_no in range(1, max_rounds 1): current evaluate_harness(harness, testset) history.append({round: round_no, stage: current, **current}) failures get_failures(harness, train_pool) if not failures: break candidate improve_harness(harness, failures) cand_score evaluate_harness(candidate, testset) history.append({round: round_no, stage: candidate, **cand_score}) if (cand_score[accuracy] current[accuracy] and cand_score[parse_fail_rate] current[parse_fail_rate] 0.01): harness candidate return harness, history这里“只有收益为正才接受”是关键。如果无条件接受每次改进系统很容易陷入振荡上一轮加一条规则下一轮又把规则改掉白白消耗成本。3.7 运行与验证假设已经准备好train_pool和testset运行进化循环initial_harness Harness( system_prompt你是客服意图分类助手。请根据用户文本判断意图只输出 JSON{\intent\: \退款|咨询|投诉|其他\}, examples[ {user: 我钱什么时候退回来, assistant: {\intent\: \退款\}}, ], ) final_harness, history evolve(initial_harness, train_pool, testset, max_rounds5) for record in history: print(record)预期输出类似{round: 1, stage: current, accuracy: 0.86, parse_fail_rate: 0.04, size: 50} {round: 1, stage: candidate, accuracy: 0.88, parse_fail_rate: 0.02, size: 50} {round: 2, stage: current, accuracy: 0.88, parse_fail_rate: 0.02, size: 50} {round: 2, stage: candidate, accuracy: 0.86, parse_fail_rate: 0.03, size: 50}每一轮打印当前版本和候选版本。候选版本没有明显收益时保持原 Harness 不变。这样反复若干轮后Harness 会积累越来越多针对真实错误分布的补充规则。注意这个示例是教学骨架不是生产代码。真实运行时必须补充日志、重试、限流、超时、API 账单统计和模型输出安全校验。4. 判断 Harness 改动好坏要用实验而不是看单次输出4.1 不要用“感觉”评估 Harness自进化经常犯的一个错误是改了一版 prompt跑了两条测试样本发现效果不错就直接上线。但大模型输出有随机性单次结果不能代表真实水平。正确做法是固定一个 golden testset。这个测试集要有明确答案覆盖主要场景、边界场景和容易被误导的相似表达。每次 Harness 改动都要在同一个测试集上重新跑一遍记录指标。4.2 用置信区间判断差异是否可靠当测试集数量不够大时准确率差 1 个百分点可能只是随机波动。可以计算 95% 置信区间来辅助判断。import math def wilson_interval(positive: int, total: int, z: float 1.96) - tuple: if total 0: return (0.0, 0.0) p positive / total denom 1 z * z / total center (p z * z / (2 * total)) / denom margin z * math.sqrt(p * (1 - p) / total z * z / (4 * total * total)) / denom return center - margin, center margin对比两个 Harness 时不能只看点估计还要看区间是否重叠。如果两个版本的置信区间大面积重叠说明差异可能来自随机性不适合立刻切流量。4.3 记录 Harness 版本和实验参数每次实验都要记录足够多的上下文否则无法复盘。推荐用表格维护版本记录版本system prompt 改动few-shot 数量温度准确率解析失败率平均延迟成本/千次v1.0 baseline无10.286%4%1.2s1.1 元v1.1 规则增加退款边界描述10.288%2%1.3s1.2 元v1.2 换示例增加投诉示例30.384%3%1.5s1.4 元这里“成本/千次”要根据自己项目统计。Harness 改动有时会显著增加 prompt 长度进而增加 token 消耗不能只看准确率。4.4 生产环境用灰度发布验证线上指标离线测试集准确率提升不代表线上效果一定变好。因为线上输入分布和测试集可能不一致。生产环境建议按流量灰度先 5% 流量运行新 Harness观察 1 小时。比较新旧版本在核心指标上的差异准确率、用户投诉率、人工介入率、平均处理时长。数据稳步优于旧版本再逐步扩大到 20%、50%、100%。任意一项核心指标恶化立即回滚到旧版本。灰度发布的前提是系统具备版本标识和日志采集能力。每条请求要记录 Harness 版本号否则无法区分效果差异来自模型输出还是来自流量变化。5. 换 Harness 后效果下滑按这条链路排查换 Harness 后模型“变笨”先不要怀疑模型按以下顺序排查。5.1 先确认 Harness 真的换了吗现象线上效果突然下滑但代码看起来没有变化。排查步骤检查 Harness 版本号是否真的发布到目标环境。检查是否有缓存服务返回了旧版本。检查配置中心或环境变量是否在不同环境间被覆盖。很多“换 Harness 变差”其实是灰度比例、缓存或配置导致新旧版本混布。先确认版本服务化再谈模型策略。5.2 再检查输入输出层现象返回内容解析失败或者结果字段为空。检查方式打印 model raw output看是否被 Markdown 包裹。检查max_tokens是否太小导致输出被截断。检查上下文长度裁剪逻辑长文本是否被截断到关键部分之外。处理建议要求模型只输出 JSON并在系统提示中给出完整格式示例。解析层加正则兜底。上下文裁剪时要保留关键信息不能简单从头截断。5.3 再检查模型策略层现象解析正常但意图判断错误增多。检查方式对比新旧 system prompt是否有互相矛盾的指令。检查 few-shot 示例是否覆盖了当前高频输入。检查新增示例是否带有错误标签或者顺序是否把噪声放在最前面。处理建议用失败样本聚类定位是哪几类输入变差了。把错误示例从 few-shot 中移出补充正确且贴近真实分布的示例。更新 system prompt 时保留已验证有效的部分减少“重写式”改动。5.4 再检查工具调用和函数定义现象模型应该调用工具但总是编造参数或返回空结果。检查方式检查工具 Schema 是否包含必填字段和枚举值说明。检查模型厂商是否有对工具调用的特殊格式要求。检查是否存在同名函数或语义含糊的字段。处理建议工具描述写清楚“什么时候调用”和“绝对不要调用”。参数默认值和枚举值写完整。对工具返回结果增加结构校验失败时让模型重试一次。5.5 再检查评估层现象系统认为新 Harness 更好用户却觉得更差。检查方式检查自动评估指标是否和线上核心指标一致。检查测试集是否被污染比如测试样本出现在训练池中。检查评分标准是否被模型生成的规则带偏。处理建议保持 golden testset 固定定期由人工抽检。自动评估只作为候选筛选重要变更继续保留人工抽检。5.6 最后检查随机性与配置漂移现象同样 Harness今天测试 86%明天测试 83%。检查方式确认 temperature 和其他采样参数没有漂移。确认测试集是否被随机抽样。确认模型版本是否被服务侧悄悄更新。处理建议评估时固定随机种子。在代码中显式记录模型名称和版本。温度不要在生产环境随意调整需要调整时走灰度流程。5.7 排查顺序清单顺序检查项典型证据处理建议1版本与缓存旧版本还在响应检查发布和缓存2输出解析raw 输出非 JSON增加解析兜底3输入截断长文本关键信息丢失调整裁剪逻辑4prompt 指令指令存在矛盾精简系统提示5few-shot 质量示例标签错误重建示例集6工具 Schema模型乱传参数补全字段描述7评估集测试集泄漏隔离训练池和测试集8随机参数温度或模型变了固定配置并记录版本6. 自进化系统走向生产的最佳实践6.1 Harness 要像代码一样管理不要把 Harness 只存在在线配置中心更不要散落在 Chat 对话框里。建议把每版 Harness 定义成文件纳入 Git 管理关键变更走评审流程。一个经典目录结构prompts/ intent/ baseline.json v1.1_refund_rule.json v1.2_new_examples.json harness_examples.json system_prompt.txt每次上线通过自动化流程构建 Harness 对象并在日志里记录版本号。这样即使线上出问题也能快速定位是哪一版 Harness 导致。6.2 为自进化设置收益门槛自进化系统要避免“每轮都改”的冲动。建议给收益门槛增加约束准确率至少提升 0.5 个百分点才接受。候选版本在连续 3 轮评估中保持稳定才进入灰度。解析失败率不能变差超过 1 个百分点。单次 token 消耗增加幅度超过阈值时需要人工审批。收益门槛的存在是为了防止系统为了拟合小批量训练样本而牺牲整体稳定性。不要无条件相信模型生成的改进规则。规则可以自动生成是否上线必须由回归数据和人工评审共同决定。6.3 安全执行模型生成
返回列表