Cursor:如何構(gòu)建 AI Coding 最佳實踐?
在AI編程的新時代,Cursor正以其創(chuàng)新的IDE平臺,重新定義代碼與開發(fā)者的互動方式。隨著LLM技術(shù)的進步,Cursor不僅在底層模型上進行了革命性的提升,更在UI/UX設(shè)計上不斷突破,為程序員提供了一個更為智能、高效的編程環(huán)境。本文深入探討了Cursor如何通過AI的力量,提升編程體驗,以及它對未來編程模式的深刻洞見。
AI coding 是模型推理能力增加之后的下一個競爭高地,除了模型廠商、AI Labs 之外,這個領(lǐng)域的參與者也有著 Cursor 這樣的初創(chuàng)團隊。作為一個 LLM-first IDE,Cursor 在今年迅速出圈,一方面在于底層模型 Claude Sonnet 3.5 模型 coding 能力提升帶來的體驗升級,另一方面也在于團隊在 AI Coding UI/UX 上的持續(xù)投入。
本篇內(nèi)容是 Lex 對 Cursor 團隊訪談的詳細整理,團隊創(chuàng)始成員 Aman Sanger (CEO)、Arvid Lunnemark(CTO)、Sualeh Asif(COO)和 Michael Truell(設(shè)計主管)詳細分享了 Cursor 產(chǎn)品體驗、infra、模型訓練、數(shù)據(jù)安全等細節(jié)以及他們對于 AI coding、AI Agent 的思考,通過這些分享也能了解 Cursor UI/UX 背后的理念。
? o1 不會干掉 Cursor,AI Coding 領(lǐng)域才剛剛開始;
? 圍繞代碼預(yù)測、補齊等各類任務(wù) Cursor 還訓練了一系列專門的小模型;
? Cursor 正在試驗一個叫做 Shadow Space 的產(chǎn)品概念,通過在后臺運行一個隱藏窗口讓 AI 在不影響到開發(fā)者的操作的情況下進行 coding 任務(wù);
? 團隊在 code base indexing 上投入了大量精力,這個 indexing 系統(tǒng)會成為接下來其他代碼任務(wù)可以展開的基礎(chǔ);
? 未來編程會是自然語言和代碼將共存,根據(jù)具體任務(wù)選擇最有效的交互;
? AI 正在重塑編程體驗,提高效率的同時保持程序員的創(chuàng)造力和控制力;
? Cursor 認為 Claude 3.5 Sonnet 的綜合實力更強,Sonnet 最強的地方在于能夠很好地理解開發(fā)者表述并不清晰的目標,預(yù)測程序員接下來的操作、給出適當建議;
? 即便是 SOTA 模型也不擅長找 bug,這會是 Cursor 的機會;
? 當前的代碼任務(wù)基準測試并不能準確反映模型的真實能力,因為現(xiàn)實中的代碼任務(wù)更加復雜多樣,并且充滿了模糊性和上下文依賴。Cursor 團隊更傾向于通過真實用戶的使用反饋來評估模型的性能;
? 目前還沒有人能很好地解決 models routing 問題,底座模型和自有模型之間可以初步實現(xiàn)模型切換,但如果是 GPT-4o、Claude sonnet 和 o1 之間的切換可能要更加復雜。
?? 目錄 ??
01 Cursor 的誕生
02 Cursor 的產(chǎn)品
03 Cursor 是如何提高產(chǎn)品響應(yīng)速度的
04 Priompt :以網(wǎng)頁為靈感的提示詞工程
05 Shadow Workspace:
Coding Agent 的工作流設(shè)計
06 SOTA 模型也不擅長找 bug
07 Code Indexing 和 Context
08 Scaling law 和復現(xiàn) o1 模型
一、Cursor 的誕生
Github Copilot 是第一個 LLM-driven 的消費級應(yīng)用
Lex:代碼編輯器這個領(lǐng)域整體是什么樣的?
Michael:代碼編輯器(code editor)主要用來開發(fā)軟件。對外行來說,可以把代碼編輯器想象成是一個專門給程序員設(shè)計的高級版的文字處理器。之所以說它是高級版,是因為代碼有不同結(jié)構(gòu),而代碼編輯器能做的事情比普通的文字處理器要多得多。
比如,代碼編輯器能讓我們直觀地區(qū)分代碼中不同的標記、快速瀏覽代碼、在代碼庫里快速瀏覽內(nèi)容,就像在網(wǎng)上點擊超鏈接一樣,快速跳轉(zhuǎn)到需要的定義;甚至還能檢查錯誤,幫助發(fā)現(xiàn)一些簡單的 bug。代碼編輯器主要的功能一般就是這些。但我認為,在接下來的 10 年里,由于軟件開發(fā)方式發(fā)生變化,代碼編輯器的概念也會發(fā)生很大的改變。
Lex:Cursor 是新一代代碼編輯器,flok 了VS Code 的一個分支。你們自己使用代碼編輯器的經(jīng)歷是什么樣的?
Aman:一開始我們都是用 Vim 做代碼編輯。當時還沒有 Neovim,只有 Vim 和一個終端。2021 年 Copilot 發(fā)布的時候,我很想體驗一下 Copilot,但由于 Copilot 只能在 VS Code 上使用,所以我就開始用 VS Code 了。Copilot 和 VS Code 這個組合的使用體驗特別好,所以即便我很喜歡 Vim,我還是轉(zhuǎn)向了 VS Code。在我們開發(fā) Cursor 之前,VS Code 都是我的默認編輯器。
Arvid:我覺得 GitHub Copilot 有一個被低估的方面是,即使它的代碼補齊出現(xiàn)了錯誤,但最多只是讓人覺得有點麻煩,我們再多打一個字符,它可能就懂我們的需求了,所以也不會太差。
Sualeh:其實就是通過“犯錯-糾正”的過程來迭代。Copilot 還有一個被低估的地方,它是第一個真正的 AI 產(chǎn)品,也是第一個 LLM-driven 的消費級產(chǎn)品。
Lex: Cursor 是怎么誕生的?
Michael:大概 2020 年的時候,OpenAI 提出了 Scaling Law,從那時候開始 LLM 領(lǐng)域的進步就變得清晰可預(yù)測,只要算力和數(shù)據(jù)夠多,模型表現(xiàn)就能更好,也是在那時候,開始有很多人討論“這項技術(shù)的進步能給我們帶來什么”,“它要怎么去改善各種不同的知識工作領(lǐng)域”等等。
有幾個時刻讓我感受到 scaling law 的預(yù)測變得越來越具體。第一個是 Copilot beta 版本推出,第二時刻是 GPT-4 發(fā)布的時候。
GPT-4 的提升讓我們看到 scaling laws 對于“算力-模型能力”的預(yù)測已經(jīng)可以落到具體的地方了,有可能很快就能開發(fā)出來更多有價值的東西。而且,如果我們繼續(xù)往下做,不僅能點對點地解決問題,甚至整個編程領(lǐng)域都可以用到這些模型,只不過需要我們搭載一個不一樣的編程環(huán)境,提供一種不同的編程方式。這就是為什么我們開始圍繞這個更大的 vision 去進行開發(fā)。
Sualeh:2022 年 6 月左右,Shengtong 和 Aman 打過一個賭,預(yù)測到 2024 年 6 月或 7 月,人們能不能靠模型能力拿到 IMO 金牌。雖然很確定模型能取得進步,但我當時的想法是模型贏得奧數(shù)金牌完全不可能,但 Aman 認為可以。
Aman:不過我還要補充一點,能取得多大進步,也取決于我們在哪個領(lǐng)域。數(shù)學就是一個很好的領(lǐng)域,尤其是形式化定理證明(formal theorem proving),因為我們能通過信號來驗證對不對,所以 RL 就能很好地起作用。不過,即便有的模型可以在數(shù)學能力上超越人類,但是我們還是沒有達到 AGI。
Cursor 是什么?
Lex:VS Code 可以說在某種程度上統(tǒng)一了開發(fā)者社區(qū),既然已經(jīng)可以在 VS Code 里安裝很多 Copilot 這樣的 AI extension,你們?yōu)槭裁催€要重新做一個 VS Code?
Michael:開發(fā)一個編輯器的想法其實是自然而然形成的。因為在開發(fā) Cursor 的時候,我們想的是,模型肯定還會變得更好,能力還會提高,不但能顯著提高生產(chǎn)力,也會從根本上改變現(xiàn)在我們開發(fā)軟件的方式。如果只是在現(xiàn)有的編輯器里加一個插件,對編輯器的控制提升是很有限,我們不像被這些限制束縛,希望能夠構(gòu)建最有用的東西。
Lex:VS Code 和 Copilot 的組合可以說是 Cursor 最直接的競爭對手,Cursor 要如何在競爭中獲勝?
Aman:如果我們回看之前的幾次科技浪潮,會發(fā)現(xiàn)它們的普遍特點是,有某一件大事發(fā)生,然后圍繞這個大事件一波新的公司開始出現(xiàn)。但現(xiàn)在不同的是,每年只要有一個模型的能力取得了飛躍,都會出來一波新的功能,有一波新的可能性。尤其是在代碼領(lǐng)域,甚至都不需要一年,只要領(lǐng)先幾個月,就可以讓我們的產(chǎn)品更有用。一年后我們再回過頭來看今天的 Cursor,會發(fā)現(xiàn)它也已經(jīng)過時了。Microsoft 確實做了很多非常出色的事情,但是從編程的角度上來說,我覺得他們不像別的初創(chuàng)公司一樣在一直創(chuàng)新。
Sualeh:我其實不會從功能的角度來考慮,我會從程序員的能力角度來看這個問題。o1 模型剛出來的時候,我就覺得肯定還會有很多不同的模型,比如更長的上下文、或者算力更快的模型。所有這些聽起來很瘋狂的想法都值得嘗試,最后大概能有 1/10 的想法可以真正做成比較有用的東西,我們希望它們推出的速度能更快。
還有一個被低估的事實是,我們其實是在給自己制作這個工具。我們之所以有 Cursor 這個想法也是因為我們能明確感受到模型能力的提升,但 Copilot 給我們帶來的體驗并沒有變得更好,也很疑惑為什么。當然,Copilot 賣得很好,對于 Microsoft 來說也是一個很成功的業(yè)務(wù),但相當長時間 Copilot 都沒有新東西出來,我個人來說會很想試試新的東西。
Arvid:我們是一整個團隊在開發(fā) Cursor,不管是開發(fā)用戶體驗,還是探索模型的交互方式,我們都在同步去開發(fā)怎么才能讓模型給出更好的答案,比如怎么構(gòu)建 prompt,怎么找到上下文,怎么用 Cursor Tab 訓模型等等。
二、Cursor 的產(chǎn)品
Cursor Tab
Lex:Cursor 的交互中, Tab 鍵是一個很獨特的存在,它可以看作是增強版的自動補全,幾乎什么都會??梢哉归_講講 Tab 鍵的邏輯的嗎?
Sualeh:我們很想要實現(xiàn)的一件事就是讓模型幫我們做代碼編輯。為此我們嘗試了很多種辦法,當我們有了能力很強的模型之后,為了讓使用體驗更加流暢,我們花了很大功夫提高了推理速度,優(yōu)化用戶體驗。
Tab 鍵存在的目標是,如果用戶接受了某一處編輯建議,模型應(yīng)該很自然地就知道下一個可能需要編輯的位置在哪里。比如說在我改動了一個地方之后,模型就應(yīng)該知道下一處要改動的地方需要跳轉(zhuǎn)到 18 行下面,而不是像 Vim 那樣需要用戶自己來按 18JJ 這樣的快捷鍵。
所以我們解決這個需求的方式就是 Tab 鍵。用戶只需要按下 Tab 鍵,模型就可以自動跳轉(zhuǎn)到第 18 行可能需要編輯的位置,顯示下一條編輯建議,再按一下 Tab 鍵,又會顯示下一條,可以這么一直按下去。
所以 Tab 背后的核心思想是:如何讓編輯過程的熵為 0。一旦用戶表達了他們的想法,模型應(yīng)該能夠推斷出接下來的編輯內(nèi)容,也就是說沒有新的信息需要用戶輸入。但現(xiàn)在用戶還是需要輸入一些字符,才能讓計算機理解他們的想法。理想情況下,模型應(yīng)該能夠“讀懂”用戶的想法,所有不需要新信息的編輯部分都應(yīng)該通過按 Tab 鍵來跳過。
Aman:如果我們觀察不同類型語言模型的 loss,會發(fā)現(xiàn)在代碼領(lǐng)域,比特每字節(jié)(bits per byte)的 loss 比語言領(lǐng)域要低。也就是說,在代碼領(lǐng)域,很多 token 和字符完全是可以預(yù)測的。所以除了自動補全以外,在預(yù)測用戶編輯代碼后的下一步操作時,這種可預(yù)測的現(xiàn)象會更明顯。
Cursor Tab 就是要消除編輯器中所有低熵的操作。一旦確定了用戶的操作步驟,就應(yīng)該直接跳過這些低熵的操作,讓用戶直接跳到下一處編輯點。
Lex:Cursor 是怎么做預(yù)測的?背后的技術(shù)細節(jié)是什么樣的?
Aman:首先,Cursor 的延遲很低。我們訓練了專門的小模型來解決這類任務(wù)。這些模型很依賴 pre-fill tokens,也就是說,這些模型面對的是非常長的 prompt,需要處理很多代碼行,但是實際生成的 token 并不多。這種情況下使用稀疏模型(Sparse Model)就很合適,這是一種 MoE 模型。這是我們做的一個突破,這個突破顯著提高了模型處理長上下文時的性能。
另一個關(guān)鍵點是我們基于推測解碼(Speculative Decoding)構(gòu)建了推測編輯(Speculative Edits)。
這兩個因素在我看來是 Cursor 生成質(zhì)量高、速度快的關(guān)鍵。
緩存在這里的作用很大,由于輸入的 token 非常多,如果每在一個給定行輸入,都要在 token 上重新運行模型,那么延遲會很高,GPU 也會因為過載而崩掉,所以就需要設(shè)計模型的 prompt,這樣它們就可以進行緩存。我們也會跨請求重用 KV Cache,這樣就減少了工作量和需要的算力。
Lex:除了代碼生產(chǎn)、代碼補齊、跨行編輯,以及在同一個文件內(nèi)的不同位置之間跳轉(zhuǎn)外,Cursor 的 Tab 鍵還能做哪些事情?
Sualeh:我們接下來想通過 Tab 鍵來實現(xiàn)在不同文件之間的跳轉(zhuǎn)。有可能用戶先編輯了某個文件,但是想要在另一個文件中繼續(xù)編輯,這樣的話 Tab 也應(yīng)該要能跳轉(zhuǎn)到另一個文件。
Arvid:這個過程可以概括成下一步動作預(yù)測(next action prediction)。比如有時候在終端運行命令,需要 Cursor 根據(jù)已經(jīng)寫好的代碼來推薦命令,它雖然能給出一些建議,但如果沒有更多的信息,用戶很難判斷到底對不對。所以,Tab 就可以引導用戶先跳轉(zhuǎn)到定義,了解了定義知識以后再跳轉(zhuǎn)回來,這樣用戶就知道了這個概念,愿意接受下一處補全。
Michael:Coding 是一個很獨特的領(lǐng)域。很多時候,在編程中其實是可以根據(jù)用戶前面的工作來預(yù)測接下來 5 分鐘他們想要做什么的。
所以我們可能可以發(fā)展到這樣一個狀態(tài):在人類開發(fā)者已經(jīng)做了一些工作之后,接下來要么讓 Cursor 幫忙接管接下來 5 分鐘的任務(wù),對于人類員工來說,只需要稍微看一下 Cursor 的步驟,發(fā)現(xiàn)它完成得很不錯,再在屏幕上點擊 Cursor 做出的改動就可以了。
Code diff
Lex:Cursor diff 會通過紅綠對比來告訴我們怎么修改代碼,在聊天窗里也可以查看并且接受 diff。diff 的設(shè)計邏輯是什么樣的?
Sualeh:我們總共有四到五種不同的 diff 視圖,比如我們就為自動補全優(yōu)化了專門的 diff 視圖,這個 diff 界面和審查大塊代碼時的 diff 界面是不一樣的。針對處理多個不同文件的情況,我們也在優(yōu)化響應(yīng)的 diff 視圖。
從 high-level 角度,自動補全會要求更快的閱讀速度,程序員的視線需要集中在一個特定區(qū)域,不能關(guān)注到太多地方,避免注意力分散,所以我們做這個任務(wù)的 diff 的時候會優(yōu)先考慮這個問題。
現(xiàn)在自動補齊的 diff 界面中,除了代碼寫作框外,如果我們想要刪掉某個位置的代碼,添加另一個代碼,它會在旁邊獨立顯示一個框。
我們圍繞代碼補齊做過三、四種不同的 diff 界面。最初是類似于 Google Doc 的刪除線的形態(tài),還嘗試過紅色高亮塊等等形態(tài),最終選定了這個方案。下一版迭代會更有趣。首先會有一個藍色高亮來突出 AI 給出建議的位置,但具體的建議內(nèi)容不會直接顯示出來,用戶可以通過按住 Option 鍵的方式來查看 AI 的建議到底是什么,如果松開 Option 就又會回到原始代碼界面。
Arvid:我個人很期待接下來可以圍繞 diff 做出很多改進和優(yōu)化。diff 涉及的場景通常是代碼審查里面的驗證難題,diffs 很適合小范圍的代碼改動,但如果代碼改動的范圍比較大,或者涉及到多個文件,要來回審查這些 diff 其實就有點難了。
關(guān)于這一點,我們其實也有幾種解決思路:
其中一個想法是,在比較大規(guī)模的代碼改動中,有些 diff 的信息量很大,很重要,而有些 diff 只是一樣的信息來回重復,也就是說它們的熵很低。所以我們就把重要的那些 diff 高亮,不重要的標成灰色。
另一種思路是,我們可以有一個模型來對這些 diff 進行審查對比,如果找到某個地方有 bug 的話,就用紅色波浪線劃出來,讓用戶重新審查這里的 diff。
這些想法都讓我覺得在產(chǎn)品體驗上我們還有很多事情值得做。
Lex:這些產(chǎn)品思路最終想達到的目標是讓人類工程師在代碼編輯和審查中只關(guān)注他們最需要閱讀的內(nèi)容,從而達到最佳效果?
Arvid:我們也考慮過設(shè)計一個模型來做這件事,現(xiàn)在 diff 環(huán)節(jié)的算法只是普通的算法,沒有特別智能。雖然我們在設(shè)計這套算法的時候?qū)⑷祟惖闹悄苋谌肓诉M去,但在實際執(zhí)行中,算法并不會關(guān)心處理的具體任務(wù)是什么,而這正是我們希望模型能做到的事情。
Sualeh:問題就在于,這些模型會越來越聰明,如果模型越來越聰明,它們能提出的代碼改動的內(nèi)容和范圍也會越來越大。如果改動越來越大,程序員就要做越來越多的代碼審查工作,而 Cursor 就可以幫他們做這個,這樣他們就不需要花大把的時間來做代碼審查。
Lex:涉及到多個文件的代碼審查時,diff 又是怎么設(shè)計和實現(xiàn)的?
Aman:就像 Arvid 剛才說的,我們可以把人從代碼審查中解放出來。現(xiàn)在,我們要花很長時間去理解陌生的代碼,而且它找出的 bug 往往非常多。但是使用 LLM 就可以很大程度上提高審查的體驗,比方說,Arvid 剛剛說的那些想法就可以引導用戶關(guān)注真正重要的地方。
代碼審查的用戶體驗設(shè)計通常要考慮到 reviewer 和寫代碼的人兩類角色,但如果寫代碼的是 LLM 的話,我們就可以不用考慮代碼編寫的具體體驗了,從而可以更多去圍繞 reviewer 來設(shè)計整個產(chǎn)品體驗,從而讓 reviewer 可以輕松高效地完成任務(wù)。
我覺得只是關(guān)注代碼審查環(huán)節(jié)本身的話并不能真正解決問題,我們在產(chǎn)品設(shè)計中可以更有創(chuàng)意,去探索可能性的邊界。
Arvid:我覺得需要指出來的一點是,順序也很關(guān)鍵(ordering matters)。一般來說,在審查時我們會先看到一串文件列表,然后習慣性地從上往下看。但實際上,有些內(nèi)容因為邏輯上是基礎(chǔ)的,應(yīng)該最先理解這部分內(nèi)容,之后才是其他部分信息。這種梳理順序的工作就可以交給模型,讓模型來引導我們?nèi)フ业叫畔⑦壿嬳樞颍賮硗瓿蓪彶椤?/p>
Lex:未來代碼的創(chuàng)作過程是不是會越來越多地使用自然語言?變得像寫書一樣。
Arvid:有時候會用到自然語言,但不是所有的編程任務(wù)都會用到自然語言。比如,如果我和 Sualeh 一起編程,Sualeh 可能坐在電腦前敲鍵盤,而我在開車,那我會告訴 Sualeh 要怎么去做。但也有些有時候,要給 Sualeh 解釋清楚要做什么很麻煩,那我就會直接接過鍵盤,給他演示一下要怎么做,我只需要寫一部分代碼,他就懂了,這種溝通方式很簡單直接。對 AI 來說也是這樣的。有時候最簡單的溝通方式就是給 AI 一個例子,這樣它就會繼續(xù)往下做完這個任務(wù)。
或者,如果我們要設(shè)計網(wǎng)站,最簡單的辦法并不是告訴 AI 我想要的是什么,而是直接拖動、繪制頁面,給它展示應(yīng)該怎么做。可能到最后我們也會通過腦機接口讓 AI 理解我們的想法,到那時自然語言一定會有一席之地,但是我覺得大多數(shù)時候,自然語言不會是大多數(shù)人寫代碼的方式。
底層模型
Lex: Cursor 背后的模型是什么?
Aman:除了調(diào)用最新一代模型能力之外,Cursor 自己也訓練了一些自定義模型(custom models),這些模型會配合那些在復雜推理任務(wù)上表現(xiàn)更好的頭部模型,共同完成任務(wù)。
Cursor Tab 就是一個很好的例子,在 Cursor Tab 的需求下,我們訓練了一個針對這個特定任務(wù)的模型,最新一代特定模型在特定任務(wù)上的表現(xiàn)甚至超過前沿模型,這一點從評估結(jié)果就能看出來。
另一個需要特定任務(wù)模型的是 Apply,在 Apply 任務(wù)中,自定義模型不僅很有必要,而且效果也很好。雖然頭部模型很擅長做代碼規(guī)劃、生成大致的修改框架,但是它們不能很好地顯示 diff。
無論是 Sonnet 還是 o1,這些模型都會在一些簡單的細節(jié)上出錯,比如數(shù)代碼行,尤其是在處理超大文件時,這類問題會更普遍。為了解決這個問題,我們就讓模型先勾勒出一個大致的代碼塊,用來表示需要修改的內(nèi)容,然后再訓一個模型把更改 Apply 到文件中。
我們也還在探索怎么把 o1 模型的能力嵌入到產(chǎn)品體驗里,我覺得如何目前就 o1 的最佳實踐還沒有定論,但比較明確的方向是,它可以讓我們更容易地在后臺處理一些任務(wù)、agent 的屬性更強。
Aman:o1 也有一些明顯的限制,先拋開能力本身,它不支持流式輸出這一點就很影響體驗。o1 目前的狀態(tài)更像是一個 V0 版本,還有很多需要改進的方面。
Lex:有消息說 GitHub Copilot 可能會以某種方式整合 o1 模型的能力,也因此會有人說“Cursor 完了”,你們怎么看這件事?
Michael:我認為這個領(lǐng)域與過去 2010 年左右的軟件領(lǐng)域有些不同,因為這里的上限真的非常高。我認為再等 3-4 年,到那個時候最好的 AI 編程產(chǎn)品可能比現(xiàn)在的要實用得多。就當下說只要能打造出更好的產(chǎn)品,就有機會超越那些擁有大量用戶的競爭者。因此,我認為接下來的幾年關(guān)鍵在于打造最好的產(chǎn)品和系統(tǒng),不僅包括模型引擎的改進,還包括優(yōu)化代碼編輯體驗。
Aman:Cursor 相比其他產(chǎn)品對于用戶的附加值不僅僅在于能快速整合 o1 這樣的新模型,它的價值還來自于我們針對各種類型任務(wù)開發(fā)的專有模型,這些模型可能在用戶不知情的情況下默默發(fā)揮作用,并且每個功能都是圍繞用戶體驗精心設(shè)計的。
Lex:在你們的實踐經(jīng)驗中,GPT 和 Claude 對比,誰的代碼能力更強?不過由于 Cursor 各個環(huán)節(jié)涉及到的模型不同,答案可能不是絕對的?
Aman:沒有哪個模型能在所有方面的表現(xiàn)都比其他模型更好,包括速度、代碼編輯能力、處理大量代碼的能力、上下文長度和代碼能力等等。不過,就目前來看,我覺得整體上表現(xiàn)最好的模型是 Sonnet,這也是大家的共識。
o1 確實很有意思,它很擅長推理,如果給它一些非常難的編程面試題問題或者 LeetCode 題目,它可以處理得很好,但是它不像 Sonnet 那樣能很好地理解到用戶的模糊需求。
至于其他的頭部模型,我并不是想說它們是針對基準測試訓練出來的,但確實存在一個顧慮是,和中腰部水平模型相比,它們在基準測試中表現(xiàn)很出色,但一旦涉及到超出這些范圍的任務(wù),這些模型的表現(xiàn)就會下降。
但當我們的任務(wù)范圍超出基準測試時,Sonnet 是最能保持其原有能力的模型,它在基準測試中展現(xiàn)的能力和在實際代碼任務(wù)中的表現(xiàn)是保持一致的。
Lex:前面提到的 Apply 這個功能可以查看代碼,提出很好的建議,告訴我們接下來怎么做。對我們來說,把這兩個模型結(jié)合起來好像也不難,為什么你們覺得并不簡單?
Sualeh:和大家的猜測相反,Apply 的實現(xiàn)并沒有采用確定性算法(deterministic algorithm)。
Aman:人們在其他代碼產(chǎn)品那里看到的 Apply 其實都是對 Cursor Apply 的簡單模仿,可能很多人覺得 Apply 是可以通過確定性匹配的方式來實現(xiàn),但這種方式下有 40% 的概率都會出錯,產(chǎn)品體驗也會很差。
我們在設(shè)計 Apply 的時候還能最智能的模型在生成代碼時,使用較少的 token,從而降低延遲和成本。我們可以給出一個非常粗略的代碼,讓模型去跑,因為跑通這個框架的代碼對模型來說很簡單。
這樣的形式還可以繼續(xù)下去??梢杂迷絹碓街悄艿哪P蛠碜鲆?guī)劃,然后讓不那么智能的模型來跑。比如我們可以用 o1 或者更智能的模型來做更 high-level 的規(guī)劃,再先后讓 Sauna 和 Apply 來處理。圍繞“如何讓 Cursor 反應(yīng)更快”也有很多細節(jié)在里面。
三、Cursor 是如何提高產(chǎn)品響應(yīng)速度的
Lex:你們是怎么提高 Cursor 響應(yīng)速度的?
Aman:其中一個重要組成就是推測編輯(speculative edits),這是從推測解碼(speculative decoding)中衍生出來的。
可以先解釋一下推測解碼是什么。大部分情況下,尤其是在 LLM 生成受內(nèi)存限制的情況下,并行處理 tokens 比逐個生成 tokens 更快。如果查看每秒生成的 tokens 數(shù)量,會發(fā)現(xiàn)處理 prompt tokens 的速度比逐個生成 tokens 要快得多。推測解碼可以通過并行處理提高模型速度。
傳統(tǒng)的推測解碼是用一個很小的模型來預(yù)測 draft tokens,然后用更大的模型來做驗證。但因為預(yù)測的 code 實際就是已有的 code 本身,而我們已經(jīng)很熟悉這些 code,所以可以直接把原始的 code 片段輸入到模型中,讓模型去驗證代碼相不相符。絕大多數(shù)情況下,模型會認為這些 code 片段是正確的,并且直接原樣輸出。
這樣,我們可以并行處理足夠多的代碼行,直到模型預(yù)測的文本與原始 code 出現(xiàn)不一致的地方。這時,模型會生成新的 token,我們則根據(jù) code 的匹配程度判斷什么時候重新開始檢測代碼塊。
最終呈現(xiàn)出來的效果就像是加速版的代碼編輯,看起來就像是模型在以更快的速度重寫所有 code。所以我們就可以用和 diff 一樣的界面,只不過數(shù)據(jù)傳輸?shù)男矢摺?/p>
Sualeh:這樣設(shè)計的好處是,我們可以在數(shù)據(jù)傳輸?shù)臅r候就開始做代碼審查而不是等到全部加載完才開始整個過程。這個設(shè)計很有意思,但其實 speculation 這個路徑現(xiàn)在已經(jīng)很常見了,不僅僅是 LLM,CPU 和數(shù)據(jù)庫實踐中都有用到 speculation。
Lex:具體到 chat、diff 這種功能上,是怎么讓模型響應(yīng)這么快的?
Aman:我們用了很多策略,其中一個比較有意思的就是緩存預(yù)熱(cache warming)。當用戶在輸入時,我們能預(yù)判他們可能用到的上下文信息。我們之前提到過,復用 KV catch 可以降低延遲和成本,還能跨請求共享。只要用戶開始輸入內(nèi)容,我們就可以立即使用當前的文件內(nèi)容預(yù)熱緩存,這樣用戶按下回車后,需要預(yù)處理的 token 就少了很多,可以更快開始生成響應(yīng),大大降低了首次響應(yīng)時間(TTFT)。
Lex:還有哪些更 high-level 的緩存機制可以幫助提升響應(yīng)速度?
Aman:在 Cursor Tab 的設(shè)計里,系統(tǒng)可以預(yù)測用戶可能會接受哪個建議,提前處理可能會發(fā)生的下一個請求操作。這種方法結(jié)合了緩存和預(yù)測。通過預(yù)測用戶的選擇,系統(tǒng)可以提前緩存下一個建議,這樣一來,當用戶按下 Tab 鍵的時候,系統(tǒng)就會立即給用戶呈現(xiàn)下一個建議。這是一種啟發(fā)式的策略,雖然模型本身沒有變化,但通過更 high level 的緩存機制,會讓用戶感覺響應(yīng)速度很快。
Sualeh:如果我們能讓 KV Cache 變得更小,就可以做更多預(yù)測。比如,系統(tǒng)可以預(yù)測并緩存接下來 10 個可能的建議,用戶在這 10 個選項中選中一個的概率會比單個預(yù)測要高得多。用戶可能輸入新字符后會選擇緩存中的其他選項。這個策略在 RL 上也很有用,單個預(yù)測樣本可能不夠準確,但如果有多個預(yù)測選項,其中至少有一個正確的概率就會大大提升。
模型內(nèi)部會對于哪個建議是正確的、用戶想要的是什么建議,都存在一定的不確定性。我們在用 RL 訓 Cursor Tab 的模型時的其中一個事情就是預(yù)測模型生成的 100 個建議中,哪一個對用戶來說更合適,更符合他們的偏好。
模型可能在某些方面能夠做出很準確的預(yù)測,而在其他方面預(yù)測得就不是太準確,基于用戶反饋,我們可以對模型進行獎勵或懲罰,如果用戶喜歡這個建議,就給它獎勵,如果模型喜歡而用戶不喜歡,就給它懲罰。通過這種方式,我們可以訓練模型輸出更多用戶會喜歡的建議。
Aman:雖然這樣不能直接提高響應(yīng)速度,但是二者之間其實是有聯(lián)系的。因為即使是小模型,只要能用 RL 訓模型,就有可能達到與大模型相當?shù)男阅芩健3饲懊娴?KV catch 的角度,還有一些技術(shù)能幫忙提高速度。
比如,兩年前比較主流的是多頭注意力機制(multi-head attention),現(xiàn)在已經(jīng)逐漸轉(zhuǎn)向使用更加高效的注意力機制,比如 group query 或者 multi-query attention,這些機制能在更大的 batch size 下更快地生成 token。
但這些方法并不會影響首個 token 的預(yù)填充速度,它們主要是提升的是后續(xù) token 的生成速度。這是因為用戶生成 token 時面臨的瓶頸不再是在所有 token 上執(zhí)行高度可并行的矩陣乘法,而是在處理 long context 和更大規(guī)模的 batch size 時,如何快速讀取那些緩存的 keys 和 values。這就又涉及到內(nèi)存帶寬的問題,我們可以通過壓縮 keys 和 values 來提升速度。group query 或者 multi-query attention 的目的都是減少 KV Cache 的大小。
DeepSeek 開發(fā)的 MLA(Multi-Latent Attention,多隱向量注意力機制)也是一種,但MLA 的思路更新:用一個大的共享向量來存儲所有keys 和 values,同時為每個 token 配備較小的向量,這樣系統(tǒng)就只需存儲較小的向量,它的原理是把所有注意力頭的鍵值都轉(zhuǎn)換成一個隱向量,這個向量隨后會在時間維度上擴展。
Lex:這些在處理內(nèi)存限制上的細節(jié)最終是如何影響用戶體驗的?
Aman:主要有兩方面的影響。首先,我們可以大幅增加緩存容量,因為 KV Cache 占用空間變小了。這也意味著我們可以緩存更多內(nèi)容,提高緩存命中率(cache hits),從而減少首個 token 的生成時間。其次,即使用戶的請求量增加、批次變大,模型推理時的速度也不會明顯下降,因為模型能以匹配的速度生成 token。
Sualeh:這種方法還能支持更長的 prompt,從而給到模型的提示也更明確。
Aman:KV Cache 是“所有 prompts 的總大小”和“并行處理的 prompt 數(shù)量”的乘積,所以這兩個維度中任何一個的增加也都不會降低 token 生成的延遲。
四、Priompt :以網(wǎng)頁設(shè)計為靈感的提示詞工程
Lex:我們剛剛提到,基準測試中的 prompt 往往結(jié)構(gòu)清晰、表述規(guī)范。Arvid 也寫過一篇 Prompt Design 的文章,在你看來一個好的 prompt 能起到什么作用?
??
Arvid 在 Prompt Design 一文中參考現(xiàn)代網(wǎng)頁設(shè)計實踐提出了“提示詞設(shè)計”的概念,認為二者的共性在于都要做到清晰有效的溝通、對動態(tài)內(nèi)容作出響應(yīng)、涉及到不同“屏幕尺寸”的適應(yīng)等。
Arvid:每個模型都不太一樣,對不同的 prompt 的反應(yīng)也不一樣,比如之前的一系列模型都對 prompt 的要求非常嚴格,上下文窗口也很小。
在代碼開發(fā)場景中,我們會遇到大量和 prompt 相關(guān)的信息,包括文檔、添加的文件和對話歷史等。這就帶來一個問題:在 context window 有限的情況下,該如何篩選和組織這些信息?拿現(xiàn)在的模型來說,即使上下文窗口更長了,但要是塞滿整個窗口,模型的響應(yīng)速度就會變慢,有些時候還會被 prompt 混淆,而且有的模型比其他模型更容易受到混淆。
為了解決這個問題,我們開發(fā)了一個叫 Priompt 的內(nèi)部系統(tǒng),它在一定程度上幫我們解決了這個問題。
Priompt 借鑒了現(xiàn)代網(wǎng)頁開發(fā)的最佳實踐。和固定版式的雜志排版不同,網(wǎng)站開發(fā)中會涉及到的一個情況是,不同設(shè)備的中信息的展示多少、格式等是動態(tài)變化的,而用戶到底在哪里查看網(wǎng)站開發(fā)者事前并不知道,但無論終端怎么變,都要保證網(wǎng)站信息在不同設(shè)備上正常顯示。AI 提示詞工程也是類似,我們要做到無論 input 內(nèi)容多大、怎么變,output 的格式都能正確展示。
我們比較喜歡用 React 庫的聲明式編程方法(declarative approach),也就是說,我們可以通過 JSX 直接描述期望的 UI 呈現(xiàn)方式,例如通過設(shè)置樣式屬性或CSS類名來聲明元素的展示層級(如z-index)或其他視覺特性。
就像瀏覽器有自己的渲染引擎一樣,Cursor 也有一個 Priompt 渲染器,它的作用是把內(nèi)容合理地排布在頁面上,我們只需要告訴它你想要什么,它就會幫你實現(xiàn)。
我們發(fā)現(xiàn)這種方法非常有用,而且它的作用也在不斷演變,一開始設(shè)計它是為了應(yīng)對有限的上下文窗口,現(xiàn)在它幫我們把數(shù)據(jù)處理和實際展示分成了兩個部分,這樣做的好處是 debug 就會變得更容易:在不實際修改代碼的情況下,我們可以先通過輸入 prompt、Priompt 幫助預(yù)渲染的方式來看某個代碼改動是否真的有效。
Arvid:Priompt 和 React 類似,它還有一些組件,比如文件組件會獲取當前光標的位置,因為理論上用戶正在查看的那行代碼往往是最重要的。我們會給不同的代碼行設(shè)置優(yōu)先級,光標所在行的優(yōu)先級最高,每遠離一行優(yōu)先級就降低一級。最終在渲染的時候,系統(tǒng)會計算一共能顯示多少行代碼,并以光標所在行為整個代碼的中心。
Aman:Priompt 和還有一些更復雜的功能,如果整個代碼庫中有大量代碼塊,我們還可以使用 retrieval 、embedding 和 re-ranking scores 等方式讓組件自動設(shè)定優(yōu)先級。
Lex:為了讓模型更好理解用戶提問,是不是也可以用到類似方法?
Arvid:我們的目標是,“讓用戶做自己的事情就好”,我們的工作或者說整個 Cursor 要做的就是如何去 retrieve 相關(guān)信息。
Lex:我和 Perplexity 的 CEO Aravind Srinivas 也聊過這個問題,他認為要讓用戶想怎么問就怎么問。對于程序員來說,我們是不是還可以提出更高的要求?在完全放任用戶隨意提問和引導用戶給出更多 prompt 之外是不是也存在一種情況,即系統(tǒng)在鼓勵甚至要求用戶把想法表達得更清楚,這里說的不是語法或者句子要多規(guī)范,而是 prompt 中體現(xiàn)出的思考深度。
Aman:我認為即便模型能力已經(jīng)接近完美,當用戶向模型提出需求的時候,往往還是沒法完全表達自己的想法。要解決這個問題有幾個方法:
? 第一,讓模型直接告訴用戶,基于用戶的問題,它還是不太確定這部分內(nèi)容,讓用戶再明確一下;
? 第二,如果模型可以一次生成 5-6 種可能的結(jié)果,基于這些結(jié)果也可以告訴用戶,由于用戶的問題有一些模糊的地方,模型會把所有可能的結(jié)果都展示出來,讓用戶來選擇最合適的。
Lex:讓模型主動提問有多難?我是不是需要通過提問來獲得更多信息,從而減少一些可能發(fā)生歧義的情況?
Sualeh:最近我們在 Cursor 里新增了一個文件推薦功能。用戶在編輯問題的時候,模型就能猜到問題是什么,比如,用戶在編寫 API 代碼的時候,模型會根據(jù)這個文件之前的提交記錄,推測出客戶端和服務(wù)器端的相關(guān)代碼可能也很重要。這背后存在一個技術(shù)上的難題:怎么在歷史記錄中找到之前的信息,并根據(jù)用戶當前給的 prompt 判斷出哪些文件最重要?目前我們的版本還比較簡單,這個功能還在試驗階段,相信未來會越來越精確。有個這個功能,用戶就可以很方便地添加文件,讓模型來編輯。
比如說,當用戶在編寫 API 時,可能還需要修改使用這個 API 的客戶端代碼和處理 API 請求的服務(wù)器端代碼。如果 Cursor 能在用戶輸入 prompt 并按下回車鍵之前,就幫助理解這些模糊的地方,就能提供很大幫助。
五、Shadow Workspace:Coding Agent 的工作流設(shè)計
Lex:你們怎么看 Agent?
Arvid:雖然目前 agent 在很多場景下還不是特別實用,不過我覺得它們離真正派上用場已經(jīng)不遠了。有些任務(wù)非常適合使用 agent,比如我們遇到了一個 產(chǎn)品 bug,這個 bug 可能是“聊天框里的內(nèi)容不能復制粘貼”,我只需要用兩句話來說明這個任務(wù):“這里出問題了,請修復一下”,agent 就會立刻去處理。第二天我回來看看結(jié)果就行了。
在這個任務(wù)里,Agent 首先能定位到正確的文件,嘗試重現(xiàn)并修復 bug,然后驗證修復后的代碼對不對。這個過程可能需要很長時間,所以我很希望能有這樣的 agent 來幫忙。
很多人覺得代碼 Agent 最終會完全取代程序員,但我不這么想,因為編程的價值在于迭代,很多人在看到一個初始版本之前并不明確地知道自己想要什么。在大多數(shù)的編程任務(wù)里,用戶需要的是一個能立即給出初始版本的系統(tǒng),讓他們可以立即開始迭代優(yōu)化、補充更多信息。
Lex:在 Replica Agent 的設(shè)計中,Agent 不僅能設(shè)置開發(fā)環(huán)境、解決軟件包問題、配置數(shù)據(jù)庫,還能部署應(yīng)用,這種設(shè)計是不是符合你們對于代碼 Agent 的預(yù)期?Cursor 會開發(fā)類似的功能嗎?
Arvid:是的,Replica Agent 的確是在這個方向上。對于某些類型的編程來說,這個工具非常好用。
目前 Cursor 還沒有去積極開發(fā)類似的產(chǎn)品,不過我們的目標是讓程序員的工作更輕松有趣,那些繁瑣的重復性任務(wù)完全可以交給 agent 處理。我們甚至可以讓 agent 在后臺運行,理解程序員的操作意圖。
假設(shè)有一個同時涉及后端和前端的 pull request,程序員在前端工作時,可以讓一個 agent 在后臺運行,理解程序員的做法。當程序員從前端轉(zhuǎn)到后端部分時,agent 就可以生成一些初始代碼,供程序員在這一基礎(chǔ)上進行迭代。
Lex:Arvid 寫過一篇文章叫 Shadow Workspace: Iterating on Code in the Background??梢跃唧w講一下 Shadow Workspace 嗎?
Arvid:我們希望很多任務(wù)可以在后臺處理完成,我們也在這個方向上做嘗試。
除了緩存預(yù)熱(cache warming)或者確定進入命令提示詞的正確上下文之外,我們還沒有太多后臺操作。整體想法是,如果我們能在后臺進行計算,那么就可以在更長的時間維度上幫助用戶完成任務(wù),不僅僅是預(yù)測接下來幾行你要寫什么,而是預(yù)測在接下來的 10 分鐘里,用戶打算做什么,通過在后臺處理,可以投入更多的計算資源。
基于這個想法我們實驗了 Shadow Workspace 。想要充分利用后臺處理的優(yōu)勢,就需要給模型提供反饋信號。如果沒有反饋,單純延長模型的思考時間也能提升性能,比如 o1 就是個很好的例子。
另一種提升性能的方式是讓模型迭代和獲取反饋。對于程序員來說,一個非常重要的反饋來源是 language server ,它們可以在開發(fā)者 coding 的時候就給出錯誤提示,還支持跳轉(zhuǎn)到代碼的定義位置,理解代碼的結(jié)構(gòu)。我們的做法和 VS code 一樣,基于 LSP 給開發(fā)者作出對應(yīng)提示,但我們還想在不影響用戶的前提下,在后臺把同樣的信息提供給底層的 LLM 模型。
??
Language Server Protocol (語言服務(wù)器協(xié)議,簡稱 LSP)是微軟在 2016 年提出的一套統(tǒng)一的通訊協(xié)議方案。,定義了一套代碼編輯器或 IDE 與語言服務(wù)器之間使用的協(xié)議,語言服務(wù)器提供自動完成、轉(zhuǎn)到定義、查找所有引用等語言功能。每種編程語言都有其獨立的 language server,這些 language server 都會通過 LSP(language server protocol)與VS Code進行交互,由此 VS Code 就不需要自己內(nèi)置一些東西來支持各類提示需求。
所以 Shadow Workspace 背后的思路是,也許我們可以在后臺運行一個隱藏窗口,通過特定的標志,把這個隱藏的窗口設(shè)置成不可見狀態(tài),開發(fā)者用戶視角下是無法看到這個窗口的。在這個窗口中,AI agent 可以隨意修改代碼,只要它們不保存就行,因為隱藏窗口和主窗口共用一個文件夾,只要不保存修改,就不會影響到實際文件。然后 agent 可以從 linting 中獲得反饋,實現(xiàn) go to definition 功能,對代碼進行迭代。
最終的預(yù)期是 Agent 可以在后臺執(zhí)行一切。
我們的很多 blog 也都在在探討怎么實現(xiàn)這件事,因為確實有點復雜。我們希望這個系統(tǒng)能在用戶的電腦上運行,這樣它就能精確地鏡像用戶的環(huán)境。
在 Linux 系統(tǒng)上,我們可以鏡像文件系統(tǒng)。通過這種方式對文件進行修改,會讓 AI 以為自己是在操作實際文件,但這些修改都是存儲在內(nèi)存中的。要實現(xiàn)這個功能,需要開發(fā)一個類似內(nèi)核的擴展。在 Mac 和 Windows 系統(tǒng)上,實現(xiàn)起來可能會稍微困難一些,但這個技術(shù)挑戰(zhàn)也很有意思。
Aman:為了避免人類開發(fā)者和后臺 agent 同時工作時可能出現(xiàn)的文件寫入混亂,我們還設(shè)計了一個寫入鎖定的限制。具體來說,在個過程中,我們 LLM 會對文件寫入權(quán)限加鎖,Agent 只在 Shadow Workspace 中操作,所有改動都只存在于內(nèi)存中,而不直接修改磁盤上的實際文件。在這個過程中, LLM/Agent 仍然可以觸發(fā)代碼檢查和獲取語法提示。當 Agent 需要運行代碼時,系統(tǒng)會發(fā)出提示,如果用戶同意這個操作,就會從 language server 或 Shadow Workspace 那里解除鎖定。
六、SOTA 模型也不擅長找 bug
Lex:讓模型修改文檔這件事聽起來很有趣,以后我們就可以讓 agent 去執(zhí)行一系列任務(wù),第二天再來看這個 Agent 同事都完成了哪些工作。
Aman:我們可能會設(shè)計不同的運行版本。有些任務(wù)比較簡單,比如用戶在編程時,有些操作模型幾分鐘就可以幫用戶完成,這種時候可以讓代碼在用戶的本地機器上運行。但有些任務(wù)更復雜,需要更長時間來完成更大的更改,可能更適合在遠程沙盒環(huán)境中執(zhí)行。這就帶來了一個問題:如何精確地復制或最大程度復制用戶的本地環(huán)境,確保遠程沙盒與用戶本地環(huán)境中運行代碼的效果一致。
Lex:我覺得 Agent 應(yīng)用范圍不應(yīng)該局限于 coding。比如說我們現(xiàn)在正在錄的這期播客就涉及視頻剪輯、上傳視頻、翻譯和配音等,我可能會希望 Agent 可以幫助我們把很多和視頻編輯不直接相關(guān)的任務(wù)自動化。在 coding 上,我比較期待 agent 能幫忙找 bug,特別是邏輯錯誤,以及幫助確定大方向等等。
Aman:有一個很有意思的現(xiàn)象是,如果用戶給出的 prompt 是找 bug,那么模型的準確率其實很低,在這類任務(wù)上即便是最聰明的模型表現(xiàn)也很差,甚至是 o1 這樣的模型。
Lex:怎么解釋這個現(xiàn)象?
Aman:模型是 pre-train 數(shù)據(jù)分布的一個強映射,隨著 loss 越來越低,模型的泛化能力也會不斷提升,但目前 loss 還沒有低到能讓模型在代碼領(lǐng)域完全實現(xiàn)泛化。我們目前使用到的最新一代的模型很擅長代碼生成和問答,這是因為在 pre-train 階段這類數(shù)據(jù)特別多,GitHub 上有幾萬億個 token,Stack Overflow 上也有海量的問答內(nèi)容。
但是如果我們想讓模型做一些網(wǎng)上很少見的任務(wù),比如 Cursor Tab 要做的根據(jù)已完成的編輯預(yù)測下一處編輯,這些模型在這類任務(wù)和場景上的弱點就會暴露出來。漏洞檢測(bug detection)也是一個很好的例子能說明模型的這個短板?;ヂ?lián)網(wǎng)上真實的 bug 檢測和修復的完整案例其實很少,并不像代碼問答那樣數(shù)據(jù)豐富,所以模型在這類任務(wù)上就表現(xiàn)得很吃力。
不過我認為這是模型能力遷移的問題。就像我們已經(jīng)看到的,我們可以把模型在 pre-tarin 階段獲得的通用的代碼理解能力遷移到 Cursor Tab 的任務(wù)上。如果一個通用模型在代碼方面很強,也應(yīng)該能通過類似的方式把它的能力遷移到 bug 檢測任務(wù)上,只是需要一些適當?shù)囊龑Ш驼{(diào)整。
Sualeh:需要說清楚的一點是,這些頭部模型其實對代碼的理解是很到位的。在 pre-train 階段,在構(gòu)建內(nèi)部 representation 時 ,我們幾乎可以確定,在處理流程的某個環(huán)節(jié),模型能夠感知到代碼中可能存在一些問題,但是僅僅是感知到“不對勁”是不夠的,最關(guān)鍵的問題在于,人類對于哪些bug真正重要有著準確的判斷力,比如有的 bug 無關(guān)緊要,有的卻會導致服務(wù)器宕機。
人類工程師之所以能做到這一點一部分也是行業(yè)經(jīng)驗和文化的積累。為什么資深工程師很厲害,是因為他們知道 3 年前有人寫了一段有問題的代碼導致了服務(wù)器宕機,相比之下,如果只是在做實驗性質(zhì)的代碼,有一些 bug 也沒關(guān)系,因為主要目的是嘗試和體驗。所以如果在寫實驗代碼時,模型過分較真,不停地給出提示,反而會很煩人。
但如果是在寫生產(chǎn)環(huán)境的代碼,比如寫一個數(shù)據(jù)庫,在 Postgres 或 Linux 這樣的系統(tǒng)寫代碼,或者假如我們是 Linus Torvalds 這樣的人(注:Linux 的創(chuàng)始人),那就必須做到萬無一失,任何 edge case 的 bug 都不能有,這就要求模型能準確理解開發(fā)者對代碼質(zhì)量的要求程度。
Aman:但即使作為開發(fā)者我們把對模型代碼任務(wù)的質(zhì)量要求調(diào)到最高,模型還是不能完全理解到這些微妙的差異。
Lex:但其實人類工程師要真正做到準確判斷不同 bug 的重要性也很難。比如你們也有一個原則是,如果某一段代碼可能會帶來不可控的影響,應(yīng)該給它特別注釋去說明“This line of code is dangerous.”,甚至還會用到大寫標記來突出。
Arvid:是的,我覺得這個原則對今天的 AI 模型同樣適用。如果每一行代碼上都有專門的標注,那么模型就會更關(guān)注這一部分,也更有可能發(fā)現(xiàn)這一部分的bug。但這個做法本身也也存在爭議。一些人會覺得這種做法不太美觀,比如 Sualeh 就不喜歡。
除非我們可以做到所有代碼都能通過嚴格的數(shù)學方法來證明其正確性,到那個時候就可以隨意寫代碼了,因為只要驗證通過,我們就能確定這里沒有引入到任何 bug。
Sualeh:雖然從代碼審美角度來看我并不喜歡這種做法,但我認為它確實對模型和人類都有用,因為人類經(jīng)常會忘記很多事情,而且很容易犯一些小錯誤,從而導致服務(wù)器崩潰。就算我們進行了大量的測試,但在這方面我們還是要格外謹慎。
Aman:是的,就拿普通的文檔注釋來說,人們在修改代碼時往往只是匆匆掃一眼,想著“哦,我知道怎么做”,但實際上我們還需要更加明確地提醒他們注意某些細節(jié),否則很容易就疏忽了。
Arvid:我認為未來人們不會再手寫測試代碼了。當 coding 的同時,AI 模型會自動為這段代碼生成一個規(guī)范說明(spec),開發(fā)者只需要審核這個規(guī)范是否符合預(yù)期。同時,推理模型會通過計算來驗證代碼實現(xiàn)是否完全符合這個規(guī)范。我覺得這種方式將適用于大多數(shù)代碼功能的測試。
Michael:這件事是不是又會涉及到我們在前面提到的,人們在開發(fā)軟件時可能很難很清楚地描述自己的目標和意圖,而有時候之所以難以證明代碼實現(xiàn)符合預(yù)期,也可能正是因為我們很難準確地描述出我們想要什么。
即便模型給出了一個 spec ,我們還是要面對一個問題:我們真的能做到 formal verification 嗎?這在技術(shù)上是否可行?我覺得這里面還有很多需要深入探討的地方。又比如 spec 是用自然語言編寫的還是用公式來表達?即便是 spec 也還有很多細節(jié)很難被清晰界定。所以只是考慮 formal verification 還不夠。
Lex:你在前面提到模型在處理 bug findings 這類任務(wù)時通常表現(xiàn)不是很好,長遠來看你的預(yù)期是什么樣的?
Sualeh:我覺得模型首先應(yīng)該能幫助我們解決那些簡單的小錯誤,它應(yīng)該能快速檢查并及時發(fā)現(xiàn)“差一錯誤(off by one error)”這種簡單的 bug,因為這類問題非常常見。在這個時候模型就應(yīng)該給出對應(yīng)提示,但長遠來看,它肯定還需要能夠捕捉到更難發(fā)現(xiàn)的bug。
Michael:我覺得很重要的一點是,找 bug 能力是讓 AI 完成更多 coding 任務(wù)的必要條件。當我們想要讓 AI 幫我們構(gòu)建越來越多的系統(tǒng)時,就不僅需要它幫助做代碼生成,還需要能驗證代碼的正確性,如果沒有這種驗證能力,我們前面聊到的這些模型在代碼任務(wù)上的問題就很難解決,讓 AI 擁有找 bug 的能力不僅僅是為了找出人類寫代碼時產(chǎn)生的 bug,更關(guān)鍵的是能夠驗證和檢查 AI 生成的代碼。
Arvid:關(guān)于如何實現(xiàn)讓 AI 更好地找到 bug 我們也有過很多次討論,比如如何訓練一個 bug 檢測模型,還有一個更受歡迎的想法是:“制造 bug 比找 bug 更簡單”,所以對應(yīng)的思路是,我們可以先訓練一個模型,讓它學會在現(xiàn)有的正確代碼中注入各種類型的 bug,基于這種方式我們會得到大量帶有已知 bug 的訓練數(shù)據(jù),然后,就可以用這些合成數(shù)據(jù)來訓練另一個模型,專門用于發(fā)現(xiàn)和檢測代碼中的 bug。這只是眾多可能方法中的一個例子,還有很多其他的訓練思路可以嘗試。
Michael:還可以有其他思路來完成。我們可以先想象有一個 access 范圍足夠?qū)挼哪P停@個模型可以接觸到包括代碼在內(nèi)的各種信息,因為只盯著一個文件來找 bug 其實是很難的,對人類來說也很難,所以通常情況下我們的做法是運行代碼、查看traces、通過調(diào)試器逐步檢查。這是另一個完全不同的方向。
所以這里有兩種不同的產(chǎn)品形態(tài)。一種是有一個非常專業(yè)且運行速度很快的模型在后臺運行,一直去尋找 bug,另一種情況就是開發(fā)者已經(jīng)很明確有一個 bug 需要解決,在這種情況下,人們可能會投入大量的計算資源來做這件事。
Lex:你們考慮過代碼生成、編輯和 debugging 環(huán)節(jié)里引入付費的可能性嗎?如果能幫助發(fā)現(xiàn) bug,或者生成讓用戶非常滿意的代碼,用戶愿意為之付費或者打賞,而除了獲得收入之外,付費也是比“接受代碼”更強的信號來幫助優(yōu)化產(chǎn)品和模型。
Arvid:這個思路很有意思但也很有爭議,并且還涉及到我們對于用戶心理的把握,也涉及到算力成本和定價之間的平衡。但整體上我們會覺得引入這個機制可能會讓產(chǎn)品變得不那么有趣,可能通過訂閱的方式,每月支付一定費用后享受所有這些功能更符合開發(fā)者的需求,而不是將 debugging 等功能點單獨付費,即便是打賞機制也會有影響。
Lex:在具體的代碼任務(wù)和代碼終端結(jié)果之間有更好的信息交互?比如是否存在一個類似于 code -> terminal -> output -> analysis -> code suggestions 這樣的循環(huán)和反饋機制?
Aman:用戶在使用 command+K 功能的時候會利用到終端上下文信息,但我們目前還沒有實現(xiàn)循環(huán)反饋的部分,但我們覺得這樣的功能應(yīng)該很有價值,問題在于這個功能是在前臺執(zhí)行,還是像我們之前討論的那樣在后臺執(zhí)行。
Lex:前面提到基準測試并不能真實反應(yīng)模型代碼任務(wù)的能力?這二者之間有什么區(qū)別?如果要評估模型,我們看到的基礎(chǔ)測試有什么不足?
Sualeh:基準測試和現(xiàn)實中的代碼任務(wù)中間有一個非常重要且關(guān)鍵的細節(jié)差異,那就是現(xiàn)實中的代碼任務(wù)并不是“編程面試題”。在現(xiàn)實的工作中,人們有時會用不標準的英語來表達任務(wù)需求,或者會給出“照我之前那樣做”、“添加這個,然后幫我做那個,再做一個 UI 元素” 之類的指令。很多任務(wù)都是依賴于具體場景的。
所以對于模型和產(chǎn)品來說,真正需要的是理解用戶意圖并完成他們想要的事情,真實的人類需求往往是模糊的、不那么明確的,而不是“面試題”那樣具有非常明確、詳細規(guī)范說明的任務(wù)。
Michael:除了 Sualeh 和 Aman 提到的問題外,基準測試還存在一個問題是,實際可以建模的內(nèi)容與真實的編程之間存在一定的偏差,這種偏差很難概括,因為真實的編程是很混雜的,有些時候很難去明確解釋什么是對的,什么是不對的。
而且,由于測試集是公開數(shù)據(jù)集的原因,這件事會變得更難。有兩方面的原因,首先,公開的基準測試有時會被進行針對性地“爬坡優(yōu)化”(hill climbing),另一方面,要從模型中剔除掉這些公開基準測試的數(shù)據(jù)也非常難。
舉個例子,SWE-Bench 是目前最受歡迎的 Agent 基準測試之一,但它的測試數(shù)據(jù)也是 Foundation Model 的訓練數(shù)據(jù)的一部分。所以如果我們給到 Foundation Model 一個 SWE-Bench 問題,即使沒有提供代碼庫的上下文,模型還是可以“編造”出一個正確的文件路徑和函數(shù)名。
??
SWE-Bench 是一個用于評估 LLM 解決從 GitHub 獲取的現(xiàn)實世界軟件問題的能力的基準測試。該基準測試包括向 Agent 提供代碼存儲庫和問題描述,并要求它們生成可解決問題描述的補丁。SWE-bench 中的每個測試樣本都來自 GitHub 上 12 個開源 Python 存儲庫之一中已解決的 GitHub issue。每個樣本都有一個關(guān)聯(lián)的拉取請求 (PR),其中包括解決方案代碼和用于驗證代碼正確性的單元測試。
為了更準確地評估 AI 模型的軟件工程能力,OpenAI 在對 SWE-bench 的改進基礎(chǔ)上推出了 SWE-bench Verified。
Aman:在這種情況下,模型可以直接在 issues 和 pull requests 上訓練,也許各個實驗室會開始做得更好,或者他們已經(jīng)在數(shù)據(jù)清理方面做得不錯了,但他們不太可能完全剔除掉本身的訓練數(shù)據(jù)。這些都是一些最受歡迎的 Python 庫,比如 SimPy。我不認為他們會為了在基準測試中獲得真實的評估分數(shù),而犧牲模型在 SimPy 這些主流 Python 庫上的性能。
Michael:由于基準測試的這些 bug,很多大模型團隊開始用其它測評方式來獲得模型反饋,比如讓真人實打?qū)嵉厝ナ褂眠@些系統(tǒng)并提供定性反饋。我還知道有一些 foundation model 公司中,有專門的員工就是專門做這件事。在我們內(nèi)部,除了用我們自己的私有測試集外,我們也非常依賴這種定性評估。
七、Code Indexing 和 Context
Code base Indexing
Lex:如何防止Cursor對數(shù)據(jù)庫進行未經(jīng)授權(quán)的或錯誤的修改?
Sualeh:目前確實有一些還不錯的解決方案,我們也在基于 PlantScale 開發(fā)一個 API ,這個 API 的核心功能是為數(shù)據(jù)庫提供分支(branches)。如果開發(fā)人員在開發(fā)某個功能并想要對整個數(shù)據(jù)庫進行測試,但又不想直接對整個數(shù)據(jù)庫進行測試時,就可以通過給數(shù)據(jù)庫添加 branches 來做這件事。他們實現(xiàn)這一功能的方式是在 write-ahead log 中添加一個分支,而要做到完全正確涉及很多技術(shù)復雜性。今天數(shù)據(jù)庫公司也在不斷迭代來應(yīng)對新的需求。
我們使用的一個數(shù)據(jù)庫 Turbopuffer 未來可能會實現(xiàn) write-ahead log 的分支功能,AI agents可以利用這些分支進行測試,這可能會成為數(shù)據(jù)庫必須支持的一個功能。
并且我覺得到未來所有東西都需要 branches,隨著 branches 越來越多就要設(shè)計出更好的算法來做內(nèi)存、CPU 以及其它資源的優(yōu)化。
Lex:隨著用戶規(guī)模的擴大,Cursor 遇到哪些挑戰(zhàn)嗎?
Michael:用戶增長的過程其實也是每秒請求數(shù)不斷增加一個數(shù)量級的過程。一開始我們是用通用組件進行緩存和數(shù)據(jù)庫操作,隨著系統(tǒng)規(guī)模越來越大,就會遇到各種問題,今天我們的規(guī)模就會出現(xiàn)表溢出(table overflows)這樣的問題。所以到后來,我們也構(gòu)建了一些自定義系統(tǒng),比如我們的 indexing 系統(tǒng),用于計算代碼庫的語義索引并回答關(guān)于代碼庫的問題。我覺得系統(tǒng)一直最難 scale 的事情之一。
Sualeh:我有一些朋友是很資深的工程師,他們經(jīng)常提到,在系統(tǒng) scale 的過程中,很難準確預(yù)判判斷系統(tǒng)會在哪個環(huán)節(jié)出問題,即使事先做出了預(yù)測,但還是會有遺漏,比如每次增加新功能時總會發(fā)生一些意外。
不過對于剛剛提到的代碼 indexing 系統(tǒng),我們目前在做的事情是,在當上傳代碼時,我們將所有代碼分塊讓然后發(fā)送出去。我們對待客戶問題非常謹慎,將代碼 embedding 存儲在數(shù)據(jù)庫中實際上儲存的并不是代碼本身的內(nèi)容,這樣做的好處是可以確保我們不會引入客戶端的bug。此外,我們還在服務(wù)器上存儲了很多關(guān)于代碼塊的詳細信息,并且所有內(nèi)容都已加密處理。
我們的方法是先把所有代碼分塊,然后將這些代碼做 embedding,在這之后,我們把這些 emebdings 存儲到數(shù)據(jù)庫中,而不是去存儲任何源代碼。這么做首先客戶確保不會引入用戶代碼庫中的 bug,另外這些存到服務(wù)器上的所有內(nèi)容也都是加密的。
在這個過程中我們遇到的一個技術(shù)難點就是,如何確保本地 index 和代碼庫的狀態(tài)與服務(wù)器上的保持一致?
我們最終采取的技術(shù)方案是,給每一個文件和文件夾都設(shè)置一個哈希值,其中文件夾的哈希值是其所有子文件和子文件夾哈希值的組合。這個過程可以遞歸進行,直到根目錄。這其實是相對復雜的一種方式,還有另一種簡單的方法是,為每一個文件保存一個哈希值,然后再以每分鐘為單位嘗試從服務(wù)器上下載這些哈希值,找出哪些文件在服務(wù)器上不存在,從而保證客戶端和服務(wù)器之間的狀態(tài)一致。
但這種操作會給客戶端帶來嚴重的網(wǎng)絡(luò)負擔,沒有人希望使用 Cursor 時,我們一直占用它們的網(wǎng)絡(luò)帶寬,而且這種操作也會給數(shù)據(jù)庫帶來龐大負擔,差不多每秒鐘都要讀取數(shù) 10TB,甚至接近 20TB 的數(shù)據(jù)庫,所以肯定不能這樣做。
所以我們采取的方法是只嘗試對項目根目錄的單個哈希值進行比對,如果發(fā)現(xiàn)有不匹配,才進一步去找出具體哪里不一致,再通過子節(jié)點一層一層向下找到具體哪里發(fā)生了變化。這種逐層檢查和遞歸的方式,能夠在確保同步準確性的同時最大程度地減少網(wǎng)絡(luò)和數(shù)據(jù)庫成本,因為對于大多數(shù)用戶、大部分任務(wù)來說,哈希值都是一致的。這個結(jié)構(gòu)叫做 Merkle Tree。
Sualeh:代碼檢索系統(tǒng)的 scale 之所以很難是因為,不僅用戶量增加,其中一些客戶的代碼庫相當龐大的,我們一開始設(shè)計的時候參考的是 Electron 這樣大型的代碼庫,但它的規(guī)模顯然和那些存在了20 年、擁有海量文件的公司的代碼庫還差很多,與此同時還需要考慮到怎么支持一大群程序員來使用。
這里涉及很多細節(jié),構(gòu)建一個簡單的方案很容易,但要考慮到擴展到支持大量用戶、大量公司客戶顯然是個很困難的問題。如果去拓展代碼檢索系統(tǒng)是 Cursor 規(guī)模擴展過程中遇到的挑戰(zhàn)之一。過去幾周幾個月里一直在處理這些擴展性問題。
Aman:我們在設(shè)計這個 index 系統(tǒng)的時候也加入了很多巧妙的細節(jié)。比如,成本的瓶頸并不在于向量數(shù)據(jù)庫或數(shù)據(jù)庫中存儲的數(shù)據(jù)量激增,而在于 embedding ,假如一個公司中有好幾個人使用了相同的一段代碼,就沒必要為每個人的每一次操作單獨做 embedding 的計算,即便這些代碼在不同 branches 上,或者只是做了一些本地修改。
在這個時候,就可以使用到一個技巧:對給定代碼塊的哈希值所計算出的實際向量進行緩存。這意味著,當公司里第 n 個人需要嵌入他們的代碼庫時,系統(tǒng)就可以快速響應(yīng)。而且,這個過程中我們其實不需要在服務(wù)器上存儲源代碼,因為只調(diào)用到了向量數(shù)據(jù)庫和向量緩存中存儲向量。
Lex:對代碼庫 indexing 的投入帶來的好處是什么?
Arvid:我認為最明顯的好處是,當用戶在龐大的代碼庫中想要查找某個功能的具體實現(xiàn)位置時,可能只記得個大概,比如“我想找到我們實現(xiàn) X 功能的地方”,但在普通的文本搜索中,用高糊并不清楚應(yīng)該搜索什么關(guān)鍵詞,如果有了 code base 的 indexing,就可以向一個 code base chatbot 提問,很多時候,code base chatbot 都能準確找到對應(yīng)的代碼位置。
Aman:我認為在未來,這個功能只會變得越來越強,我們也在努力提高檢索的質(zhì)量。我認為這代碼搜索這部分的想象力比人們想象中的要大。
Lex:在這個過程中為什么沒有考慮過端側(cè)方案?
Arvid:在本地做 embedding 聽起來很厲害,但實際操作起來很難。有一點我想指出的是,用戶們所使用的設(shè)備性能參差不齊,比如有些用戶用的是最新的MacBook Pro,但實際中超過80%的用戶用的是 Windows系統(tǒng)的電腦,而且其中很多電腦的性能都不是很好。因此,本地模型實際上實際上只適用于最新的高性能電腦而且會帶來很大的負擔,即使我們想實現(xiàn)本地嵌入,目前也沒辦法集中精力去實現(xiàn)這一點。
Sualeh:除了計算機性能的限制之外,還有個現(xiàn)實問題是這種方案會犧牲輕松和高效的體驗。大公司的代碼庫規(guī)模極大,即便一個公司給自己的程序員都配上了最高性能的電腦,處理這么大的代碼庫也會非常吃力,即便是頭部公司的頂尖程序員,如果一切都在本地運行,體驗也會非常糟糕。
Aman:是的,在處理近似最近鄰算法(nearest neighbors)和大型代碼庫時,本地做 embedding 會大量占用內(nèi)存和CPU 資源?,F(xiàn)在端側(cè)模型的發(fā)展的一個趨勢是向 MoE方向發(fā)展,好處是它更多地依賴于內(nèi)存帶寬,而不是 GPU,但缺點是這些模型通常都很大,甚至可能需要多個節(jié)點來支持,即使是性能非常好的 MacBook 也無法支持這些模型。特別是在 coding 場景,這不僅是一個模型夠不夠好的問題,而是模型能否滿足開發(fā)者日益增長的期望。也許對于一些問題,本地模型已經(jīng)模型夠用,但人們總想用最好、最智能、最強大的模型。但這些模型對于大多數(shù)人來說,在本地運行都非常困難。
Lex:相對于中心化的頭部 AI Labs,還是有不少人在提升端側(cè)模型能力的,尤其是在開源社區(qū)。你們怎么看這一趨勢?
Arvid:除了端側(cè)模型,還有一個我很喜歡的替代案,但目前還處于研究階段,就是用同態(tài)加密(homomorphic encryption)來做 LLM 的推理,也就是說,我們在本地設(shè)備上的輸入會被加密后發(fā)送到云端來做計算推理,這部分可以調(diào)用頭部模型能力來完成,但服務(wù)器看不到原始數(shù)據(jù),當服務(wù)器完成推理計算后返回答案,我們可以在本地進行解密,整個過程中只有用戶自己才能看到最終的結(jié)果。
這個技術(shù)還很早期,并且這里面的關(guān)鍵在于如何降低計算成本。同態(tài)加密可以很好解決目前的用戶數(shù)據(jù)隱私會暴露給模型的問題,所以如果這件事能實現(xiàn)就會影響很大。因為隨著模型能力越來越強、可以帶來的經(jīng)濟價值是越來越高的。
??
同態(tài)加密(homomorphic encryption):密碼學中的一種特殊加密技術(shù),它允許在不解密數(shù)據(jù)的情況下對密態(tài)數(shù)據(jù)執(zhí)行特定的計算操作,并且計算結(jié)果仍然是密文狀態(tài),對密態(tài)結(jié)果解密后可以得到與直接用明文數(shù)據(jù)計算相同的結(jié)果。這一技術(shù)被用于隱私計算與安全多方協(xié)同計算領(lǐng)域。
如何解決 Context 問題
Lex:Cursor 是怎么解決 Context 問題的?模型自動找出上下文這件事有多難?
Michael:Context 是一個很復雜的問題,我認為未來我們的確可以在自動找上下文這件事上做得更好,但也需要指出來的是,自動識別 context 這件事是有成本的。
首先,當我們給模型提供的上下文越多,它們的響應(yīng)速度就越慢、請求的成本就越高,這就會犧牲我們對模型能力的調(diào)用以及可以在后臺處理的任務(wù)就會減少,此外,對于許多模型來說,如果 prompt 中包含大量信息,它們也會感到困惑。因此,我們在給模型提供上下文時需要確保信息的準確性和相關(guān)性都很高。
我們其實已經(jīng)在產(chǎn)品中實現(xiàn)了一些自動上下文的功能,這是我們希望做得更好的地方,比如更好的 indexing 系統(tǒng)、embedding 和 retrieval 等。
這里面還有很多很有意思的學術(shù)問題,既有我們內(nèi)部在嘗試的,也有一些共識性的討論。
比如,如何讓語言模型真正理解一個新的信息語料庫?很多人都會提到的一個方向是,能不能讓上下文窗口無限大?如果可以實現(xiàn),那么能不能讓模型在具體的任務(wù)中考慮到這個無限大上下文?如果這個問題成立,那么接下來就又會考慮能不能對無限大的上下文進行緩存?
與此同時我們也在嘗試其他思路,比如類似于模型微調(diào)的思路,將這些信息融入到 weights 中進行學習。如果模型更多地是在 weights 級別上學習到這些信息,而不是在上下文的話,那么結(jié)果又會不一樣。
但最終要怎么實現(xiàn)目前還沒一個定論。
Aman:讓模型直接在 weights 層面學習這個路徑可以先用 VS Code 來做概念驗證。因為 VS Code 本質(zhì)是開源的,也就是說,模型在 pre-train 階段就學習過這些代碼,甚至也學習過相關(guān)的代碼問答內(nèi)容,然后經(jīng)過微調(diào)和 RLHF 后,這些模型就被訓練到能夠回答一些代碼相關(guān)的通用問題。當我們問這個模型和 VS Code 相關(guān)的問題時,雖然有時候它會產(chǎn)生幻覺,但有時候它確實能很好給出答案,我認為這只是它碰巧表現(xiàn)得還不錯,但如果我們專門地對模型進行訓練或者 post-training,從而讓它更好地理解整個代碼庫,可能結(jié)果又會不一樣?
還有一個值得探索的問題是,我們到底是希望模型能夠端到端地完成所有工作,比如自己做完 retrieval、回答問題、生成代碼,還是說我們更希望將 retrieval 和底層模型獨立開?如果是后者,可能在未來幾個月內(nèi)就會出現(xiàn)一批比今天開源 SOTA 模型還要強的模型,在這種情況下,我們可能可以把一個高質(zhì)量的開源模型單獨訓練成 retrieval 模型,由這個獨立的 retrieval 模型給更強的頭部底層模型提供 context。
八、Scaling law 、復現(xiàn) o1 模型
Scaling laws
Lex:你們怎么看接下來 scaling law 的發(fā)展?
Aman:我覺得 Chinchilla 之后,大家某些程度上在 scaling law 上有些走偏,現(xiàn)在大家更關(guān)心的是,怎么在給定的inference budget下,讓模型的表現(xiàn)盡可能好。
Scaling law 實際上考慮的維度比我們之前提到的算力規(guī)模、參數(shù)數(shù)量和數(shù)據(jù)量要多得多。例如,inference computer 就是一個顯而易見的維度,我認為 context 長度也是一個。如果有人跟關(guān)注這兩者的優(yōu)化,那么可能就會訓練出一個處理超長上下文時成本更低、速度更快的模型,即便訓這個模型需要投入多 10 倍的算力,但這個過程中優(yōu)先級目標是 long context window 和 inference compute。所以怎么理解人們對不同緯度之間的關(guān)系,以及圍繞這些緯度做權(quán)衡和探索其實很有意思。
Lex:也有人認為 Scaling law 即將遇到上限。
Aman:單純就智能能力講的話,一定是模型越大、能力越好。
我很看好看好蒸餾。蒸餾也許是解決 data wall 的另一種方法。當數(shù)據(jù)不夠用的時候,我們可以先在已有這些 tokens 上訓練一個非常大的模型,然后將其蒸餾成一個較小的模型。這樣一來,與直接訓練這個小模型相比,我們可能能夠從這個更小的模型中獲得每個token的更多信息。
如果投入大量資金進行訓練,能夠得到最具性價比的模型,那么要調(diào)整多少個參數(shù)來實現(xiàn)。應(yīng)該重視模型推理時間的計算。然而,有些人可能已經(jīng)采取了一種過于簡單的方法來關(guān)注推理時間的計算,即他們只是用遠超必要數(shù)量的數(shù)據(jù)來過度訓練那些70億參數(shù)的模型,就像Llama。
如果你真的很在意這個問題,也許可以采用 Google Gamma-27B 的做法:不要僅僅訓練 token,而是直接訓練模型來最小化與Gemma 27B分布之間的KL散度(KL divergence)。這就是知識蒸餾的思路。我們實際上是在用這個 270 億參數(shù)的模型處理所有這些token,最終目的是得到一個更小的模型。
如何復現(xiàn) OpenAI o1
Lex:你們怎么看 OpenAI o1?Test time compute system 未來會將在代碼任務(wù)中扮演什么角色?
Aman:Test time compute 提供了 scaling up 之外的一個不同的思路,即,我們也可以通過增加 inference 使用的 flops 來提升模型性能,通過更長時間的 inference 來實現(xiàn)和更大規(guī)模模型的同等質(zhì)量的輸出。
有一個很有意思的現(xiàn)實是,有些任務(wù)可能需要一個擁有 100 萬億參數(shù)、基于100 萬億 tokens 訓練的超大模型才能解決,但這樣的問題可能只占到 queries 的 1% 甚至 0.1%。那么,這種情況下愿意投入如此巨大資源、時間和算力去訓練一個成本高昂但使用頻率極低的模型是否還有意義呢?這樣做感覺很浪費。
相比之下,一個更合理的策略是,訓練一個規(guī)模較小的模型,這個模型能夠高效地處理 99.9% 的查詢,然后對于那些對智能水平極高的 query,可以選擇通過更長的 inference time 來實現(xiàn)解決。
Lex:如何判斷某個問題需要哪種程度的智能?能不能根據(jù)實際情況動態(tài)決定,比如什么時候使用GPT-4,什么時候使用小模型、什么時候又需要用到 o1?
Aman:這個問題還沒有答案,我覺得目前還沒有人能很好地解決這種 model routing 問題。我們在 Cursor Tab 上做過類似的初步嘗試,但如果是 GPT-4o、Claude sonnet 和 o1 之間的切換可能要更加復雜。
這里還會涉及到個一個問題是,我們需要什么水平的模型來幫助判斷某個任務(wù)是否超出了 GPT-4 水平模型的能力范圍?可能需要一個 o1 水平的模型來作判斷。這個問題目前也沒有答案。
Lex:OpenAI 的做法是不直接給用戶展示思維鏈,而是讓模型對思維鏈進行總結(jié)。同時他們還在后臺監(jiān)控這些思維鏈,以確保模型不會嘗試操控用戶,你怎么看這種做法?
Michael:對于OpenAI來說的一個顧慮可能是他們不想讓人們從他們的模型中提煉出這種能力。如果能夠訪問到那些被隱藏的思維鏈數(shù)據(jù),復刻 o1 可能會變得更加容易,因為我們可以直接看到模型得到最終結(jié)果所采取的步驟,這些數(shù)據(jù)是非常重要的。
Lex:CoT 數(shù)據(jù)可以被用來直接訓模型嗎?
Michael:有一些類似情況可以參考,不過也只是推測。之前有些模型的 API 會提供所有生成 token 的對數(shù)概率(log probabilities)的訪問權(quán)限,包括對 prompt tokens 的概率,不過后來一些模型 API 移除了這些功能。其中一個猜測就是:如果外界可以拿到對數(shù)概率數(shù)據(jù),就像今天我們可以拿到被 OpenAI 隱藏的 CoT 數(shù)據(jù)一樣,這些數(shù)據(jù)都能幫助提供更多信息,讓人們能夠把 SOTA 模型的能力提取出來,再蒸餾到自有模型中。
編譯:海外獨角獸
本文由人人都是產(chǎn)品經(jīng)理作者【海外獨角獸】,微信公眾號:【海外獨角獸】,原創(chuàng)/授權(quán) 發(fā)布于人人都是產(chǎn)品經(jīng)理,未經(jīng)許可,禁止轉(zhuǎn)載。
題圖來自Unsplash,基于 CC0 協(xié)議。
- 目前還沒評論,等你發(fā)揮!