
當你的 Agent 在測試集上表現不穩定時很多團隊的第一反應是換底座模型比如從開源 7B 換成更大的 70B或者從 GPT-4o 換成“當前最強”的模型。結果常常是有提升但幅度不大而且換了供應商之后原來的工具調用方式可能又要重寫一遍。另一個常見反應是微調模型。但微調成本高、數據難準備而且很多 Agent 場景里模型其實沒有“知識缺陷”真正的問題出在它不知道該在什么時機調用工具、工具參數怎么填、調用失敗后如何恢復、結果不滿 意時應該繼續檢索還是直接作答。這些問題不發生在模型參數內部而發生在模型和外部環境之間的那一層代碼與配置里。這一層現在被越來越多開發者稱為 LLM Harness。最近在 Hacker News 上出現了一個很能概括這個方向的標題Auto-train the harness, not the LLM. cross-model, cross-benchmark gains。大意是自動優化外層 Harness而不是訓練 LLM 本身并且把這種優化帶來的收益遷移到多個模型和多個評測基準上。這個觀點聽起來有些反直覺但放在 Agent 應用大量落地的背景下它比“繼續卷底座模型”更貼近工程現實。這篇文章不是為了介紹某個具體倉庫而是想把這個思路拆開什么是 Harness、為什么要自動訓練 Harness、怎么用最小工程驗證它是否真的有效。1. 為什么說 Agent 的瓶頸可能不在模型而在 Harness先看一個高頻場景。你給 LLM 接上了搜索工具和計算器業務流程大概是系統提示詞告訴模型“不確定就搜索”工具描述里寫清楚搜索接口能做什么模型返回一個結構化工具調用你的代碼去執行函數再把結果拼回上下文讓模型繼續推理。聽上去很順實際跑起來卻經常出現三類問題第一模型該搜索的時候不搜索不該搜索的時候反而搜索。這不是模型“笨”而是提示詞里沒有定義清楚判斷條件工具描述也沒有告訴模型什么樣的問題屬于“需要實時信息”。第二工具結果回填格式混亂。模型可能返回一個很長的網頁摘要上下文被撐爆或者返回了 JSON 數組但你的解析器只處理了對象。這些格式問題本質上由 Harness 環節的人為規定造成。第三Agent 陷入死循環。模型反復調用同一個工具拿到相似結果然后繼續調用。如果循環次數、停 止條件、結果去重沒有兜底再強的模型也會在真實環境里打轉。如果你把這些問題歸因于“模型能力不夠”就會走上換模型或微調的路。但稍微復盤一下就會承認模型大多是按照它看到的那套系統提示、工具定義、消息歷史去決策的。模型像一個經驗豐富但完全聽信流程的員工真正決定工作質量的是他手里的操作手冊和上級給的授權邊界。這個操作手冊和授權邊界就是 Harness。Harness 不是某個大模型廠商提出的專有概念。只要你在做 Agent、寫 RAG、做工具調用其實已經不知不覺寫了大量 Harness 代碼。問題在于過去我們把這些代碼當成“調用 API 的臨時膠水”沒有意識到它們是可以系統設計的、擁有獨立版本、需要評測和優化的核心部件。從很多公開討論來看過去半年“Harness 工程”這個詞出現的頻率明顯升高。圍繞 DeepSeek、Codex 等模型的封裝工具也開始出現。大家開始默認一個前提當模型能力差距縮小到一定程度Agent 效果的上限不取決于你選哪個底座模型而取決于你在這層外圍工程上做得有多細。2. 什么是 LLM Harness模型、環境與任務之間的膠水層要理解 Auto-train Harness先得把 Harness 的邊界畫清楚。LLM Harness 可以理解為為了讓 LLM 完成真實任務而在模型之外增加的提示模板、工具定義、循環控制、上下文管理、結果校驗與安全邊界的總稱。它至少包含四塊內容。第一塊是認知接口。也就是模型“看到”什么。系統提示詞、用戶問題的組織方式、工具名稱和描述、Few-shot 示例、輸出格式約束都屬于認知接口。模型不會直接看到你的內部工具它只能看到你給它描述過的工具。因此工具描述寫得好不好直接決定模型會不會調用正確的工具。很多團隊只把工具描述當作文檔隨手寫一句“查詢訂單狀態 API”模型在復雜語境里自然容易誤用。第二塊是執行循環。LLM 本身沒有手它不能真正執行搜索、不能寫數據庫、不能發送 HTTP 請求。模型能做的只是輸出一個結構化的工具調用請求。誰來執行這個請求誰來把執行結果放回消息歷史誰來決定是繼續讓模型推理還是終止這些是 Harness 的運行時控制部分。ReAct 模式、Tool Calling 循環、LangChain Agent 里的執行器、各類 Agent 框架中的 Loop本質都屬于這一層。第三塊是穩定性機制。真實環境是不穩定的。工具可能超時第三方 API 可能返回臟數據模型可能連續多次輸出無效 JSON甚至可能在一次回復中同時給出最終答案和工具調用。Harness 需要處理這些異常重試、截斷、錯誤提示、回退策略、最大輪次限制。沒有這層機制模型即使知道答案也可能會被一次工具異常帶偏。第四塊是安全和數據邊界。一個 Agent 能訪問哪些工具、每個工具允許哪些參數、調用前是否需要審批、日志里能不能出現敏感字段這些通常不會被模型自身感知而是由 Harness 在調用執行前強制執行。越是進入生產環境這部分的分量越重。把模型和外層 Harness 分開看會發現它們想解決的問題不同。層面主要問題改進方式成本類型LLM 參數知識、推理、指令遵循預訓練、微調、RLHF算力和數據成本高Harness工具調用、流程控制、穩定性提示詞優化、循環策略、代碼邏輯開發和評測成本高評測體系改進是否真實存在基準集、交叉驗證、回歸測試評測基建成本Harness 經常被誤認為只是“提示詞工程”其實提示詞只是認知接口的一部分。更重要的是Harness 是可以寫代碼、做控制流、跑自動化評測的系統。正因為它是系統所以可以在不改變模型權重的情況下被優化自動化的優化就變得有可能性。這就是 Auto-train Harness 的核心前提。3. Auto-train Harness 的思路調的不是模型參數而是決策策略“Auto-train”這個詞聽起來很大它未必意味著你要做 PyTorch 訓練。在 Agent 場景里它更接近一種搜索或自動調優過程把 Harness 的關鍵變量從人工配置變成可枚舉、可變異的參數空間然后通過自動評測尋找更優配置。傳統手工調 Harness 是幾天前最常見的做法。一個人對著系統提示詞改三版把工具描述從“搜索網頁”改成“當用戶詢問最新新聞時使用此工具獲取搜索結果”再跑一遍評測集看準確率有沒有漲。這種方式的問題在于評測集的噪聲經常比提示詞差異帶來的收益還大人工很難判斷一個改動是真正有效還是碰巧有效。自動優化至少能保證候選配置都跑在同一個評測集上打分一致最后用規則選出表現最好的配置而不是靠感覺。如果要自動訓練的變量只有提示詞那它其實還是提示詞搜索。可以把優化空間擴大一些系統提示詞與工具描述換措辭、換結構、增加邊界條件說明。工具順序與可見性模型不一定要看到全部工具按任務路由到不同工具子集可能更好。循環控制最大迭代次數、提前終止條件、連續相同工具結果時是否中斷。輸出解析與校驗要求模型先輸出 JSON 再輸出解釋或者反過來。模型路由策略簡單任務用便宜小模型復雜任務才交給大模型。Few-shot 示例選擇從已完成任務中挑相似樣例放入上下文。這些變量共同決定了一個 Agent 的實際行為邊界。而且它們大多不綁定某個具體模型。換句話說一套合理的 Harness 配置在換一個底座模型之后大概率仍然有效。這正是“cross-model”收益能成立的根本原因如果你的優化只針對某個模型的表達能力那它很難遷移如果你的優化改善了工具描述結構、循環控制這一層通用機制它就能在多個模型上同時帶來增益。Cross-benchmark 的道理同樣如此。不同基準會考察不同能力比如有些考察多跳推理有些考察工具調用準確性有些考察最終答案是否簡潔。如果一個 Harness 變體只在某個基準上提升可能是過擬合到該基準的數據風格只有多個基準同時提升才能說明它優化的是比較通用的行為。3.1 Auto-train 與微調的區別很多人會問Auto-train Harness 是不是一種微調并不是。對比維度微調 LLMAuto-train Harness對象模型權重配置、提示詞、循環策略成本GPU、訓練框架、數據標注評測任務、API 調用、搜索算法遷移性一般只對當前模型有效跨模型遷移可能性更高迭代速度小時到天分鐘到小時風險可能改變模型通用能力主要影響 Agent 行為邊界這兩者不互斥。如果場景高度垂直微調仍然有價值。但如果只是想讓 Agent 更會調用工具、更少陷入循環、更穩定地輸出結果先花時間優化 Harness 的性價比通常更高。Show HN 標題里“not the LLM”的重點應該理解為優化重心轉移而不是否定所有的模型訓練。4. Cross-Model、Cross-Benchmark 究竟該怎么驗證很多團隊做過類似的事給提示詞加一句“請一步步思考”然后在自己的評測集上看到分數漲了就說 prompt engineering 有效。但如果把同一套提示詞換一個模型效果可能反而下降。這說明這個改進只對單個模型有效屬于某種模型偏好耦合不是真正的 Harness 改進。要驗證一個 Auto-train Harness 方案是否真的帶來了跨模型、跨基準增益需要一個相對嚴謹的評估矩陣。至少應該包含三個模型和兩個以上評測基準。比如三個模型分別來自不同機構評測基準分別覆蓋工具調用、多輪對話、信息檢索或代碼生成。優化的 Harness 在開發集上搜索時就應當在多個模型上同時評估選取平均表現更好的配置而不是只盯著主力模型。把數據分成開發集和測試集也很重要。開發集用來搜索和選擇 Harness 配置測試集在最終配置選定后只跑一次。如果開發集和測試集來自同一個基準可能存在風格相似導致的過擬合所以更穩 妥的做法是額外準備一個 Held-out Benchmark也就是模型和 Harness 都沒有見過的新評測基準。只有最終配置在 Held-out Benchmark 上也保持優勢時才有底氣說“提升是真的”。一句話跨模型驗證是為了防止改進只對自己用的模型有效跨基準驗證是為了防止改進只對某一個評測集有效。Show HN 標題中提到的“gains”如果缺少這種矩陣驗證仍然只能視為一種初步觀察。5. 最小實現一個可落地的 Harness 自動優化雛形下面用一個與具體廠商無關的 Python 示例來演示 Auto-train Harness 的完整鏈路。這里不依賴某一家模型 SDK而是把模型調用抽象成call_llm()。實際項目中根據你用的模型服務換成對應客戶端即可。5.1 定義一份 Harness 配置先看 Harness 配置示例。它描述的是Agent 的系統提示詞、可選工具列表、循環控制參數。學習這類思路時盡量把配置與代碼分離因為 Harness 本身會被反復修改。{ harness_name: react_tool_agent_v1, system_prompt: You are a helpful research agent. If the question asks about real-time facts, call web_search before answering., tools: [ { name: web_search, description: Search the web for keywords and return relevant snippets., parameters: { type: object, properties: { keywords: { type: string, description: search keywords } }, required: [keywords] } }, { name: calculator, description: Evaluate a arithmetic expression., parameters: { type: object, properties: { expression: { type: string, description: A mathematical expression, for example 3 * (7 2) } }, required: [expression] } } ], loop: { max_rounds: 5, stop_when: no_tool_call } }這份配置的核心價值在于把 Harness 關心的東西集中到一個文件里。修改工具描述、調整系統提示詞、限制最大輪次都通過配置完成不需要改 Agent 主邏輯。5.2 寫一個最小評測循環下面代碼的目標是給定一份 Harness 配置和一個模型在一個簡單評測集上返回準確率和 token 成本。代碼演示的是核心思路并不負責處理所有真實 SDK 差異。# harness/evaluator.py import json def to_openai_tool(tool_meta): return { type: function, function: { name: tool_meta[name], description: tool_meta[description], parameters: tool_meta.get( parameters, {type: object, properties: {}} ), }, } def execute_tool(name, args_json, example): 模擬執行工具。實際項目需要替換為真實搜索或計算邏輯。 args json.loads(args_json) if name calculator: expression args.get(expression, ) try: result eval(expression, {__builtins__: {}}, {}) except Exception: result calculation_error return fresult{result} if name web_search: # 在演示里我們用 example 中預置的 context 代替真實網頁結果。 context example.get(context, ) return ffound:{context[:300]} return unknown_tool def judge_answer(answer, expected): 演示用判斷真實場景建議引入獨立的答案評估 prompt 或精確匹配。 return float(expected.strip().lower() in answer.lower()) def run_single(harness_cfg, model_name, example): messages [ {role: system, content: harness_cfg[system_prompt]}, {role: user, content: example[question]}, ] max_rounds harness_cfg[loop][max_rounds] tools [to_openai_tool(t) for t in harness_cfg[tools]] for _ in range(max_rounds): resp call_llm(model_namemodel_name, messagesmessages, toolstools) assistant resp.choices[0].message messages.append(assistant) tool_calls assistant.tool_calls or [] if not tool_calls: answer assistant.content or return judge_answer(answer, example[expected]), resp.usage.total_tokens for call in tool_calls: result execute_tool(call.function.name, call.function.arguments, example) messages.append( { role: tool, tool_call_id: call.id, content: result, } ) return 0.0, 0 def evaluate_candidate(harness_cfg, model_name, examples): total 0 correct 0 total_tokens 0 for example in examples: score, token_cost run_single(harness_cfg, model_name, example) correct score total_tokens token_cost total 1 return { accuracy: correct / max(total, 1), avg_cost: total_tokens / max(total, 1), }這里真正的核心不是代碼本身而是它建立了一個評測入口同一份 Harness 配置同一個模型同一批例子跑出的分數才能互相比較。call_llm()在示例中沒有定義因為它只是模型供應商 SDK 的一層薄封裝。真實開發時用 OpenAI、Anthropic、本地部署的 DeepSeek、Qwen 等任意服務替換均可。5.3 實現自動搜索隨機搜索已經能證明問題自動優化的算法可以從很簡單的隨機搜索開始。雖然聽起來不高級但它能幫助你快速驗證流水線是否通暢也能作為后續貝葉斯優化、進化算法的基線。# harness/optimizer.py import copy import random def random_search(base_config, eval_models, dev_set, rounds10): prompt_pool [ You are a helpful agent. Only call tools when necessary., You are a research agent. If you are not fully certain, search first., You are an assistant. Answer directly if you know; otherwise call tools., ] max_rounds_pool [3, 5, 8] best_cfg None best_score -1.0 for i in range(rounds): candidate copy.deepcopy(base_config) candidate[system_prompt] random.choice(prompt_pool) candidate[loop][max_rounds] random.choice(max_rounds_pool) # 調整工具展示順序。順序本身會影響模型先嘗試哪個工具。 random.shuffle(candidate[tools]) # 在多個模型上同時評估避免只對單個模型有效。 acc_list [] for model_name in eval_models: metric evaluate_candidate(candidate, model_name, dev_set) acc_list.append(metric[accuracy]) avg_acc sum(acc_list) / len(acc_list) print(f[round {i}] avg_acc{avg_acc:.3f} acc_list{acc_list}) if avg_acc best_score: best_score avg_acc best_cfg candidate return best_cfg, best_score5.4 最終配置的跨基準驗證選出最優配置后不能立刻上線還需要在 Held-out Benchmark 上驗證。這段代碼會把最終配置在先前沒有優化過的評測集上運行一遍觀察它是否還保持優勢。def validate_on_heldout(final_cfg, eval_models, heldout_examples): print(--- held-out validation ---) for model_name in eval_models: metric evaluate_candidate(final_cfg, model_name, heldout_examples) print( f{model_name}: faccuracy{metric[accuracy]:.3f}, favg_cost{metric[avg_cost]:.2f} )到這里我們已經有了一條完整的 Auto-train Harness 雛形鏈路配置化 Harness、可重復評測、多模型打分、自動搜索、最后跨基準驗證。算法可以從隨機搜索變成更復雜的方法但這條鏈路本身不會變。6. 運行思路與效果驗證怎樣算一次優化真正成功運行上述腳本時你不需要一開始就用大規模評測集。可以先準備 50 到 100 條代表性樣例再選擇兩到三個模型跑 10 到 20 輪搜索。重點不是跑出多高的分數而是確認優化鏈路能穩定運行。預期你會看到類似下面的輸出示意。這里的數字只是為了展示格式不是真實評測結果。[round 0] avg_acc0.451 acc_list[0.47, 0.44, 0.45] [round 1] avg_acc0.438 acc_list[0.45, 0.43, 0.44] [round 2] avg_acc0.472 acc_list[0.50, 0.46, 0.46] [round 3] avg_acc0.466 acc_list[0.51, 0.43, 0.46] ... best_score0.491 acc_list[0.52, 0.48, 0.48]判斷成功的標準不是只挑 acc_list 中某個模型最高的那輪而是看平均分是否穩定高于基線。如果候選配置在模型 A 上大幅提升在模型 B 上明顯下降那這種方案很可能是在迎合模型 A 的表達偏好并不算跨模型收益。當最終配置進入 Held-out Benchmark 時你還需要關注當時在開發集上的優勢是否還在。如果開發集提升明顯Held-out 卻完全無效說明優化過程過擬合了開發集的題目風格。運行失敗時第一步不要急著看模型 API 報錯先檢查評測輸入流水線樣例有沒有正常加載、工具執行函數是否可用、call_llm()返回格式是不是符合預期。很多“模型表現差”的結論最后都來自評測腳本 bug而不是模型問題。建立一條干凈可復現的評測基線比任何優化算法都重要。7. Harness 自動優化的常見問題與排查思路問題現象可能原因排查方式解決方案每次搜索分數波動很大評測樣例太少模型采樣有隨機性增加樣例量或同題多次采樣取平均固定溫度或用多次運行中位數代替單次分數模型 A 提升但模型 B 下降優化到了模型 A 的特殊表達偏好查看候選配置在模型 A/B 上的詳細 log將優化目標改成多模型平均分或加入約束懲罰最大下降幅度開發集漲了Held-out Benchmark 不漲Harness 過擬合了開發集風格檢查兩項評測集分布差異增加不同任務類型的評測集減少開發集與測試集重疊Token 成本明顯上升循環次數變多上下文里重復內容增加打印每輪消息數量和 token 用量增加提前終止條件對相似工具結果做去重Harness 優化后輸出不如手寫版本自動搜索沒有覆蓋關鍵變量檢查候選配置的差異程度擴大參數空間允許對工具描述做改寫上線后效果與評測不一致線上環境分布和評測集不同記錄線上輸入與工具調用日志持續回流線上樣本定期增量評測自動搜索最大的坑并不是算法選得不好而是評測集與真實任務不匹配。如果你拿一組答案很簡短的單輪問答去做 Harness 搜索選出來的配置可能特別喜歡“直接回答”而不是“調用工具”。一旦上線面對需要多輪工具調用的真實問題效果自然下降。因此開發集需要覆蓋足夠多的真實形態至少包含需要調用工具、不需要調用工具、工具調用失敗后重試等典型分支。常見問題里還有一個隱蔽點模型服務版本的波動。同一個模型名稱背后供應商可能悄然更新版本。今天跑出 0.50 分明天同樣是 0.46不一定是你的 Harness 變差而是模型行為漂移。團隊內部要把模型版本固定為可見字段才能區分變化來自模型還是來自 Harness。8. 工程化落地建議把 Harness 當成獨立項目來管理Harness 工程化可以在團隊里落地為幾個清晰動作。第一個動作是配置與代碼分離。不要把系統提示詞硬編碼在 agent 源碼里尤其是不要散落在多個 service 文件中。統一維護一份 Harness 配置包含提示詞、工具描述、路由規則和循環參數。這樣后續優化可以在配置層面做實驗而不用頻繁提交業務代碼。第二個動作是建立評估矩陣。至少要有一個腳本可以輸入候選配置、指定模型列表和評測集名稱輸出性能與成本表格。沒有這個矩陣任何關于“Harness 是否改進”的討論都容易淪為空談。矩陣里建議同時記錄模型名稱與版本、評測集版本、Harness 配置 hash、運行時間和總 token 成本。第三個動作是搜索與人工 review 結合。自動優化可以發現人想不到的提示詞寫法但它發現問題的方式是分數驅動。分數高不代表安全不代表符合產品規則。上線前必須人工 review 自動選出的配置確認工具權限邊界沒有被擴大確認模型在敏感問題上仍能正確拒絕。第四個動作是嚴格控制工具權限。無論 Auto-train Harness 實驗結果多好生產環境的工具調用都必須遵守最小權限原則。搜索工具只能訪問白名單地址數據庫工具只能執行只讀查詢或經過審批的寫操作涉及用戶隱私的字段在日志中脫敏。Harness 優化能做的是讓模型更準確地調用工具但無法替代權限系統本身。第五個動作是回歸測試。當你的核心模型從 GPT 換成 DeepSeek、Qwen 或其它模型時所有經過優化的 Harness 配置都要重新跑一遍小規模回歸測試。跨模型遷移是一種期望但每種模型對提示詞的敏感點不同不能默認遷移一定成立。9. 結語先把評估矩陣搭起來再談是否 Auto-trainAuto-train the harness, not the LLM真正想表達的是Harness 不再應該被當作模型調用之外的附屬品而應該被當作一個可以被設計、評測與搜索優化的系統。模型負責輸出智能Harness 負責把智能安全穩定地轉化為行動。如果你現在正在做 Agent 開發可以暫時不引入復雜的自動優化算法先做三件事把 Harness 配置化建立一份包含多個模型的小評測集跑出一個穩定的 baseline。當你發現手工調整提示詞已經難以穩定提升時再把隨機搜索或更高級的優化算法接到這條鏈路上。到那時你會更理解“Auto-train Harness”的價值它不承諾某個魔法提示詞它只提供一種系統化的方式讓你在模型不變的前提下找到更好的外圍策略。建議先收藏這篇文章并在下一次 Agent 調試時嘗試把問題歸因從“模型不行”改寫成“Harness 哪里還不夠穩”你會發現調試思路開闊很多。