反饋驅(qū)動(dòng)的AutoDebug Agent:從失敗測試到自動(dòng)修復(fù))
凌晨兩點(diǎn)半線上告警把我和枕頭拆散打開日志一瞧又是空指針而且就在同事上周重構(gòu)完的支付模塊里。這種時(shí)候我腦子里反復(fù)滾著一句話能不能寫個(gè)Agent讓它自己把bug給修了。說干就干這就是AutoDebug Agent的由來——一個(gè)基于真實(shí)運(yùn)行反饋、能自主定位缺陷并生成修復(fù)方案的Agent項(xiàng)目。這里說的缺陷是軟件世界里的bug不是工業(yè)視覺里那種軸承、試管的外觀缺陷檢測。AutoDebug Agent做的是把一段真實(shí)的失敗信息丟給Agent讓它自己去復(fù)現(xiàn)、診斷、寫補(bǔ)丁、跑測試然后再根據(jù)新的測試結(jié)果決定是收工還是繼續(xù)修。它解決的是開發(fā)過程中最磨人的那部分——大量重復(fù)的、低級(jí)的、但又必須有人蹲在電腦前盯著的bug修復(fù)工作適合日常開發(fā)被bug反復(fù)糾纏的程序員、維護(hù)一堆歷史工程的老兵、想往CI/CD流水線里塞自動(dòng)修復(fù)能力的DevOps以及想把Agent產(chǎn)品化成內(nèi)部工具的技術(shù)負(fù)責(zé)人。1. 這個(gè)Agent到底在修什么核心思路與場景拆解1.1 為什么寫AutoDebug Agent它和其他自動(dòng)化工具差在哪很多AI自動(dòng)修復(fù)的演示是在精心準(zhǔn)備的代碼庫里跑通一個(gè)預(yù)埋好的缺陷反饋也是設(shè)計(jì)好的跑通了就錄個(gè)視頻發(fā)出來。真拿這種思路去修真實(shí)項(xiàng)目里的bug基本會(huì)撞得頭破血流——真實(shí)世界里哪有那么多讀一遍代碼就能看出來的缺陷。AutoDebug Agent的思路不是讀代碼找bug而是讓Agent進(jìn)入一個(gè)觀察-診斷-修復(fù)-驗(yàn)證的閉環(huán)把每次代碼真實(shí)執(zhí)行產(chǎn)生的信號(hào)當(dāng)成下一輪判斷的依據(jù)。用最簡單的話說它不是靠猜而是靠試。你給它一個(gè)失敗的測試它先看為什么失敗改完再跑一遍看是不是真的解決了沒解決就帶著新的失敗信息重新診斷。這跟傳統(tǒng)自動(dòng)化測試工具有本質(zhì)區(qū)別。靜態(tài)掃描工具能告訴你這里可能越界但它不會(huì)替你寫補(bǔ)丁再跑一遍回歸驗(yàn)證。CI系統(tǒng)能把失敗的構(gòu)建甩到你臉上但它不會(huì)自己動(dòng)手把問題修好再重新提交。AutoDebug Agent真正想接手的是定位-修改-驗(yàn)證這一整條動(dòng)作鏈而不僅僅是發(fā)現(xiàn)。1.2 真實(shí)反饋是什么以及它為什么是會(huì)修的關(guān)鍵真實(shí)反饋是AutoDebug Agent標(biāo)題里最關(guān)鍵的定語。什么是真實(shí)反饋就是代碼真實(shí)執(zhí)行之后產(chǎn)生的信號(hào)不是人腦模擬出來的理想輸出也不是人工標(biāo)注好的標(biāo)準(zhǔn)答案。最典型的一類反饋是測試失敗信息。拿Python項(xiàng)目舉例pytest跑完一個(gè)用例失敗輸出里通常包含斷言實(shí)際值和期望值、拋異常的行號(hào)、堆棧里經(jīng)過哪些函數(shù)。這套信息對(duì)Agent來說就是雷達(dá)信號(hào)模型看到期望值是True實(shí)際值是False、看到traceback定位到某個(gè)文件它才有條件把問題和代碼位置關(guān)聯(lián)起來。除了測試輸出還有幾類反饋同樣重要編譯和類型錯(cuò)誤TS類型不匹配、Rust借用檢查失敗、Go空指針解引用警告運(yùn)行時(shí)堆棧和日志線上服務(wù)異常日志帶request_id和調(diào)用鏈上下文靜態(tài)分析告警lint規(guī)則觸發(fā)、安全掃描報(bào)告、復(fù)雜度告警版本控制歷史git blame、最近的提交記錄能告訴Agent這個(gè)文件最近被誰動(dòng)過、改了什么用戶行為信息復(fù)現(xiàn)步驟、異常截圖、一句話描述尤其是UI類缺陷這些反饋的共同特點(diǎn)是它們是一手信息直接來自代碼運(yùn)行的結(jié)果。讓Agent基于這些信號(hào)去修而不是基于它對(duì)代碼的感覺這是AutoDebug Agent區(qū)別于其他demo級(jí)Agent的本質(zhì)差異。反饋的顆粒度直接決定了修復(fù)能力的上限。給Agent的信息越接近一個(gè)真實(shí)工程師調(diào)試時(shí)看到的信息它就越能做出靠譜的判斷。如果你只丟給它一個(gè)測試失敗的結(jié)論再強(qiáng)的模型也只能是在黑暗中瞎摸。1.3 適用場景和不適用場景先把丑話說前面我得先潑一盆冷水AutoDebug Agent不是萬能的也不是拿來替代程序員的。實(shí)測下來最適合的是這幾類場景單元測試和集成測試覆蓋較高的模塊覆蓋率至少60%以上否則反饋太稀疏Agent根本沒法定位異常類型明確的bug比如空指針、越界、超時(shí)、版本兼容性問題能在幾個(gè)文件范圍內(nèi)定位的中小型缺陷修完之后有回歸測試可以驗(yàn)證的模塊不適合的場景也很明確設(shè)計(jì)層面的架構(gòu)問題比如緩存一致性設(shè)計(jì)錯(cuò)了這不是一次修復(fù)循環(huán)能解決的跨十幾個(gè)服務(wù)、幾十張數(shù)據(jù)表的鏈路故障反饋信息爆炸而且大量缺失依賴外部硬件、特殊設(shè)備或真實(shí)用戶流的環(huán)境Agent沒法在本地復(fù)現(xiàn)完全沒有測試覆蓋的遺留系統(tǒng)一個(gè)文件三千行Agent盲修的風(fēng)險(xiǎn)極高這個(gè)工具的價(jià)值不是替代工程師而是把修bug這個(gè)動(dòng)作里最耗時(shí)的可復(fù)現(xiàn)、可定位、可驗(yàn)證環(huán)節(jié)壓縮到分鐘級(jí)。我在設(shè)計(jì)AutoDebug Agent時(shí)的目標(biāo)很樸素讓Agent像實(shí)習(xí)生一樣先把能查的查了能改的改了把真正需要人類判斷的部分留給我。2. 技術(shù)架構(gòu)與關(guān)鍵設(shè)計(jì)Agent的骨架怎么搭2.1 感知層把缺陷信息變成模型看得懂的輸入Agent要干活第一步是拿到它能用的信息。感知層是所有反饋信號(hào)的入口也是我最先設(shè)計(jì)、后來改動(dòng)最多的模塊。設(shè)計(jì)原則只有一條把原始信號(hào)做結(jié)構(gòu)化處理、壓縮體積、按診斷優(yōu)先級(jí)排序再喂給模型。原始信號(hào)是各種格式混雜的pytest輸出是純文本GitHub Actions日志是一大坨時(shí)間戳加著色控制字符線上日志是JSON堆棧是帶文件路徑和行號(hào)的多行文本。如果直接把拷貝的原始輸出丟給模型效果會(huì)非常差——上下文被無關(guān)信息塞滿模型反而找不到重點(diǎn)。我的做法分三步第一步歸一化。寫一組解析器把不同測試框架的失敗輸出轉(zhuǎn)成統(tǒng)一結(jié)構(gòu)包括測試名稱、失敗類型、斷言詳情、堆棧列表。這一步的作用是把機(jī)器輸出變成結(jié)構(gòu)化事件。第二步壓縮。堆棧按規(guī)則排序后只保留應(yīng)用內(nèi)代碼的frame刪除框架內(nèi)部和第三方庫的frame日志按級(jí)別過濾保留ERROR和WARN去掉INFO和DEBUG的噪音。壓縮的目標(biāo)是把原始10KB的反饋壓到2KB以內(nèi)同時(shí)保住關(guān)鍵信息。第三步排序。把信息按診斷價(jià)值排序先給核心異常類型和消息再給出現(xiàn)異常的文件和行號(hào)接著是相關(guān)堆棧然后才是測試上下文和額外日志。模型讀token是有位置偏置的開頭的內(nèi)容權(quán)重最高所以一定要把最該讓模型看到的東西放前面。這一步看起來不起眼但直接決定了后面修復(fù)循環(huán)能不能跑通。我的經(jīng)驗(yàn)是80%的Agent失敗不是模型不夠聰明而是喂給模型的信息不對(duì)或不夠。2.2 決策與行動(dòng)層修復(fù)循環(huán)的設(shè)計(jì)AutoDebug Agent的核心是一個(gè)修復(fù)循環(huán)像人的調(diào)試流程一樣分階段推進(jìn)。第一步是復(fù)現(xiàn)。Agent拿到反饋后先嘗試運(yùn)行相關(guān)測試或命令確認(rèn)缺陷能不能復(fù)現(xiàn)。這個(gè)階段如果復(fù)現(xiàn)不了Agent應(yīng)該停下來問人而不是瞎猜。第二步是診斷。模型基于反饋信息和代碼上下文生成假設(shè)指出最可能的根因。這個(gè)階段的輸出不直接是代碼而是自然語言的診斷結(jié)論包括證據(jù)和懷疑點(diǎn)。第三步是修復(fù)。根據(jù)診斷結(jié)論生成一個(gè)最小化代碼變更。我要求Agent盡量只改相關(guān)行不要順手重構(gòu)不相關(guān)的代碼。第四步是驗(yàn)證。跑測試、跑lint、編譯收集新的反饋。如果測試通過進(jìn)入回歸檢查如果失敗帶著新反饋回到第二步形成循環(huán)。這個(gè)循環(huán)的本質(zhì)是一個(gè)假設(shè)-驗(yàn)證-修正的迭代過程。每輪迭代模型都根據(jù)最新的測試結(jié)果修正自己對(duì)根因的判斷。我把核心骨架寫成偽代碼def autodebug_fix_loop(issue, feedback_store, model, tools): context build_context(issue, feedback_store) for attempt in range(MAX_ATTEMPTS): if attempt 0: diagnosis model.diagnose(context, feedback_store.last_failure()) if diagnosis.get(unreproducible): return {status: needs_human, reason: 無法復(fù)現(xiàn)} else: diagnosis model.refine_diagnosis(diagnosis, new_feedback) patch model.generate_patch(diagnosis, codebase_context) if not validate_patch(patch): continue # 補(bǔ)丁語法都不對(duì)直接重來 apply_patch(patch) result run_tests_and_checks() if result.failed: new_feedback feedback_store.record(result) continue if run_regression().failed: # 當(dāng)前測試過了但回歸掛了 new_feedback feedback_store.record(run_regression()) continue return {status: fixed, patch: patch, attempts: attempt 1} return {status: timeout, last_feedback: feedback_store.latest()}關(guān)鍵點(diǎn)在于循環(huán)不是無限跑的。我給MAX_ATTEMPTS設(shè)定默認(rèn)值5最多嘗試五輪。原因有兩層一是每輪都會(huì)消耗token和計(jì)算資源二是從實(shí)踐中看五輪還修不好繼續(xù)下去大概率是模型在同一個(gè)錯(cuò)誤假設(shè)里打轉(zhuǎn)不如收集好上下文交給人類。另一個(gè)設(shè)計(jì)細(xì)節(jié)是validate_patch這一步。不要直接讓模型生成的補(bǔ)丁覆蓋文件——先用AST解析、語法檢查甚至先看diff的改動(dòng)范圍。語法不對(duì)立刻丟棄這個(gè)環(huán)節(jié)能攔截掉一大部分模型幻覺式輸出。2.3 記憶層讓Agent跨會(huì)話學(xué)習(xí)Agent記憶確實(shí)是能力提升的隱藏杠桿。AutoDebug Agent的短期記憶就是當(dāng)前修復(fù)會(huì)話的上下文這沒問題真正有價(jià)值的是長期記憶。我自己的長期記憶實(shí)現(xiàn)思路是這樣的用一個(gè)向量庫或者簡單的JSON文件記錄三類經(jīng)驗(yàn)。第一類是修復(fù)過的缺陷特征包括錯(cuò)誤類型、發(fā)生在什么模塊、根因是什么、最后怎么修的。第二類是有用的命令和查詢模板比如查這個(gè)服務(wù)全部日志用grep -r order_id logs/這樣的固定模式。第三類是項(xiàng)目特有的約定比如這個(gè)倉庫提交前必須跑make format。每次修復(fù)成功后把這次的診斷結(jié)論和補(bǔ)丁摘要寫進(jìn)記憶庫。下次遇到類似錯(cuò)誤Agent先檢索記憶庫把歷史相似案例作為上下文注入。這個(gè)設(shè)計(jì)在積累幾十個(gè)案例后效果明顯相當(dāng)于Agent在自己給自己加經(jīng)驗(yàn)。記憶庫要防止臟數(shù)據(jù)。我只記錄經(jīng)過驗(yàn)證的成功案例不記錄失敗嘗試。失敗的嘗試往往帶有誤導(dǎo)性會(huì)讓Agent把錯(cuò)誤的修復(fù)路徑當(dāng)成可能方案。2.4 安全邊界Agent能做什么、不能做什么搞Agent的人最容易忽略的就是安全邊界。AutoDebug Agent能執(zhí)行命令、能改代碼、能跑測試這在本地開發(fā)環(huán)境還好一旦接入CI或者給了它一定的倉庫權(quán)限風(fēng)險(xiǎn)立即放大。我做的第一道防線是沙箱執(zhí)行。Agent通過一個(gè)受限的runtime執(zhí)行命令只允許白名單內(nèi)的操作跑測試、讀文件、改倉庫內(nèi)文件、執(zhí)行g(shù)it diff和git log。禁止網(wǎng)絡(luò)請求、禁止訪問其他目錄、禁止安裝系統(tǒng)級(jí)依賴。第二道防線是文件修改策略。補(bǔ)丁應(yīng)用到真實(shí)代碼前先在臨時(shí)分支上應(yīng)用、跑驗(yàn)證、通過后再合回當(dāng)前分支。我習(xí)慣用git stash加臨時(shí)branch的流程這樣即使Agent闖禍一條checkout就能完全恢復(fù)。第三道防線是審批門檻。涉及刪除、push、合入主干這些高影響操作全部停下來等人點(diǎn)確認(rèn)。Agent可以當(dāng)好實(shí)習(xí)生但不能讓它掌握發(fā)布權(quán)限。還有一點(diǎn)容易被漏超時(shí)控制。每條命令必須有超時(shí)上限比如跑測試最多10分鐘。沒有超時(shí)的Agent就像沒有辭退機(jī)制的實(shí)習(xí)生能把整個(gè)CI卡死。我見過把Agent掛在一條等待輸入的命令上拖了半個(gè)小時(shí)的場景別問我怎么知道的。3. 實(shí)操記錄從零搭一個(gè)能修缺陷的Agent3.1 環(huán)境準(zhǔn)備與框架選型實(shí)際操作前先說環(huán)境。我建議的起步配置是Python 3.11以上寫Agent骨架本身用Python最順手一個(gè)支持工具調(diào)用的強(qiáng)模型目標(biāo)是修復(fù)的代碼倉庫帶測試套件再加Docker或venv做沙箱??蚣苓@塊我經(jīng)歷過三個(gè)階段最早直接用function calling手寫后來用LangChain現(xiàn)在留在自研輕量框架加LangChain組件混搭。這里先給結(jié)論如果你的目標(biāo)是給一個(gè)特定倉庫做自動(dòng)修bug沒有必要上大型編排器一個(gè)函數(shù)調(diào)用循環(huán)足夠了。起步階段需要的東西不多核心三個(gè)文件一個(gè)工具定義文件、一個(gè)修復(fù)循環(huán)主文件、一個(gè)反饋解析器目錄。工具定義文件負(fù)責(zé)給模型描述你能調(diào)用什么修復(fù)循環(huán)主文件控制整個(gè)流程反饋解析器目錄放各個(gè)測試框架的解析邏輯。3.2 核心代碼實(shí)現(xiàn)修復(fù)循環(huán)逐行拆解我把最核心的實(shí)現(xiàn)拆開講。第一步是工具定義以跑測試為例用function calling風(fēng)格定義TOOLS [ { type: function, function: { name: run_test, description: 運(yùn)行指定測試用例并返回 pytest 輸出, parameters: { type: object, properties: { test_path: {type: string, description: 測試文件或測試用例路徑} }, required: [test_path] } } }, { type: function, function: { name: read_file, description: 讀取倉庫內(nèi)指定文件的指定行范圍, parameters: { type: object, properties: { path: {type: string}, start_line: {type: integer}, end_line: {type: integer} }, required: [path] } } }, { type: function, function: { name: apply_patch, description: 以 unified diff 格式應(yīng)用代碼修改, parameters: { type: object, properties: { diff: {type: string} }, required: [diff] } } } ]主循環(huán)是核心部分實(shí)際代碼里要注意每個(gè)函數(shù)調(diào)用的結(jié)果必須完整存進(jìn)消息歷史模型才能基于真實(shí)結(jié)果繼續(xù)推理。很多人寫Agent時(shí)犯一個(gè)錯(cuò)誤只把工具調(diào)用的結(jié)果字符串塞進(jìn)日志但忘了告訴模型這個(gè)結(jié)果是來自哪次調(diào)用、對(duì)應(yīng)哪個(gè)動(dòng)作。我建議每個(gè)工具調(diào)用結(jié)果前加一個(gè)結(jié)構(gòu)化標(biāo)記比如命令: pytest tests/test_user.py exit_code: 1 輸出: ...這樣模型能準(zhǔn)確理解反饋和動(dòng)作的對(duì)應(yīng)關(guān)系。補(bǔ)丁應(yīng)用和驗(yàn)證環(huán)節(jié)同樣關(guān)鍵。模型輸出的patch可能格式不對(duì)需要專門的解析器把unified diff解析成實(shí)際的文件修改。我踩過的坑是模型會(huì)在patch里寫假的行號(hào)標(biāo)記但實(shí)際diff內(nèi)容對(duì)不上文件行數(shù)。這時(shí)不應(yīng)該強(qiáng)套apply而應(yīng)該直接把patch原樣返回給模型讓它重新生成。理解和容忍模型輸出的這種不穩(wěn)定性是寫Agent的基本功。3.3 接入真實(shí)反饋日志、測試、堆棧的一手處理接入真實(shí)反饋是AutoDebug Agent的重頭戲。以最常見的pytest場景為例測試運(yùn)行后用subprocess拿到的輸出是這樣的import subprocess, json, re def run_tests(test_path): proc subprocess.run( [pytest, test_path, -p, no:cacheprovider, --tbshort], capture_outputTrue, textTrue, timeout600 ) return parse_pytest_output(proc.stdout proc.stderr)parse_pytest_output函數(shù)要提取以下字段失敗用例列表、每個(gè)失敗用例的斷言消息、截取的堆棧、異常類型比如AssertionError、IndexError。這個(gè)結(jié)構(gòu)化結(jié)果會(huì)直接作為新反饋進(jìn)入修復(fù)循環(huán)。我強(qiáng)烈建議把原始輸出也留一份在日志里方便人工排查時(shí)對(duì)照。接入線上運(yùn)行時(shí)錯(cuò)誤的思路也類似把錯(cuò)誤日志、堆棧、關(guān)聯(lián)的上下文信息一起打包。關(guān)鍵點(diǎn)是讓反饋帶上時(shí)間和空間上下文而不是丟一個(gè)孤零零的異常消息。比如2025-01-15T02:30:00Z 服務(wù)order-svc 請求req_88ab2f1 出現(xiàn)KeyError: status比KeyError: status給模型的信號(hào)多得多。反饋處理管線做成一個(gè)獨(dú)立模塊后還可以做一件事給每種反饋類型打標(biāo)簽。比如按編譯錯(cuò)誤單元測試失敗集成測試失敗運(yùn)行時(shí)崩潰靜態(tài)分析告警分類。這個(gè)標(biāo)簽會(huì)作為上下文的一部分傳給模型讓它在診斷時(shí)知道當(dāng)前面對(duì)的是什么性質(zhì)的缺陷。3.4 評(píng)價(jià)指標(biāo)與參數(shù)調(diào)整AutoDebug Agent跑起來之后你得知道它干得好不好。我用的評(píng)價(jià)指標(biāo)有五項(xiàng)修復(fù)成功率驗(yàn)證通過并完成回歸的patch數(shù)除以嘗試修復(fù)的問題總數(shù)平均修復(fù)輪數(shù)每次成功修復(fù)平均跑了多少輪回歸率通過了目標(biāo)測試、但讓其他測試掛掉的patch比例單次修復(fù)耗時(shí)從輸入issue到輸出patch的平均分鐘數(shù)單次修復(fù)成本token消耗量直接關(guān)系成本這幾個(gè)指標(biāo)相互關(guān)聯(lián)。比如壓低了平均修復(fù)輪數(shù)token成本自然下降但也可能提高回歸率追求高修復(fù)成功率就要允許更多輪迭代。我的默認(rèn)參數(shù)是MAX_ATTEMPTS5temperature0.3top_p0.9。temperature太低容易機(jī)械重復(fù)太高容易發(fā)散。還有一個(gè)我觀察到的細(xì)節(jié)模型的診斷質(zhì)量比直接生成patch質(zhì)量更重要。與其讓模型直接給修復(fù)代碼不如先強(qiáng)制它用自然語言描述根因、列出證據(jù)、寫出驗(yàn)證計(jì)劃再進(jìn)入代碼生成。這一步相當(dāng)于給模型一個(gè)思考工作區(qū)診斷質(zhì)量上去了后面的patch質(zhì)量會(huì)明顯提升。這也是AutoDebug Agent里Agent部分的核心價(jià)值——它不是一個(gè)單次生成的prompt工具而是有完整推理鏈的執(zhí)行者。4. 常見問題與排查技巧實(shí)錄4.1 反饋信號(hào)太弱Agent反復(fù)瞎改這是我遇到最多的失敗模式。Agent第一輪修復(fù)失敗后第二輪給出的patch跟第一輪幾乎一樣說明它沒有得到足以修正判斷的新信息。根因是反饋太稀疏比如日志只寫了測試失敗沒有具體斷言。排查思路是先看給Agent的反饋里到底有沒有差異信息。如果Agent已經(jīng)定位到某個(gè)函數(shù)但不知道函數(shù)內(nèi)部實(shí)際執(zhí)行到哪一步可以在反饋里加入traceback的中間層。另一個(gè)有效手段是讓Agent自己加調(diào)試輸出——比如讓它往代碼里插臨時(shí)的print跑一次測試后再刪掉。這個(gè)方法在實(shí)踐中非常有用相當(dāng)于把調(diào)試這個(gè)動(dòng)作也交給了Agent。但要注意臨時(shí)調(diào)試輸出必須在最終patch里清除干凈。我有一條規(guī)則最終diff里不允許出現(xiàn)print、debugger關(guān)鍵字否則自動(dòng)拒絕。這條規(guī)則把不少看起來修好了但其實(shí)是靠打印撐著的垃圾補(bǔ)丁擋在了門外。4.2 上下文塞滿了日志模型開始失憶長日志、大堆棧、多輪工具調(diào)用結(jié)果都會(huì)把上下文塞滿。模型失憶的癥狀是明明前面已經(jīng)定位到文件了后面生成patch時(shí)卻引用了錯(cuò)誤的行號(hào)或者開始重復(fù)前面已經(jīng)試過的失敗方案。應(yīng)對(duì)策略有兩個(gè)方向。第一是壓縮日志超出閾值后讓模型先做一個(gè)日志摘要把幾KB的原始輸出壓縮成關(guān)鍵的幾百字再進(jìn)入下一輪。這個(gè)先總結(jié)再推理的兩階段法效果很好。第二是重構(gòu)上下文結(jié)構(gòu)不要無限追加對(duì)話歷史而是維護(hù)三個(gè)獨(dú)立槽位——問題描述、當(dāng)前診斷結(jié)論、最近一輪反饋。每輪只把這三個(gè)槽位刷新給模型而不是把所有歷史消息全部丟進(jìn)去。這樣上下文長度可控也符合人調(diào)試時(shí)的認(rèn)知方式。4.3 誤修復(fù)測試過了但坑更深了這是AutoDebug Agent最危險(xiǎn)的問題——目標(biāo)測試通過了但Agent的修改破壞了別的行為或者把一個(gè)表面的斷言修成了更隱蔽的錯(cuò)誤。我遇到過一個(gè)典型案例一個(gè)函數(shù)原本應(yīng)返回列表Agent改成返回None恰好有個(gè)測試斷言結(jié)果為空時(shí)返回None于是過了單測但整個(gè)模塊的調(diào)用方全炸了。這類問題的核心是驗(yàn)證范圍不夠。我的強(qiáng)制方案是目標(biāo)測試通過后必須再做兩步。第一步跑當(dāng)前文件所在的整個(gè)測試文件不只是失敗的那一條第二步有條件的話跑一次完整測試套件。另外提交前會(huì)要求Agent給出patch的安全自述解釋為什么這個(gè)改動(dòng)是安全的、改動(dòng)影響哪些模塊。這個(gè)自述會(huì)作為人工審查的參考。效果好但會(huì)增加一兩分鐘成本值得。4.4 安全和連接問題Agent會(huì)話、超時(shí)那些坑實(shí)操中還會(huì)遇到一類跟Agent本身運(yùn)行環(huán)境有關(guān)的問題。比如某些Agent運(yùn)行時(shí)在建立會(huì)話時(shí)會(huì)返回空標(biāo)識(shí)和無效服務(wù)名的錯(cuò)誤常見原因是服務(wù)端版本與客戶端不匹配、會(huì)話過期或者網(wǎng)絡(luò)鏈路不穩(wěn)定。這類錯(cuò)誤往往不是Agent邏輯的問題而是基礎(chǔ)設(shè)施。我建議做好兩件事一是所有工具調(diào)用都帶超時(shí)和重試二是注意會(huì)話的持久化和恢復(fù)。Agent在中間斷了上下文丟失就只能從頭再來。給修復(fù)循環(huán)加一個(gè)checkpoint機(jī)制每輪結(jié)束后把上下文快照存下來重連時(shí)從最近一個(gè)快照恢復(fù)能省大量時(shí)間。沙箱環(huán)境還有一個(gè)容易被忽視的安全點(diǎn)不要給Agent無限的文件系統(tǒng)權(quán)限。我發(fā)生過一次Agent好心修改了配置文件的事故。從那以后我在apply_patch工具里強(qiáng)制加了路徑白名單檢查凡目標(biāo)路徑不在倉庫目錄內(nèi)的一律拒絕。這是成本極低的微調(diào)但能擋住很多低級(jí)事故。5. 工具選型與前沿參考站在現(xiàn)有框架和產(chǎn)品上做5.1 主流Agent框架怎么選LangChain、Dify、CrewAI做AutoDebug Agent之前我先研究了一圈現(xiàn)有框架。個(gè)人選型觀如下LangChain生態(tài)最全適合有工程能力、想深度定制的團(tuán)隊(duì)。它的工具調(diào)用、記憶模塊都比較成熟但抽象層偏厚調(diào)試起來麻煩。尤其當(dāng)你需要精確控制每輪上下文的時(shí)候反而會(huì)被框架束縛。Dify適合快速原型和業(yè)務(wù)側(cè)落地可視化編排讓你不用寫太多代碼就能搭一個(gè)Agent工作流。但它的抽象不太適合精細(xì)控制代碼修復(fù)這種高交互、多循環(huán)的任務(wù)。CrewAI擅長老多Agent協(xié)作比如讓診斷Agent和修復(fù)Agent分工。我試驗(yàn)過把診斷和修復(fù)拆成兩個(gè)角色效果有一點(diǎn)但開銷翻倍收益不大后來還是合并成一個(gè)完整循環(huán)。我的選擇是用原生function calling寫核心循環(huán)必要時(shí)用LangChain的消息模型來管理歷史但不是整個(gè)流程都套框架。這種半自研的好處是核心邏輯完全可控壞處是需要自己維護(hù)一些邊緣邏輯。考慮到要寫的是生產(chǎn)可用的工具可控性比省事重要。5.2 向Codex CLI與Claude Skills學(xué)什么產(chǎn)品化的編碼Agent給AutoDebug Agent提供了很好的設(shè)計(jì)參考。Codex CLI這類工具給我的啟發(fā)是命令行優(yōu)先的交互形態(tài)。它把Agent做成了終端里的一條命令開發(fā)者在代碼目錄里就能啟動(dòng)拿到上下文后直接開始診斷和修改。AutoDebug Agent也應(yīng)該保持這種最小侵入——不要求把整個(gè)開發(fā)流程搬到某個(gè)IDE或平臺(tái)而是作為一條命令、一個(gè)API接入現(xiàn)有工作流。我在實(shí)現(xiàn)時(shí)也選擇了類似的形態(tài)在倉庫根目錄執(zhí)行一條命令A(yù)gent自行讀取git狀態(tài)、定位最近變更、跑測試、開始修復(fù)循環(huán)。Claude Skills的思路更值得研究把技能看作可復(fù)用的、經(jīng)過驗(yàn)證的能力單元。放到AutoDebug Agent里就是我可以把收集pytest反饋、檢查git歷史、運(yùn)行靜態(tài)分析封裝成獨(dú)立的技能模塊并給每個(gè)技能寫清楚適用條件和輸出格式。這樣Agent在遇到特定場景時(shí)能精準(zhǔn)調(diào)用而不是每次都在原始信息里重新摸索。技能化的另一個(gè)好處是可組合、可分享團(tuán)隊(duì)里積累的調(diào)試技能可以沉淀下來復(fù)用。5.3 輕量自研 vs 大型編排器我的建議如果要給一個(gè)明確的建議我的答案是一開始不要先買來一堆框架先用最原始的function calling把修復(fù)循環(huán)跑通再根據(jù)痛點(diǎn)決定要不要引入更重的抽象。原因很現(xiàn)實(shí)Agent的核心是基于反饋?zhàn)鐾评矶皇蔷幣帕硕嗌賯€(gè)節(jié)點(diǎn)。你拖出10個(gè)節(jié)點(diǎn)但如果每個(gè)節(jié)點(diǎn)喂給模型的信息都是一坨沒處理的原始日志效果還不如一條精心設(shè)計(jì)的循環(huán)??蚣苣軒湍愎芾磉吘壡闆r但替代不了對(duì)反饋信號(hào)的處理。我自己現(xiàn)在保留了一個(gè)約300行的核心循環(huán)加上一堆針對(duì)不同測試框架的反饋解析器。它比任何框架都穩(wěn)定因?yàn)樵谀莻€(gè)循環(huán)里我知道每一步在干什么模型看到的每一條反饋我都親手驗(yàn)證過格式。如果后續(xù)要擴(kuò)展到多倉庫、多Agent協(xié)作再考慮把循環(huán)包裝成服務(wù)接入更完善的編排層不遲。我個(gè)人在實(shí)際項(xiàng)目里最深刻的體會(huì)是AutoDebug Agent這個(gè)東西真正的瓶頸不是模型而是反饋信號(hào)的質(zhì)量和循環(huán)設(shè)計(jì)的穩(wěn)健性。你給Agent喂什么它就修什么你讓它在什么邊界內(nèi)活動(dòng)它就在什么邊界內(nèi)靠譜。我給團(tuán)隊(duì)交付這個(gè)工具的時(shí)候特意把無法復(fù)現(xiàn)就停下來問人和通過測試后必須跑全量回歸寫成兩條不可繞過的規(guī)則。踩過幾次坑之后這兩條規(guī)則救過我太多次。如果你也想搞一個(gè)自己的AutoDebug Agent建議從最小的修復(fù)循環(huán)開始先把反饋管好技能化封裝跟上再慢慢把邊界往外擴(kuò)。等到你的Agent能穩(wěn)穩(wěn)地修完一批又一批歷史issue并且在修完的同時(shí)沒有引入新的坑你會(huì)覺得這幾十個(gè)小時(shí)的折騰值了。