量的關(guān)鍵杠桿)
我先說個(gè)結(jié)論用了這么久的AI編程助手大部分“AI寫得不對(duì)”的問題根子根本不在模型智商而在“context-mode”也就是上下文模式。這個(gè)詞在國(guó)內(nèi)討論還真不多但我覺得它才是決定AI寫代碼質(zhì)量的最關(guān)鍵一環(huán)——沒有之一。它解決的是“AI怎么知道你當(dāng)前真正在想什么、改什么、項(xiàng)目里有哪些約束”的問題。如果你正準(zhǔn)備把AI塞進(jìn)日常開發(fā)流程或者已經(jīng)用過但總覺得效果飄忽不定這篇就專門掰開揉碎講上下文模式。1. 上下文模式到底是干什么的為什么它決定AI輸出質(zhì)量1.1 一個(gè)被嚴(yán)重低估的工程質(zhì)量杠桿很多人把AI編程助手當(dāng)成“高級(jí)補(bǔ)全工具”覺得只要把問題問得夠清楚AI就能給出完美代碼。實(shí)際用過的人都知道完全不是這么回事。AI的每次生成本質(zhì)上都是“基于當(dāng)前給它看到的所有信息做一次概率預(yù)測(cè)”。它能看到什么、看不到什么完全由上下文模式?jīng)Q定。同樣一句“幫我加個(gè)緩存”在只有當(dāng)前文件上下文和擁有整個(gè)項(xiàng)目的調(diào)用鏈、數(shù)據(jù)模型、歷史改動(dòng)記錄這兩種模式下產(chǎn)出代碼的差距可以大到像兩個(gè)不同水平的人寫的。我見過不少團(tuán)隊(duì)興致勃勃引入AI輔助開發(fā)結(jié)果發(fā)現(xiàn)AI生成的代碼經(jīng)常跟現(xiàn)有架構(gòu)打架明明項(xiàng)目里統(tǒng)一用某個(gè)工具函數(shù)處理時(shí)間AI卻自己new了一個(gè)Date格式化明明數(shù)據(jù)庫(kù)表結(jié)構(gòu)里字段叫user_nameAI卻按userName來寫查詢。這些問題的元兇都不是提示詞寫得不好而是上下文模式?jīng)]有把項(xiàng)目里已有的“約定俗成”喂給AI。上下文模式的核心任務(wù)就是解決“AI的臨時(shí)記憶該裝什么”這個(gè)問題。它決定了哪些文件內(nèi)容會(huì)進(jìn)入AI的視野哪些歷史對(duì)話會(huì)被保留哪些倉(cāng)庫(kù)掃描結(jié)果會(huì)被當(dāng)作約束條件。理解了這個(gè)你才算真正邁過了“會(huì)用AI寫代碼”和“用好AI寫代碼”之間的分水嶺。1.2 上下文就是AI的工作記憶類比一下就懂了把上下文模式想象成給一個(gè)記憶力超強(qiáng)但“只看眼前”的實(shí)習(xí)生分配任務(wù)。這個(gè)實(shí)習(xí)生智商很高但有個(gè)特點(diǎn)你給他看什么材料他就基于什么材料干活。你要是只甩給他一個(gè)文件他就盯著這一個(gè)文件發(fā)揮你要是把整個(gè)項(xiàng)目文檔、代碼規(guī)范、相關(guān)模塊的源碼都擺在他面前他就能寫出跟團(tuán)隊(duì)風(fēng)格一致的代碼。人跟人協(xié)作時(shí)很多背景知識(shí)是不用說的——大家都默認(rèn)知道項(xiàng)目分層是什么樣、命名規(guī)范是什么、線上環(huán)境有什么限制。但AI沒有這種“默認(rèn)”。它唯一的了解渠道就是上下文模式給它的信息。這就是為什么很多人覺得AI寫的代碼“一股機(jī)味”不像團(tuán)隊(duì)自己人寫的——因?yàn)樯舷挛哪J綁焊鶝]把團(tuán)隊(duì)的技術(shù)債、風(fēng)格偏好轉(zhuǎn)達(dá)給AI。在具體技術(shù)層面上下文模式涉及一個(gè)核心指標(biāo)上下文窗口。這是AI單次能處理的最大信息量你可以理解為工作臺(tái)上的最大面積。窗口是有限的但項(xiàng)目代碼是無限的。上下文模式要做的就是在有限的窗口里塞進(jìn)最值得看的內(nèi)容。這本身就是一道做減法的工程題。2. 上下文模式的主要形態(tài)與選型思路2.1 按作用范圍劃分單文件、多文件與全倉(cāng)庫(kù)上下文模式在實(shí)際工具里通常體現(xiàn)為不同的作用范圍。最基礎(chǔ)的是單文件模式AI只能看到你當(dāng)前打開的那個(gè)文件頂多再加上你粘貼到對(duì)話框里的代碼。這種模式輕量、反應(yīng)快適合問一些孤立的小問題比如“這個(gè)函數(shù)為什么報(bào)錯(cuò)”“幫我給這段代碼加注釋”。但它的上限也很明顯一旦問題牽扯到別的文件里的定義或調(diào)用AI就只能靠猜了。往上一個(gè)層級(jí)是多文件模式你可以手動(dòng)把相關(guān)文件添加進(jìn)上下文AI會(huì)同時(shí)看到這些文件的內(nèi)容。這個(gè)模式是目前我覺得性價(jià)比最高的形態(tài)因?yàn)樗尅澳恪眮頉Q定看什么而不是讓工具盲目掃描。比如改一個(gè)接口我就把接口定義文件、實(shí)現(xiàn)文件、調(diào)用方的代碼一起加進(jìn)上下文AI就能理解改動(dòng)的牽連面。再往上就是全倉(cāng)庫(kù)模式工具會(huì)建立索引AI可以按需檢索整個(gè)代碼庫(kù)里的相關(guān)內(nèi)容。這種模式聽起來很美實(shí)際用起來卻要留個(gè)心眼。倉(cāng)庫(kù)一大檢索結(jié)果五花八門AI經(jīng)常會(huì)把不相關(guān)的模塊也作為參考反而產(chǎn)生信息污染。全倉(cāng)庫(kù)模式適合跨模塊排查問題或新人理解老項(xiàng)目架構(gòu)但日常改BUG時(shí)未必比定向添加幾個(gè)文件效果更好。2.2 按信息獲取方式劃分顯式指定、自動(dòng)掃描與對(duì)話記憶除了范圍上下文模式還有一個(gè)維度是獲取方式。顯式指定最直接就是你告訴AI“去看哪個(gè)文件、關(guān)注哪個(gè)部分”。這種方式的最大優(yōu)點(diǎn)是完全可控信息是精確的不會(huì)有多余干擾。缺點(diǎn)是費(fèi)手每次都要手動(dòng)維護(hù)一份“材料清單”。自動(dòng)掃描則是工具通過監(jiān)聽文件變更、Git改動(dòng)記錄自動(dòng)把相關(guān)文件塞進(jìn)上下文。比如你改了A文件工具自動(dòng)把引用A的B文件也加進(jìn)來。這個(gè)模式省心但偶爾會(huì)好心辦壞事比如自動(dòng)加進(jìn)來的文件過多導(dǎo)致上下文被無關(guān)內(nèi)容占滿反而擠掉了真正重要的信息。我傾向于把自動(dòng)掃描當(dāng)成“輔助”而不是“全權(quán)代理”。對(duì)話記憶則是另一種容易被忽略的上下文形態(tài)。它指的是AI能記住你們之前聊過什么、你糾正過它什么。有些上下文模式開啟長(zhǎng)對(duì)話記憶后AI會(huì)沿用之前幾輪對(duì)話里的偏好和修正比如你說過“不要用可選鏈”之后它再生成代碼時(shí)就會(huì)避開這種寫法。這是把協(xié)作經(jīng)驗(yàn)沉淀下來的機(jī)制非常值得長(zhǎng)期用。2.3 選擇上下文模式的三個(gè)判斷標(biāo)準(zhǔn)選哪種模式我最看重三個(gè)標(biāo)準(zhǔn)。第一是相關(guān)性密度也就是單位上下文里有多少信息真正有用。單文件模式的相關(guān)性密度最高但覆蓋不足全倉(cāng)庫(kù)模式覆蓋足但密度會(huì)被稀釋。第二是維護(hù)成本手動(dòng)指定雖然準(zhǔn)但每次任務(wù)都手動(dòng)配置也很煩需要權(quán)衡。第三是反饋閉環(huán)也就是AI能不能知道自己上次哪里錯(cuò)了并糾正對(duì)話記憶在這里起主要作用。有一個(gè)粗糙的經(jīng)驗(yàn)法則任務(wù)越聚焦上下文范圍越要小任務(wù)越開放才需要?jiǎng)佑酶蟮乃饕秶?。改一個(gè)函數(shù)三步之內(nèi)的調(diào)用關(guān)系用多文件手動(dòng)指定就夠排查一個(gè)偶發(fā)的線上異常才值得讓AI去全倉(cāng)庫(kù)里搜線索。明確任務(wù)邊界再倒推需要多大的上下文范圍這比盲目追求“看得越多越好”要實(shí)用得多。3. 實(shí)操階段配置上下文模式的關(guān)鍵步驟與參數(shù)3.1 建立項(xiàng)目級(jí)代碼索引的正確姿勢(shì)不管用哪種上下文模式第一步都應(yīng)該是把項(xiàng)目的關(guān)鍵信息結(jié)構(gòu)化地喂給AI。我在實(shí)操中會(huì)先在項(xiàng)目根目錄維護(hù)一份AGENTS.md這樣的說明文件把項(xiàng)目的技術(shù)棧、目錄結(jié)構(gòu)、命名規(guī)范、特殊約束寫進(jìn)去然后讓上下文模式把這份文件作為“永久啟動(dòng)項(xiàng)”。這么做的好處是AI在每次會(huì)話開始時(shí)就先讀這份文件就像給實(shí)習(xí)生一份入職手冊(cè)后面再讓它干活它的行為就會(huì)明顯更貼合團(tuán)隊(duì)習(xí)慣。配置這個(gè)說明文件有幾個(gè)要點(diǎn)。一是要寫“禁止項(xiàng)”而不僅僅是“要做什么”。比如“不要修改 xxx 模塊的接口定義”“不允許在業(yè)務(wù)代碼里直接操作原生SQL”這種負(fù)面清單對(duì)AI糾偏的效果特別顯著。二是要描述目錄職責(zé)而不是貼目錄列表。直接貼整個(gè)目錄樹意義不大AI記不住也理解不了但寫明“src/services 放業(yè)務(wù)編排層src/repos 放數(shù)據(jù)訪問層跨層調(diào)用一律走 services”就能讓AI生成新文件時(shí)選對(duì)位置。其次是配置文件里通常需要設(shè)置忽略列表。有些工具支持類似context.ignore的配置把 node_modules、構(gòu)建產(chǎn)物目錄、鎖文件排除在上下文掃描之外。這一步看著不起眼實(shí)際對(duì)上下文質(zhì)量的提升非常明顯。因?yàn)橐蕾嚹夸浝锏奈募?dòng)輒成千上萬如果不排除AI進(jìn)行全倉(cāng)庫(kù)模式掃描時(shí)會(huì)被海量無關(guān)代碼淹沒檢索相關(guān)性的精度會(huì)斷崖式下降。3.2 控制上下文規(guī)模窗口占用與優(yōu)先級(jí)管理上下文窗口是所有上下文模式的硬約束所以掌握基本的占用估算很重要。一個(gè)粗略的換算經(jīng)驗(yàn)是1個(gè)英文字符約占1個(gè)token左右1個(gè)中文字符約占1.5到2個(gè)token。一個(gè)300行左右的源碼文件大概會(huì)占用掉 2000 到 3000 個(gè)token。主流工具的上下文窗口常見在數(shù)萬到十幾萬token之間聽起來很大但如果你一次性把整個(gè)項(xiàng)目的二十個(gè)核心文件都加進(jìn)去窗口很快就會(huì)報(bào)警。所以我會(huì)給上下文里的文件排優(yōu)先級(jí)。第一優(yōu)先級(jí)是當(dāng)前正在修改的文件本身第二是它直接依賴的接口、類型定義、Schema第三是調(diào)用方的代碼用來確認(rèn)改動(dòng)不破壞外部契約第四才是項(xiàng)目級(jí)規(guī)范說明文件。按這個(gè)優(yōu)先級(jí)順序添加文件就算窗口再緊張也能保證最關(guān)鍵的約束信息都在。有一類工具會(huì)把上下文按“會(huì)話內(nèi)文件列表”展示出來我強(qiáng)烈建議你每次開會(huì)話時(shí)養(yǎng)成檢查這個(gè)列表的習(xí)慣??纯蠢锩媸遣皇腔爝M(jìn)了過期文件、無關(guān)模塊及時(shí)做清理。很多AI輸出質(zhì)量不穩(wěn)定的問題其實(shí)就藏在那些你沒注意到的多余上下文里。3.3 典型場(chǎng)景的上下文配置示例我舉一個(gè)真實(shí)的例子某次要給一個(gè)結(jié)算模塊增加新的計(jì)費(fèi)規(guī)則。這個(gè)任務(wù)橫跨數(shù)據(jù)模型、業(yè)務(wù)服務(wù)、對(duì)外接口三個(gè)層面。我沒有直接開啟全倉(cāng)庫(kù)模式而是手動(dòng)指定了這幾個(gè)文件計(jì)費(fèi)規(guī)則的表結(jié)構(gòu)遷移文件、結(jié)算服務(wù)的核心實(shí)現(xiàn)、對(duì)外暴露的REST接口定義、項(xiàng)目根目錄的架構(gòu)說明文件。四個(gè)文件加上當(dāng)前會(huì)話上下文總量控制得很舒服AI生成的代碼不但符合表結(jié)構(gòu)字段命名還自動(dòng)遵循了服務(wù)層已有的事務(wù)邊界寫法。另一個(gè)典型場(chǎng)景是排查編譯報(bào)錯(cuò)。這種任務(wù)最好用單文件模式起步先把報(bào)錯(cuò)文件丟給AI讓它解釋錯(cuò)誤原因。如果它提到某個(gè)外部符號(hào)或依賴再按需把那部分代碼加進(jìn)上下文。這樣做的好處是鏈路短、反饋快不會(huì)在排查初期就被大量無關(guān)文件干擾判斷。排查類任務(wù)講究的是“沿著線索逐步展開”不是一張信息大網(wǎng)撒下去這點(diǎn)跟開發(fā)類任務(wù)的上下文策略有很大區(qū)別。4. 上下文模式的常見問題與排查技巧4.1 上下文被無關(guān)文件污染AI反而變笨很多人在從單文件模式切換到多文件或全倉(cāng)庫(kù)模式后發(fā)現(xiàn)自己IDE里的AI反而開始亂寫。最典型的表現(xiàn)是AI引用了不該引用的工具類或者融合了多個(gè)模塊的不同風(fēng)格生成出一段四不像代碼。原因幾乎可以斷定是上下文里塞進(jìn)了大量相關(guān)性弱的文件把真正關(guān)鍵的信息擠到邊緣去了。排查方法是先清空上下文然后按我前面說的優(yōu)先級(jí)順序重新一個(gè)個(gè)添加文件。每次添加完一個(gè)文件都觀察AI在后續(xù)任務(wù)里的行為是否更準(zhǔn)。如果添加某個(gè)文件后反而開始出現(xiàn)錯(cuò)誤傾向說明這個(gè)文件本身就是干擾源應(yīng)該剔除。這種“控制變量法”排查上下文污染效率遠(yuǎn)高于盲目清空重開。4.2 上下文過期文件更新了AI還在用舊邏輯另一個(gè)高頻坑是上下文里的內(nèi)容跟磁盤上的實(shí)際代碼不一致。比如你改了某個(gè)函數(shù)簽名但上下文是靠啟動(dòng)會(huì)話時(shí)的快照建立的AI對(duì)話時(shí)用的還是舊簽名于是生成的調(diào)用代碼全部對(duì)不上。這在我早期使用自動(dòng)掃描模式時(shí)踩過好多次后來養(yǎng)成了習(xí)慣每次大幅度改動(dòng)文件后要么手動(dòng)刷新上下文要么干脆重開會(huì)話。如果使用的工具支持“基于Git變更同步上下文”我會(huì)優(yōu)先開啟并且確保每次提交前帶著新改動(dòng)開會(huì)話。還要特別留意一個(gè)場(chǎng)景代碼里存在被注釋掉的舊邏輯塊。AI默認(rèn)會(huì)把這些注釋內(nèi)容當(dāng)作有效信息學(xué)習(xí)如果你在重構(gòu)期間保留了大量歷史注釋代碼AI參考到它們后很容易輸出過時(shí)代碼。遇到這種情況我會(huì)在上下文說明文件里加一句“忽略所有被注釋的舊實(shí)現(xiàn)”讓AI從源頭上避開這些干擾。4.3 上下文不足AI開始憑空發(fā)明接口和污染對(duì)應(yīng)的是另一種情況上下文相關(guān)文件沒加夠AI只能用訓(xùn)練記憶里的“常見套路”來填空。比如你項(xiàng)目里明明有個(gè)封裝好的冪等工具但上下文里沒提AI根本不知道它的存在就自己用Redis手寫了一套。這種行為最難排查因?yàn)锳I生成的代碼看起來能跑但和項(xiàng)目里已有的能力重復(fù)屬于隱性技術(shù)債。這種問題的解決辦法不是把整個(gè)項(xiàng)目的文件都塞進(jìn)上下文而是在項(xiàng)目的AGENTS.md里明確羅列“能力清單”。把項(xiàng)目里已經(jīng)封裝好的公共能力比如緩存工具、冪等組件、統(tǒng)一異常處理、日志工具逐條寫明白標(biāo)注“已存在不要重復(fù)實(shí)現(xiàn)”。AI只要讀到這些就會(huì)優(yōu)先復(fù)用而不是重新發(fā)明。這個(gè)技巧對(duì)降低AI生成代碼與現(xiàn)有架構(gòu)的沖突非常有效實(shí)操中強(qiáng)烈建議落實(shí)。4.4 上下文模式常見問題速查表現(xiàn)象根因處理方式AI總引用不存在的API依賴方代碼未進(jìn)上下文添加被調(diào)用模塊的入口文件輸出風(fēng)格與項(xiàng)目不一致規(guī)范說明文件缺失建立并掛載AGENTS.md規(guī)范全倉(cāng)庫(kù)模式下答非所問掃描范圍過大壓縮忽略列表或改多文件模式改了文件但AI還在用舊代碼上下文快照過期手動(dòng)刷新上下文或重開會(huì)話上下文窗口頻繁報(bào)滿單次添加文件過多按優(yōu)先級(jí)刪減只留關(guān)鍵文件AI重復(fù)造輪子已有能力未告知在規(guī)范文件寫明現(xiàn)有組件清單5. 我自己的使用習(xí)慣與后續(xù)擴(kuò)展方向5.1 日常開發(fā)中已經(jīng)固化的上下文鐵律用久了之后我給自己總結(jié)了幾條關(guān)于上下文模式的鐵律。第一條是“開工前必寫規(guī)范”不管項(xiàng)目多小我都會(huì)花十分鐘給AI準(zhǔn)備一份項(xiàng)目速覽這筆投資的回報(bào)率高得驚人。第二條是“會(huì)話按任務(wù)開不按時(shí)間開”一個(gè)會(huì)話只圍繞一個(gè)明確任務(wù)任務(wù)完成就開新會(huì)話避免舊對(duì)話記憶干擾新方向。第三條是“上下文寧缺毋濫”只在AI明確表示“少了信息”時(shí)才追加文件絕不提前把整倉(cāng)代碼都喂進(jìn)去。這幾條習(xí)慣看上去不起眼但它們直接決定了我和AI協(xié)作的效率。我身邊不少同事也配置了頂級(jí)的AI工具但產(chǎn)出質(zhì)量的差距很大細(xì)聊下來幾乎都是上下文管理習(xí)慣的差距而不是工具本身。一個(gè)會(huì)管理上下文的人哪怕用一個(gè)基礎(chǔ)模型也能寫出符合項(xiàng)目約束的代碼一個(gè)不會(huì)管理上下文的人就算模型再?gòu)?qiáng)也只能得到一堆“正確但沒用”的答案。5.2 這個(gè)方向還可以怎么深入上下文模式這個(gè)方向目前能玩的點(diǎn)其實(shí)還很多。一個(gè)是把上下文模式跟項(xiàng)目沉淀結(jié)合起來比如把多個(gè)歷史會(huì)話里AI犯過的錯(cuò)誤整理成一條條“團(tuán)隊(duì)避坑規(guī)范”持續(xù)回灌到規(guī)范文件里讓后邊的會(huì)話越來越懂你們團(tuán)隊(duì)。另一個(gè)是利用工具的指令模板功能把“代碼審查”“性能優(yōu)化”“寫單元測(cè)試”這些高頻任務(wù)的上下文范圍固化下來每次調(diào)用直接復(fù)用不用重新配置。我覺得后續(xù)更值得關(guān)注的是上下文管理的自動(dòng)化程度比如按文件依賴圖自動(dòng)計(jì)算關(guān)鍵路徑、自動(dòng)識(shí)別過期內(nèi)容并標(biāo)記這些能力會(huì)讓上下文模式從“手動(dòng)調(diào)教”進(jìn)化為“智能編排”。不過在那之前先把基礎(chǔ)的手動(dòng)管理做扎實(shí)一定是穩(wěn)賺不賠的投入。我自己的下一步是把規(guī)范文件按模塊拆分讓AI拿到任務(wù)時(shí)只加載對(duì)應(yīng)模塊的規(guī)范進(jìn)一步降低上下文噪音這也是我對(duì)context-mode這個(gè)方向最期待的部分。