拆解到工具調(diào)用實(shí)戰(zhàn))
這兩年如果你經(jīng)常刷技術(shù)社區(qū)的帖子估計(jì)已經(jīng)被“Agent”這個(gè)詞刷屏了。從大模型剛火起來(lái)時(shí)大家還在比誰(shuí)的Prompt寫(xiě)得更花哨到現(xiàn)在討論焦點(diǎn)已經(jīng)變成了“讓大模型自己動(dòng)手干活”——這個(gè)能自己動(dòng)手干活的東西就是LLM Agent。說(shuō)白了LLM Agent就是讓大模型不再滿足于“你問(wèn)我答”而是變成一個(gè)能主動(dòng)拆解任務(wù)、調(diào)用工具、試錯(cuò)糾偏、最后交付結(jié)果的執(zhí)行者。這篇文章我會(huì)把Agent的底層構(gòu)成、任務(wù)拆解機(jī)制、完整工作流和實(shí)操中的常見(jiàn)坑一次性講清楚無(wú)論你是剛接觸AI的新手還是已經(jīng)在寫(xiě)代碼的開(kāi)發(fā)者應(yīng)該都能找到用得上的東西。LLM Agent最吸引人的地方不是它“更聰明”而是它把大模型從“嘴上會(huì)、手上不會(huì)”的狀態(tài)解放了出來(lái)。單獨(dú)一個(gè)大模型你問(wèn)它“幫我分析一下這份銷售數(shù)據(jù)”它能給你一套方法論但如果你要的是“讀取文件、清洗數(shù)據(jù)、算指標(biāo)、畫(huà)圖、生成報(bào)告”它一步都動(dòng)不了。Agent在中間補(bǔ)上了規(guī)劃、工具調(diào)用、結(jié)果校驗(yàn)這幾塊拼圖才讓“獨(dú)立完成任務(wù)”從概念變成了工程現(xiàn)實(shí)。1. LLM Agent的本質(zhì)從“會(huì)聊天”到“會(huì)干活”1.1 Agent不是一個(gè)新模型而是一套架構(gòu)很多人第一次聽(tīng)說(shuō)LLM Agent時(shí)會(huì)下意識(shí)以為它是一種新的大模型。這是個(gè)誤區(qū)。LLM Agent并不是某個(gè)具體的模型而是在大模型外面套了一層“執(zhí)行體系”。你可以把大模型理解成一個(gè)極其聰明但四肢不勤的實(shí)習(xí)生他懂很多知識(shí)邏輯推理能力很強(qiáng)但你要讓他干活他既不知道第一步做什么也沒(méi)有手去做具體操作。Agent這套架構(gòu)就是給這個(gè)實(shí)習(xí)生配上“計(jì)劃表”“工具箱”“記事本”和“復(fù)盤機(jī)制”。計(jì)劃表負(fù)責(zé)把目標(biāo)拆成步驟工具箱負(fù)責(zé)真的去做事比如查數(shù)據(jù)庫(kù)、發(fā)請(qǐng)求、讀寫(xiě)文件、執(zhí)行代碼記事本負(fù)責(zé)記住做到哪一步了、中間結(jié)果是什么復(fù)盤機(jī)制負(fù)責(zé)在出錯(cuò)時(shí)調(diào)整方案。模型本身還是那個(gè)模型變的只是它周圍多了一套讓它“落得了地”的機(jī)制。我習(xí)慣用一個(gè)小公司來(lái)類比大模型是老板Agent框架是公司的運(yùn)營(yíng)流程。老板負(fù)責(zé)拍板決策流程負(fù)責(zé)把決策變成部門分工和執(zhí)行動(dòng)作。沒(méi)有流程老板再聰明也只是一張嘴有了流程公司才能運(yùn)轉(zhuǎn)起來(lái)。1.2 Agent的四個(gè)核心模塊一個(gè)標(biāo)準(zhǔn)LLM Agent至少包含四個(gè)模塊缺一個(gè)都會(huì)導(dǎo)致任務(wù)完不成或完成質(zhì)量變差。第一個(gè)是規(guī)劃模塊它負(fù)責(zé)把用戶需求翻譯成一個(gè)可執(zhí)行的步驟列表。比如用戶說(shuō)“整理這份合同里的風(fēng)險(xiǎn)條款”規(guī)劃模塊要判斷出先讀文件、再定位關(guān)鍵條款、然后按類別整理、最后生成摘要。規(guī)劃質(zhì)量直接決定了后續(xù)執(zhí)行有沒(méi)有方向。第二個(gè)是工具模塊它是一組Agent可以調(diào)用的外部能力接口。比如代碼解釋器、文件讀寫(xiě)接口、搜索接口、數(shù)據(jù)庫(kù)查詢接口、郵件發(fā)送接口等。工具模塊的設(shè)計(jì)本質(zhì)上是在回答一個(gè)問(wèn)題Agent有哪些“手”可以伸出系統(tǒng)去影響世界。第三個(gè)是記憶模塊它解決的是“上下文不夠用”和“前后不一致”的問(wèn)題。短期記憶讓Agent記住當(dāng)前任務(wù)里已經(jīng)執(zhí)行完的步驟和中間結(jié)果長(zhǎng)期記憶則讓Agent跨會(huì)話保留歷史偏好和沉淀下來(lái)的經(jīng)驗(yàn)比如某個(gè)用戶習(xí)慣什么格式的報(bào)告。第四個(gè)是執(zhí)行與反饋模塊它負(fù)責(zé)調(diào)用工具、獲取結(jié)果、檢查結(jié)果是否合理、根據(jù)新的觀察調(diào)整下一步動(dòng)作。這一步是Agent真正“動(dòng)起來(lái)”的關(guān)鍵閉環(huán)也是和單純對(duì)話式大模型最明顯的分水嶺。1.3 和普通對(duì)話式大模型到底差在哪為了把區(qū)別說(shuō)透我列了個(gè)對(duì)比表維度普通對(duì)話式大模型LLM Agent交互方式一輪一輪問(wèn)答每輪獨(dú)立一次性給出目標(biāo)內(nèi)部多輪推進(jìn)任務(wù)處理直接輸出文字答案拆解成子任務(wù)逐步執(zhí)行工具能力基本不具備可調(diào)用搜索、代碼、文件、API等出錯(cuò)處理答錯(cuò)就錯(cuò)了能觀察結(jié)果、自我糾正、重試狀態(tài)保持僅靠上下文窗口有專門記憶機(jī)制支持長(zhǎng)任務(wù)交付物文字回復(fù)可執(zhí)行結(jié)果、文件、報(bào)告、操作動(dòng)作表格可能有點(diǎn)抽象舉一個(gè)具體的例子你讓對(duì)話式模型“幫我在服務(wù)器上跑一個(gè)Python腳本統(tǒng)計(jì)日志里的錯(cuò)誤數(shù)”它只會(huì)給你一段代碼運(yùn)行還得你自己來(lái)。而Agent會(huì)自己寫(xiě)腳本、自己調(diào)用終端執(zhí)行、自己讀輸出結(jié)果如果報(bào)錯(cuò)它還能看錯(cuò)誤信息然后改代碼重跑最后告訴你統(tǒng)計(jì)結(jié)果。同樣一個(gè)需求一個(gè)是指路的一個(gè)是跑腿的。2. Agent如何規(guī)劃任務(wù)從目標(biāo)到行動(dòng)的拆解過(guò)程2.1 第一步把用戶模糊目標(biāo)變成機(jī)器可執(zhí)行的子任務(wù)所有Agent工作的起點(diǎn)都是用戶一句往往不夠精確的話。比如“幫我準(zhǔn)備一下下周匯報(bào)的材料”這句話單獨(dú)扔給任何系統(tǒng)都沒(méi)有辦法執(zhí)行因?yàn)樗鄙偬嘈畔ⅰgent規(guī)劃模塊要做的第一件事就是和目標(biāo)相關(guān)“探查與補(bǔ)全”。它會(huì)先判斷任務(wù)里哪些信息已經(jīng)明確哪些信息存在歧義哪些信息需要調(diào)用工具去補(bǔ)充。這里最核心的技術(shù)是“任務(wù)分解”。好的任務(wù)分解不是把所有步驟平鋪開(kāi)而是有層級(jí)、有依賴關(guān)系的。比如準(zhǔn)備匯報(bào)材料可以分解成收集近期項(xiàng)目數(shù)據(jù)、整理關(guān)鍵進(jìn)展、提煉亮點(diǎn)、生成匯報(bào)文檔。而“收集近期項(xiàng)目數(shù)據(jù)”這一步又可以繼續(xù)拆成訪問(wèn)項(xiàng)目管理系統(tǒng)、查詢?nèi)蝿?wù)狀態(tài)、匯總工時(shí)統(tǒng)計(jì)。每個(gè)子任務(wù)有自己的輸入、輸出和驗(yàn)收標(biāo)準(zhǔn)。我在實(shí)操時(shí)發(fā)現(xiàn)規(guī)劃模塊的性能很大程度上取決于給它的指令約束。如果不加任何約束模型容易把任務(wù)拆得過(guò)于宏大比如拆出十個(gè)甚至二十個(gè)子任務(wù)很多根本不必要。后來(lái)我習(xí)慣在規(guī)劃Prompt里明確寫(xiě)“子任務(wù)數(shù)量控制在3到6個(gè)”“每個(gè)子任務(wù)必須能在一個(gè)操作內(nèi)完成主體工作”規(guī)劃質(zhì)量明顯穩(wěn)定很多。2.2 兩種主流規(guī)劃模式先計(jì)劃后執(zhí)行還是邊做邊想目前Agent規(guī)劃大致分兩條路線各有各的適用場(chǎng)景。一種是Plan-and-Execute模式也就是先把整個(gè)任務(wù)完整拆解成步驟清單然后按清單逐項(xiàng)執(zhí)行。這個(gè)模式在任務(wù)邊界清晰、步驟可以預(yù)先窮舉的場(chǎng)景下非常高效比如生成一份周報(bào)步驟基本固定取數(shù)據(jù)、算指標(biāo)、填模板、導(dǎo)出。優(yōu)點(diǎn)是執(zhí)行過(guò)程穩(wěn)定、每一步都有預(yù)期缺點(diǎn)是如果任務(wù)中途出現(xiàn)意外情況按原計(jì)劃走容易偏離實(shí)際。另一種是ReAct模式也就是“推理”和“行動(dòng)”交替進(jìn)行。它的執(zhí)行單元是一個(gè)循環(huán)先根據(jù)當(dāng)前觀察思考下一步該做什么做一步觀察結(jié)果再根據(jù)新結(jié)果思考下一步。這種模式非常靈活特別適合開(kāi)放式任務(wù)比如“調(diào)研某個(gè)技術(shù)方向的最新進(jìn)展”因?yàn)檫^(guò)程中會(huì)發(fā)現(xiàn)新線索需要?jiǎng)討B(tài)調(diào)整路徑不可能提前預(yù)設(shè)所有步驟。用生活場(chǎng)景類比Plan-and-Execute像按照菜譜做菜你提前知道全部步驟照著做就行ReAct像在陌生城市找一家餐館你邊走邊看路牌發(fā)現(xiàn)走錯(cuò)了就換個(gè)方向?,F(xiàn)在的落地系統(tǒng)里兩者經(jīng)常混著用Agent先用Plan-and-Execute搭出整體框架再用ReAct在每一步內(nèi)部做動(dòng)態(tài)試錯(cuò)。2.3 為什么必須有“觀察”這一步初學(xué)者最容易忽略的是“觀察”在Agent閉環(huán)里的位置。很多人覺(jué)得Agent就是“模型生成一串動(dòng)作然后執(zhí)行器執(zhí)行完就完事”這是一個(gè)非常普遍的誤解。真正可靠的Agent一定在行動(dòng)之后緊跟著“獲取反饋”和“校驗(yàn)結(jié)果”。原因很簡(jiǎn)單工具執(zhí)行結(jié)果不會(huì)總是符合預(yù)期。舉個(gè)例子Agent決定調(diào)用一個(gè)股票行情接口查詢股價(jià)結(jié)果接口返回了錯(cuò)誤碼如果Agent不觀察執(zhí)行結(jié)果就直接進(jìn)入下一步它可能拿著錯(cuò)誤的空數(shù)據(jù)繼續(xù)做分析最后產(chǎn)出一份完全跑偏的報(bào)告。加入觀察步驟Agent才能判斷“剛才那一步成功了沒(méi)有”“結(jié)果合不合理”“需不需要換個(gè)工具重新試一次”。這個(gè)“行動(dòng)-觀察-再?zèng)Q策”的循環(huán)就是ReAct的核心價(jià)值。它讓Agent不再像流水線上的機(jī)械臂那樣只知道往前沖而是像人一樣邊做邊看錯(cuò)了能回頭。在實(shí)際系統(tǒng)中每一輪循環(huán)產(chǎn)生的“思考-行動(dòng)-觀察”記錄會(huì)被完整保存下來(lái)既是為了讓模型基于最新事實(shí)做決策也是為了后續(xù)排查問(wèn)題時(shí)有據(jù)可查。我強(qiáng)烈建議任何初學(xué)Agent的人都先在自己的系統(tǒng)里把這個(gè)循環(huán)日志打出來(lái)你會(huì)看到很多有意思的現(xiàn)象。3. 獨(dú)立完成任務(wù)的完整工作流拆解3.1 任務(wù)輸入與系統(tǒng)初始化我以一個(gè)實(shí)際做過(guò)的模擬場(chǎng)景為例假設(shè)要讓Agent完成“在某跨平臺(tái)系統(tǒng)里查找最近一個(gè)月提交的所有代碼變更按模塊分類統(tǒng)計(jì)數(shù)量并生成一份周度報(bào)告”。這個(gè)任務(wù)比“寫(xiě)一首詩(shī)”這類純文本任務(wù)復(fù)雜得多足夠說(shuō)明Agent的工作流程。整個(gè)流程的起點(diǎn)是任務(wù)輸入。用戶的原始指令會(huì)被包裝成一個(gè)結(jié)構(gòu)化任務(wù)描述加上系統(tǒng)預(yù)設(shè)的上下文。系統(tǒng)Prompt里通常會(huì)寫(xiě)清楚Agent的角色、邊界、可用工具、輸出要求和工作習(xí)慣。比如我會(huì)在系統(tǒng)Prompt里強(qiáng)調(diào)“你是一個(gè)代碼倉(cāng)庫(kù)數(shù)據(jù)助理你的任務(wù)是通過(guò)調(diào)用數(shù)據(jù)分析工具完成用戶請(qǐng)求每一步都必須在行動(dòng)前說(shuō)明目的最終報(bào)告必須包含統(tǒng)計(jì)表格和原始數(shù)據(jù)來(lái)源?!背跏蓟A段還會(huì)把可用的工具列表和工具說(shuō)明書(shū)一起注入上下文。工具說(shuō)明書(shū)要非常具體告訴模型每個(gè)工具是干什么的、接受什么參數(shù)、返回什么格式、什么時(shí)候用。比如“查看代碼變更記錄參數(shù)為時(shí)間范圍和模塊名返回JSON數(shù)組包含commit_id、模塊名、變更行數(shù)、提交人”。3.2 任務(wù)拆解與工具的準(zhǔn)備在這個(gè)例子里Agent的規(guī)劃模塊經(jīng)過(guò)推理把目標(biāo)拆成了幾個(gè)子任務(wù)確定時(shí)間范圍、調(diào)用代碼變更記錄工具、匯總數(shù)據(jù)、按模塊分類統(tǒng)計(jì)、生成報(bào)告。這個(gè)拆解結(jié)果看起來(lái)順理成章但其實(shí)每一步都是模型“想”出來(lái)的不是寫(xiě)死在代碼里的。緊接著是工具的準(zhǔn)備。這里的“準(zhǔn)備”包括確認(rèn)工具可用、檢查必要參數(shù)是否齊全、處理工具間依賴關(guān)系。比如“按模塊分類統(tǒng)計(jì)”這個(gè)子任務(wù)依賴前一步“調(diào)用變更記錄工具”的返回結(jié)果所以Agent會(huì)設(shè)計(jì)一個(gè)內(nèi)部緩存機(jī)制把前一步的觀察結(jié)果存入記憶供后續(xù)步驟引用。這個(gè)設(shè)計(jì)讓Agent可以“拿著上一步的產(chǎn)出做下一步的輸入”整個(gè)工作流才有連貫性。3.3 循環(huán)執(zhí)行一個(gè)典型的Agent運(yùn)行軌跡下面是這個(gè)Agent執(zhí)行過(guò)程中的一段真實(shí)路徑我把它簡(jiǎn)化成了可讀的日志格式用戶目標(biāo): 統(tǒng)計(jì)某跨平臺(tái)系統(tǒng)最近一個(gè)月的代碼變更按模塊分類生成周度報(bào)告 思考: 需要先獲取時(shí)間范圍內(nèi)的代碼變更記錄時(shí)間范圍應(yīng)該從今天往前推30天。 行動(dòng): 調(diào)用工具 get_code_changes(start_date2024-05-01, end_date2024-05-31) 觀察: 成功返回68條變更記錄包含字段: commit_id, module, lines_changed, author 思考: 已拿到原始數(shù)據(jù)68條記錄分布在模塊A、模塊B、模塊C三個(gè)模塊接下來(lái)需要按模塊聚合 行動(dòng): 調(diào)用工具 aggregate_by_module(data[...]) 觀察: 聚合完成模塊A變動(dòng)25處模塊B變動(dòng)28處模塊C變動(dòng)15處 思考: 數(shù)據(jù)已經(jīng)聚合還需要補(bǔ)充每個(gè)模塊的主要變更內(nèi)容摘要以便報(bào)告有說(shuō)服力 行動(dòng): 調(diào)用工具 summarize_changes(moduleA, commits[...]) 觀察: 摘要生成完成 ...上面這個(gè)軌跡看起來(lái)很簡(jiǎn)單但你們注意看每一輪“思考”都是基于上一輪“觀察”的實(shí)際輸出而不是模型閉著眼睛想象出來(lái)的。這是Agent系統(tǒng)和大模型直接輸出最本質(zhì)區(qū)別的地方。大模型直接寫(xiě)報(bào)告是憑訓(xùn)練時(shí)學(xué)到的統(tǒng)計(jì)規(guī)律在“編”Agent寫(xiě)報(bào)告是拿著工具查回來(lái)的真實(shí)數(shù)據(jù)在“寫(xiě)”兩者可信度完全不在一個(gè)量級(jí)。這一輪輪循環(huán)會(huì)一直持續(xù)到Agent認(rèn)為目標(biāo)已經(jīng)達(dá)成。它會(huì)自己檢查所有子任務(wù)都完成了嗎中間結(jié)果有沒(méi)有缺失最后輸出的報(bào)告是否覆蓋了用戶原始需求如果一切OK它就生成最終交付物如果不OK它會(huì)繼續(xù)進(jìn)入循環(huán)或者主動(dòng)請(qǐng)求用戶補(bǔ)充信息。3.4 工具調(diào)用的底層實(shí)現(xiàn)原理聊到這里需要揭秘一下“Agent調(diào)用工具”在工程上到底是怎么實(shí)現(xiàn)的。大模型本身并不會(huì)真的去執(zhí)行什么操作它只會(huì)輸出文本。之所以看起來(lái)像“調(diào)用工具”是因?yàn)槲覀円龑?dǎo)模型輸出一段結(jié)構(gòu)化的JSON里面包含“要調(diào)用的工具名”和“傳給工具的參數(shù)”。系統(tǒng)拿到這段JSON后由代碼去匹配注冊(cè)好的工具函數(shù)執(zhí)行真正的操作然后把返回值重新拼進(jìn)模型的上下文。一個(gè)工具定義通常長(zhǎng)這樣{ name: get_code_changes, description: 獲取代碼倉(cāng)庫(kù)中指定時(shí)間范圍內(nèi)的變更記錄, parameters: { type: object, properties: { start_date: { type: string, description: 開(kāi)始日期格式Y(jié)YYY-MM-DD }, end_date: { type: string, description: 結(jié)束日期格式Y(jié)YYY-MM-DD } }, required: [start_date, end_date] } }模型看到這樣的工具定義后在合適的時(shí)候會(huì)輸出類似這樣的內(nèi)容{ tool: get_code_changes, params: { start_date: 2024-05-01, end_date: 2024-05-31 } }系統(tǒng)解析這個(gè)JSON執(zhí)行對(duì)應(yīng)的Python函數(shù)得到結(jié)果后把它包裝成一段文本塞回給模型“工具返回成功獲取68條記錄模塊A 25條模塊B 28條模塊C 15條。”模型基于這段文本繼續(xù)思考下一步。這種設(shè)計(jì)的好處是工具擴(kuò)展非常容易。你想讓Agent多一個(gè)能力只需要給它注冊(cè)一個(gè)新工具并寫(xiě)好描述模型不需要重新訓(xùn)練就能在合適的場(chǎng)景下調(diào)用它。這也是為什么現(xiàn)在Agent框架層出不窮因?yàn)殚T檻確實(shí)降低了。順帶說(shuō)一個(gè)細(xì)節(jié)工具描述的措辭直接影響模型會(huì)不會(huì)用。描述寫(xiě)得含糊模型就不知道這個(gè)工具啥時(shí)候用描述寫(xiě)得具體并配上使用示例調(diào)用準(zhǔn)確率會(huì)顯著提高。3.5 結(jié)果匯總與自檢機(jī)制Agent執(zhí)行完所有子任務(wù)后不會(huì)像聊天機(jī)器人那樣直接丟一段回復(fù)就算完事。一個(gè)工程上可用的Agent必須要有自檢機(jī)制我把這一階段叫“出口質(zhì)檢”。自檢通常包括三個(gè)層面。第一是完整性檢查原始目標(biāo)里的每一項(xiàng)要求是否都有對(duì)應(yīng)交付物有沒(méi)有漏掉的子任務(wù)。第二是一致性檢查最終報(bào)告里的數(shù)據(jù)是否和工具返回的原始數(shù)據(jù)一致有沒(méi)有出現(xiàn)模型自己腦補(bǔ)出來(lái)的數(shù)字。第三是格式檢查交付物是否符合用戶要求的格式比如用戶要Markdown就不能給純文本用戶要表格就不能給一大段散文。這個(gè)自檢環(huán)節(jié)很多人懶得做但實(shí)際項(xiàng)目里吃過(guò)虧。有一次我搭建的Agent在生成報(bào)告時(shí)把工具返回的統(tǒng)計(jì)數(shù)字“123”寫(xiě)成了“132”如果只靠人工事后核對(duì)這種錯(cuò)誤很難發(fā)現(xiàn)。后來(lái)我在自檢環(huán)節(jié)加了一步“摘要對(duì)齊”讓模型把報(bào)告里的關(guān)鍵數(shù)字一一對(duì)應(yīng)回工具返回值這類錯(cuò)誤基本就絕跡了。4. 實(shí)操手寫(xiě)一個(gè)最小可用的Agent核心循環(huán)4.1 代碼骨架不依賴框架也能跑現(xiàn)在工具編排框架很多但我建議想搞懂原理的人先從零寫(xiě)一個(gè)最小循環(huán)。幾十行Python代碼就能展示Agent的本質(zhì)等理解透了再去用框架你會(huì)發(fā)現(xiàn)自己能看懂很多框架內(nèi)部的黑魔法。下面這個(gè)Demo用模擬函數(shù)代替真實(shí)工具調(diào)用核心是讓你看清“循環(huán)”長(zhǎng)什么樣import json import random tools [ { name: get_sales_data, description: 獲取指定時(shí)間段的銷售數(shù)據(jù)返回總銷售額和訂單數(shù), parameters: { type: object, properties: { start_date: {type: string}, end_date: {type: string} }, required: [start_date, end_date] } }, { name: calculate_growth, description: 比較兩個(gè)數(shù)值返回同比增長(zhǎng)率, parameters: { type: object, properties: { current: {type: number}, previous: {type: number} }, required: [current, previous] } } ] def execute_tool(tool_name, params): # 模擬工具執(zhí)行真實(shí)場(chǎng)景這里會(huì)調(diào)用外部API或運(yùn)行代碼 if tool_name get_sales_data: return {total_sales: random.randint(80, 120), orders: random.randint(1000, 2000)} elif tool_name calculate_growth: return {growth_rate: round((params[current] - params[previous]) / params[previous] * 100, 2)} return {error: unknown tool} def llm_decision(context): # 模擬大模型決策根據(jù)上下文決定調(diào)用哪個(gè)工具 # 真實(shí)場(chǎng)景中這一步會(huì)把上下文發(fā)給大模型解析返回的JSON if get_sales_data not in context: return json.dumps({tool: get_sales_data, params: {start_date: 2024-05-01, end_date: 2024-05-31}}) else: return json.dumps({tool: calculate_growth, params: {current: 100, previous: 80}}) def run_agent(user_goal): context f用戶目標(biāo): {user_goal}\n max_iterations 5 result None for i in range(max_iterations): decision json.loads(llm_decision(context)) tool_name decision[tool] params decision.get(params, {}) observation execute_tool(tool_name, params) context f行動(dòng): 調(diào)用{tool_name}, 參數(shù){params}\n context f觀察: {json.dumps(observation)}\n print(f--- 第{i 1}輪循環(huán) ---) print(f工具: {tool_name}) print(f觀察結(jié)果: {observation}) # 判斷任務(wù)是否結(jié)束實(shí)際場(chǎng)景由模型自己判斷這里簡(jiǎn)化 if tool_name calculate_growth: result observation break if result is None: print(達(dá)到最大迭代次數(shù)任務(wù)未完成) else: print(f最終結(jié)果: 銷售數(shù)據(jù)同比增長(zhǎng){result[growth_rate]}%) # 實(shí)際場(chǎng)景中接下來(lái)會(huì)讓模型基于context生成最終報(bào)告 run_agent(分析本月銷售數(shù)據(jù)并計(jì)算環(huán)比增長(zhǎng)情況)運(yùn)行這段代碼你能看到Agent每次決策、調(diào)用工具、拿到觀測(cè)結(jié)果的完整軌跡。雖然這里的llm_decision是寫(xiě)死的模擬邏輯但把它替換成真正的大模型API調(diào)用后整個(gè)框架就活起來(lái)了。4.2 關(guān)鍵參數(shù)的選擇與驗(yàn)證真正把一個(gè)Agent接入大模型時(shí)有幾個(gè)參數(shù)是繞不開(kāi)的我也踩過(guò)不少坑。max_iterations是最重要的安全閥。它的作用是限制Agent最多循環(huán)多少輪防止模型在某個(gè)問(wèn)題上反復(fù)橫跳停不下來(lái)。我見(jiàn)過(guò)一個(gè)Agent因?yàn)樗阉鹘Y(jié)果不理想在同一個(gè)查詢上重試了二十多次既浪費(fèi)token又拖垮任務(wù)。建議所有面向生產(chǎn)的Agent都設(shè)置一個(gè)合理的上限比如15輪超過(guò)了就轉(zhuǎn)入人工處理。temperature代表思維彈性。對(duì)需要精確計(jì)算和執(zhí)行的Agent任務(wù)我一般把temperature控制在0到0.3之間。別小看這個(gè)參數(shù)溫度一高模型輸出的JSON都可能開(kāi)始不守格式工具調(diào)用參數(shù)偶爾會(huì)“靈機(jī)一動(dòng)”寫(xiě)錯(cuò)。而如果任務(wù)本身需要?jiǎng)?chuàng)造性比如生成營(yíng)銷文案溫度可以適度調(diào)高到0.7以上。工具的返回結(jié)果長(zhǎng)度也值得關(guān)注。有些接口返回的數(shù)據(jù)很長(zhǎng)塞進(jìn)上下文既占空間又容易讓模型“看花了眼”。我習(xí)慣在工具函數(shù)里做一次預(yù)處理只返回任務(wù)所需的摘要字段把原始數(shù)據(jù)單獨(dú)存儲(chǔ)需要時(shí)再查。這一招對(duì)控制上下文成本非常關(guān)鍵。4.3 從最小循環(huán)到框架使用的經(jīng)驗(yàn)自己跑通最小循環(huán)之后你再去看那些開(kāi)源編排框架理解速度會(huì)快很多。框架本質(zhì)上就是在幫我們解決幾個(gè)重復(fù)勞動(dòng)統(tǒng)一工具注冊(cè)格式、管理多輪對(duì)話狀態(tài)、提供現(xiàn)成的記憶存儲(chǔ)、支持并行工具調(diào)用、封裝日志追蹤等。我的建議是先在框架里跑一個(gè)最小Demo再用自己寫(xiě)的最小循環(huán)做對(duì)照你會(huì)很快理解那些抽象接口背后到底在做什么。等要用到高級(jí)特性比如多Agent協(xié)同、流式執(zhí)行、人機(jī)審核節(jié)點(diǎn)時(shí)再深入研究框架文檔就不吃力了。使用框架時(shí)有一個(gè)容易忽略的點(diǎn)框架會(huì)替你做很多隱式的上下文處理一旦出了詭異問(wèn)題排查難度會(huì)比自寫(xiě)代碼更高。所以即便用了框架也務(wù)必打開(kāi)“詳細(xì)日志模式”把每次工具調(diào)用的輸入輸出都打出來(lái)否則出了問(wèn)題你根本不知道模型在哪個(gè)環(huán)節(jié)產(chǎn)生了幻覺(jué)。5. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄5.1 模型幻覺(jué)導(dǎo)致工具參數(shù)錯(cuò)誤癥狀模型明明看到了工具參數(shù)說(shuō)明卻在調(diào)用時(shí)傳了一個(gè)不存在的字段名比如日期格式寫(xiě)成了2024/05/01而不是2024-05-01。原因在于大模型對(duì)數(shù)字格式、日期格式這類精細(xì)約束并不可靠它傾向于“按理解自由發(fā)揮”。解法我常用的有三層。第一層是工具函數(shù)里做嚴(yán)格的參數(shù)校驗(yàn)格式不對(duì)直接報(bào)出清晰錯(cuò)誤信息讓模型有機(jī)會(huì)根據(jù)錯(cuò)誤信息自己修正。第二層是在工具描述里給出一個(gè)示例比如start_date: 2024-05-01, 注意使用橫線分隔示例比抽象描述有效得多。第三層是在外層加規(guī)則約束如果同一個(gè)工具連續(xù)三次返回參數(shù)校驗(yàn)錯(cuò)誤就中斷Agent并轉(zhuǎn)人工避免死磕。5.2 上下文膨脹導(dǎo)致任務(wù)中途“失憶”癥狀任務(wù)執(zhí)行到一半模型開(kāi)始忘記最初的目標(biāo)做出和用戶需求無(wú)關(guān)的行動(dòng)。原因很簡(jiǎn)單每一輪工具調(diào)用都會(huì)把結(jié)果追加進(jìn)上下文積累幾十輪后早期的重要信息被淹沒(méi)在大量中間觀察中。解決這個(gè)問(wèn)題的核心思路是記憶管理。我通常的做法是定期做“關(guān)鍵信息摘要”每執(zhí)行完一個(gè)階段就讓模型把當(dāng)前進(jìn)展、關(guān)鍵數(shù)據(jù)、未完成事項(xiàng)壓縮成一段摘要然后丟棄部分冗余的中間日志。更進(jìn)階的做法是引入向量檢索記憶讓模型在執(zhí)行每一步前先去記憶庫(kù)檢索最相關(guān)的歷史信息而不是把全部歷史都堆在上下文里。這兩種手段都能顯著延長(zhǎng)Agent能穩(wěn)定處理的任務(wù)長(zhǎng)度。5.3 Agent陷入死循環(huán)或重復(fù)嘗試癥狀A(yù)gent在某一步反復(fù)調(diào)用同一個(gè)工具參數(shù)幾乎一樣得到的結(jié)果也一樣但它就是不斷重試像陷入了一個(gè)死循環(huán)。這個(gè)問(wèn)題在開(kāi)放式任務(wù)里特別常見(jiàn)因?yàn)槟P桶l(fā)現(xiàn)結(jié)果不理想又沒(méi)有更好的替代方案只能寄希望于碰運(yùn)氣。預(yù)防手段除了設(shè)置max_iterations還可以啟用“重復(fù)動(dòng)作檢測(cè)”。系統(tǒng)層面記錄最近幾輪的工具調(diào)用組合如果發(fā)現(xiàn)連續(xù)N輪調(diào)用相同工具且參數(shù)相似就中斷循環(huán)并在上下文里提示模型“你正在重復(fù)嘗試請(qǐng)改變策略或?qū)で髱椭?。這個(gè)機(jī)制看起來(lái)簡(jiǎn)單但在實(shí)際項(xiàng)目中救過(guò)我很多次尤其是那些依賴外部搜索引擎的任務(wù)搜索接口抽風(fēng)時(shí)Agent就會(huì)瘋狂重試。常見(jiàn)問(wèn)題典型表現(xiàn)核心原因推薦解法參數(shù)幻覺(jué)日期格式錯(cuò)誤、字段不存在模型精細(xì)約束能力弱工具校驗(yàn)、示例描述上下文爆炸中途遺忘目標(biāo)歷史信息過(guò)多摘要壓縮、向量記憶重復(fù)死循環(huán)同工具反復(fù)調(diào)用缺乏替代策略重復(fù)檢測(cè)、迭代上限工具權(quán)限過(guò)寬Agent執(zhí)行了危險(xiǎn)操作工具接口無(wú)權(quán)限控制最小權(quán)限、白名單策略結(jié)果格式失控報(bào)告結(jié)構(gòu)混亂輸出約束不足輸出Schema校驗(yàn)、自檢機(jī)制5.4 工具權(quán)限與安全邊界問(wèn)題這個(gè)坑新手最容易忽視。Agent有了工具調(diào)用能力后就等于給大模型發(fā)了一把“真實(shí)世界”的鑰匙。如果這把鑰匙能刪除服務(wù)器文件、能發(fā)郵件、能調(diào)用付費(fèi)接口又沒(méi)有做任何限制那么模型的一次幻覺(jué)就可能造成實(shí)際損失。我在生產(chǎn)環(huán)境里的做法是“最小權(quán)限原則”。給Agent的每類任務(wù)單獨(dú)配置工具集合比如做數(shù)據(jù)分析的Agent只能讀取特定目錄的文件沒(méi)有寫(xiě)權(quán)限調(diào)外部API的工具必須走審批網(wǎng)關(guān)超過(guò)一定成本自動(dòng)熔斷。還有一個(gè)容易被忽略但非常有效的設(shè)計(jì)是“關(guān)鍵操作人工復(fù)核”Agent可以生成操作指令但像發(fā)送對(duì)外郵件、刪除數(shù)據(jù)、修改線上配置這類高影響動(dòng)作必須有一個(gè)“確認(rèn)節(jié)點(diǎn)”由人來(lái)批準(zhǔn)。別小看這個(gè)設(shè)計(jì)它能讓Agent從“實(shí)驗(yàn)玩具”升級(jí)成“可信工具”。5.5 可觀測(cè)性追蹤每一步?jīng)Q策排障過(guò)程中最痛苦的往往不是問(wèn)題本身而是你連問(wèn)題發(fā)生在哪一步都不知道。沒(méi)有日志的Agent就像一個(gè)黑盒你只看到它輸出了個(gè)離譜結(jié)果完全不知道是模型決策錯(cuò)了還是工具返回錯(cuò)了。所以我建議從第一天就做好可觀測(cè)性設(shè)計(jì)。每個(gè)人的日志格式可以不一樣但至少要包含三類信息每輪的思考內(nèi)容、每輪調(diào)用的工具和參數(shù)、每輪觀察到的結(jié)果。把這個(gè)軌跡完整記錄下來(lái)很多問(wèn)題一眼就能定位。有一次我發(fā)現(xiàn)Agent生成的分析報(bào)告少了某個(gè)模塊的數(shù)據(jù)回看日志才知道是工具查詢時(shí)參數(shù)里漏傳了模塊名這事如果沒(méi)日志我得猜半天。6. 從Demo到可用系統(tǒng)幾個(gè)落地習(xí)慣6.1 先收窄場(chǎng)景再追求通用初學(xué)Agent時(shí)很容易陷入一個(gè)誤區(qū)試圖做一個(gè)“什么任務(wù)都能干”的萬(wàn)能Agent。我早期也這么干過(guò)結(jié)果就是系統(tǒng)看起來(lái)很強(qiáng)實(shí)際什么都干不精而且排查問(wèn)題時(shí)頭痛欲裂。后來(lái)我調(diào)整了策略先按場(chǎng)景垂直化比如只做數(shù)據(jù)分析、只做日程管理、只做報(bào)告生成把每一個(gè)場(chǎng)景打磨到可靠再考慮橫向擴(kuò)展。原因在于Agent的可靠性高度依賴工具集合和規(guī)劃邏輯。你給它的工具越聚焦它做決策時(shí)越不容易混亂。一個(gè)只配了三個(gè)數(shù)據(jù)分析工具的Agent知道自己所有能力邊界在數(shù)據(jù)分析規(guī)劃自然更精準(zhǔn)而一個(gè)配了幾十個(gè)工具的通用Agent光是在“選哪個(gè)工具”這件事上就有大量出錯(cuò)空間。6.2 建立評(píng)估指標(biāo)不靠感覺(jué)調(diào)優(yōu)Agent系統(tǒng)的調(diào)優(yōu)特別容易陷入“感覺(jué)變好了/變壞了”的模糊狀態(tài)??煽啃栽趺戳炕医o自己訂了三類核心指標(biāo)推薦你也試試。第一類是任務(wù)完成率跑一批固定測(cè)試任務(wù)統(tǒng)計(jì)Agent成功完整跑完的比例。第二類是工具調(diào)用有效率統(tǒng)計(jì)所有工具調(diào)用中成功且結(jié)果合理的次數(shù)比例。第三類是單任務(wù)成本統(tǒng)計(jì)每個(gè)任務(wù)平均消耗的token數(shù)和API調(diào)用費(fèi)用。這三類指標(biāo)每次改動(dòng)系統(tǒng)后都重新測(cè)一輪用數(shù)據(jù)說(shuō)話比憑感覺(jué)靠譜得多。我見(jiàn)過(guò)不少團(tuán)隊(duì)調(diào)Prompt調(diào)了幾十版一問(wèn)怎么知道變好了答不上來(lái)那就是沒(méi)有建立評(píng)估閉環(huán)。6.3 保留人工審核節(jié)點(diǎn)最后聊一個(gè)態(tài)度問(wèn)題。現(xiàn)在關(guān)于Agent“全自主”的宣傳很多但真正拿到生產(chǎn)環(huán)境里我越來(lái)越認(rèn)同一個(gè)原則不是所有環(huán)節(jié)都追求無(wú)人化而是“能自動(dòng)的盡量自動(dòng)關(guān)鍵處必須留人”。比如日常數(shù)據(jù)整理、初稿生成、例行檢查這類低風(fēng)險(xiǎn)環(huán)節(jié)讓Agent全自動(dòng)跑沒(méi)問(wèn)題。但在涉及大額支出、對(duì)外發(fā)布、法律風(fēng)險(xiǎn)等場(chǎng)景保留一個(gè)人類確認(rèn)點(diǎn)不是倒退而是對(duì)Agent能力邊界最務(wù)實(shí)的尊重。我做過(guò)一個(gè)自動(dòng)化報(bào)告系統(tǒng)最開(kāi)始全流程無(wú)人干預(yù)結(jié)果有一次模型把數(shù)據(jù)解讀方向完全搞反了生成的結(jié)論和事實(shí)剛好相反還好發(fā)出前有人工審核環(huán)節(jié)攔了下來(lái)。自那以后我所有的生產(chǎn)級(jí)Agent都會(huì)認(rèn)真設(shè)計(jì)人機(jī)協(xié)作點(diǎn)這反而是Agent能走得更遠(yuǎn)的原因。6.4 我的三點(diǎn)體會(huì)講完這么多原理和實(shí)操最后說(shuō)幾句個(gè)人感受。第一次跑通Agent全流程的時(shí)候看著模型自己規(guī)劃、調(diào)工具、糾錯(cuò)那種感覺(jué)確實(shí)挺震撼的。但用久了你會(huì)意識(shí)到Agent的“獨(dú)立”并不是什么神秘能力而是工程上把決策、執(zhí)行和反饋反復(fù)收斂的產(chǎn)物。它依然會(huì)錯(cuò)會(huì)困惑會(huì)在意想不到的地方翻車只是它比普通對(duì)話系統(tǒng)多了一項(xiàng)關(guān)鍵能力錯(cuò)得起改得了。所以如果你也想動(dòng)手做一個(gè)Agent我的建議是別從宏大構(gòu)想開(kāi)始從一個(gè)特別具體的、你自己真正會(huì)重復(fù)使用的小任務(wù)開(kāi)始。寫(xiě)一個(gè)最小循環(huán)加一個(gè)真實(shí)好用的工具讓它完成任務(wù)給你看然后順著日志把毛病一個(gè)個(gè)修掉。這個(gè)過(guò)程你會(huì)踩很多坑但那正是理解和掌控Agent最好的路徑。等這一套走通了再回頭看我前面講的這些原理你會(huì)有完全不同的體會(huì)。