2024年,訓練AI寫代碼的方法遇到了一個不算新鮮但一直沒解決好的問題。
你想讓一個模型學會像真正的程式設計師那樣幹活,那它就得在真實的軟體項目里摸爬滾打,遇到各種各樣的任務,還要有人告訴它做對了沒有。問題是,真實世界的任務從哪來?靠人一條條寫,太慢太貴;靠模型自己瞎編,又怕跟真實場景脫節。於是大家把主意打到了開源代碼託管平台上,那裡堆著幾百種編程語言寫成的海量項目,簡直是天然的題庫。
但這裡藏著一個別人沒太注意的限制。已有的方法基本上都得靠項目里留下的"痕跡"來出題:有人提的issue、別人寫的pull request、開發者留下的commit記錄,或者乾脆是項目自帶的文檔和測試用例。
這就好比你想給學生出一套編程練習題,但你規定自己只能從老師批改過的作業本里摘題目。那些從沒被人明確提出過bug、沒寫過文檔、沒配測試的功能,哪怕代碼本身寫得再漂亮、邏輯再複雜,你也沒法把它變成一道題。這不是代碼不夠多的問題,是能拿來出題的代碼,一直被這些"記錄"給卡住了脖子。
如果不解決這個限制,會發生什麼?意味著大量已經實現、已經跑通、已經在生產環境裡工作的功能代碼,永遠進不了訓練數據。就像圖書館裡有幾萬本書,但你規定只能把讀者寫過讀後感的書拿出來教學生閱讀,剩下的書哪怕內容再好,也只能爛在書架上。
來自小米大模型團隊等機構的研究者們,提出了一個叫CodeMidas的方案,思路挺直接:別管這段代碼有沒有issue、有沒有PR、有沒有人寫過文檔,只要它是能跑起來的代碼,就能變成一道訓練題。
代碼本身,就是唯一的原材料。
一、這件事到底難在哪
先說說傳統做法的具體樣子。像SWE-bench這類經典數據集,是從GitHub上抓取issue和對應的修復PR配對而成,模型要做的就是看著issue描述去寫出能讓相關測試通過的補丁。這類方法效果不錯,但天花板很明顯:只有那些認真寫了issue、認真提了PR的倉庫才能貢獻任務。
另一條路線是圍繞已有測試做文章,比如故意往正確代碼里注入bug,讓模型去修,這類方法(如SWE-smith)不需要issue,但仍然依賴項目已經寫好的測試用例作為"地基"。還有的方法利用函數文檔字符串反推需求描述。
這幾條路子有個共同的軟肋,那就是它們都在某個環節上依賴開發記錄*:指issue、PR、commit這類記錄軟體變更過程的文本或文件。
數據集的規模天然被這些記錄的覆蓋率鎖死了。論文裡做了一張對比表,列出了七八個同類方法各自還需要哪些輸入才能工作,結果一目了然:CodeMidas是表里唯一一個完全不需要issue、不需要PR、不需要commit、不需要已有測試、也不需要現成描述文字的方法,同時支持的編程語言數量也是最多的,達到23種。
這就好比考古學家發掘古代遺址,過去的做法是只挖那些地表上留有明顯標記(比如墓碑、界碑)的地方,CodeMidas相當於換了個思路:直接對整片土地做地質掃描,任何埋在地下的東西都有機會被發掘出來,不再依賴地表上有沒有人立過碑。
如果繼續依賴開發記錄,代價是顯而易見的:數據集規模永遠追不上開源世界代碼總量的增長速度,而且不同語言、不同類型的項目在issue和PR的豐富程度上天差地別,這會導致訓練數據在語言和領域上嚴重失衡。
二、CodeMidas怎麼把一段代碼變成一道題
整套流程分成四個階段,論文裡配了一張漏斗圖,從初篩的22575個候選任務,一路收窄到最後保留的5545個高質量任務,中間每一步都在做減法,把不可靠的題目篩掉。
**任務設計和代碼庫改造**
第一步,讓一個智能體(agent,也就是能自主執行多步操作的AI程序)去逛這個代碼庫,找那些有明確對外接口、行為可觀察的功能。可能是命令行工具,可能是純函數,也可能是有狀態的類庫API。找到候選功能後,agent會順藤摸瓜,把這個功能涉及的核心實現代碼整段刪掉,同時調整周圍代碼,讓剩下的部分依然能構成一個連貫的、待完成的項目起點,原來被刪掉的代碼則單獨保留,作為這道題的參考答案。
這個過程有點像把一台已經組裝好的機械鐘拆掉齒輪組,但錶盤、指針、外殼全部保留原樣,讓維修學徒照著錶盤上殘留的痕跡重新做一套能走時的齒輪。如果直接把整個項目都清空重來,題目就失去了真實代碼庫該有的複雜度和依賴關係,學徒練的就不是修鐘的本事,而是從零造鐘,這和真實工作場景是兩碼事。
**執行驅動的測試構造**
光有題目和答案還不夠,得有一把尺子來判斷學生做得對不對。CodeMidas這一步的做法是,讓agent把任務描述里提到的每一條行為要求,轉換成具體的測試用例,然後拿參考答案(也就是被刪掉的那段原始代碼)在沙箱裡真跑一遍,記錄下真實的輸出結果,作為這些測試用例的標準答案。
這裡有個細節處理得挺講究:如果任務描述里沒有明確規定某個細節(比如報錯資訊的具體措辭),測試就不會死板地要求輸出必須一字不差,只檢查那些真正被要求的行為,比如是不是拋出了正確類型的異常。agent還會反過來審查每一條測試斷言,把那些依賴內部實現細節、和任務描述無關的過度限制找出來並替換掉。
這一步的意義在於區分"必須做對的事"和"做法不重要的事"。就像批改一篇命題作文,你不能因為學生用了跟範文不一樣的開頭句式就判他跑題,你只該檢查他有沒有覆蓋題目要求的核心論點。如果測試寫得太死,會把很多用不同思路、但同樣正確的解法誤判為失敗,這樣的訓練信號是有毒的,會教壞模型。
**環境準備和執行一致性檢查**
準備好題目和測試後,還要確認這道題本身沒有邏輯漏洞。CodeMidas會在六個全新的容器里跑測試:兩個用空白(缺失核心功能)的代碼庫跑,必須全部失敗;四個用參考答案跑,必須全部通過。
這一步是在確認"這道題確實有解,而且缺了這塊代碼就真的做不出來"。類比一下,出考卷前老師自己先做一遍標準答案,確認能拿滿分,再故意空出那一欄交白卷試試,確認真的拿不到分,這樣才能保證考卷本身沒印錯題。
**滾動執行後過濾**
這是CodeMidas整套流程里最花心思的一環,因為前三步只能保證測試邏輯上沒問題,但沒法保證題目沒有"作弊漏洞"。這裡做了三件事:
第一,泄漏檢測。讓另一個agent專門去代碼庫里翻找,看能不能靠一些殘留的編譯產物、緩存文件、構建過程中留下的痕跡,不做真正的開發工作就把答案套出來。這就好比考試前監考老師專門去搜查考場,看有沒有小抄藏在桌肚裡,發現了就直接取消這道題的資格。
第二,答案審核。讓一個agent實際去解四遍這道題,再讓另一個審核agent對照任務要求、參考答案和測試判定結果,檢查有沒有"明明做對了卻被測試判錯"(假陰性)或者"明明做錯了卻被測試判對"(假陽性)的情況,一旦發現測試本身有缺陷,這道題就被剔除。
第三,通過率篩選。用一個前沿模型對每道題多次嘗試,如果全部嘗試都通過,或者全部失敗,這道題就會被拿掉,因為這兩種極端情況說明不了任務本身到底有沒有問題,可能是題目太簡單/太難,也可能是測試有暗病,留著這種題對訓練沒有區分度。
經過這一整套流水線,最開始掃描出來的22575個候選任務,一路篩到只剩5545個,淘汰率超過75%。這個數字本身就說明了一件事:從代碼里自動挖題,"能挖出來"和"挖得可靠"完全是兩回事,大部分初篩結果其實是帶毛病的。
三、5545道題都長什麼樣
這批最終留下的任務,來自3185個不同的開源代碼庫,覆蓋23種編程語言,橫跨15個技術領域。
語言分布上,Python占21.4%,TypeScript占18.3%,Go占16.2%,加上C++和JavaScript,前五種語言就占了將近八成的任務量,不過剩下的18種語言裡也有C、Java、Rust、Ruby、Kotlin等主流語言,覆蓋面相當寬。
技術領域方面,系統軟體類任務占比最高,達17.4%,其次是Web技術14.6%,開發者工具13.6%,這三塊合起來接近一半。此外還有AI/ML、數據科學、多媒體、區塊鏈、遊戲開發、安全、硬體、移動開發等多個領域都有覆蓋。
參考答案*:指CodeMidas在刪除代碼前保留下來、能讓測試全部通過的原始實現,相當於這道題的標準答案。
參考答案的代碼量中位數是142行,四分位區間在66到305行之間,超過六成的任務需要動兩個以上的源文件才能完成,這說明這批任務不是那種"填一行空"的玩具題,而是需要模型理解跨文件依賴關係的真實工程任務。
四、拿這批題練出來的模型,到底強在哪
研究團隊用這5545個任務,通過GRPO算法(一種強化學習訓練方法)對MiMo-V2.5模型做了訓練,然後在五個完全不相關的外部測試集上驗證效果。
GRPO*:Group Relative Policy Optimization的縮寫,一種強化學習訓練算法,通過比較同一批多次嘗試的相對得分來更新模型,不需要額外訓練一個評分模型。
結果相當亮眼,五個測試全部提升,而且提升幅度都不小。
| 測試集 | 訓練前得分 | 訓練後得分 | 提升幅度 | 考察方向 |
|---|---|---|---|---|
| SWE-bench Pro | 50.3% | **54.4%** | +4.1個百分點 | 長周期軟體工程任務 |
| DeepSWE | 10.0% | **21.7%** | +11.7個百分點 | 真實issue修復 |
| ProgramBench | 4.5 | **21.5** | +17.0個百分點 | 從零構建完整程序 |
| RepoZero C2Rust | 40.5% | **51.8%** | +11.3個百分點 | 代碼翻譯 |
| Terminal-Bench v2.1 | 63.7% | **72.2%** | +8.5個百分點 | 終端命令行操作 |
DeepSWE和ProgramBench的提升尤其值得說道說道。DeepSWE的分數幾乎翻倍,從10%直接跳到21.7%,這意味著原本每十個issue只能修好一個,訓練後能修好兩個多。ProgramBench考察的是讓模型從零重寫一個完整程序,這個任務比修bug難得多,提升幅度反而是五個測試里最大的,達到17個百分點。
值得琢磨的是,這五個測試集覆蓋的任務類型五花八門,issue修復、從零寫程序、代碼語言翻譯、命令行操作,彼此差異很大,但訓練效果都能遷移過去。這說明CodeMidas挖出來的任務,不是針對某一類狹窄場景的偏科訓練,而是真的鍛煉出了某種通用的編程能力。
五、任務數量和質量,哪個更重要
研究團隊做了一組對照實驗,專門回答一個問題:如果只看數量不看質量,會發生什麼?
他們準備了四組訓練數據:從高質量的5545個任務里隨機抽1000個、抽3000個,以及全部5545個,再額外準備一組約8000個任務,這組是初篩後但沒經過環境清理、執行一致性檢查、也沒經過後續過濾的"毛坯版"數據。
結果很說明問題。1000、3000、5545這三組高質量數據呈現清晰的遞增趨勢,在DeepSWE上的得分從17.57一路漲到19.05再到21.70,說明高質量數據是越多越好,沒有出現邊際效益遞減的明顯拐點。
但更值得關注的是那組8000個的毛坯版數據。即便任務數量比高質量的3000組還多,它在三個評測集上的表現卻全部低於經過清理篩選的3000組,在DeepSWE上更是被5545組高質量數據甩開了4.59個百分點。
| 訓練數據 | SWE-bench Pro | DeepSWE | CodeMidas Val |
|---|---|---|---|
| 高質量1k | 52.86 | 17.57 | 41.30 |
| 高質量3k | 54.02 | 19.05 | 43.22 |
| 高質量5k(全量) | **54.40** | **21.70** | **44.73** |
| 未清理8k | 53.81 | 17.11 | 40.24 |
這個結果推翻了一個直覺,很多人會覺得訓練數據"多多益善",哪怕帶點噪聲也無所謂,反正數據量大能稀釋掉。但這組實驗清楚地告訴我們:3000道精心把關的題目,效果能超過8000道良莠不齊的題目。
這就好比健身,與其每天花兩小時做一堆動作變形、姿勢不標準的訓練(哪怕訓練時長更長),不如花四十分鐘做幾個動作規範、真正刺激到目標肌群的訓練。數量堆上去了,但如果動作本身有偏差,練出來的可能是錯誤的發力習慣,反而不如少而精的訓練更有效果。這也反過來證明了CodeMidas那套繁瑣的過濾流程,泄漏檢測、答案審核、通過率篩選,不是可有可無的裝飾,是真正影響訓練效果的關鍵環節。
六、訓練過程中,AI的"行為習慣"發生了什麼變化
除了看最終分數,研究團隊還扒了訓練過程中模型解題行為的變化,這部分分析挺有意思,相當於給AI做了一次行為觀察。
他們盯了三個指標:代碼庫探索程度(編輯代碼前先讀了多少文件、搜索了多少次)、代碼打草稿的比例(寫進代碼的內容有多少是之前在推理過程里就構思過的)、以及自我驗證的多樣性(寫完代碼後執行了多少種不同的驗證命令)。
代碼探索*:指agent在動手修改代碼之前,通過讀文件、搜索關鍵詞等方式了解項目結構的行為,次數越多說明越謹慎、越不會瞎改。
數據顯示,訓練早期agent平均只做27.2次探索動作,訓練後期漲到40.1次;打草稿比例從0.358漲到0.629,幾乎翻倍;驗證命令的多樣性從2.03種漲到2.53種。三項指標全部同步上升,說明模型在強化學習的過程中,自己學會了"先想清楚再動手,動手後再檢查"這套更可靠的工作方式,而不是訓練前那種上手就改、改完就交的莽撞風格。
更有說服力的是,研究者還專門驗證了自我驗證行為和最終成功率之間的關係:在同一個任務、同一個訓練階段下,那些agent自己主動寫了檢查代碼並執行了的解答,平均通過率比沒做自我驗證的高出4.2個百分點。
這個發現最打動人的地方在於,這些行為變化不只出現在CodeMidas自家的測試集上,在完全沒見過的SWE-bench Pro、ProgramBench、Terminal-Bench上同樣能觀察到類似的探索增加、驗證增多的趨勢。這說明訓練學到的不只是"怎麼答對CodeMidas的題",而是更底層的解題習慣,這種習慣能跨場景遷移。
有一個細節挺值得琢磨:在ProgramBench上,探索次數從55.7漲到83.6,交互輪數卻從155.1降到了122.8,也就是說模型探索得更多了,但整體花的輪次反而更少了。這暗示模型學會了把力氣花在刀刃上,前期多看幾眼項目結構,能避免後面走彎路、反覆試錯,這和"磨刀不誤砍柴工"是同一個道理。
七、這套方法的邊界在哪
不過這裡也得說句實話,CodeMidas這套流程本身極其依賴agent的能力。無論是任務設計、測試構造,還是最後的泄漏檢測和答案審核,每一步都得靠另一個大模型來完成判斷,這意味著如果底層用來做數據構造的模型本身能力有限,那生成出來的題目質量也會打折扣,這套方法某種程度上是在用AI的能力去生產訓練AI的數據,存在一定的自舉依賴。
另外,論文裡提到最終保留的5545個任務,只占最初候選池22575個的24.6%,超過四分之三的候選題目在某個環節被剔除了。這說明"把任意一段代碼變成一道可靠的訓練題"這件事本身成本不低,雖然比人工出題省事很多,但也遠沒到"隨便拿一段代碼就能直接用"的地步。
Q&A
Q1:CodeMidas是什麼?
A:CodeMidas是一套自動化流程,只用源代碼作為輸入,就能把開源代碼庫里已經實現的功能變成可執行、可驗證的編程訓練任務,不需要依賴issue、PR、commit這類開發記錄。
Q2:CodeMidas構建的訓練數據集訓練出來的模型效果怎麼樣?
A:研究團隊用5545個CodeMidas任務訓練MiMo-V2.5模型後,在DeepSWE、ProgramBench、Terminal-Bench等五個外部測試集上全部取得提升,其中ProgramBench提升了17個百分點,DeepSWE幾乎翻倍。
Q3:CodeMidas的訓練數據是不是越多越好?
A:不完全是,實驗顯示3000個精心篩選過的高質量任務效果能超過8000個未經清理的任務,說明數據質量比單純堆數量更重要,但在保證質量的前提下,任務數量增加確實能帶來持續的性能提升。






