资讯动态

同一个模型,为什么Harness不同效果天差地别?

发布时间:2026/10/27 23:35:52 来源:尧图企业网站定制
先说个我这周真实遇到的事。一个之前跑得好好的工单信息抽取服务因为同事觉得外面套的东西太复杂反正都是同一个模型把原来的Harness工程换成了一个极简调用脚本。结果上线半天抽取结果乱到没法看该调用外部工单接口的时候不调不该调的时候乱调输出的JSON字段时有时无。同一个底座模型同一个API地址唯一变的就是模型外面那层壳。所以我才想认真聊聊同样的模型不同Harness差距咋就这么大呢这篇是周记番外篇第52期上。如果你在做LLM应用、Agent框架选型、提示词工程或者正在纠结为什么我的模型调用这么不稳那这篇应该能给你一点启发。上篇先把差距来源和Harness的职责拆清楚下篇再讲Agent化改造和更复杂的业务场景。1. 同一个模型、两个壳实测结果天差地别1.1 一个简化就搞出事故的信息抽取任务我这边遇到的具体任务是工单信息抽取。模型要从一段售后聊天记录里抽紧急程度、责任部门、是否需要回访三个字段。原方案是这样的模型API前面挂了一套Harness包含了一个小的工具注册表可以查历史工单、查部门值班表、一个输出JSON Schema校验器还有一轮解析失败自动纠错的逻辑。同事把它简化成了一段十行代码system prompt写一句你是信息抽取助手输出JSON然后把聊天记录塞进去等结果json.loads。简化后的效果非常典型第一次调用模型在JSON外面加了句好的这是抽取结果json.loads直接抛异常。重试一次模型把是否需要回访写成了is_return_visit_needed和下游字段名对不上。遇到一个模糊表述的工单模型直接回答我不能确定建议人工查看而原来的Harness会触发查历史工单工具给出有依据的判断。问题不在于模型变笨了而是外部那层壳把模型能发挥的上下文、工具和约束全拿掉了。同样的模型外面套的Harness不同实际效果就是两个物种。1.2 排错链路我一开始也怀疑是模型抽风我第一反应也是是不是模型服务抽风。于是拿原方案里完全相同的用户消息直接请求模型裸接口。结果模型在相同system prompt下能给出合规JSON。这就奇怪了说明模型能力没变变的是调用方式。后来逐段对比才发现简化版把前几轮聊天记录全部塞进上下文里面混着一堆工具返回的调试日志。模型在第五轮已经分不清当前事实和历史中间结果。简化版没有任何输出Schema约束模型按自己的习惯选字段名。最致命的是简化版丢失了最大重试次数用完后怎么办的降级逻辑。一旦第一次解析失败后续全乱套。排查到这儿我基本确认问题出在Harness这一层。上线前没人觉得壳有用出事故才想起来这也是很多LLM项目的通病。2. Harness到底在管哪些事它比提示词大得多2.1 Harness、Agent、Prompt Engineering的边界现在社区里经常把Harness、Agent、Prompt Engineering混着说尤其是DeepSeek HarnessAgent Harness这些词。我的理解是概念关注的问题主要动作Prompt Engineering把人的意图表达清楚写system/user消息、设计few-shot、调语气Harness让模型在真实环境里稳定可运行工具注册、上下文管理、输出校验、重试降级、日志Agent让模型自主完成多步任务规划、决策、观察、循环Harness不是提示词也不等于Agent。Agent更像一种行为模式而Harness是这个行为模式赖以运行的底座。我见过不少团队把写个system prompt当成做了提示词工程又把接一个Agent框架当成做了Harness工程。其实都不完整。Prompt是给模型看的说明书Harness是把说明书、工具、反馈回路、错误处理都装进去的一套工程结构。2.2 一套能用的Harness至少要装下这些模块从实际项目看一个能上生产的Harness至少需要这几块入口与模型路由统一接收请求选模型、选参数temperature、max_tokens。提示词模板层把系统指令、动态任务指令、few-shot示例组织成稳定结构。工具注册表声明每个工具的名称、描述、参数Schema并做调用前校验。上下文管理器决定哪些历史内容进模型哪些进摘要哪些直接丢弃。输出解析与校验把模型输出转成结构化数据按Schema校验字段。重试与降级针对模型繁忙解析失败超时分别处理。日志追踪记录每次请求的prompt、输出、工具调用方便复现问题。这里每一块看起来都不难难的是把它们组合起来并且在模型升级、工具变更时不崩。打个比方模型是发动机Harness是底盘和线束。发动机决定动力上限但线束要是接触不良油门信号传不到轮子上动力再猛也没用。很多人在意发动机参数却忽略线束等抛锚了才回头查。2.3 为什么说模型决定上限Harness决定下限模型的参数量、训练数据决定了它的能力上限这个上限不是靠工程能突破的。但一个应用真正的底线——稳定输出、正确调用工具、不出低级错误——是由Harness决定的。我见过太多类似案例用同一个模型A组做出的功能在线上跑了一个月没问题B组照抄模型却天天出bug。差的就是外面这层壳。上限高不代表下限高能力再强的模型把它丢进一个没有约束、没有校验、没有错误恢复的调用环境里也会表现得像个刚学会说话的小孩。所以不要再说模型强就够了。在实际工程里模型只是零件Harness才是把零件装成能开整车的那个角色。3. 差距最明显的三个点工具、结构化输出、上下文3.1 工具定义模型不是不会用工具是不知道你什么意思先说工具。很多Harness差距大第一刀就切在工具定义上。我见过一个团队接天气查询工具参数Schema里写了unit字段但description没写单位。结果模型凭自己的训练记忆默认单位是华氏度所有温度都错。你怪模型吗它只是按最可能的理解去填参数。好的工具定义应该做到三件事写清楚什么时候用description里明确You should use this tool when ...写清楚什么时候不要用很多工具出错是因为模型在不需要的场景也调所以要加OTHERWISE, do not call this tool写清楚参数边界和示例单位、枚举值、格式都给出来。给一个工具描述的示例我用的是JSON格式{ name: query_work_order, description: 查询历史工单。仅当用户询问工单状态、处理进度、历史结论时使用。如果只是闲聊或与工单无关不要调用。, parameters: { type: object, properties: { order_id: { type: string, description: 工单编号格式如WO20240115-001 } }, required: [order_id] } }注意这里我把不要调用的边界直接写进description实测下来能明显减少乱调用。工具数量也要控制。同一层给模型塞三四十个工具模型选择准确率会下降。如果业务确实工具多我习惯先做一个分类路由让模型先选工具组再进对应的子Harness而不是把几十个工具平铺给它。和DeepSeek这类中文对话模型配Harness的时候我的感受是工具描述用中文直说效果往往比翻译腔英文更好别套用英文Agent模板。这个结论不绝对但值得在你自己模型上试一次。3.2 结构化输出JSON飘忽不定的根子在没立规矩第二个大差距是结构化输出。同一个模型你直接说输出JSON和你说按这个Schema输出JSON缺少字段会被重试结果完全不一样。最典型的场景模型在JSON外层加说明文字好的结果如下{...}。裸调用的json.loads直接崩。模型把字段名从level写成紧急程度和下游字段映射不上。模型遇到不确定信息不是输出unknown而是干脆编一个值。Harness能做什么我的方案是三件事。第一在提示词里给出明确的JSON Schema让模型照着填。不是笼统的输出JSON而是把字段名、类型、枚举值都写清楚{ type: object, properties: { level: { type: string, enum: [高, 中, 低] }, department: { type: string }, need_callback: { type: boolean } }, required: [level, department, need_callback] }第二写一个宽容的解析器。先不急着json.loads先把响应里的JSON代码块截出来再尝试解析。解析失败以后把异常信息作为一条新消息回传给模型让它修一次。这个解析-纠错回路能让格式成功率从70%拉到98%以上。第三设置降级。纠错一次还失败就别死磕了记录日志、返回解析失败给上层或者切到更简单的模型任务。这里要特别说一句不要所有错误都无脑重试尤其是模型繁忙这种服务端错误。无脑重试只会让排队更严重正确做法是退避重试、控制并发、必要时降级到备用模型或备用提示词模板。结构化输出这块是最能感受到模型没变Harness一变结果就大变的地方。3.3 多轮上下文模型不是被模型坑了是被喂坏了第三个差距在多轮上下文。很多Harness把每一次用户消息、每一次工具返回都原封不动塞进历史塞到超过模型的上下文窗口然后被截断。截断后会发生什么模型把之前某轮的工具结果当成最终答案或者重复做已经做过的事。我踩过的一个具体坑让模型多轮调用工具修改工单状态。每轮工具返回都塞进历史到第五轮时模型已经忘了自己第一轮改过状态又提交了一次一模一样的修改。后来查日志才看到历史里有两页是工具返回的调试信息把关键状态挤没了。现在我的上下文策略比较朴素固定保留最近K轮完整消息更早的内容压缩成结构化摘要摘要里只留已经完成的事、当前目标、关键约束工具调用结果单独管理不一股脑塞进用户/助手消息重要的常量用户ID、目标、截止时间放在离系统提示词足够近的地方避免被截断。不同模型对上下文的敏感位置不一样。比如有的模型更关注提示词末尾的内容如果把重要指令放在很前面长上下文时它可能忘记。Harness里应该给提示词模板预留可调位置做A/B测试而不是写死。4. Harness和Agent到底什么关系4.1 Agent是驾驶策略Harness是底盘Harness和Agent区别是最近被问烂的问题。我自己的理解是Agent是思考-行动-观察的循环策略它决定模型下一步该干什么Harness是让这个循环能真正跑起来的底盘。Agent说我要调用工具Harness负责把工具真正接进去Agent说我观察到结果了Harness负责把观察结果整理好放回上下文。所以有了Agent不代表有Harness。很多人的Agent跑不稳不是Agent逻辑不对而是Harness太简陋没有工具结果校验、没有最大循环限制、没有历史摘要机制。Agent每多一个循环上下文就膨胀一轮三轮以后模型就开始神游。而反过来Harness也不一定非要跑Agent。很多一次性任务直接Harness结构化输出就够了。这俩不是包含关系更像策略和基础设施的关系。4.2 我的经验先别急着上Agent我给自己定过一条硬性规则一个任务如果可以用单次调用工具输出Schema解决就不要上Agent。为什么Agent化以后平均延迟翻倍、token成本上升、可复现性下降。一旦中间某轮模型选错工具后面全错而且很难定位。什么时候才需要Agent任务是真正的多步决策——比如模型需要先查资料、再根据资料决定下一步、可能需要反复尝试。这种情况下Agent循环才有意义。而即便这个时候我也建议把Agent约束在一个严格设计的Harness里限制最大步数、每步只暴露当前阶段相关工具、步间做摘要压缩。5. 搭Harness的实操顺序和一串踩坑记录5.1 从裸API到三层防护的演进如果你现在还在裸调API我的建议是别一次上太重按三层往上加。第一层提示词模板和基础输出约束。把system prompt、任务指令、few-shot分开固定字段名要求按Schema输出。这一步最简单能解决一半的格式问题。第二层工具注册和上下文管理。定义好工具Schema加一个上下文管理器控制哪些内容进去、哪些压缩、哪些丢弃。这一步能解决乱调用上下文膨胀问题。第三层校验、重试和日志。解析失败自动纠错服务端错误退避重试所有请求和响应都落到日志。这一步解决生产环境看不见、复现不了的问题。我实际项目里的结构大致是这样my_harness/ ├── prompts/ │ ├── system.md │ ├── task_tpl.yaml │ └── few_shot/ ├── tools/ │ ├── registry.json │ └── handlers/ ├── output/ │ ├── schemas/ │ └── validators.py ├── context/ │ └── manager.py └── logs/目录不重要重要的是每一层职责清楚。我见过很多项目把所有逻辑塞进一个chat函数里刚开始跑得动一旦业务复杂就再也改不动了。5.2 DeepSeek模型Harness在内网部署的几条经验热搜里很多人问deepseek harness附带skill怎么部署到内网服务器这块我专门踩过坑。先说大原则Harness只是模型外面的壳它不负责保存模型。模型本身要跑在内网通常是本地或内网集群的推理服务暴露一个兼容API地址给Harness调用。所以部署分两半一半是模型服务一半是Harness工程。模型服务这边把权重和推理引擎放到内网用内网域名或IP提供API。Harness配置里只写这个内网地址不硬编码任何外部依赖。Harness工程这边要注意离线依赖。Python环境需要的包提前下载到内网源pip配置成内网源安装。插件或者skill这类东西我习惯把它们当成一组提示词工具定义校验规则以独立目录形式部署。每个skill目录里有自己的prompt文件、工具注册文件和测试用例。这样换skill不用动主程序版本管理也清楚。内网部署还有一个容易漏的点权限控制。模型服务放在内网不代表所有人都能直接调最好加一层API Key或白名单。日志里如果包含工单、聊天记录这类业务数据要做脱敏。我以前就因为把完整聊天记录打到日志里被运维找过。插件管理上我的原则是少而稳。真正有用的插件就那几类输出校验、重试退避、日志追踪、限流控制。所谓提示词优化插件要谨慎它会在运行时动态改写你的模板一次改动可能把之前调好的效果带偏。另外强烈建议给Harness做版本回退能力。有一次我升级了某个skill的提示词模板线上效果立刻变差靠回退到上一个版本才救回来。没有回退机制的Harness在高频迭代时就是一颗定时炸弹。5.3 避坑清单哪些地方最容易过度设计搭Harness常见的过度设计我也踩过一上来就上万能Agent。结果是工具调用链越来越深出错概率指数上涨。工具描述越写越长。description超过几百字以后模型反而抓不住重点。我一般控制在三到五句话。所有错误都无脑重试。解析失败重试一次可以模型繁忙也重试十次只会把服务拖垮。插件越加越多。每个插件都意味着prompt模板被改动、延迟增加。加插件之前先问自己没有它行不行试图让模型一次输出超长结构化内容。比如要求一次输出100个字段的完整JSON模型很容易中途格式崩坏。不如拆成两三次子任务每次只做一件事稳定得多。还有一点不要试图用Harness弥补模型安全或合规上的硬伤那是另一个层面的事。6. 验证Harness效果的一个笨办法6.1 固定评测集不要看demoHarness改得好不好不能靠肉眼感觉。我现在的做法是固定一套评测集大约三五十条全是线上真实遇到过的、最有代表性的输入。每次改动Harness跑一遍统计几个指标指标说明格式正确率输出能被解析且通过Schema校验的比例工具调用正确率该调的工具是否正确调用、不该调的是否没调最终结果准确率抽取/回答内容是否和人工标注一致平均延迟单任务的P50/P95耗时单任务token成本包含重试消耗的总token数这套东西不高级但特别有用。很多时候你觉得这次优化有效果一跑评测集发现只是demo选得好。我有一次优化提示词demo看着变聪明了评测集准确率反而降了三个点立刻回退。6.2 顺手给下篇留个话头这篇先聊到这儿。如果你也在折腾Harness建议先拿固定评测集把所有改动跑一遍再谈优化。模型是零件Harness是装配工艺同样的零件装得好不好成品差距就是天上地下。下篇我会继续拆Agent Harness、多模型协同和更复杂的Skill管理到时候用实际业务案例说话。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑