指南)
1. 從一次微調翻車說起Agent場景下SFT為什么不夠用了前幾天我往項目里加Agent能力模型要能自己決定調哪個工具、傳什么參數、看結果之后決定下一步做什么。一開始我很天真想著這不就是指令跟隨的升級版嗎把工具調用的輸入輸出整理成對話樣本跑一輪SFT就完事。結果模型確實學會了輸出“調用搜索工具”這幾個字但參數經常傳錯搜索完拿到結果之后完全不知道該怎么用有時候甚至在一個死循環(huán)里反復調同一個接口失敗一次就再來一次像是被困住了一樣。這個現象逼著我重新審視一個基礎問題我們平時說的SFT在Agent場景下到底在訓練什么傳統(tǒng)SFT的樣本長這樣用戶問“北京的天氣怎么樣”模型答“北京今天晴22度”。一個輸入一個輸出答案就結束了。但在Agent場景里一個樣本是一條完整的軌跡用戶提出目標模型決定先搜索搜索返回結果模型分析結果發(fā)現不夠還要再調用一個天氣API拿到數據后匯總出最終答案。中間每一步都是決策每一步都可能錯而且錯誤會像滾雪球一樣累積到最終結果里。所以Agentic SFT給我的第一課就是它是監(jiān)督微調但監(jiān)督的不再是“最終的答案”而是“達成答案的整條決策路徑”。我們要教模型的不只是“該說什么”更是“該在什么時候做什么、做完之后怎么看結果、結果不對勁怎么改”。這篇文章就是我目前對這個話題的全部認知積累持續(xù)迭代持續(xù)記錄。我盡量寫得直白一點把我踩過的坑、觀察到的現象、還沒想明白的問題都說清楚。適合正在做Agent微調、或者準備把模型從“對話模型”改造成“干活模型”的同行參考。2. Agentic SFT到底在“學”什么從單輪問答到多步決策2.1 輸出空間的變化模型從“寫答案”變成“做決策”傳統(tǒng)SFT的核心假設是給定輸入最優(yōu)輸出是唯一的或者至少是高度確定的。SFT要做的就是讓模型去擬合這些輸入輸出對學一個從指令到回復的映射。Agentic SFT徹底打破了這一點。模型的輸出不再是一段最終回復而是一個行動序列。它先要判斷“我現在要不要調用工具”然后決定“調哪個工具”再生成“符合接口規(guī)范的參數”接著閱讀“工具返回結果”最后綜合所有信息繼續(xù)下一步。這本質上是一個決策過程而不僅僅是文本生成過程。舉個例子一個典型的Agent軌跡樣本里模型輸出通常長這樣{ thought: 用戶想知道A股大盤走勢我需要先獲取指數數據, action: call_tool, tool_name: get_stock_index, params: {index: sh000001, period: today} }關鍵在于模型要把“調用工具”這件事當成一種正常的文本輸出。它并不真的去調用任何東西它只是在“生成”一段符合工具接口協(xié)議的結構化文本然后由外層框架去實際執(zhí)行。這就有意思了我們訓練的目標本質上是讓模型學會“說人話”之外的另一種語言——工具協(xié)議語言。這就帶來一個直接后果SFT的數據不能再是簡單的“問題-答案”對而必須是“目標-行動-觀察-決策”的完整閉環(huán)。少了任何一環(huán)模型都學不會真正的Agent行為。2.2 監(jiān)督信號的粒度每一小步都要單獨負責傳統(tǒng)SFT里一個樣本只有一個監(jiān)督信號就是最終答案。哪怕模型在中間推理時胡說八道只要最后答案對了loss就是小的。但Agent場景不一樣錯誤會傳導。我后來在訓練里用了“逐點監(jiān)督”per-step supervision的思路對軌跡里的每一步分別計算loss而不是只在最終答案上算loss。具體來說一條軌跡可以拆成多個訓練單元單元一用戶說目標期望模型輸出“思考調用工具A”單元二工具A返回結果期望模型輸出“分析結果調用工具B”單元三工具B返回結果期望模型輸出“匯總最終答案”每一步都是獨立的監(jiān)督目標。這樣做的好處是哪怕最終答案因為外部工具的不確定性失敗了模型也能學到“在這個狀態(tài)下正確的下一步應該是做什么”。這在Agent場景里非常重要因為工具執(zhí)行可能失敗但模型對于“該調用哪個工具”的判斷仍然是有監(jiān)督價值的。2.3 為什么說“會背答案”不等于“會用工具”剛跑完第一輪Agentic SFT的時候我測了幾個訓練集里的用例表現非常好工具調用規(guī)范、參數準確、多步規(guī)劃也有模有樣。但換到全新的任務上立馬露餡。后來我意識到一個本質問題模型在傳統(tǒng)SFT里學了太多“從問題直接到答案”的捷徑。對Chat模型來說這是優(yōu)點因為它能高效回答。但對Agent來說這個先驗反而是阻力。模型傾向于自以為是地直接輸出答案而不是先想一想“我需要哪些信息、哪些信息我沒有、我需要調用什么工具來獲取”。我一度以為是數據量不夠加了幾千條樣例之后問題依然存在。直到我對比了訓練集和評測集的分布才發(fā)現模型學到的是“看到相似的問法就模仿相似的軌跡”它并沒有真正學到“工具調用是一個為了彌補自身知識不足而采取的手段”。這個認知讓我后來在設計數據時刻意加入了大量“模型不調用工具就會答錯”的樣例逼迫模型學會依賴工具。效果有提升但離真正的泛化還有距離。3. 數據為王Agentic SFT的訓練數據到底怎么造3.1 軌跡數據的三種形態(tài)Agentic SFT的數據不是天上掉下來的。目前常見的獲取方式有三種我分別試過感受很不一樣。第一種人工構造軌跡。找?guī)讉€核心業(yè)務場景自己模擬Agent的行為手工寫完整的多輪軌跡。優(yōu)點是質量可控每條數據都符合我們想要的Agent行為范式缺點也明顯慢、貴、覆蓋場景有限。適合冷啟動不適合撐起大規(guī)模訓練。第二種從真實系統(tǒng)日志里扒軌跡。如果你的Agent已經上線跑了一段時間日志里本身就是大量真實軌跡。把這部分日志清洗、過濾挑出高質量的會話記錄下來直接當作訓練數據。這個數據源最貼近真實分布但問題在于日志里優(yōu)質軌跡的比例往往不高需要大量過濾和重寫。而且日志里很多軌跡是帶有外部狀態(tài)依賴的清洗的時候要額外小心。第三種用更強的模型蒸餾。把任務描述扔給一個能力更強的模型讓它扮演Agent生成軌跡然后拿這些軌跡來訓練小模型。這是目前實踐中最常用、也最容易規(guī)?;囊粭l路。但本質上蒸餾是在“壓縮教師模型的行為模式”如果教師模型本身就是錯的學生模型只會錯得更穩(wěn)定。3.2 數據里的信號密度比總量更重要的事我在實驗里發(fā)現一個反直覺的結論Agentic SFT的數據量提升帶來的收益會迅速進入平臺期但數據里的“信號密度”卻始終顯著影響效果。什么叫信號密度就是一條軌跡里包含的“關鍵決策點”的數量和多樣性。同樣是3000條數據如果每條都只有一個工具調用、一個觀察、一個最終答案模型能學到的東西非常有限。但如果里面有大量需要三次以上工具調用、或者中間出現工具失敗和恢復的軌跡模型的Agent能力會有質的提升。所以我后來造數據時重點盯這幾個信號多步依賴第二個工具的調用參數依賴第一個工具的輸出而不是獨立的兩次調用拼在一起。這類數據教會模型“信息流轉”。失敗恢復工具返回了錯誤碼模型需要判斷是換參數重試還是換工具。這類數據教會模型“容錯”。中途改計劃拿到工具返回后發(fā)現和最初的設想不一致模型需要基于新信息調整后續(xù)步驟。這類數據教會模型“plan revision”。拒絕調用的場景用戶問了一個模型已能回答的問題期望模型直接回答而不是非要去調工具。這類數據教會模型“何時不應該調用工具”。最后這一點經常被忽略。很多團隊造數據時無限強調工具調用結果模型變成了一個“調用工具強迫癥”連“今天星期幾”這種問題都要先調一下日歷API再回答。效率和成本都繃不住。3.3 構造數據時我用到的具體配方以我目前在做的客服Agent為例我整理了一套比較實用的數據構造流程從歷史工單里挑出100個高頻場景作為數據構造的“骨架”對每個場景設計2到3種不同路徑一條最短路徑、一條帶糾錯的路徑、一條需要換工具的路徑人工編寫前50條作為質量錨點確保風格一致把剩余場景交給教師模型批量蒸餾生成后逐條人工審核在最終數據集里控制比例多步軌跡不低于40%失敗恢復軌跡不低于20%單步軌跡控制在30%以下所有工具調用的參數值都做隨機池化防止模型過擬合具體的參數字面量這套流程跑下來的數據集規(guī)模也就一萬多條但訓練出來的Agent在評測集上的表現比我之前用五萬條粗糙數據訓練出來的結果要好不少。信號密度確實比總量更重要。4. 訓練細節(jié)里藏著魔鬼Loss設計與序列建模的取舍4.1 不是所有token都值得同等的監(jiān)督第一版訓練我直接把整條對話歷史拼成一個序列當成普通SFT去fine-tune了。結果是loss掉得很漂亮但模型行為完全不對。后來我才意識到在Agent軌跡里不同類型的文本監(jiān)督價值完全不同。用戶指令、工具返回結果、歷史觀察記錄——這些是模型需要“閱讀”的上下文不應該參與loss計算。模型真正需要學習生成的是它的思考、工具調用指令和最終回復。如果這部分輸入文本也參與了loss模型會把大量容量浪費在“模仿工具返回格式”這種無用功上真正要被訓練的部分反而被稀釋了。所以第一件事就是加mask。在訓練時把用戶消息、工具返回、系統(tǒng)提示這些部分全部mask掉只對模型自身生成的token計算loss。def build_agent_sample(conversation): conversation: List[Dict], 每條記錄包含 role 和 content role 包括 system / user / assistant / tool_result 只對 assistant 的文本計算 loss其余部分 masked input_ids, labels [], [] for msg in conversation: tokens tokenizer.encode(msg[content]) input_ids.extend(tokens) if msg[role] assistant: labels.extend(tokens) # 參與 loss else: labels.extend([-100] * len(tokens)) # 不參與 loss return input_ids, labels4.2 對“動作關鍵幀”施加更高的權重即使是在assistant生成的文本內部不同內容的重要性也不一樣。思考過程是軟性的就算措辭不太對意思到了就行。但工具調用的參數是硬性的參數值一旦錯了后面全盤崩潰。我在實驗里做過一個調整對工具調用相關的token特別是參數值、函數名額外提高loss權重比如乘以2.0。這樣模型會把更多學習容量分配到“準確生成工具指令”這個關鍵行為上。從效果來看工具調用的格式正確率有明顯提升而思考部分的質量并沒有因此變差。順帶說一句有人會糾結要不要給“思考”部分也降低權重我覺得不用太極端。思考措辭的質量高低對后續(xù)行為的影響是隱性的保持正常的訓練權重即可重點還是要把工具調用部分突出出來。4.3 序列打包的細節(jié)坑Agent軌跡天然比普通對話要長。一條多輪工具調用軌跡算上所有工具返回結果動輒三四千token。訓練時如果處理不當會遇到兩個典型問題。第一個問題是超長序列截斷。粗暴截斷會把中間的決策上下文切斷模型看到的是前后文不搭的輸入能學到個啥。我的做法是滑動窗口切分把長軌跡切成多個有重疊的窗口保證每個窗口里都至少包含一個完整的工具調用決策段。第二個問題是短軌跡拼接。為了提升訓練效率很多框架會把多段短文本packing到一起。但如果packing不當可能會導致模型跨樣本學習本來不相干的兩段軌跡被模型強行關聯(lián)。我的處理方式是在packing時加入分隔符并在計算attention時把跨樣本的部分mask掉。如果框架不支持這種mask就干脆不packing單條樣本訓練雖然慢一點但穩(wěn)。4.4 超參數配置的一個參考基準我目前的Agentic SFT跑得比較順的超參配置大致是這樣的超參數值說明基礎學習率5e-6Agent軌跡訓練容易過擬合務必用低學習率warmup比例3%太少容易前期震蕩太多會拖慢收斂epoch2超過2輪loss還在降但評測效果開始倒退batch size32每條樣本較長顯存受限時先用梯度累積工具調用token權重2.0突出關鍵動作幀對話歷史mask開啟輸入側全部不限參與loss這個配置不一定通用但可以作為起步基準。我個人強烈建議從低學習率開始因為Agent軌跡數據通常是高度重復的同樣的工具調用格式會反復出現學習率稍微高一點模型就會開始原地打轉訓練集上的行為非常華麗測試集上一塌糊涂。5. 評測Agentic SFT只看成功率遠遠不夠5.1 你測的到底是“模型的能力”還是“任務的運氣”我一開始評測Agent效果就盯著一個指標端到端任務成功率。后來發(fā)現這個指標單獨看非常騙人。舉一個具體的現象。給模型布置一個“查詢訂單狀態(tài)”的任務如果最終答對了我以為是Agent能力好。但翻日志發(fā)現模型第一次調工具就把訂單ID傳錯了工具返回錯誤模型居然把錯誤信息原樣搬進了最終回復里而用戶恰好能從那段錯誤信息里看到訂單狀態(tài)——外部工具的錯誤返回“湊巧”包含了正確信息。這種情況下標注“成功”會嚴重高估模型的真實Agent能力。所以我現在評測時把成功率拆成多個維度來觀察格式合規(guī)率模型輸出的工具調用是否符合接口規(guī)范是不是每次都能解析出合法的工具名和參數動作正確率在當前狀態(tài)下模型選擇的工具是否是合理的工具參數是否準確地表達了用戶意圖信息利用率模型在生成最終回復時是否真的用上了工具返回結果中的關鍵字段失敗恢復率工具調用失敗后模型是選擇了合理的重試/替代方案還是直接擺爛最終任務成功率整個流程最終是否解決了問題只有這五個指標一起看才能定位所謂的“成功”到底靠的是模型能力還是運氣。5.2 構建評測集的坑不要讓訓練數據污染評測結果這個坑我印象太深了。有一次我從同樣的業(yè)務場景里分別抽訓練集和評測集只是換了些具體的參數值、改了點措辭結果評測效果出奇地好。后來我把訓練集和評測集的語義相似度算了一下發(fā)現好多評測用例和訓練用例重疊度很高模型根本就是在模擬訓練數據里的軌跡評測效果自然虛高。正確的做法是評測場景必須和訓練場景在任務類型、工具組合、交互模式上有可見的差異。如果訓練時只見過搜索類工具的調用評測時就應該補充一些調用計算器、調用數據庫查詢接口的場景。另外不要用同一個Agent框架里的同一條軌跡生成器既產訓練數據又產評測數據否則模型的“軌跡模仿”能力會被誤認為Agent規(guī)劃能力。5.3 一個更細的做法行為軌跡對齊我現在在嘗試一種更細的評測方案不再只看結果而是把模型在評測任務里的完整軌跡和標注人員預寫的“專家軌跡”做對齊。對齊的計算方式是序列級別的編輯距離看模型需要多少步增刪改才能走到專家軌跡的路徑上。這個指標的好處是能區(qū)分兩種看似相同的結果一種是模型直接完成任務的路徑和專家路徑一致另一種是模型繞了一大圈、東錯西錯、最后碰巧完成。兩者的編輯距離差異非常大。前者才是我們想要的行為模式后者說明Agent決策質量還有很大問題。不過在實操中要小心一個點Agent任務通常有多條合理路徑專家軌跡不能只有一條。我現在的做法是每條評測任務預寫2到3條不同類型的合理路徑只要模型的軌跡和其中任何一條的編輯距離較小就認為該步行為合理。6. Agentic SFT和Agentic RAG訓練與檢索的分工邊界6.1 Agentic RAG是什么“Agentic RAG”最近被討論得很多簡單說就是讓模型自主決定何時檢索、檢索什么、從哪個來源檢索而不是像傳統(tǒng)RAG那樣在每條用戶請求前面都無腦做一次向量檢索。區(qū)別于傳統(tǒng)RAG的“固定流程”Agentic RAG是模型根據問題判斷“現在有沒有足夠信息來回答”沒有就去檢索檢索結果不夠再檢索一輪直到信息充足為止。我在實踐中的體會是Agentic RAG里的“Agentic決策”能力恰好就是Agentic SFT需要訓練的那部分能力。SFT負責把“在信息不足時主動檢索”這件事變成模型的固有能力RAG負責提供檢索的基礎設施和知識來源。6.2 SFT和RAG的同與不同能力底座與外部知識的邊界有人可能會覺得既然有了RAG模型不需要再通過SFT去學“事實知識”SFT就沒那么重要了。這個觀點對傳統(tǒng)RAG場景有一定道理但對Agent場景完全行不通。需要想清楚一個分工RAG解決的是“知識從哪里來”SFT解決的是“模型如何組織行動”。即使查詢都用RAG來做模型依然需要通過SFT學會“如何格式化一個檢索查詢”“如何判斷當前檢索結果是否足夠”“如何在檢索結果不足時換一種查詢思路”。這些行為模式不是RAG組件能給的而是模型自身需要具備的能力。我做過一個對比實驗在完全相同的RAG檢索鏈路下分別用普通SFT模型和Agentic SFT模型作為控制器前者的檢索行為非常僵化只會在固定的字段位置做一次檢索而后者的多輪檢索成功率有明顯提升。所以SFT和RAG不是替代關系而是底座和插槽的關系。SFT先把“會檢索”的能力訓練出來RAG再把這個能力接到真正的知識源上。6.3 組合使用時的訓練建議我在把SFT和RAG組合到同一個Agent系統(tǒng)里的時候有幾個心得。第一Agentic SFT訓練時不要脫離檢索工具去造數據。有些團隊為了簡化訓練把RAG檢索封裝成一個純文本輸入輸出的黑盒接口只在接口里塞一段檢索結果。這樣訓練出來的模型對“檢索結果可能不完整”“檢索結果需要二次加工”這類真實狀態(tài)缺乏感知。建議訓練數據里的工具返回內容盡量保留真實檢索系統(tǒng)可能產生的不完美狀態(tài)比如返回空結果、返回低相關片段、返回超時錯誤讓模型見到真實世界的噪聲。第二RAG的檢索策略本身也需要SFT數據來覆蓋。我的數據里專門有一類樣本觸發(fā)場景是“第一輪檢索結果太泛、沒有命中具體信息”期望模型的行為是“基于第一次的結果改寫檢索詞進行第二輪更精確的檢索”。這類行為模型靠提示詞也能寫出來但提示詞控制不穩(wěn)定的情況很多把它作為SFT訓練樣本的效果穩(wěn)定得多。第三注意控制“檢索過快”的行為。我在評測時發(fā)現經過Agentic SFT訓練的模型有一種傾向是太容易觸發(fā)RAG檢索什么都想查一下。原因很簡單訓練數據里檢索的密度太高了模型的先驗變成“看到任務就先檢索”。所以現在造數據時我會刻意加入一批“直接回答才是最優(yōu)策略”的樣本告訴模型有些問題是可以用自身知識直接回答的。7. 踩坑實錄四類典型翻車場景的排查鏈路7.1 翻車一SFT之后模型變“笨”了這是很多做Agent微調的人都會遇到的事通用能力跑到Agent能力然后模型在通用任務上明顯退步。我排查下來的原因有兩個方向。第一個方向是數據配比失衡。Agentic SFT數據量過大壓縮了通用數據的比例模型把所有容量都花在了擬合工具調用上把原先學會的推理、寫作、常識問答技巧沖淡了。解決思路是控制Agentic SFT訓練數據的配比上限并在訓練時混合一批高質量通用指令數據。我的做法是7比3的比例七成Agent軌跡數據、三成通用對話數據能壓住退化又不影響Agent能力的學習。第二個方向是學習率過高。Agent軌跡里工具調用格式是高度重復的高學習率會在極短的步數內把“工具調用”的模式刻進模型同時把其他能力全部覆蓋掉。把學習率降到5e-6甚至更低之后退化現象會明顯緩解。建議每次微調前先拿極小的驗證集跑一個50步的實驗觀察通用能力在訓練過程中的變化曲線再做全量訓練。7.2 翻車二工具調用格式像“家族遺傳病”一個讓我很頭疼的現象當訓練數據里的工具調用格式統(tǒng)一為“調用某個搜索API后將結果紋絲不動粘貼到回答中”時模型學到的是“工具調用就是為了照抄結果”。換了業(yè)務場景之后模型的格式完全混亂甚至在沒有任何工具定義的場景里也隨機輸出一段形似工具調用的文本。排查下來問題出在訓練數據缺乏“對工具結果做分析”的樣本。模型只見過“調用后原樣搬運結果”沒學過“調用之后結合自身理解重新組織答案”。解決方法是造數據時在同一批訓練集里增加一類樣本其目標行動是“閱讀工具返回結果后提煉關鍵信息忽略無關字段再整合生成回答”。這類數據能教會模型將工具當作信息來源而不是當作復制粘貼的對象。7.3 翻車三Loss在降評測不動懷疑人生有一段時間我的訓練loss曲線非常漂亮但評測集上的成功率一點沒變。后來我把模型在評測集上的輸出數據和訓練集數據做了一個序列相似度對比發(fā)現模型的高頻輸出軌跡和訓練集里的若干條軌跡高度雷同。這個現象的本質是模型把“高頻軌跡”背下來了而不是把“決策規(guī)則”學會了。尤其在數據量不多、軌跡模式單一的情況下模型很容易把訓練集里有代表性的一條軌跡當成標準答案背下來。于是換一個場景就崩。解決方法是擴充軌跡多樣性。造數據時同一個任務多寫幾條完全不同的合理路徑訓練時每條軌跡做參數隨機化讓相同語義的表達有不同的措辭。這些手段都能有效壓縮模型“背軌跡”的空間逼它抽象出通用的決策規(guī)則。7.4 翻車四多輪對話里的上下文污染Agent系統(tǒng)通常要維護多輪對話歷史。微調時如果沒有設計好跨輪樣本模型很容易被前幾輪會話里的工具調用歷史干擾導致行為漂移。我遇到的具體問題是第二輪的對話里模型不該去訪問一個只和第一輪相關的工具但它還是去了。因為訓練數據里很多樣本是從一條完整軌跡直接切出來的而切分后的第二條樣本的對話歷史里還殘留著第一輪的“大量工具調用痕跡”模型就把“看到工具就調用”的錯誤規(guī)則學回去了。解決方法是構造訓練樣本時明確區(qū)分“當前任務的目標工具集”和“歷史會話中已經用過的工具集”。我給每條樣本標注了哪些工具在當前輪次是可用的哪些是歷史遺留的不可用工具并刻意構造一些“歷史工具調用記錄和當前目標沖突”的場景。這樣模型才能在真實的多輪環(huán)境中學會正確判斷上下文邊界。8. 持續(xù)記錄的下一步方向目前這套Agentic SFT流程已經在我的兩個項目里跑通了效果穩(wěn)定但遠談不上終極方案。我還沒想明白但準備接下來重點實驗的問題還有幾個一個是“軌跡長度對泛化的影響”?,F有數據里決策步數大多在3到8步之間如果任務需要12步以上的長程決策模型表現依舊不穩(wěn)定。我在考慮是否要構造更長鏈條的數據但長軌跡不僅標注成本高訓練時也更容易被前面的決策錯誤帶偏需要單獨設計對“偏離修正”的監(jiān)督方式。另一個是“外部狀態(tài)是否應該作為模型輸入的一部分”。比如工具返回的實時數據、當前時間、用戶所在城市這些外部狀態(tài)變量在訓練數據里很多時候是缺位的真實部署時又必需。把外部狀態(tài)注入訓練樣本理論上能提升模型的泛化能力但具體以什么格式注入、注入哪些狀態(tài)、狀態(tài)缺失時怎么辦我還在摸索。還要想的是“如何讓SFT和強化學習階段配合得更好”。SFT訓練出來的Agent決策穩(wěn)定性直接影響后續(xù)RL階段的探索效率。目前我的思路是把SFT階段做“保守訓練”只教會模型做出正確決策的最低必要能力把更激進的探索空間留給RL。但這個邊界到底劃在哪里還需要更多實驗來驗證。這次關于Agentic SFT的記錄就先寫到這里。