以每秒 1000 個 Token 編輯檔案
像 GPT-4o 這類前沿模型在進行大規模編輯時往往表現不佳,常見問題包括倦怠、準確性不足,以及高延遲。
這是程式碼代理所顯現的一項弱點。
要精準編輯數百行程式碼往往需要多次模型調用,有時甚至會讓代理陷入無限迴圈。就連小而獨立的修改也常常充滿漏洞。
最糟的是,現有模型在進行大幅度編輯時速度緩慢,打斷了開發者的工作流。
我們針對完整檔案程式碼編輯任務的一個重要變體,訓練了專用模型,稱為fast apply。
複雜的程式碼修改可分為兩個階段:規劃與套用。
在 Cursor 中,規劃階段透過與強大先進模型互動的聊天介面進行。
將變更套用到目前檔案應該相當簡單,且立即生效。

我們的快速套用模型在效能上超越 GPT-4 與 GPT-4o,並在準確度/延遲權衡曲線上推進帕累托前緣。
透過一種為程式碼編輯量身打造的推測式解碼變體(稱為 speculative edits),我們在 70B 模型上達成 ~1000 tokens**(約 3500 字元/秒) 的速度。
這表示相較於以 Llama-3-70b 進行的標準推理,可獲得 約 13 倍 的提速;相較於我們先前部署的 GPT-4 推測式編輯,則約有 9 倍的提速。
預設情況下,我們會讓語言模型在目前檔案、對話歷程與目前程式碼區塊的條件下,產生完整重寫的檔案。
在這篇文章中,我們說明如何訓練與評估全新的模型。
我們解釋為何選擇重寫檔案而非使用差異(diff),以及試算式編輯如何帶來極大的速度提升。
評估提示式重寫
我們建立了一個包含約 450 次完整檔案編輯(檔案行數均少於 400 行)的評測資料集,並以 Claude-3 Opus 作為評分者,評估多個以提示驅動的模型之表現。
在數十個精選範例中,基於 Opus 的評分與我們評分的吻合度高於 GPT-4-Turbo 或 GPT-4o。

這些分數很可能偏向 Claude 模型的輸出。
不過,這些分數也與我們對各模型的質性評估相符。

我們推測 Claude 的優勢表現是後訓練所致。
Claude 模型在助理訊息中會輸出上千行程式碼(LOC),而 GPT-4 則會省略部分程式碼,並以 ... 或註解標示遺漏區段。
GPT-4 的表現不佳也可能是由於無關的變動所致。
GPT-4 會刪除被註解的程式碼與不必要的換行。
它傾向於「修正/清理」與當前任務無關的程式碼。
速度量測
我們將速度定義為:
這樣做的優點包括:
- 統一不同分詞器之間的速度
- 在不同提示/生成的 Token 長度下,以單一我們關注的數字呈現結果(而不是同時統計 TTFT 與生成速率(字元/秒))
- 提供生成速度的保守下限,因為延遲包含 TTFT。對於大多數分詞器與文本而言,一個 token 約為 3–4 個字元,因此將每秒字元數除以 4,可得到每秒 token 的下限。

若將 gpt-4-turbo 的推測式編輯帶來的加速一併計入:

Diff 模型
為什麼我們要讓模型重寫整個檔案,而不是提供差異(diff)建議?
我們發現語言模型在處理 diff 格式的編輯時表現不佳,可能有以下幾個原因:
用更少的 Token 思考 - 輸出上限越高,模型就能進行更多次前向傳遞來找到正確解法。
Diff 會迫使模型用更少的 Token 思考。
Diff 屬於分佈外資料 -
在前訓練階段,特別是在後訓練階段,模型更可能接觸過完整檔案的程式碼,而不是程式碼的 diff。
輸出行號 - 若 tokenizer 將一串數字(例如 123)視為單一標記,則必須在單一(通常是第一個)輸出標記上決定該 diff 的正確行號。
此外,模型在計數行號方面向來表現不佳。
受Aider的 diff 格式啟發,我們解決了行號對應的問題。
模型不採用標準的 diff 格式,而是將 diff 區塊作為搜尋/取代區塊提出:
diff
@@ ... @@
function binarySearch(arr, x) {
- let low = 0, high = arr.length - 1;
- while (low <= high) {
- let mid = Math.floor((low + high) / 2);
- if (arr[mid] === x) {
- return mid;
- }
- low += 1;
- }
- return -1;
+ let low = 0, high = arr.length - 1;
+ while (low <= high) {
+ let mid = Math.floor((low + high) / 2);
+ if (arr[mid] === x) {
+ return mid;
+ } else if (arr[mid] < x) {
+ low = mid + 1;
+ } else {
+ high = mid - 1;
+ }
+ }
+ return -1;
}我們將所有以 - 或 開頭的行,替換為以 + 或 開頭的行。
這些差異包含多餘的 - 與 + ,因此差異解析系統能在面對輕微的模型失誤時保持穩健。
多數模型無法產生精準的差異(diff),僅有 Claude Opus 例外。

訓練
claude-3-opus-diff 的 apply 模型比 gpt-4-turbo-spec 更快也更精準,但還是太慢。
無法在任何 Anthropic 的模型中實作 speculative edits,因此我們需要訓練並部署一個效能優異的自訂模型。
合成數據
我們一開始先提供少量「快速套用」提示,以及大量的 cmd-k 提示。

cmd-k 提示大致符合我們在快速套用時所需的資料。
它包含一則編輯指示,以及目前檔案中的程式碼選取範圍。
針對每個編輯指令,我們先讓 GPT-4 依據目前檔案產生聊天回應,再由語言模型「套用」這些變更。
我們利用一小組「真實」的套用輸入,來產生更多且更高品質的套用資料點。
最後,我們以 80/20 的比例將這些資料集串接在一起,作為微調用的資料。

模型訓練
我們訓練 DeepSeek Coder Instruct 與 Llama 3 系列模型。為了改進我們的微調資料集,我們:
- 我們對小型檔案進行降採樣,因為它們在我們的訓練集(<100 行程式碼,LOC)中比例過高。
- 我們會依檔名下采樣訓練樣本的數量。
- 我們會對未產生任何動作(no-op)的資料點進行降採樣。

我們發現,我們的最佳模型(llama-3-70b-ft)的表現幾乎追上 claude-3-opus-diff,並且優於 gpt-4-turbo 與 gpt-4o。

三個微調模型在評測中都勝過 gpt-4-turbo,但我們切身感受到微調版 deepseek-33b 與 llama-3-70b 之間的差異。
Llama-3-70b 的整體表現優於其他微調模型與 gpt-4-turbo。
其他微調模型仍不太實用,往往不如 GPT-4 有用。
試探性編輯
我們最大的成果來自我們自訂的推測式解碼演算法,稱為「speculative edits」。
它等同於整個檔案重寫,但速度最高可快 9 倍。
在程式碼編輯中,我們在任何時間點對草稿權杖(token)有強烈的先驗,因此可以使用確定性演算法來推測後續的權杖,而不需要倚賴草稿模型。
我們與Fireworks合作,部署我們具備強大推測式編輯支援的高速套用模型。
他們擁有出色的推理引擎,並為我們的自訂推測邏輯建置了完整的 API 支援。
這使得在 Llama-3 上透過推測式編輯獲得的效益比 GPT-4 更大,也就是說,相較於速度次快的模型,可達到 4–5 倍的加速。

未來展望
長上下文訓練 - 我們正在開發長上下文訓練,可重寫最長達 2500 行的檔案。
對 RoPE 位置 ID 採用單純的線性擴展效果不佳——目前社群對 Llama 3 70B 的長上下文微調也同樣如此。
知識蒸餾 - 我們也希望把現有模型的「快速套用」能力蒸餾到更小的模型,特別是 llama-3-8b。
處理較大型檔案時,較小模型所帶來的更低延遲會更為關鍵。
更高的準確度-利用新推出模型的資料進行某種形式的 on-policy 強化學習(RL),可望帶來額外的效能提升。
除了在聊天中的實用性外,fast-apply 也是打造更進階程式碼生成系統的關鍵基石。
隨著模型在推理與規劃上的能力提升,低延遲的套用將帶來愈來愈多的效益!
如果你還沒試過,建議在 Cursor 裡體驗這個功能!這是一個小小的
例子,體現了我們在產品上所做的打磨與深度。
這篇部落格文章大致體現了我們在 Anysphere 進行的應用研究。
我們打造針對特定應用的推論加速(如推測式編輯)、訓練並評估特定任務的模型,並將這些成果打包成實用功能交付給使用者。
我們正在招募研究工程師與軟體工程師!你可以在此處進一步了解 Anysphere。