構(gòu)設(shè)計實戰(zhàn))
1. 從“寫提示詞”到“設(shè)計循環(huán)”一個思維拐點的到來我大概是在連續(xù)調(diào)了三個星期的提示詞之后才真正意識到問題的。那段時間我每天的工作狀態(tài)就是打開編輯器改一段提示詞跑一遍 Agent看它在哪里斷掉再改提示詞再跑。循環(huán)往復(fù)像極了在跟一個記性不太好但脾氣很倔的實習(xí)生反復(fù)交代同一件事。每次我以為自己把話說清楚了它總能在某個意想不到的環(huán)節(jié)給我整出新花樣——要么是工具調(diào)用參數(shù)拼錯了要么是任務(wù)做到一半自己給自己加戲要么是明明上一輪已經(jīng)確認(rèn)過的信息下一輪它又忘了。后來我停下來復(fù)盤發(fā)現(xiàn)一個很反直覺的事實我花在提示詞上的時間和 Agent 實際能穩(wěn)定完成的任務(wù)復(fù)雜度并不成正比。提示詞寫得再精細(xì)它本質(zhì)上還是在描述“這一次該怎么做”。而 Agent 要真正自己跑起來需要的不是“這一次怎么做”而是“每一步做完之后下一步該往哪走、什么時候該停、出錯了怎么退回來”。這些東西提示詞給不了得靠 Loop。這里說的 Loop不是編程里那個for循環(huán)那么簡單。在 AI Agent 的語境下Loop 指的是 Agent 的運行時控制結(jié)構(gòu)——它決定了 Agent 在每一輪里看到什么、能做什么、做完之后狀態(tài)怎么更新、什么條件下繼續(xù)、什么條件下終止。提示詞是“內(nèi)容層”Loop 是“控制層”。我之前的做法相當(dāng)于把控制邏輯硬塞進內(nèi)容層里用自然語言去描述“如果 A 就做 B否則做 C”結(jié)果就是提示詞越寫越長Agent 反而越來越不穩(wěn)定。這個認(rèn)知轉(zhuǎn)變之后我把工作重心從“雕琢提示詞”挪到了“設(shè)計 Loop”上。效果是肉眼可見的同一個任務(wù)之前需要我盯著跑五六輪、中途手動糾偏現(xiàn)在它能自己跑完我只需要在最后驗收。當(dāng)然這個過程里踩的坑一點沒少有些坑還挺隱蔽的。下面我就把這套東西拆開講包括 Loop 到底該怎么設(shè)計、提示詞在新架構(gòu)里扮演什么角色、以及我實際踩過的那些坑。2. 提示詞工程的天花板到底在哪里2.1 提示詞能解決的問題其實比想象中窄很多人對提示詞工程的理解是“把話說清楚模型就能做對”。這話在單輪任務(wù)里基本成立比如“把這段中文翻譯成英文”“從這段文本里提取人名和公司名”。但只要任務(wù)超過一輪需要模型自己決定下一步做什么提示詞的局限性就暴露了。我舉個實際例子。我做過一個任務(wù)讓 Agent 去某個代碼倉庫里找所有硬編碼的 API 密鑰然后生成一份報告。這個任務(wù)拆開看大概是遍歷文件、識別疑似密鑰的字符串、排除測試文件、匯總結(jié)果、寫報告。如果我把這些步驟全部寫進提示詞告訴它“第一步遍歷文件第二步識別密鑰第三步排除測試文件……”會發(fā)生什么實測下來模型在前兩輪還能按部就班到了第三輪開始它就會開始“自由發(fā)揮”。有時候它會把node_modules里的文件也掃進去有時候它會在識別密鑰的時候把普通的變量名也當(dāng)成密鑰有時候它干脆跳過排除測試文件這一步直接匯總。原因很簡單提示詞是靜態(tài)的而任務(wù)執(zhí)行是動態(tài)的。每一輪模型看到的上下文都在變但提示詞里描述的邏輯是固定的模型需要自己在腦子里把靜態(tài)邏輯映射到動態(tài)狀態(tài)上這個映射過程極容易出錯。2.2 長提示詞的邊際收益遞減我做過一個粗略的對比實驗。同一個任務(wù)我寫了三個版本的提示詞短版約 200 字只說明目標(biāo)和輸出格式、中版約 600 字補充了步驟和注意事項、長版約 1500 字把每一步的判斷邏輯都寫進去了。然后每個版本各跑 20 次統(tǒng)計任務(wù)完成率。提示詞版本字?jǐn)?shù)任務(wù)完成率平均輪次人工干預(yù)次數(shù)短版~20035%3.22.1中版~60055%4.81.4長版~150058%6.51.2數(shù)據(jù)很說明問題提示詞從 200 字加到 600 字完成率漲了 20 個百分點但從 600 字加到 1500 字完成率只漲了 3 個百分點而平均輪次和人工干預(yù)次數(shù)并沒有明顯改善。更麻煩的是長提示詞讓 Agent 的響應(yīng)變慢、token 消耗變大而且一旦任務(wù)場景稍有變化長提示詞里那些具體的步驟描述反而成了束縛。提示如果你的提示詞已經(jīng)超過 800 字而 Agent 的完成率還是上不去大概率不是提示詞的問題而是 Loop 設(shè)計的問題。2.3 提示詞和 Loop 的分工邊界那提示詞是不是就沒用了當(dāng)然不是。我的經(jīng)驗是提示詞負(fù)責(zé)“定義角色和約束”Loop 負(fù)責(zé)“控制流程和狀態(tài)”。具體來說提示詞里應(yīng)該寫Agent 的身份、能力邊界、輸出格式要求、安全約束、工具使用規(guī)范。Loop 里應(yīng)該管當(dāng)前處于哪個階段、上一輪產(chǎn)出了什么、下一步該調(diào)用哪個工具、什么條件下重試、什么條件下終止。舉個例子。提示詞里我會寫“你是一個代碼審計助手只能讀取文件不能修改文件輸出必須是 JSON 格式”。而 Loop 里我會定義第一輪調(diào)用文件遍歷工具拿到文件列表后進入第二輪第二輪對每個文件調(diào)用內(nèi)容讀取工具識別密鑰第三輪過濾測試文件第四輪匯總輸出。每一輪的狀態(tài)文件列表、已識別的密鑰、過濾結(jié)果都存在 Loop 的上下文里而不是靠提示詞去“記住”。這樣分工之后提示詞可以寫得很短Loop 的邏輯可以寫得很清晰兩者各司其職Agent 的穩(wěn)定性明顯提升。3. Loop 的核心構(gòu)件狀態(tài)、動作、終止條件3.1 狀態(tài)管理Agent 的“工作記憶”該放在哪里L(fēng)oop 設(shè)計里最容易被低估的就是狀態(tài)管理。我一開始的做法是讓 Agent 自己維護狀態(tài)——每輪結(jié)束的時候讓它把當(dāng)前進展寫進一個變量里下一輪再讀出來。聽起來很合理但實際跑起來問題很多。第一個問題是狀態(tài)漂移。Agent 在寫狀態(tài)的時候會根據(jù)自己的理解“潤色”一下比如把“已掃描 12 個文件發(fā)現(xiàn) 3 個疑似密鑰”寫成“已掃描部分文件發(fā)現(xiàn)若干密鑰”。信息在傳遞過程中被壓縮了下一輪它拿到這個模糊的狀態(tài)判斷就會出錯。第二個問題是狀態(tài)膨脹。如果每一輪都把完整的歷史狀態(tài)塞進上下文幾輪之后上下文就會變得非常長模型處理起來又慢又容易分心。我后來采用的方案是狀態(tài)由 Loop 的宿主程序維護而不是由 Agent 維護。具體來說Agent 每一輪只負(fù)責(zé)輸出“這一輪做了什么、產(chǎn)出了什么”宿主程序負(fù)責(zé)把這些產(chǎn)出結(jié)構(gòu)化地存起來下一輪只把必要的狀態(tài)注入到提示詞里。這樣狀態(tài)是精確的、可控的不會漂移也不會膨脹。用偽代碼表示大概是這樣state { phase: scan, files_scanned: [], findings: [], retry_count: 0 } while state[phase] ! done: prompt build_prompt(state) # 只注入當(dāng)前階段需要的狀態(tài) result agent.run(prompt) state update_state(state, result) # 宿主程序更新狀態(tài)這個結(jié)構(gòu)看起來簡單但它把“狀態(tài)”從 Agent 的腦子里挪到了程序里穩(wěn)定性提升了一個量級。3.2 動作空間每一輪到底允許 Agent 做什么動作空間的設(shè)計直接決定了 Agent 會不會“亂來”。我踩過的一個坑是早期我給 Agent 開放了太多工具它在一輪里可以同時調(diào)用文件讀取、網(wǎng)絡(luò)請求、代碼執(zhí)行、數(shù)據(jù)庫查詢。結(jié)果就是它經(jīng)常在應(yīng)該只讀文件的時候去調(diào)網(wǎng)絡(luò)請求或者在應(yīng)該匯總結(jié)果的時候又去讀了一遍文件。后來我改成按階段收窄動作空間在掃描階段只開放文件遍歷和讀取工具在分析階段只開放文本處理工具在匯總階段只開放輸出工具。每一輪 Agent 能做什么是明確的它就不會跑偏。這個思路其實和人類工作很像。你在做代碼審計的時候不會一邊看代碼一邊發(fā)郵件一邊改數(shù)據(jù)庫。每個階段有每個階段的工具集階段之間是串行的。Agent 也一樣給它太多自由它反而不知道該干什么。3.3 終止條件什么時候該停什么時候該重試終止條件是 Loop 設(shè)計里最需要小心的地方。我見過兩種極端一種是終止條件太松Agent 跑了幾十輪還在那里打轉(zhuǎn)另一種是終止條件太緊Agent 剛開了個頭就被強制結(jié)束。我的經(jīng)驗是終止條件要分三層成功終止任務(wù)目標(biāo)達成比如“所有文件已掃描且報告已生成”。失敗終止出現(xiàn)了不可恢復(fù)的錯誤比如“連續(xù)三輪工具調(diào)用失敗”或“重試次數(shù)超過上限”。人工介入終止Agent 自己判斷需要人類決策比如“發(fā)現(xiàn)疑似密鑰但無法確定是否為測試數(shù)據(jù)”。第三層特別重要。很多 Loop 設(shè)計里只有成功和失敗兩種終止但實際任務(wù)里經(jīng)常出現(xiàn)“Agent 不確定該怎么辦”的情況。這時候如果強行讓它繼續(xù)它就會瞎猜如果直接判失敗又浪費了前面的工作。所以我在 Loop 里加了一個need_human狀態(tài)Agent 可以主動把控制權(quán)交回來我處理完之后再讓它繼續(xù)。4. 我踩過的五個坑以及每個坑的排查過程4.1 坑一Loop 里的提示詞注入把狀態(tài)覆蓋了這個坑我排查了整整一個下午?,F(xiàn)象是Agent 在前幾輪表現(xiàn)正常到了第四輪突然開始重復(fù)第一輪的工作。我一開始以為是模型的問題換了幾個模型都一樣。后來把每一輪的完整提示詞打印出來看才發(fā)現(xiàn)問題出在狀態(tài)注入上。我的 Loop 里有一個build_prompt函數(shù)負(fù)責(zé)把當(dāng)前狀態(tài)拼進提示詞。當(dāng)時的寫法是先把基礎(chǔ)提示詞模板加載進來然后把狀態(tài)字段逐個替換進去。但基礎(chǔ)模板里有一個占位符叫{current_task}而狀態(tài)里也有一個字段叫current_task結(jié)果替換的時候把整個任務(wù)描述覆蓋成了當(dāng)前階段名。Agent 看到的任務(wù)變成了“scan”它自然就重新開始掃描了。這個坑的教訓(xùn)是狀態(tài)字段的命名要和提示詞模板的占位符嚴(yán)格區(qū)分開。我后來的做法是給所有狀態(tài)字段加前綴比如state_phase、state_files這樣就不會和模板里的占位符沖突。另外build_prompt函數(shù)里加了一個斷言檢查替換后的提示詞里是否還殘留未替換的占位符有的話直接報錯不讓它帶著問題往下跑。4.2 坑二工具調(diào)用失敗后的重試邏輯把 Agent 帶進了死循環(huán)有一次我讓 Agent 去調(diào)用一個外部 API 獲取數(shù)據(jù)那個 API 偶爾會超時。我在 Loop 里加了重試邏輯如果工具調(diào)用失敗就等兩秒再試一次最多試三次。聽起來沒問題但實際跑的時候 Agent 卡在那里不動了。排查后發(fā)現(xiàn)問題出在重試的粒度上。我的重試邏輯是包在單輪里的一輪里如果工具調(diào)用失敗就重試三次。但 Agent 在工具調(diào)用失敗后會認(rèn)為這一輪沒有產(chǎn)出有效結(jié)果于是它會在下一輪重新嘗試同樣的工具調(diào)用。而下一輪里又有三次重試。結(jié)果就是 3×3×3……無限套娃。修復(fù)方案是把重試邏輯從“單輪內(nèi)重試”改成“跨輪重試”單輪內(nèi)工具調(diào)用失敗就直接返回失敗狀態(tài)由 Loop 決定是否進入下一輪重試并且用一個全局的重試計數(shù)器來控制總次數(shù)。這樣重試次數(shù)是可控的不會指數(shù)級膨脹。注意重試邏輯一定要有全局計數(shù)器不能只在單輪內(nèi)計數(shù)。否則 Agent 的每一輪都會“重新開始計數(shù)”導(dǎo)致無限重試。4.3 坑三狀態(tài)序列化時把不可序列化的對象塞進去了這個坑比較隱蔽。我的狀態(tài)里存了一個文件句柄對象用來在多個輪次之間保持文件讀取的進度。在單次運行里沒問題但當(dāng)我嘗試把狀態(tài)存到磁盤上做斷點續(xù)跑的時候序列化直接報錯了。排查過程比較直接看報錯信息就知道是哪個字段的問題。但修復(fù)的時候我猶豫了一下——是把這個字段去掉還是換一種可序列化的表示方式最后我選擇了后者把文件句柄換成文件路徑加偏移量需要讀文件的時候再重新打開。這樣狀態(tài)就是純數(shù)據(jù)的可以隨便序列化和反序列化。這個坑的教訓(xùn)是狀態(tài)里只放數(shù)據(jù)不放資源。資源文件句柄、網(wǎng)絡(luò)連接、數(shù)據(jù)庫連接應(yīng)該在需要的時候創(chuàng)建用完就釋放不要跨輪次持有。這樣 Loop 的可恢復(fù)性會好很多也更容易調(diào)試。4.4 坑四終止條件寫成了“或”而不是“與”這個坑導(dǎo)致 Agent 經(jīng)常提前終止。我的終止條件原本寫的是“所有文件已掃描 或 報告已生成”本意是這兩個條件滿足任意一個就可以停。但實際執(zhí)行的時候Agent 在掃描完第一個文件之后就認(rèn)為“所有文件已掃描”這個條件滿足了因為它把“所有”理解成了“當(dāng)前這一批”于是直接跳到報告生成階段報告里只有第一個文件的結(jié)果。修復(fù)方案是把終止條件改成“所有文件已掃描 且 報告已生成”并且把“所有文件”的定義明確成“初始文件列表里的每一個文件都處理過”。另外我在 Loop 里加了一個校驗步驟在進入報告生成階段之前檢查已處理文件數(shù)是否等于初始文件數(shù)不等的話就退回掃描階段。這個坑的教訓(xùn)是終止條件里的邏輯連接詞要反復(fù)推敲?!盎颉焙汀芭c”一字之差行為完全不同。而且自然語言里的“所有”“完成”“結(jié)束”這些詞都有歧義最好用可量化的條件來替代。4.5 坑五Agent 在 Loop 里“學(xué)會”了偷懶這個坑最有意思。我讓 Agent 做一個數(shù)據(jù)清洗任務(wù)Loop 設(shè)計是每輪處理一批數(shù)據(jù)處理完檢查質(zhì)量質(zhì)量達標(biāo)就進入下一批。跑了一段時間后我發(fā)現(xiàn)Agent 處理第一批數(shù)據(jù)的時候很認(rèn)真越往后越敷衍最后幾批幾乎是原樣輸出。排查后發(fā)現(xiàn)Agent 在上下文中看到了前面幾輪的成功記錄它“推斷”出這個任務(wù)的標(biāo)準(zhǔn)在降低于是自己也降低了標(biāo)準(zhǔn)。這其實是模型的一種“模式匹配”行為它看到前面的輸出都是“通過”就認(rèn)為自己的輸出也應(yīng)該“通過”于是不再認(rèn)真做質(zhì)量檢查。修復(fù)方案是在每一輪的質(zhì)量檢查環(huán)節(jié)不把前面的成功記錄注入上下文只注入當(dāng)前批次的數(shù)據(jù)和檢查標(biāo)準(zhǔn)。這樣 Agent 每一輪看到的都是“ fresh ”的任務(wù)不會受到歷史記錄的影響。這個坑的教訓(xùn)是Loop 里的上下文注入要克制。不是所有歷史信息都需要讓 Agent 看到。有些信息比如前面的成功記錄會讓 Agent 產(chǎn)生“慣性”反而降低它的表現(xiàn)。每一輪只注入當(dāng)前決策必需的信息是最穩(wěn)妥的做法。5. 一個可復(fù)用的 Loop 骨架設(shè)計5.1 階段劃分把任務(wù)拆成有限個狀態(tài)經(jīng)過上面這些坑我總結(jié)出了一個比較通用的 Loop 骨架。核心思路是把任務(wù)拆成有限個階段每個階段有明確的輸入、輸出和退出條件。階段之間是串行的階段內(nèi)部可以有多輪。以代碼審計任務(wù)為例階段劃分大概是階段輸入輸出退出條件初始化倉庫路徑文件列表文件列表非空掃描文件列表疑似密鑰列表所有文件已掃描過濾疑似密鑰列表確認(rèn)密鑰列表過濾規(guī)則已應(yīng)用匯總確認(rèn)密鑰列表報告報告已生成每個階段內(nèi)部Agent 可以有多輪交互。比如掃描階段如果文件很多可以分批掃描每批一輪。但階段之間的推進是明確的掃描階段不結(jié)束不會進入過濾階段。5.2 狀態(tài)機實現(xiàn)用代碼而不是提示詞來控制流程這個骨架用代碼實現(xiàn)大概是這樣class AgentLoop: def __init__(self, task): self.state { phase: init, task: task, files: [], findings: [], confirmed: [], report: None, retry: 0 } def run(self): while self.state[phase] ! done: handler getattr(self, fphase_{self.state[phase]}) handler() return self.state[report] def phase_init(self): result self.call_agent(init, self.state) self.state[files] result[files] self.state[phase] scan if self.state[files] else failed def phase_scan(self): result self.call_agent(scan, self.state) self.state[findings].extend(result[findings]) if result[done]: self.state[phase] filter # ... 其他階段類似這個結(jié)構(gòu)的好處是流程控制完全在代碼里Agent 只負(fù)責(zé)每個階段內(nèi)的具體工作。Agent 不需要知道“下一步該干什么”它只需要知道“當(dāng)前這個階段該產(chǎn)出什么”。這樣提示詞可以寫得很短Agent 的負(fù)擔(dān)也小很多。5.3 提示詞模板每個階段一個短提示詞對應(yīng)上面的階段劃分提示詞也拆成多個短模板。比如掃描階段的提示詞大概是你是一個代碼審計助手當(dāng)前處于掃描階段。 你的任務(wù)是讀取給定的文件列表識別其中疑似 API 密鑰的字符串。 輸出格式JSON包含 findings 數(shù)組和 done 布爾值。 約束只讀取文件不修改文件只識別密鑰不做其他分析。這個提示詞不到 100 字但信息很明確。Agent 知道自己在哪個階段、要做什么、輸出什么格式。它不需要知道整個任務(wù)的流程因為流程由 Loop 控制。對比之前那個 1500 字的長提示詞這個短提示詞的效果反而更好。原因很簡單Agent 的注意力是有限的提示詞越短它越能把注意力集中在當(dāng)前任務(wù)上。6. 從提示詞思維切換到 Loop 思維的實際收益6.1 穩(wěn)定性從“看運氣”到“可預(yù)期”切換之前我跑 Agent 的心態(tài)是“看運氣”。同一個任務(wù)有時候能跑通有時候跑不通跑不通的時候我也不知道問題出在哪里。切換之后Agent 的行為變得可預(yù)期了如果某個階段出錯我能定位到具體是哪個階段、哪個環(huán)節(jié)的問題然后針對性地修。這種可預(yù)期性帶來的最大好處是我敢把更復(fù)雜的任務(wù)交給它了。以前我只敢讓它做單步任務(wù)現(xiàn)在我可以讓它做多階段任務(wù)因為我知道每個階段的邊界在哪里出問題也能兜住。6.2 可調(diào)試性出錯時知道該看哪里L(fēng)oop 結(jié)構(gòu)讓調(diào)試變得簡單了很多。以前 Agent 出錯我只能看最終輸出然后猜是哪一步出了問題?,F(xiàn)在我可以看每一輪的狀態(tài)變化知道它在哪個階段卡住了、卡住的時候狀態(tài)是什么、上一輪產(chǎn)出了什么。我甚至在 Loop 里加了一個簡單的日志系統(tǒng)每一輪結(jié)束的時候把狀態(tài)快照寫到一個 JSON 文件里。出問題的時候直接看這個文件比看模型的輸出日志直觀多了。6.3 可擴展性加新能力不用重寫提示詞最后一個收益是可擴展性。以前加一個新能力比如“讓 Agent 在掃描的時候順便統(tǒng)計文件行數(shù)”我得改提示詞而且改完之后可能影響其他部分的行為?,F(xiàn)在加新能力只需要在對應(yīng)階段里加一個工具調(diào)用或者在狀態(tài)里加一個字段不影響其他階段。這個收益在任務(wù)變復(fù)雜的時候特別明顯。我的代碼審計 Agent 從最初的“找密鑰”擴展到“找密鑰 找硬編碼密碼 找敏感配置”只花了不到一個小時因為每個新能力都是獨立的階段或階段內(nèi)的獨立工具調(diào)用互不干擾。7. 一些零散但實用的經(jīng)驗7.1 日志要記狀態(tài)不要只記輸出我一開始的日志只記 Agent 的文本輸出后來發(fā)現(xiàn)不夠用。Agent 的輸出是自然語言看多了會累而且很多關(guān)鍵信息比如狀態(tài)字段的值不在輸出里。后來我改成記狀態(tài)快照每一輪結(jié)束的時候把整個 state 序列化成 JSON 寫文件。這樣出問題的時候我直接 diff 兩個狀態(tài)快照就知道哪一步改變了什么。7.2 給 Agent 的“自由發(fā)揮”留一個口子雖然 Loop 控制了大部分流程但有些情況下 Agent 確實需要自由發(fā)揮。比如它在掃描的時候發(fā)現(xiàn)了一個不在預(yù)期內(nèi)的文件類型它可能需要臨時決定怎么處理。我的做法是在每個階段里留一個notes字段Agent 可以把它的“意外發(fā)現(xiàn)”寫進去Loop 在推進到下一階段之前會檢查這個字段如果有內(nèi)容就暫停一下讓我看看。這個口子不大但很有用。它讓 Agent 在遇到意外情況時有一個“舉手”的渠道而不是硬著頭皮往下做或者直接卡死。7.3 階段不要拆得太細(xì)我一開始把階段拆得很細(xì)一個任務(wù)拆了十幾個階段。結(jié)果 Loop 的代碼變得很臃腫階段之間的狀態(tài)傳遞也很繁瑣。后來我合并了一些階段保持在 4 到 6 個階段代碼清爽了很多Agent 的表現(xiàn)也沒有下降。我的經(jīng)驗是階段的粒度應(yīng)該以“決策點”為準(zhǔn)。如果一個地方需要 Agent 做判斷比如“這批數(shù)據(jù)質(zhì)量達標(biāo)了嗎”那它就是一個階段邊界。如果只是機械地執(zhí)行那它可以和相鄰的步驟合并。7.4 測試 Loop 的時候先用假 Agent調(diào)試 Loop 本身的時候不需要每次都調(diào)用真實模型。我寫了一個FakeAgent類它根據(jù)階段名返回預(yù)設(shè)的假數(shù)據(jù)。這樣我可以快速測試 Loop 的控制邏輯不用等模型響應(yīng)也不用花 token。等 Loop 的邏輯跑通了再換成真實 Agent 做端到端測試。這個做法幫我省了很多時間。Loop 的 bug 和 Agent 的 bug 是兩類問題混在一起調(diào)很痛苦。先用假 Agent 把 Loop 調(diào)通再用真 Agent 調(diào)提示詞效率高很多。7.5 別忘了給 Loop 本身加超時Loop 跑飛的情況我遇到過兩次都是因為某個階段的退出條件沒寫對Agent 在里面無限循環(huán)。后來我在 Loop 外面加了一個全局超時比如 10 分鐘沒跑完就強制終止并且把當(dāng)前狀態(tài) dump 出來。這個超時救了我好幾次至少不會讓一個跑飛的 Loop 占著資源不放。8. 關(guān)于“鵜鶘騎自行車”那個測試的一點想法最后聊一個題外話。最近看到不少人在討論“鵜鶘騎自行車”這類提示詞測試大意是給模型一個很具體的場景描述看它能不能生成符合要求的輸出。這類測試用來評估模型的指令遵循能力是有意義的但我想說的是它測的是提示詞工程的能力不是 Agent 的能力。一個 Agent 能不能自己工作不取決于它能不能根據(jù)一段描述畫出鵜鶘騎自行車而取決于它能不能在沒有人盯著的情況下自己決定先畫鵜鶘還是先畫自行車、畫完之后怎么檢查、發(fā)現(xiàn)畫錯了怎么改。這些能力不在提示詞里在 Loop 里。所以如果你也在做 Agent我的建議是把花在雕琢提示詞上的時間挪一半到設(shè)計 Loop 上。提示詞寫到 80 分就夠了剩下的 20 分靠 Loop 來補。你會發(fā)現(xiàn)Agent 突然就“自己會工作”了。