Agent開(kāi)發(fā):從系統(tǒng)編排到工具調(diào)用實(shí)戰(zhàn))
1. 從“調(diào)模型”到“搭系統(tǒng)”前端視角下的Agent開(kāi)發(fā)認(rèn)知糾偏很多前端同行第一次聽(tīng)到“Agent開(kāi)發(fā)”這個(gè)詞腦子里蹦出來(lái)的第一反應(yīng)往往是這是不是又要搞模型訓(xùn)練是不是得先學(xué)會(huì)PyTorch再啃幾篇Transformer的論文最好還能自己微調(diào)一個(gè)模型出來(lái)我當(dāng)初也是這么想的甚至一度覺(jué)得這玩意兒離自己挺遠(yuǎn)——畢竟前端日常打交道的是DOM、組件生命周期、狀態(tài)管理跟梯度下降、損失函數(shù)八竿子打不著。但真正上手做了幾個(gè)Agent項(xiàng)目之后我發(fā)現(xiàn)這個(gè)認(rèn)知偏差大得離譜。Agent開(kāi)發(fā)的核心根本不是模型訓(xùn)練而是系統(tǒng)編排。模型是別人訓(xùn)好的你拿過(guò)來(lái)用就行就像你寫(xiě)前端不會(huì)自己去實(shí)現(xiàn)一個(gè)瀏覽器內(nèi)核一樣。你要做的事情是把模型當(dāng)成一個(gè)能力很強(qiáng)的“外部服務(wù)”然后圍繞它設(shè)計(jì)一套能穩(wěn)定運(yùn)轉(zhuǎn)的流程。這個(gè)認(rèn)知轉(zhuǎn)變非常關(guān)鍵。一旦你把它理解成“系統(tǒng)編排”前端工程師的很多既有技能就立刻變得有用了狀態(tài)管理、異步流程控制、錯(cuò)誤處理、接口設(shè)計(jì)、用戶(hù)體驗(yàn)——這些全是前端每天都在干的事情。你不需要成為算法工程師你需要的是一個(gè)“AI應(yīng)用架構(gòu)師”的思維。這篇文章就是寫(xiě)給那些對(duì)Agent開(kāi)發(fā)感興趣、但被“模型訓(xùn)練”四個(gè)字嚇住的前端同行。我會(huì)把Agent開(kāi)發(fā)拆成幾個(gè)核心模塊講清楚每個(gè)模塊到底在干什么、為什么這么設(shè)計(jì)、前端背景的人怎么快速上手。全文不會(huì)涉及任何模型訓(xùn)練的技術(shù)細(xì)節(jié)因?yàn)槟歉静皇侨腴T(mén)階段該關(guān)心的事。提示如果你現(xiàn)在還在糾結(jié)“要不要先學(xué)深度學(xué)習(xí)”我的建議是先放下這個(gè)念頭。Agent開(kāi)發(fā)的門(mén)檻在工程側(cè)不在算法側(cè)。先把系統(tǒng)跑起來(lái)再回頭補(bǔ)理論效率高得多。2. Agent的本質(zhì)一個(gè)帶工具調(diào)用能力的循環(huán)系統(tǒng)2.1 為什么說(shuō)Agent不是“更聰明的聊天機(jī)器人”很多人對(duì)Agent的理解停留在“能聊天的AI”這個(gè)理解會(huì)導(dǎo)致你在設(shè)計(jì)系統(tǒng)時(shí)走偏。聊天機(jī)器人的核心是“一問(wèn)一答”而Agent的核心是“目標(biāo)驅(qū)動(dòng)的循環(huán)”。這兩者的區(qū)別就像“計(jì)算器”和“會(huì)自己按計(jì)算器的助手”之間的區(qū)別。一個(gè)典型的Agent運(yùn)行邏輯是這樣的用戶(hù)給一個(gè)目標(biāo)Agent先思考需要做什么然后選擇一個(gè)工具去執(zhí)行拿到執(zhí)行結(jié)果后再思考下一步如此循環(huán)直到目標(biāo)完成或者達(dá)到終止條件。這個(gè)“思考-行動(dòng)-觀察”的循環(huán)才是Agent的靈魂。我用一個(gè)前端熟悉的類(lèi)比來(lái)解釋聊天機(jī)器人像是一個(gè)純函數(shù)輸入A輸出B沒(méi)有副作用而Agent像是一個(gè)帶有狀態(tài)機(jī)的異步任務(wù)隊(duì)列每一步的輸出都會(huì)影響下一步的輸入而且中間會(huì)調(diào)用各種外部API。你寫(xiě)過(guò)的那些帶輪詢(xún)、帶重試、帶狀態(tài)流轉(zhuǎn)的前端邏輯本質(zhì)上就是Agent循環(huán)的簡(jiǎn)化版。2.2 循環(huán)系統(tǒng)的三個(gè)核心組件拆開(kāi)來(lái)看一個(gè)最小可用的Agent循環(huán)需要三個(gè)東西第一是決策器。它負(fù)責(zé)根據(jù)當(dāng)前狀態(tài)決定下一步做什么。這個(gè)決策器通常就是大語(yǔ)言模型你給它一段提示詞它輸出一個(gè)結(jié)構(gòu)化的決策結(jié)果比如“調(diào)用搜索工具參數(shù)是XXX”。注意這里模型只負(fù)責(zé)“決策”不負(fù)責(zé)“執(zhí)行”。第二是工具集。工具就是Agent能調(diào)用的外部能力可以是一個(gè)HTTP接口、一個(gè)數(shù)據(jù)庫(kù)查詢(xún)、一個(gè)文件讀寫(xiě)操作甚至是一個(gè)前端頁(yè)面上的按鈕點(diǎn)擊。工具的定義要清晰輸入什么、輸出什么、什么情況下用。這部分工作對(duì)前端來(lái)說(shuō)非常親切本質(zhì)上就是設(shè)計(jì)API。第三是狀態(tài)管理器。它記錄Agent執(zhí)行過(guò)程中的所有信息用戶(hù)目標(biāo)、歷史步驟、每步的觀察結(jié)果、當(dāng)前進(jìn)度。狀態(tài)管理做得好不好直接決定Agent能不能處理復(fù)雜任務(wù)。前端的狀態(tài)管理經(jīng)驗(yàn)在這里能直接遷移過(guò)來(lái)。2.3 一個(gè)容易踩的坑把決策和執(zhí)行混在一起我見(jiàn)過(guò)不少初學(xué)者寫(xiě)的Agent把“決定調(diào)用哪個(gè)工具”和“實(shí)際調(diào)用工具”寫(xiě)在同一個(gè)函數(shù)里模型輸出什么就直接執(zhí)行什么。這種寫(xiě)法在Demo階段沒(méi)問(wèn)題但一旦任務(wù)變復(fù)雜就會(huì)失控。正確的做法是把決策和執(zhí)行徹底分離。模型只輸出一個(gè)結(jié)構(gòu)化的決策對(duì)象比如{ action: search, params: { query: 前端性能優(yōu)化方案 }, reasoning: 需要先獲取相關(guān)資料 }然后由你的代碼去解析這個(gè)對(duì)象校驗(yàn)參數(shù)合法性再?zèng)Q定是否真的執(zhí)行。這樣做的好處是你可以在執(zhí)行前加校驗(yàn)、加日志、加人工確認(rèn)也可以在模型輸出格式錯(cuò)誤時(shí)優(yōu)雅降級(jí)。這個(gè)思路跟前端處理用戶(hù)輸入是一樣的——永遠(yuǎn)不要信任外部輸入哪怕這個(gè)輸入來(lái)自模型。3. 工具調(diào)用前端工程師最容易上手的部分3.1 工具定義的本質(zhì)就是接口設(shè)計(jì)如果說(shuō)Agent開(kāi)發(fā)有什么部分是前端能無(wú)縫銜接的那一定是工具調(diào)用。工具的定義、注冊(cè)、調(diào)用、錯(cuò)誤處理這一整套流程跟前端設(shè)計(jì)SDK接口幾乎一模一樣。一個(gè)工具的定義通常包含這幾個(gè)要素名稱(chēng)、描述、參數(shù)schema、執(zhí)行函數(shù)。名稱(chēng)和描述是給模型看的模型根據(jù)這些信息判斷什么時(shí)候該用這個(gè)工具。參數(shù)schema用來(lái)約束輸入格式執(zhí)行函數(shù)就是實(shí)際干活的代碼。我習(xí)慣用這樣的結(jié)構(gòu)來(lái)定義一個(gè)工具const searchTool { name: web_search, description: 根據(jù)關(guān)鍵詞搜索網(wǎng)頁(yè)信息返回摘要列表, parameters: { type: object, properties: { query: { type: string, description: 搜索關(guān)鍵詞 }, limit: { type: number, description: 返回結(jié)果數(shù)量默認(rèn)5 } }, required: [query] }, execute: async ({ query, limit 5 }) { // 實(shí)際調(diào)用搜索接口 const results await searchApi(query, limit); return results.map(r ({ title: r.title, snippet: r.snippet })); } };這個(gè)結(jié)構(gòu)是不是很眼熟跟你在前端封裝一個(gè)請(qǐng)求函數(shù)沒(méi)有本質(zhì)區(qū)別。唯一的區(qū)別是你需要額外寫(xiě)一段“給模型看的描述”讓模型知道這個(gè)工具是干什么的。3.2 描述寫(xiě)得好不好直接決定Agent聰不聰明這里有一個(gè)非常關(guān)鍵的細(xì)節(jié)工具描述的質(zhì)量比工具本身的實(shí)現(xiàn)更重要。模型只能通過(guò)描述來(lái)理解工具的用途如果描述寫(xiě)得含糊模型就會(huì)用錯(cuò)工具或者該用的時(shí)候不用。我踩過(guò)的一個(gè)坑是早期我寫(xiě)了一個(gè)“獲取用戶(hù)信息”的工具描述只寫(xiě)了“獲取用戶(hù)信息”。結(jié)果模型在需要查訂單的時(shí)候也調(diào)這個(gè)工具因?yàn)樗X(jué)得“用戶(hù)信息”可能包含訂單。后來(lái)我把描述改成“根據(jù)用戶(hù)ID查詢(xún)用戶(hù)的基本資料包括昵稱(chēng)、注冊(cè)時(shí)間、會(huì)員等級(jí)不包含訂單和交易記錄”模型的使用準(zhǔn)確率立刻上去了。寫(xiě)工具描述有幾個(gè)經(jīng)驗(yàn)說(shuō)清楚“做什么”和“不做什么”邊界要明確參數(shù)說(shuō)明要具體最好給示例值如果有使用前提一定要寫(xiě)出來(lái)比如“需要先獲取用戶(hù)ID”描述長(zhǎng)度控制在兩三句話(huà)太長(zhǎng)了模型反而抓不住重點(diǎn)3.3 工具調(diào)用的錯(cuò)誤處理策略工具調(diào)用一定會(huì)出錯(cuò)網(wǎng)絡(luò)超時(shí)、參數(shù)錯(cuò)誤、接口返回異常這些都是常態(tài)。前端處理接口錯(cuò)誤的經(jīng)驗(yàn)在這里完全適用但有一點(diǎn)需要注意錯(cuò)誤信息要反饋給模型而不是直接拋給用戶(hù)。舉個(gè)例子如果搜索工具返回了“請(qǐng)求超時(shí)”你不應(yīng)該直接告訴用戶(hù)“搜索失敗了”而應(yīng)該把錯(cuò)誤信息作為觀察結(jié)果傳回給模型讓模型決定是重試、換工具、還是告訴用戶(hù)暫時(shí)無(wú)法完成。這個(gè)設(shè)計(jì)思路叫“錯(cuò)誤即觀察”是Agent魯棒性的關(guān)鍵。我通常會(huì)把工具執(zhí)行結(jié)果統(tǒng)一成這樣的格式{ success: true/false, data: {...}, // 成功時(shí)的數(shù)據(jù) error: ..., // 失敗時(shí)的原因 suggestion: ... // 可選的修復(fù)建議 }模型看到success為false時(shí)會(huì)結(jié)合error和suggestion來(lái)決定下一步。實(shí)測(cè)下來(lái)這種設(shè)計(jì)能讓Agent在遇到偶發(fā)錯(cuò)誤時(shí)自動(dòng)恢復(fù)而不是直接卡死。4. 提示詞工程不是寫(xiě)作文是設(shè)計(jì)協(xié)議4.1 把提示詞當(dāng)成API契約來(lái)寫(xiě)前端工程師對(duì)“契約”這個(gè)概念應(yīng)該很熟悉前后端約定好接口格式各自按約定實(shí)現(xiàn)。Agent的提示詞本質(zhì)上就是你和模型之間的契約——你告訴模型輸入是什么格式、輸出是什么格式、有哪些約束條件。很多人寫(xiě)提示詞像寫(xiě)作文堆一大堆形容詞結(jié)果模型輸出不穩(wěn)定。正確的做法是像寫(xiě)接口文檔一樣寫(xiě)提示詞結(jié)構(gòu)化、無(wú)歧義、有示例。一個(gè)我常用的提示詞骨架是這樣的你是一個(gè)任務(wù)執(zhí)行助手。你的目標(biāo)是幫助用戶(hù)完成指定任務(wù)。 你可以使用以下工具 {tools_description} 請(qǐng)嚴(yán)格按照以下JSON格式輸出你的決策 { thought: 你的思考過(guò)程, action: 工具名稱(chēng)或finish, action_input: {參數(shù)對(duì)象} } 約束條件 1. 每次只能調(diào)用一個(gè)工具 2. 如果任務(wù)已完成action設(shè)為finish 3. 參數(shù)必須符合工具定義的schema這種結(jié)構(gòu)化提示詞的好處是輸出格式穩(wěn)定解析起來(lái)不容易出錯(cuò)。前端處理JSON解析的容錯(cuò)邏輯在這里能直接復(fù)用。4.2 少樣本示例比長(zhǎng)篇說(shuō)明更有效如果你發(fā)現(xiàn)模型總是輸出格式不對(duì)最有效的解決辦法不是加更多說(shuō)明文字而是給兩三個(gè)示例。模型對(duì)示例的敏感度遠(yuǎn)高于對(duì)規(guī)則描述的敏感度。我一般會(huì)準(zhǔn)備三類(lèi)示例一個(gè)正常調(diào)用的、一個(gè)任務(wù)完成的、一個(gè)參數(shù)復(fù)雜的。這三類(lèi)覆蓋了大部分場(chǎng)景模型看了之后輸出穩(wěn)定性會(huì)明顯提升。注意示例要真實(shí)可信不要編造不存在的工具名或參數(shù)。示例里的工具必須和實(shí)際注冊(cè)的工具一致否則模型會(huì)混淆。4.3 提示詞版本管理別把提示詞硬編碼在代碼里這是一個(gè)很容易被忽視的工程問(wèn)題。初期大家習(xí)慣把提示詞直接寫(xiě)在代碼里改一次就要重新部署。但提示詞是需要反復(fù)迭代的硬編碼會(huì)讓迭代效率極低。我的做法是把提示詞抽成獨(dú)立的配置文件或者模板文件代碼里只負(fù)責(zé)讀取和填充變量。更進(jìn)一步可以給提示詞加版本號(hào)記錄每次修改的效果對(duì)比。這個(gè)思路跟前端做AB測(cè)試是一樣的——提示詞就是你的實(shí)驗(yàn)變量。5. 狀態(tài)管理與上下文控制Agent的記憶問(wèn)題5.1 為什么Agent需要“記憶”Agent執(zhí)行任務(wù)往往需要多輪循環(huán)每一輪的決策都依賴(lài)之前的結(jié)果。如果模型沒(méi)有記憶它就會(huì)重復(fù)調(diào)用同一個(gè)工具或者忘記已經(jīng)獲取的信息。所以你需要把歷史步驟整理成上下文每次調(diào)用模型時(shí)一起傳進(jìn)去。但這里有個(gè)矛盾模型的上下文長(zhǎng)度是有限的任務(wù)步驟多了之后歷史信息會(huì)超出限制。這就引出了Agent開(kāi)發(fā)中最核心的工程問(wèn)題之一上下文管理。5.2 三種上下文壓縮策略我實(shí)踐下來(lái)比較有效的策略有三種第一種是滑動(dòng)窗口。只保留最近N步的歷史更早的丟棄。簡(jiǎn)單粗暴但會(huì)丟失早期的重要信息。適合步驟少、每步信息量小的任務(wù)。第二種是摘要壓縮。把早期步驟交給模型總結(jié)成一段簡(jiǎn)短摘要只保留摘要和最近幾步的詳細(xì)記錄。這種方式能保留關(guān)鍵信息但摘要本身可能丟失細(xì)節(jié)。第三種是結(jié)構(gòu)化記憶。把歷史信息按類(lèi)型拆開(kāi)存儲(chǔ)比如“已獲取的事實(shí)”“已執(zhí)行的行動(dòng)”“待完成的目標(biāo)”每次只把相關(guān)的部分放進(jìn)上下文。這種方式最復(fù)雜但效果最好。實(shí)際項(xiàng)目中我通常是組合使用近期步驟用滑動(dòng)窗口保留原文遠(yuǎn)期步驟用摘要壓縮關(guān)鍵事實(shí)用結(jié)構(gòu)化存儲(chǔ)單獨(dú)維護(hù)。5.3 前端狀態(tài)管理經(jīng)驗(yàn)的直接遷移如果你用過(guò)Redux或者Pinia你會(huì)發(fā)現(xiàn)Agent的狀態(tài)管理思路跟它們高度相似都是維護(hù)一個(gè)中心化的狀態(tài)樹(shù)每次操作產(chǎn)生一個(gè)新的狀態(tài)快照UI或者模型根據(jù)當(dāng)前狀態(tài)渲染或者決策。區(qū)別在于前端的狀態(tài)變更通常是同步的、可預(yù)測(cè)的而Agent的狀態(tài)變更依賴(lài)模型輸出帶有不確定性。所以你需要額外的校驗(yàn)層確保模型輸出的狀態(tài)變更符合預(yù)期。這個(gè)校驗(yàn)層的設(shè)計(jì)可以參考前端表單校驗(yàn)的思路定義schema、逐字段校驗(yàn)、給出明確的錯(cuò)誤提示。6. 從Demo到可用那些只有踩過(guò)才知道的坑6.1 循環(huán)終止條件別讓Agent陷入死循環(huán)Agent最危險(xiǎn)的情況是無(wú)限循環(huán)模型一直調(diào)用工具但永遠(yuǎn)不認(rèn)為任務(wù)完成。我遇到過(guò)最夸張的一次Agent連續(xù)調(diào)用了二十多次搜索工具每次都說(shuō)“還需要更多信息”。解決辦法是設(shè)置硬性終止條件最大循環(huán)次數(shù)、最大執(zhí)行時(shí)間、連續(xù)無(wú)進(jìn)展檢測(cè)。其中“連續(xù)無(wú)進(jìn)展檢測(cè)”最有用——如果連續(xù)三步的觀察結(jié)果高度相似就強(qiáng)制終止并返回當(dāng)前結(jié)果。另外提示詞里要明確告訴模型“如果信息足夠就盡快結(jié)束”并且給出判斷標(biāo)準(zhǔn)。模型有時(shí)候會(huì)過(guò)度謹(jǐn)慎你需要引導(dǎo)它果斷收尾。6.2 工具返回結(jié)果太長(zhǎng)怎么辦有些工具返回的數(shù)據(jù)量很大比如一個(gè)搜索接口返回了二十條結(jié)果每條都有幾百字。如果全部塞進(jìn)上下文很快就會(huì)撐爆。我的處理方式是在工具執(zhí)行層做預(yù)處理只返回最相關(guān)的幾條并且截?cái)噙^(guò)長(zhǎng)的文本。比如搜索結(jié)果只返回前三條的標(biāo)題和摘要摘要超過(guò)兩百字就截?cái)?。這個(gè)預(yù)處理邏輯放在工具內(nèi)部模型不需要知道原始數(shù)據(jù)有多長(zhǎng)。這個(gè)思路跟前端做列表虛擬滾動(dòng)是一樣的——數(shù)據(jù)可以很多但渲染出來(lái)的只有可視區(qū)域那部分。6.3 模型輸出格式不穩(wěn)定解析失敗的兜底方案不管你提示詞寫(xiě)得多好模型偶爾還是會(huì)輸出格式錯(cuò)誤的內(nèi)容。這時(shí)候不能直接崩潰要有兜底方案。我的做法是分三層處理第一層用正則提取JSON部分第二層用JSON.parse嘗試解析第三層如果還失敗就調(diào)用一次模型讓它重新格式化。三層都失敗才報(bào)錯(cuò)。實(shí)測(cè)下來(lái)第一層就能解決大部分問(wèn)題因?yàn)槟P屯ǔV皇嵌噍敵隽艘恍┣昂缶Y文字。6.4 成本控制Token是要花錢(qián)的Agent每循環(huán)一次就要調(diào)用一次模型Token消耗是普通對(duì)話(huà)的好幾倍。如果不加控制一個(gè)復(fù)雜任務(wù)可能燒掉大量Token??刂瞥杀镜氖侄斡袔讉€(gè)精簡(jiǎn)提示詞、壓縮上下文、限制循環(huán)次數(shù)、對(duì)簡(jiǎn)單任務(wù)用更小的模型。其中“對(duì)簡(jiǎn)單任務(wù)用更小的模型”效果最明顯——決策步驟用大模型格式化、摘要這類(lèi)任務(wù)用小模型就夠了。我在項(xiàng)目里會(huì)做一個(gè)簡(jiǎn)單的路由根據(jù)任務(wù)復(fù)雜度選擇模型。判斷復(fù)雜度的依據(jù)包括歷史步驟數(shù)、工具數(shù)量、用戶(hù)輸入的模糊程度。這個(gè)路由邏輯本身不需要模型用規(guī)則判斷就行。7. 前端做Agent開(kāi)發(fā)的獨(dú)特優(yōu)勢(shì)與需要補(bǔ)的課7.1 優(yōu)勢(shì)工程化思維和用戶(hù)體驗(yàn)敏感度前端工程師做Agent開(kāi)發(fā)有兩個(gè)天然優(yōu)勢(shì)。第一是工程化思維你知道怎么組織代碼、怎么管理狀態(tài)、怎么處理異步、怎么做錯(cuò)誤邊界。這些在Agent開(kāi)發(fā)里全是核心技能。第二是用戶(hù)體驗(yàn)敏感度你知道怎么給用戶(hù)反饋進(jìn)度、怎么展示中間狀態(tài)、怎么設(shè)計(jì)交互流程。Agent執(zhí)行任務(wù)往往需要幾秒到幾十秒這期間的體驗(yàn)設(shè)計(jì)非常關(guān)鍵。我見(jiàn)過(guò)一些算法背景的人做的Agent功能沒(méi)問(wèn)題但用起來(lái)很難受——沒(méi)有進(jìn)度提示、錯(cuò)誤信息直接拋給用戶(hù)、中間狀態(tài)完全黑盒。這些問(wèn)題前端一眼就能看出來(lái)也最知道怎么解決。7.2 需要補(bǔ)的課理解模型的“脾氣”前端需要補(bǔ)的課主要是對(duì)模型行為的理解。模型不是確定性函數(shù)同樣的輸入可能給出不同的輸出模型會(huì)有幻覺(jué)會(huì)編造不存在的信息模型對(duì)提示詞的措辭很敏感換個(gè)說(shuō)法結(jié)果可能完全不同。這些特性意味著你不能用寫(xiě)傳統(tǒng)代碼的思維來(lái)寫(xiě)Agent。傳統(tǒng)代碼里if-else是確定的Agent里模型的決策是不確定的。你需要接受這種不確定性并通過(guò)工程手段去約束它、引導(dǎo)它、兜底它。我的建議是花幾天時(shí)間專(zhuān)門(mén)做實(shí)驗(yàn)同一個(gè)提示詞改幾個(gè)字看輸出怎么變同一個(gè)任務(wù)跑十次看結(jié)果穩(wěn)不穩(wěn)定。這種“摸脾氣”的過(guò)程是必須的沒(méi)有捷徑。7.3 一個(gè)實(shí)用的學(xué)習(xí)路徑如果你是一個(gè)前端想入門(mén)Agent開(kāi)發(fā)我建議的路徑是這樣的第一步先用現(xiàn)成的API跑通一個(gè)最簡(jiǎn)單的循環(huán)不需要任何框架就是手寫(xiě)一個(gè)while循環(huán)調(diào)用模型、解析輸出、執(zhí)行工具、把結(jié)果塞回上下文。這一步的目的是理解Agent的運(yùn)行機(jī)制。第二步把工具調(diào)用封裝成標(biāo)準(zhǔn)接口加上參數(shù)校驗(yàn)和錯(cuò)誤處理。這一步的目的是建立工程規(guī)范。第三步處理上下文管理實(shí)現(xiàn)滑動(dòng)窗口或者摘要壓縮。這一步的目的是讓Agent能處理稍復(fù)雜的任務(wù)。第四步加上日志和可觀測(cè)性記錄每一步的輸入輸出。這一步的目的是方便調(diào)試和優(yōu)化。第五步才是考慮用框架。LangChain這類(lèi)框架能幫你省一些事但也會(huì)帶來(lái)抽象泄漏的問(wèn)題。我建議先手寫(xiě)一遍理解每個(gè)環(huán)節(jié)在干什么再用框架。8. 關(guān)于Agent開(kāi)發(fā)我踩過(guò)之后才明白的幾件事第一個(gè)體會(huì)是Agent的瓶頸往往不在模型能力而在工程細(xì)節(jié)。模型再聰明如果工具描述寫(xiě)得爛、上下文管理做得差、錯(cuò)誤處理不到位Agent照樣跑不起來(lái)。反過(guò)來(lái)一個(gè)中等能力的模型配上扎實(shí)的工程能做出相當(dāng)可用的東西。第二個(gè)體會(huì)是不要追求一步到位。我一開(kāi)始總想設(shè)計(jì)一個(gè)能處理所有情況的通用Agent結(jié)果越做越復(fù)雜最后什么都做不好。后來(lái)改成針對(duì)具體場(chǎng)景做專(zhuān)用Agent每個(gè)Agent只解決一類(lèi)問(wèn)題反而效果好得多。這跟前端做組件是一樣的——先做專(zhuān)用組件有共性了再抽象。第三個(gè)體會(huì)是可觀測(cè)性比什么都重要。Agent執(zhí)行過(guò)程是個(gè)黑盒如果不記錄每一步的輸入輸出出了問(wèn)題根本沒(méi)法排查。我現(xiàn)在每個(gè)Agent項(xiàng)目第一件事就是加日志把每次模型調(diào)用、每次工具執(zhí)行、每次狀態(tài)變更都記下來(lái)。這個(gè)習(xí)慣幫我省了無(wú)數(shù)調(diào)試時(shí)間。第四個(gè)體會(huì)是提示詞是需要持續(xù)迭代的資產(chǎn)。不要指望一次寫(xiě)好要建立快速迭代的機(jī)制。我現(xiàn)在的做法是把提示詞放在獨(dú)立文件里改完立刻能測(cè)測(cè)完記錄效果。積累下來(lái)這些提示詞模板就是項(xiàng)目最值錢(qián)的部分。第五個(gè)體會(huì)是前端做Agent有天然優(yōu)勢(shì)但別被優(yōu)勢(shì)限制住。工程化思維是優(yōu)勢(shì)但也要主動(dòng)去理解模型的行為特性。兩者結(jié)合才能做出真正好用的Agent產(chǎn)品。