介紹 SWE-Check:偵測錯誤速度快 10 倍

在專門訓練的任務上,較小型的專用模型能以極低的成本和延遲,達到與頂尖通用模型匹敵的表現。

我們與 Applied Compute 合作,透過協作進行強化學習(RL)訓練來驗證這一觀點,目標是訓練出一個錯誤偵測模型。成果便是 SWE-check,它在內部同分佈評估(in-distribution evals)上達到了頂尖水準(與 Opus 4.6 的 F1 分數差距從 0.09 縮小至 0),並在異分佈評估(out-of-distribution evals)上取得了顯著進展(與 Opus 4.6 的 F1 分數差距從 0.49 縮小至 0.29)。

雖然在純粹能力方面,SWE-check 在異分佈評估上仍落後於頂尖模型,但其快上一個數量級的實際運行時間和更低的推論成本,使其能提供頂尖模型無法實現的即時且免費的錯誤偵測體驗。我們將持續改進此模型,並預期透過優化數據生成流程,能進一步縮小在異分佈評估上與頂尖表現的差距。SWE-check 的預覽版現已於 Windsurf Next 中開放使用,並將很快發布至主流版本的 Windsurf 中。

以下是我們的實作方法:

  • 在強化學習(RL)期間與生產環境原生整合
  • 使用我們稱為獎勵線性化(reward linearization)的新技術,將我們期望的全域指標轉換為樣本級別的獎勵
  • 引入多個階段的後訓練(post-training),以構建出既具備能力又符合產品使用模式的模型

SWE-check 智能體及其需求

SWE-check 智能體會分析當前的代碼差異(diff),並標記出任何可能由該變更引入的錯誤。

SWE-check 分析代碼差異的示意圖
一個新的配置標誌無聲地將輸出值從時間戳記切換為歸一化分數。每個變更的檔案在內部是一致的,但發現問題需要追蹤三個檔案間的數據契約,以找出假設出現分歧之處。

這不是典型的代碼分析任務;與在聊天介面中運作的一般編碼智能體不同,SWE-check 智能體會產生結構化的輸出,包含錯誤描述和修復方案,並能在 Windsurf 中美觀地呈現。

以下是來自我們訓練數據集的一個真實錯誤(ground truth bug)範例,讓您了解模型所接受訓練的任務類型:

存儲庫:block/goose

提交:cd0b7d69

修復追溯至此提交的錯誤之 PR(s): #5066

錯誤 1:併發與執行緒 - 高嚴重性(2 處變更)

  • 描述: 代碼在持有 extensions mutex guard 的情況下,遍歷由 self.extensions.lock().await.keys() 返回的 keys 視圖。迴圈主體隨後調用 read_resource_from_extension,該調用本身可能會嘗試鎖定同一個 self.extensions mutex。在導致重新鎖定嘗試的 await 操作中持有 mutex guard 會導致死結(deadlock),因為在請求重新鎖定之前原始 guard 並未被釋放。這表現為擴展管理器在嘗試從擴展讀取資源時掛起。
  • 修復: 在遍歷並 await 進入特定於擴展的邏輯之前,代碼現在會先克隆 keys 將擴展名稱收集到一個擁有的 Vec<String> 中,然後立即釋放鎖。隨後的遍歷在收集的命名上進行(不持有 mutex),並引用每個名稱調用 read_resource_from_extension。這防止了在 await 期間持有 extensions mutex,並消除了導致死結的重新進入鎖定嘗試。此外,還在收集操作上方添加了一條簡短的解釋性註釋,以記錄原因。
  • 真實錯誤修復:
錯誤修復的代碼對比圖

在訓練期間,模型從一個沙箱環境開始,存儲庫已檢出(checkout)到來源提交版本,其工作是輸出它識別出的錯誤及其描述和修復方案。這些錯誤會與該來源提交的真實錯誤進行比對。

此外,智能體還需要近乎即時地運作,讓用戶保持在心流(flow)狀態,不惜一切代價避免我們所稱的「半同步死亡之谷」。幸運的是,像 Cerebras 這樣的推論供應商允許在幾秒鐘內完成數千個 token 的密集中間思考,然後才輸出最終結果。

與此同時,模型必須具備極高的品質,既能可靠地找出細微的錯誤,又不會用愚蠢的假錯誤困擾用戶。在決定進行 RL 訓練之前,我們曾請同事在 SWE-check 框架中試用各種現成的頂尖模型(包括開源和閉源)。他們發現,符合品質標準的頂尖模型對於 IDE 中的按需錯誤偵測來說太慢且太昂貴。這促使我們對開源模型進行 RL 訓練,使其在該任務上變得極度專業化——既快速又強大。

我們進行了兩項主要評估:

  • 分佈內評估(in-distribution eval): 從我們數據管道生成的任務中隨機抽取的子集,與構成訓練分佈的其他任務隔離。
  • 分佈外評估(out-of-distribution eval): 在 Cognition 代碼庫內部收集的錯誤集合,在整個訓練過程中完全隔離。

以下是最終訓練完成的模型與頂尖閉源及開源模型的表現比較:

模型性能比較圖表

使用生產環境設置進行訓練

一個更小、更快、更便宜的專用模型,可以在其「專長」(即其專業領域)上達到頂尖表現。為了在我們選擇的 SWE-check 任務的所有三個軸向上提供最佳結果,我們必須複製模型在生產環境中服務的實際環境。這能確保在訓練中觀察到的任何增益都能直接轉化為 Windsurf IDE 中終端用戶體驗的提升。

為此,我們在訓練沙箱中複製了 Windsurf 框架中可用的工具集。我們還精心策劃了一個涵蓋多種編程語言的多樣化錯誤數據集,並共同迭代該數據集,以確保其分佈能代表生產環境中的預期情況。

我們還花了大量精力使訓練獎勵與用戶在 SWE-check 智能體早期版本試用期間的行為保持一致。例如,我們分析了用戶在調用 SWE-check 後切換離開所需的時間統計數據(更多細節見下一節)。

最後,也是我們認為最重要的一點,我們迭代訓練了多個模型,並與試用反饋建立了緊密的回饋迴路。雖然我們投入了大量精力針對獎勵函數訓練模型,但最終,人類的直覺判斷以及智能體在實際工作中的使用感受才是最關鍵的。試用該智能體的人員為每一次迭代提供了極其寶貴的反饋。

例如,在其中一次迭代中,我們收到反饋稱模型會不斷報告錯誤,而实际上,如果它只是查找代碼塊中某個變量的定義,就會知道該代碼塊是正確的。我們意識到智能體缺乏高效的追蹤工具來幫助它查找定義和引用,因此我們在 Windsurf 以及訓練環境中構建並公開了這些新工具,然後重新訓練。

專業化過程的關鍵在於,來自生產環境的反饋直接推動了訓練運行的迭代。所有進入模型訓練運行過程的因素,其根源都可追溯到生產環境的某些方面或來自真實用戶的反饋。

我們如何設計獎勵函數

後訓練(post-training)中使用的獎勵決定了模型的行為。我們的技術報告重點關注兩個關鍵概念:

  • 獎勵線性化(Reward linearization): 提供樣本級別的獎勵,作為群體層面統計數據爬坡(hill-climbing)的代理。我們採用一個代表用戶偏好的全域指標,並將其轉換為可分配給每個獨立樣本的回報。
  • 兩階段後訓練(Two-phase post-training): 首先最大化能力,然後通過降低延遲使模型與產品使用模式保持一致。我們發現,將後訓練分為這兩個階段,比單純針對同時捕捉能力和使用模式的單一獎勵函數進行訓練,能產生更強大的模型。

獎勵線性化

我們首先形式化訓練設置。每個輪次(rollout)τ 都有其自己的一組真實錯誤(可能為 0)。我們按以下方式對一組預測錯誤進行評分:

  1. 我們首先使用簡單的 LLM 評判通道檢查錯誤是否範圍正確——如果列表中的任何錯誤實際上是兩個不同問題的混合體,我們將分數設為 0。
  2. 然後,我們檢查列表中的每個預測錯誤是否與其中一個真實錯誤匹配。
  3. 這些檢查的結果使我們能夠計算樣本級別的精確率(precision)和召回率(recall),我們將其定義為 P(τ)R(τ)。這些數字應始終介於 0 和 1 之間。我們按以下方式處理邊界情況:
    1. 如果沒有預測錯誤且沒有真實錯誤,我們將精確率和召回率設為 1
    2. 否則,如果預測錯誤列表和真實錯誤列表中恰好有一個為空,則將精確率和召回率設為 0

我們如何匯總多個樣本的分數?有兩種合理的方法:

  • 我們可以匯總全域的真陽性(TP)、假陽性(FP)和假陰性(FN)的總數,以計算全域精確率和召回率,然後將它們組合成一個 f_β 分數
  • 我們可以在樣本上平均 P(τ)R(τ) 以獲得平均精確率和平均召回率,然後將它們組合成一個 f_β 分數

由於我們不希望模型偏向於在那些有大量真實錯誤的範例上表現過好(而以在真實錯誤較少或沒有真實錯誤的範例上表現不佳為代價),我們選擇了第二種方法。

🚨 β 的選擇: 模型的早期迭代使用 β=1,產生了許多假陽性,在試用期間將許多良性差異標記為錯誤。為了緩解這種情況,我們決定切換到 β=0.5,強調精確率。

我們定義 R_pop = E_τ[R(τ)]P_pop = E_τ[P(τ)]。我們最終希望模型提高以下指標:

f_beta 公式圖示

給定這個全域指標,我們的樣本級別獎勵應該是什麼?一個關鍵的觀察是,我們不能直接使用:

錯誤的獎勵公式圖示

因為對 f_β(τ) 取平均值並不會得出 f_β。這激發了我們關於獎勵線性化的想法,即計算 f_β 關於 P_popR_pop 的一階近似值,這樣取平均值就能奏效了!

由於我們對 P_popR_pop 的初始值(稱這些初始值為 P_pop,initR_pop,init)以及 TP/FP/FN 率的初始分佈有很好的掌握,我們可以用 P_popR_pop 的合適一階線性近似來近似 f_β 值:

一階近似公式圖示
🚨 重要的是,一階近似必須意識到 TP/FP/FN 率的初始值。在我們的運行中,TP/FP/FN 率的變化並沒有在運行過程中大幅改變結果斜率,因此我們使用了固定的線性化;如果某些初始值偏差太大,我們的方法可以通過在訓練期間重新校準一階近似來推廣。

那麼,一個有效的樣本級別獎勵函數(因為它平均後等於上述期望的 f_β 近似值)將是:

最終獎勵函數公式圖示

事實上,我們可以轉換/縮放獎勵函數,因此我們可以強制 y=1 並移除所有常數項。在我們的情況下,我們最終使用的樣本級別獎勵是 reward(τ) = ½·P(τ) + R(τ)。一個為每個樣本接收 reward(τ) 獎勵的模型最終將爬上全域 f_β 指標,正如預期那樣!

兩階段後訓練

我們的目標是訓練一個具有頂尖表現但延遲情況更好的模型。我們發現,最有效的訓練方法是將過程分為兩個不同的階段。這兩個階段僅在獎勵函數上有所不同,其餘訓練設置完全相同。

  1. 能力最大化(Capability maximization): 獎勵函數是我們在獎勵線性化部分計算的基礎獎勵函數。通過提升此獎勵,模型專注於最大化錯誤偵測技能,而不會因增量延遲而受到懲罰。能力最大化構成了整體訓練過程的大部分。
  2. 產品對齊(Product alignment): 獎勵函數是基礎獎勵函數加上一個額外的「延遲懲罰」。為了計算延遲懲罰,我們首先使用完成 token 的數量和工具調用回合數來估計輪次的延遲。然後,我們觀察了用戶在調用 SWE-check 後切換離開所需時間的統計分佈,數據來自 SWE-check 智能體早期內部版本的試用數據。
用戶切換行為分佈圖

該分佈有效地代表了我們必須保持用戶處於心流狀態的時間量。然後我們計算了該分佈的累積分佈函數(CDF),並用它來定義一個隨估計延遲縮放的懲罰。給定時間 t 的 CDF 告訴我們到那時為止已經離開的用戶比例。

我們對懲罰進行了歸一化,使其在即時響應時從 0 開始,在尾部為 1,然後在桶中點之間進行線性插值。

延遲懲罰曲線圖

產品對齊獎勵推動模型去除冗餘 token 並改進並行工具調用,同時不為了延遲而犧牲超出用戶體驗所需的性能。就訓練計算量而言,產品對齊階段比能力最大化階段短得多。

這種兩階段方法優於從一開始就使用單一的組合獎勵函數進行訓練的替代方案。當同時優化能力和產品約束時,模型傾向於收斂於局部最優解:例如,學會變得極快,但產生淺層分析,雖然滿足了延遲目標卻錯過了真正的錯誤。分開階段允許模型首先發展出對任務的真正理解,然後再學習如何高效地濃縮這種理解。

性能與延遲權衡圖

此外,在後訓練的第二階段,我們觀察到:

  • 起初,當延遲懲罰減少時,模型的性能下降極小;
  • 隨後,隨著延遲懲罰繼續減少,模型的性能開始出現更明顯的下降。

因此,第二個階段是一個可調節的旋鈕,我們可以用它來選擇最適合我們用例的性能 - 延遲配置文件。在我們的情況下,如前所述,我們根據產品使用模式選擇了帕累托前沿(Pareto frontier)上的這一點。

結論

總之,模型專業化是一種強大的工具,可以以更好的延遲、成本和用戶體驗配置文件來接近頂尖表現,並與產品功能深度對齊。

與框架原生整合確保了我們的訓練成果能在生產環境中反映出來。頻繁的試用試驗使我們能夠快速將用戶反饋轉化為訓練方案的變更。使用獎勵線性化使我們能夠有效地將生產性能指標濃縮為樣本級別以進行訓練。將後訓練分為多個階段使我們能夠在模型訓練中平衡兩個不同的目標——核心任務中的能力和產品延遲需求。

最終模型仍有意義上的改進空間——雖然它位於帕累托前沿,但在此任務上並非絕對最強大的模型。討論的訓練方案已被證明能在分佈內和分佈外評估上良好地爬坡,隨著更廣泛的數據混合和改進的基礎模型,我們預期性能會隨著時間持續提升。

您可以立即在 Windsurf Next 中試用 SWE-check 的預覽版,使用 cmd+U 快捷鍵。它很快將在 Windsurf 中正式推出。

相關文章推薦

分享網址
AINews·AI 新聞聚合平台
© 2026 AINews. All rights reserved.