跳至主內容

以每秒 1000 個 Token 編輯檔案

作者: Aman Sanger 屬於 研究


像 GPT-4o 這類前沿模型在進行大規模編輯時往往表現不佳,常見問題包括倦怠、準確性不足,以及高延遲。

這是程式碼代理所顯現的一項弱點。
要精準編輯數百行程式碼往往需要多次模型調用,有時甚至會讓代理陷入無限迴圈。就連小而獨立的修改也常常充滿漏洞。

最糟的是,現有模型在進行大幅度編輯時速度緩慢,打斷了開發者的工作流。

我們針對完整檔案程式碼編輯任務的一個重要變體,訓練了專用模型,稱為fast apply

複雜的程式碼修改可分為兩個階段:規劃套用

在 Cursor 中,規劃階段透過與強大先進模型互動的聊天介面進行。
將變更套用到目前檔案應該相當簡單,且立即生效。

A toy example of a change we want to 'apply'. It cannot easily be copy/pasted since it sketches out the change over a full class

我們的快速套用模型在效能上超越 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。

The Priompt component for grading guidelines

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

Surpisingly, claude-3-sonnet outperforms gpt-4-turbo. And gpt-4o performs similarly to gpt-4-turbo.

我們推測 Claude 的優勢表現是後訓練所致。
Claude 模型在助理訊息中會輸出上千行程式碼(LOC),而 GPT-4 則會省略部分程式碼,並以 ... 或註解標示遺漏區段。

GPT-4 的表現不佳也可能是由於無關的變動所致。
GPT-4 會刪除被註解的程式碼與不必要的換行。
它傾向於「修正/清理」與當前任務無關的程式碼。

速度量測

我們將速度定義為:

速度=重寫字元數重寫延遲(秒)\text{速度} = \frac{\text{重寫字元數}}{\text{重寫延遲(秒)}}

這樣做的優點包括:

  1. 統一不同分詞器之間的速度
  2. 在不同提示/生成的 Token 長度下,以單一我們關注的數字呈現結果(而不是同時統計 TTFT 與生成速率(字元/秒))
  3. 提供生成速度的保守下限,因為延遲包含 TTFT。對於大多數分詞器與文本而言,一個 token 約為 3–4 個字元,因此將每秒字元數除以 4,可得到每秒 token 的下限。
Top and to the right is better. opus, sonnet, gpt-4o, and haiku are on the pareto frontier.

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

With speculative edits, gpt-4-turbo performs similarly to gpt-4o. Speculative edits are not yet possible with gpt-4o, otherwise gpt-4o-spec would be the speed frontrunner.

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 is Claude Opus prompted with a modified version of Aider's diff format. It beats gpt-4-turbo-spec on speed and accuracy. gpt-4o-diff is omitted from the graph as it achieves a median speed of 2476 char/s, but performs far worse than claude-3-haiku (4.18 avg eval score).

訓練

claude-3-opus-diff 的 apply 模型比 gpt-4-turbo-spec 更快也更精準,但還是太慢

無法在任何 Anthropic 的模型中實作 speculative edits,因此我們需要訓練並部署一個效能優異的自訂模型。

合成數據

我們一開始先提供少量「快速套用」提示,以及大量的 cmd-k 提示。

An example [cmd-k](/features#cmd-k) prompt and the corresponding generation. Cmd-k lets you instruct the model to make an edit in a selected region.

cmd-k 提示大致符合我們在快速套用時所需的資料。
它包含一則編輯指示,以及目前檔案中的程式碼選取範圍。

針對每個編輯指令,我們先讓 GPT-4 依據目前檔案產生聊天回應,再由語言模型「套用」這些變更。
我們利用一小組「真實」的套用輸入,來產生更多且更高品質的套用資料點。
最後,我們以 80/20 的比例將這些資料集串接在一起,作為微調用的資料。

Our data pipeline for generating the fast-apply finetuning dataset. The fully synthetic data is lower quality. For instance, in the example above, the selection range (which we throw away) is crucial for an accurate edit.

模型訓練

我們訓練 DeepSeek Coder Instruct 與 Llama 3 系列模型。為了改進我們的微調資料集,我們:

  1. 我們對小型檔案進行降採樣,因為它們在我們的訓練集(<100 行程式碼,LOC)中比例過高。
  2. 我們會依檔名下采樣訓練樣本的數量。
  3. 我們會對未產生任何動作(no-op)的資料點進行降採樣。

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

Llama-3-70b-ft outperforms gpt-4-turbo-spec in performance.

三個微調模型在評測中都勝過 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 倍的加速。

Speculative edits give our finetuned model a **massive** speedup.

未來展望

長上下文訓練 - 我們正在開發長上下文訓練,可重寫最長達 2500 行的檔案。
對 RoPE 位置 ID 採用單純的線性擴展效果不佳——目前社群對 Llama 3 70B 的長上下文微調也同樣如此。

知識蒸餾 - 我們也希望把現有模型的「快速套用」能力蒸餾到更小的模型,特別是 llama-3-8b。
處理較大型檔案時,較小模型所帶來的更低延遲會更為關鍵。

更高的準確度-利用新推出模型的資料進行某種形式的 on-policy 強化學習(RL),可望帶來額外的效能提升。

除了在聊天中的實用性外,fast-apply 也是打造更進階程式碼生成系統的關鍵基石。
隨著模型在推理與規劃上的能力提升,低延遲的套用將帶來愈來愈多的效益!

如果你還沒試過,建議在 Cursor 裡體驗這個功能!這是一個小小的
例子,體現了我們在產品上所做的打磨與深度。

這篇部落格文章大致體現了我們在 Anysphere 進行的應用研究。
我們打造針對特定應用的推論加速(如推測式編輯)、訓練並評估特定任務的模型,並將這些成果打包成實用功能交付給使用者。

我們正在招募研究工程師與軟體工程師!你可以在此處進一步了解 Anysphere。

歸類於: 研究

作者: Aman Sanger