在 AI 編程工具引領(lǐng)潮流的當(dāng)下,許多開發(fā)者仍在觀望,疑惑這些“AI 輔助編碼”工具究竟有多大實(shí)用價(jià)值,是否值得為高昂的訂閱費(fèi)用買單。本篇文章中,從事編程工作已有 36 年的開發(fā)者 Tom Yedwab 將以 Cursor 為例,分享他對(duì)這款工具的實(shí)際體驗(yàn)與見解,希望能為仍在猶豫的讀者提供有價(jià)值的參考。
作者 | Tom Yedwab 責(zé)編 | 蘇宓出品 | CSDN(ID:CSDNnews)在 AI 編程的論壇中,我經(jīng)常會(huì)看到有軟件開發(fā)人員提出一個(gè)常見的問題:有人從 Cursor 這樣的工具中獲得價(jià)值嗎?為此付費(fèi)訂閱是否值得?
于是,在將 Cursor 作為我個(gè)人和工作項(xiàng)目中日常工具使用了幾個(gè)月后,我有一些觀點(diǎn)想和大家分享,以此來討論這究竟是一個(gè)“必備”工具,還是僅僅曇花一現(xiàn)的流行產(chǎn)品。同時(shí),我還會(huì)介紹一些快速獲得最大化收益的策略,希望能幫助那些想嘗試它的人?赡苡行┤嗽囘^ Cursor,覺得效果不盡人意,而這些建議也許能激勵(lì)你再給它一個(gè)機(jī)會(huì)。
我沒有受到 Cursor 的贊助,也不是產(chǎn)品評(píng)測(cè)者。我既不是要推崇它,也不是要貶低它,只是想分享我個(gè)人的使用體驗(yàn)。
我是誰?
首先,先向大家介紹一下我自己。我是有一名有著 36 年編程經(jīng)驗(yàn)的開發(fā)者,熟練掌握多種語言,主要專注于 C 語言為主的游戲引擎開發(fā),以及 Go、Python、JavaScript 的網(wǎng)頁開發(fā)。我假設(shè)這篇文章的讀者同樣能夠在大型代碼庫中自如地工作,能用自己擅長(zhǎng)的語言編寫和調(diào)試代碼等。對(duì)于那些希望借助 AI 學(xué)習(xí)編程概念或想讓 AI 替他們寫超出自身水平的代碼的初學(xué)者,我會(huì)提供完全不同的建議!
對(duì)我來說,AI 助手的吸引力在于幫我處理模板化和重復(fù)性的工作,這樣我可以集中精力在每個(gè)問題的核心邏輯上。我對(duì)自動(dòng)生成大量代碼并不特別感興趣,對(duì)“寫了多少行代碼”作為效率指標(biāo)持高度懷疑態(tài)度。我更希望在花費(fèi)更少時(shí)間寫同樣多代碼的情況下,有更多時(shí)間去思考邊界情況、可維護(hù)性等問題。
那么,言歸正傳:
什么是 Cursor?
Cursor 是基于 Visual Studio Code(VS Code)開發(fā)的一個(gè)分支版本,內(nèi)置了大模型(LLM)支持的功能,集成在核心界面中。這是一個(gè)專有產(chǎn)品,開發(fā)商提供了免費(fèi)和訂閱兩種方案;不過,價(jià)格表并沒有明確說明訂閱用戶的具體權(quán)益,以及與其他競(jìng)品的區(qū)別。我會(huì)結(jié)合自己的理解,在后續(xù)功能介紹中盡量說明這一點(diǎn),以下是簡(jiǎn)要總結(jié):
Tab 補(bǔ)全:這是一組專有的微調(diào)模型,提供代碼補(bǔ)全功能,并可以通過 Tab 鍵跳轉(zhuǎn)到下一個(gè)推薦操作。該功能僅對(duì)訂閱用戶開放。
內(nèi)聯(lián)編輯(Inline editing):這是一個(gè)基于聊天界面的編輯工具,可以對(duì)選定代碼進(jìn)行修改,并通過簡(jiǎn)單的差異視圖顯示更改,采用基礎(chǔ)模型如 GPT 或 Claude。此功能對(duì)免費(fèi)和付費(fèi)用戶均開放。
聊天側(cè)邊欄:同樣是基于聊天的編輯界面,允許在側(cè)邊欄進(jìn)行更大范圍的修改,支持更長(zhǎng)的討論、多文件代碼建議等,采用基礎(chǔ)模型如 GPT 或 Claude。此功能對(duì)免費(fèi)和付費(fèi)用戶均開放。
Composer:這是專門用于跨代碼庫大規(guī)模重構(gòu)的聊天界面,生成多個(gè)文件的差異視圖供用戶逐一查看和批準(zhǔn),使用基礎(chǔ)模型如 GPT 或 Claude。此功能對(duì)免費(fèi)和付費(fèi)用戶均開放。
Tab 補(bǔ)全
雖然其他由 LLM 驅(qū)動(dòng)的編碼工具更側(cè)重于聊天體驗(yàn),但在我使用 Cursor 的過程中,Tab 補(bǔ)全功能才是最符合我日常編碼習(xí)慣并能節(jié)省最多時(shí)間的功能。顯然,這個(gè)功能背后投入了大量的思考和技術(shù)研究,因此它不僅可以建議一行、多行,甚至整個(gè)函數(shù)的代碼補(bǔ)全,還可以建議下一個(gè)需要編輯的行。這樣一來,只需不斷按下 Tab 鍵,就能在整個(gè)文件中自動(dòng)完成相關(guān)的修改。
使用它的一種用法是將它當(dāng)作一個(gè)“增強(qiáng)版”代碼重構(gòu)工具。例如,假設(shè)我有一段代碼塊,其中的變量名是 under_score,而我希望將它們改為 camelCase。我只需重命名一個(gè)變量的一個(gè)實(shí)例,然后逐行按 Tab 鍵,就能更新所有需要更改的行,包括其他相關(guān)變量。許多繁瑣、容易出錯(cuò)的任務(wù)都可以通過這種方式自動(dòng)完成,而無需額外編寫腳本:
有時(shí) Tab 補(bǔ)全甚至?xí)?dú)立發(fā)現(xiàn)并提出修復(fù) bug 的建議。很多時(shí)候,當(dāng)我在 Python 或 Go 中添加依賴項(xiàng)時(shí),它會(huì)自動(dòng)建議導(dǎo)入相應(yīng)的模塊。如果我將字符串用引號(hào)給括起來,它會(huì)適當(dāng)?shù)剞D(zhuǎn)義內(nèi)容。與其他工具類似,它還可以根據(jù)函數(shù)簽名和可選的文檔字符串生成整個(gè)函數(shù)代碼:
總體而言,這個(gè)工具感覺就像在讀我的心思,能預(yù)測(cè)我接下來的操作,讓我能更少關(guān)注代碼細(xì)節(jié),而更多專注于構(gòu)建的整體架構(gòu)。
值得一提的是,補(bǔ)全速度極快,幾乎是在我停止輸入的瞬間,代碼建議就彈出來了,完全沒有等待的感覺。如果這個(gè)過程拖延太久,那對(duì)我來說肯定會(huì)是個(gè)大缺點(diǎn)。
那么,我對(duì) Tab 補(bǔ)全的抱怨是什么呢?第一個(gè)問題比較。河袝r(shí)候我沒及時(shí)看到補(bǔ)全建議就繼續(xù)輸入了,結(jié)果建議消失了。而一旦消失,似乎沒辦法讓它重新出現(xiàn),只有重新輸入一部分再試。
另一個(gè)問題剛好相反:有時(shí)補(bǔ)全的建議完全不合適,我會(huì)故意忽略它。然而,偶爾我選擇了一個(gè)不同的補(bǔ)全,但之前忽略的建議卻被悄悄應(yīng)用了。這種情況雖然不多,但已經(jīng)引發(fā)了一些難以察覺的 bug,因?yàn)槲也⑽匆庾R(shí)到不對(duì)的邏輯被誤用。這雖然不至于影響 Tab 補(bǔ)全帶來的效率提升,但確實(shí)稍微影響了體驗(yàn)。
內(nèi)聯(lián)編輯、聊天側(cè)邊欄和 Composer
據(jù)我所知,這些功能在與基礎(chǔ)模型的交互上非常相似我?guī)缀踔挥?Claude 3.5 Sonnet主要區(qū)別在于用戶界面。
內(nèi)聯(lián)編輯可以通過選中代碼并按下 Ctrl-K/Cmd-K 啟動(dòng)。我輸入想要的更改后,文件里會(huì)顯示一個(gè)清晰的差異視圖,讓我選擇接受或拒絕。我主要用它來添加小段代碼或做些小范圍的重構(gòu)。
一個(gè)典型的用法是,當(dāng)我有一個(gè)任務(wù)循環(huán)并想把它并行化時(shí),就可以用這個(gè)功能來處理:
然后,你可以通過 Ctrl+L/Cmd+L 來打開聊天側(cè)邊欄,它為多輪對(duì)話提供了更大的操作空間。不過,我對(duì)當(dāng)前測(cè)試過的 LLM 模型有個(gè)小抱怨:它們總是先返回代碼,而不是在遇到歧義時(shí)先詢問澄清。建議的代碼會(huì)有一個(gè)“應(yīng)用”按鈕,點(diǎn)擊后可以在當(dāng)前選中的文件中生成差異視圖。這對(duì)于單文件的大規(guī)模重構(gòu),或基于當(dāng)前打開的文件創(chuàng)建新文件非常有用。如果涉及其他文件,它們可以手動(dòng)添加到上下文中,不過 Cursor 會(huì)根據(jù)查詢和后臺(tái)生成的索引來猜測(cè)相關(guān)文件。
這里有一個(gè)示例:將應(yīng)用程序的數(shù)據(jù)庫 API 轉(zhuǎn)換為 REST API,并提供參數(shù)驗(yàn)證和正確的 HTTP 狀態(tài)碼,然后再編寫一個(gè)客戶端庫來訪問這個(gè) REST API:
另一個(gè)示例是將這個(gè)客戶端庫從 Python 轉(zhuǎn)換為 Go 語言,注意松散類型的 Python 代碼如何被轉(zhuǎn)換為結(jié)構(gòu)明確的結(jié)構(gòu)體類型,且符合 Go 慣用的錯(cuò)誤處理風(fēng)格!這并非簡(jiǎn)單的 1:1 重寫。
最后,Composer 專門用于跨文件的重構(gòu),這是我最少使用的功能,但它提供了一次性查看多個(gè)文件差異的良好體驗(yàn)。
.cursorrules 文件
我最初并不知道這個(gè)功能的存在,直到在(我認(rèn)為過于簡(jiǎn)略的)文檔中偶然發(fā)現(xiàn)它,那時(shí)我看到各種聊天模式始終會(huì)包含位于工作區(qū)根目錄的 .cursorrules 文件的內(nèi)容,以提供額外的上下文。我目前在嘗試?yán)盟鼇砀嬷?LLM 有關(guān)代碼庫的編碼規(guī)范、常用包和其他文檔信息。
這個(gè)功能可能有助于解決我在使用 Cursor 時(shí)遇到的一個(gè)大難題:它無法遵循代碼風(fēng)格和模式,除非這些風(fēng)格已經(jīng)存在于你正在編輯的文件中。例如,在 Khan Academy,我們使用一個(gè)專有的 Go 庫來在函數(shù)間傳遞上下文,用于日志記錄、HTTP 請(qǐng)求等場(chǎng)景,所以 LLM 需要能夠使用這個(gè)庫。過去這一直很困難,但或許一個(gè)寫得好的 .cursorrules 文件可以作為改進(jìn)的第一步。
目前的限制是每個(gè)工作區(qū)只能有一個(gè) .cursorrules 文件,因此像我們這樣包含多種語言代碼的 monorepo 將比包含一個(gè)小型代碼庫(代碼風(fēng)格一致)要復(fù)雜得多且更難設(shè)置。
另外,文檔提到 .cursorrules 文件僅在聊天模式中使用,而不適用于 Tab 補(bǔ)全。不過,我嘗試將該文件固定在工作區(qū)的一個(gè)標(biāo)簽頁中,確認(rèn)可以讓它至少部分參與到 Tab 補(bǔ)全的上下文中。
對(duì)我的工作流程的改變
像 Cursor 這樣的工具最令人興奮的地方并不是我可以更快地編寫代碼,畢竟寫代碼本身并不是瓶頸;事實(shí)上,我常常需要放慢速度,以免過分關(guān)注代碼本身而忽視要解決的高層次問題。真正的價(jià)值在于它改變了我的編碼方式。
雖然這種技術(shù)還處于早期階段,但到目前為止,我的工作方式已經(jīng)發(fā)生了以下變化,我也期待在不久的將來看到更多改變:
我現(xiàn)在在編碼時(shí)不太傾向于引入新的庫或框架。并不是說我自己會(huì)去寫加密庫,而是對(duì)于小型工具而言,直接讓 LLM 按我的需求生成定制代碼比引入一個(gè)通用庫更簡(jiǎn)單。這些通用庫通常在剛推出時(shí)小巧且輕便,但因?yàn)槭情_放的并且被越來越多的人使用,所以它們慢慢會(huì)積累我不需要的功能和選項(xiàng)。
很多庫存在的意義只是為了減少樣板代碼,過去我會(huì)覺得這很值,因?yàn)橛辛诉@些庫可以幫我省下了寫和維護(hù)代碼的時(shí)間。可現(xiàn)在,LLM 可以幫我完成這些重復(fù)性的工作,所以我覺得使用庫的成本就顯得有些不劃算了。而且,這個(gè)成本可能更高你試過讓一個(gè)寫了一年甚至更久的 Node.js 項(xiàng)目重新跑起來嗎?不過借助 LLM 干脆從頭再寫一遍。
我也不再擔(dān)心在自己的代碼中是否遵循 DRY(不要重復(fù)自己)。過早地定義抽象會(huì)導(dǎo)致后期的技術(shù)債增加,因此能夠參考其他代碼快速生成相似代碼,而不將其抽象為函數(shù)或類,為我提供了更大的靈活性。如果需要在未來將重復(fù)的邏輯重構(gòu)出來,LLM 也能提供幫助。
我對(duì)不熟悉的語言或框架的接受度也更高了。例如,多年來我一直在使用 R 語言,尤其是將它用于數(shù)據(jù)可視化。但說實(shí)話,我對(duì)它并不熟練,我對(duì) dplyr 的理解不深,總覺得有很多不同的方法可以完成同樣的任務(wù),F(xiàn)在我只需描述想要的可視化效果,LLM 就會(huì)自動(dòng)生成相應(yīng)的數(shù)據(jù)操作和 ggplot 可視化。以前花一小時(shí)的任務(wù),現(xiàn)在五分鐘就能完成,所以我更不容易放棄轉(zhuǎn)而用 Python 來做了。
也許有一天我甚至?xí)?Rust 寫點(diǎn)什么;蛟S吧。
我現(xiàn)在會(huì)先對(duì)一些小模塊做快速調(diào)整,然后再把它們整合到大項(xiàng)目里面。這樣做的部分原因是因?yàn)?LLM 處理大項(xiàng)目有些吃力,另一方面也讓我發(fā)現(xiàn)了一些以前沒想到的工作方法。比如,我可以先用 Python 這種靈活的語言來做原型,解決好技術(shù)細(xì)節(jié)后,再迅速轉(zhuǎn)成類型嚴(yán)格的 Go 代碼,直接在 Web 應(yīng)用中。我還可以讓 LLM 自動(dòng)生成測(cè)試數(shù)據(jù),或者模擬一個(gè)后端來對(duì)前端進(jìn)行開發(fā)。既然一個(gè)想法還沒完全確定下來,為什么要一下子投入在成熟的大項(xiàng)目里付出高昂的成本呢?
總結(jié)
我不確定幾年后我是否還會(huì)繼續(xù)使用 Cursor,亦或者轉(zhuǎn)向其他工具。但可以肯定的是,在我撰寫本文時(shí),我覺得 Cursor 是 LLM 編程助手的最佳工具。如果你想探索這類工具可能帶來的價(jià)值,我建議你試試 Cursor。