一個(gè)最小Agent:拆解pi-agent核心閉環(huán)與工程實(shí)踐)
1. 從能跑就行到跑得明白為什么要手寫(xiě)一個(gè) Agent市面上關(guān)于 Agent 的文章十篇里有八篇在講概念——什么自主規(guī)劃、工具調(diào)用、記憶機(jī)制配一張花里胡哨的架構(gòu)圖看完之后你依然不知道一個(gè) Agent 從零到一到底該怎么落地。我自己也經(jīng)歷過(guò)這個(gè)階段看了大量資料腦子里全是名詞真到動(dòng)手的時(shí)候連一個(gè)最小的可運(yùn)行循環(huán)都寫(xiě)不出來(lái)。后來(lái)我換了個(gè)思路不再去追那些大而全的框架而是找一個(gè)結(jié)構(gòu)足夠清晰、代碼量足夠小的參考實(shí)現(xiàn)把它拆開(kāi)、讀懂、再自己重寫(xiě)一遍。pi-agent 就是這樣一個(gè)適合剝開(kāi)看的對(duì)象——它沒(méi)有堆砌太多抽象層核心邏輯用幾百行就能說(shuō)清楚。我照著它的思路用 Python 從零實(shí)現(xiàn)了一個(gè)能跑的小 Agent整個(gè)過(guò)程踩了不少坑也積累了一些文檔里不會(huì)寫(xiě)的經(jīng)驗(yàn)。這篇文章要做的就是把這段經(jīng)歷完整地?cái)傞_(kāi)。我會(huì)講清楚一個(gè) Agent 的最小閉環(huán)由哪幾塊組成、每一塊為什么這樣設(shè)計(jì)、pi-agent 在哪些地方做了取舍、我自己實(shí)現(xiàn)時(shí)遇到了什么問(wèn)題。目標(biāo)讀者是那些已經(jīng)了解大模型基本調(diào)用、想進(jìn)一步搞明白 Agent 內(nèi)部運(yùn)轉(zhuǎn)機(jī)制的開(kāi)發(fā)者。你不需要有 Agent 開(kāi)發(fā)經(jīng)驗(yàn)但至少要能看懂 Python 代碼和 API 調(diào)用的基本寫(xiě)法。需要提前說(shuō)明的是我這里的小 Agent指的是一個(gè)具備任務(wù)理解、工具調(diào)用、結(jié)果觀察、循環(huán)推進(jìn)這四件事的最小系統(tǒng)。它不追求生產(chǎn)級(jí)的健壯性但每一個(gè)環(huán)節(jié)都是真實(shí)可用的你可以基于它繼續(xù)往上加?xùn)|西。下面進(jìn)入正題。2. 一個(gè) Agent 的最小閉環(huán)到底由哪幾塊拼成2.1 把 Agent 拆成大腦 手腳 記憶三個(gè)部件很多人一上來(lái)就想搞一個(gè)全能 Agent結(jié)果代碼寫(xiě)到一半就亂了。我的建議是先做減法把 Agent 拆成三個(gè)最基礎(chǔ)的部件每個(gè)部件只干一件事。大腦負(fù)責(zé)決策也就是根據(jù)當(dāng)前的任務(wù)狀態(tài)決定下一步該做什么。在實(shí)現(xiàn)上大腦就是一次大模型調(diào)用輸入是當(dāng)前的上下文輸出是一個(gè)結(jié)構(gòu)化的動(dòng)作指令。這個(gè)動(dòng)作可能是調(diào)用某個(gè)工具也可能是直接給出最終答案。手腳負(fù)責(zé)執(zhí)行也就是真正去干活的部分。工具可以是讀文件、發(fā)請(qǐng)求、算數(shù)學(xué)、查數(shù)據(jù)庫(kù)任何你能用代碼封裝成函數(shù)的東西都可以。手腳本身沒(méi)有智能它只負(fù)責(zé)忠實(shí)地執(zhí)行大腦下達(dá)的指令然后把結(jié)果返回。記憶負(fù)責(zé)記錄也就是維護(hù)整個(gè)任務(wù)的上下文。它要記住用戶(hù)最初說(shuō)了什么、大腦之前做過(guò)哪些決策、每個(gè)工具返回了什么結(jié)果。記憶的質(zhì)量直接決定了 Agent 能不能在多輪循環(huán)中保持連貫。這三塊拼起來(lái)就形成了一個(gè)閉環(huán)大腦讀記憶 → 做出決策 → 手腳執(zhí)行 → 結(jié)果寫(xiě)回記憶 → 大腦再讀記憶。循環(huán)往復(fù)直到大腦決定任務(wù)完成。pi-agent 的結(jié)構(gòu)基本就是這個(gè)思路只不過(guò)它在記憶管理上做了一些工程化的處理比如對(duì)歷史消息做截?cái)?、?duì)工具結(jié)果做摘要。這些后面會(huì)細(xì)講。2.2 為什么是循環(huán)而不是一次性調(diào)用這里有個(gè)容易被忽略的關(guān)鍵點(diǎn)Agent 和普通的一問(wèn)一答最大的區(qū)別就在于循環(huán)。普通的大模型調(diào)用是單輪的——你問(wèn)一句它答一句結(jié)束。但 Agent 面對(duì)的任務(wù)往往是多步的比如幫我查一下這個(gè)目錄下所有日志文件里出現(xiàn)次數(shù)最多的錯(cuò)誤碼這就至少需要三步列目錄、讀文件、統(tǒng)計(jì)。你沒(méi)法用一次調(diào)用完成因?yàn)橹虚g結(jié)果需要反饋給模型讓它決定下一步。所以 Agent 的核心是一個(gè)while循環(huán)每一輪都做四件事把當(dāng)前記憶喂給大腦、解析大腦的輸出、執(zhí)行對(duì)應(yīng)的動(dòng)作、把結(jié)果追加到記憶里。循環(huán)的終止條件通常有兩個(gè)大腦明確表示任務(wù)完成或者達(dá)到了預(yù)設(shè)的最大輪數(shù)上限。注意最大輪數(shù)上限這個(gè)保護(hù)機(jī)制一定要加。我早期版本沒(méi)加結(jié)果有一次模型陷入死循環(huán)反復(fù)調(diào)用同一個(gè)工具白白燒了一堆 token。后來(lái)我固定設(shè)成 10 輪超過(guò)就強(qiáng)制中斷并返回當(dāng)前狀態(tài)。2.3 pi-agent 在結(jié)構(gòu)上的取舍少一層抽象多一分可控我對(duì)比過(guò)好幾個(gè) Agent 實(shí)現(xiàn)pi-agent 最讓我舒服的地方是它沒(méi)有過(guò)度抽象。有些框架會(huì)引入 Planner、Executor、Memory Manager、Tool Registry 一大堆類(lèi)每個(gè)類(lèi)之間還有復(fù)雜的依賴(lài)關(guān)系讀起來(lái)像在解謎。pi-agent 則相對(duì)扁平核心邏輯集中在一個(gè)循環(huán)函數(shù)里工具用字典注冊(cè)記憶就是一個(gè)列表。這種設(shè)計(jì)的代價(jià)是擴(kuò)展性稍弱——比如你想加一個(gè)復(fù)雜的多 Agent 協(xié)作機(jī)制就得自己動(dòng)手改不少地方。但好處是可控每一輪發(fā)生了什么、模型看到了什么、工具返回了什么你都能一眼看穿。對(duì)于學(xué)習(xí)和中小型項(xiàng)目來(lái)說(shuō)這種透明性比擴(kuò)展性更重要。我自己的實(shí)現(xiàn)基本沿用了這個(gè)思路只在兩個(gè)地方做了調(diào)整一是把工具注冊(cè)改成了裝飾器寫(xiě)法加工具更方便二是給記憶加了一個(gè)簡(jiǎn)單的滑動(dòng)窗口防止上下文無(wú)限增長(zhǎng)。這兩點(diǎn)后面會(huì)展開(kāi)。3. 大腦部分怎么讓模型穩(wěn)定輸出可執(zhí)行的動(dòng)作3.1 用結(jié)構(gòu)化輸出約束模型而不是靠求它讓模型輸出可解析的動(dòng)作指令是 Agent 開(kāi)發(fā)里第一個(gè)真正的難點(diǎn)。早期我試過(guò)在提示詞里寫(xiě)請(qǐng)以 JSON 格式輸出你的決策結(jié)果模型十次里有三次會(huì)加一句好的以下是我的決策然后才給 JSON解析直接崩。后來(lái)我總結(jié)出兩條經(jīng)驗(yàn)。第一條是用 API 原生的結(jié)構(gòu)化輸出能力?,F(xiàn)在主流的大模型接口基本都支持指定返回格式比如傳入一個(gè) JSON Schema模型會(huì)保證輸出符合這個(gè) schema。這比在提示詞里求它靠譜得多。第二條是即使有結(jié)構(gòu)化輸出也要做防御性解析。因?yàn)榫W(wǎng)絡(luò)抖動(dòng)、模型版本差異等原因偶爾還是會(huì)有意外。我的做法是包一層 try-except解析失敗就把原始輸出記下來(lái)然后給模型發(fā)一條你的上一條輸出格式不對(duì)請(qǐng)重新輸出的糾正消息讓它重試一次。實(shí)測(cè)下來(lái)加上這層兜底之后解析成功率基本能到 99% 以上。下面是我用的動(dòng)作 schema簡(jiǎn)化版長(zhǎng)這樣{ type: object, properties: { thought: {type: string}, action: {type: string, enum: [call_tool, finish]}, tool_name: {type: string}, tool_input: {type: object}, final_answer: {type: string} }, required: [thought, action] }thought字段是讓模型先想一想再行動(dòng)這個(gè)字段不參與執(zhí)行但對(duì)提升決策質(zhì)量有明顯幫助。action只有兩個(gè)取值要么調(diào)工具要么結(jié)束。這種二選一的設(shè)計(jì)比讓模型自由發(fā)揮要穩(wěn)定得多。3.2 提示詞里必須寫(xiě)清楚的幾件事結(jié)構(gòu)化輸出解決了格式問(wèn)題但內(nèi)容問(wèn)題還得靠提示詞。我踩過(guò)的坑是模型不知道該用哪個(gè)工具或者明明有工具卻自己瞎編答案。提示詞里必須寫(xiě)清楚的東西有這么幾樣。第一是工具清單每個(gè)工具的名字、用途、參數(shù)格式都要列出來(lái)最好給一個(gè)調(diào)用示例。第二是決策原則比如如果任務(wù)需要外部信息優(yōu)先調(diào)用工具而不是憑記憶回答。第三是終止條件明確告訴它什么情況下應(yīng)該輸出finish。我用的系統(tǒng)提示詞大致是這樣的結(jié)構(gòu)你是一個(gè)任務(wù)執(zhí)行助手。你可以使用以下工具 - read_file(path): 讀取指定路徑的文件內(nèi)容 - list_dir(path): 列出目錄下的文件 - run_python(code): 執(zhí)行一段 Python 代碼并返回結(jié)果 決策原則 1. 需要外部信息時(shí)必須調(diào)用工具獲取不要憑猜測(cè)回答 2. 每次只做一個(gè)動(dòng)作 3. 任務(wù)完成后用 finish 動(dòng)作給出最終答案 請(qǐng)以指定的 JSON 格式輸出你的決策。這段提示詞看起來(lái)簡(jiǎn)單但每一條都是踩坑之后加上的。特別是每次只做一個(gè)動(dòng)作這條早期沒(méi)寫(xiě)的時(shí)候模型會(huì)一次性輸出好幾個(gè)工具調(diào)用導(dǎo)致執(zhí)行邏輯變得很復(fù)雜。3.3 溫度參數(shù)和模型選擇對(duì)穩(wěn)定性的影響還有一個(gè)容易被忽略的細(xì)節(jié)是溫度參數(shù)。Agent 的大腦需要的是穩(wěn)定和可預(yù)測(cè)不是創(chuàng)意。我一開(kāi)始用了默認(rèn)溫度結(jié)果同樣的輸入模型有時(shí)候調(diào)工具、有時(shí)候直接回答行為很不一致。后來(lái)把溫度調(diào)到 0 或者接近 0穩(wěn)定性明顯提升。模型選擇上我的經(jīng)驗(yàn)是決策環(huán)節(jié)用能力強(qiáng)的模型執(zhí)行環(huán)節(jié)用便宜快的模型。因?yàn)闆Q策需要理解復(fù)雜任務(wù)、選擇合適工具對(duì)模型能力要求高而執(zhí)行往往只是把參數(shù)填進(jìn)函數(shù)簡(jiǎn)單模型就夠。這種搭配能在保證效果的同時(shí)控制成本。不過(guò)這里有個(gè)權(quán)衡如果決策和執(zhí)行用的是同一個(gè)模型上下文可以完全共享實(shí)現(xiàn)簡(jiǎn)單如果分開(kāi)就要考慮兩邊上下文怎么同步。我自己的小 Agent 為了簡(jiǎn)單用的是同一個(gè)模型但在提示詞里區(qū)分了決策模式和總結(jié)模式。4. 手腳部分工具注冊(cè)與執(zhí)行的安全邊界4.1 工具不是越多越好而是越正交越好新手容易犯的一個(gè)錯(cuò)誤是拼命加工具覺(jué)得工具越多 Agent 越強(qiáng)。實(shí)際上工具太多會(huì)帶來(lái)兩個(gè)問(wèn)題一是提示詞變長(zhǎng)模型選擇困難二是工具之間功能重疊模型不知道該用哪個(gè)。我的原則是工具要正交也就是每個(gè)工具負(fù)責(zé)一個(gè)獨(dú)立的、不重疊的能力。比如read_file和list_dir是兩個(gè)正交的工具一個(gè)讀內(nèi)容一個(gè)列目錄但如果你再加一個(gè)read_text_file就和read_file重疊了只會(huì)讓模型困惑。pi-agent 的工具集也很克制核心就幾個(gè)。我自己的實(shí)現(xiàn)里工具數(shù)量控制在 5 個(gè)以?xún)?nèi)每個(gè)都有明確的邊界。如果發(fā)現(xiàn)某個(gè)任務(wù)需要新能力我會(huì)先想清楚它能不能用現(xiàn)有工具組合出來(lái)實(shí)在不行才加新工具。4.2 用裝飾器注冊(cè)工具讓加工具變成一件順手的事工具注冊(cè)的寫(xiě)法直接影響開(kāi)發(fā)體驗(yàn)。我見(jiàn)過(guò)用一個(gè)大字典手動(dòng)維護(hù)的加一個(gè)工具要改好幾個(gè)地方容易漏。后來(lái)我改成了裝飾器寫(xiě)法TOOLS {} def tool(name, description, parameters): def decorator(func): TOOLS[name] { func: func, description: description, parameters: parameters } return func return decorator tool( nameread_file, description讀取指定路徑的文件內(nèi)容, parameters{path: string, 文件路徑} ) def read_file(path): with open(path, r, encodingutf-8) as f: return f.read()這樣加工具只需要在函數(shù)上加一個(gè)裝飾器工具的描述和參數(shù)定義就在函數(shù)旁邊維護(hù)起來(lái)一目了然。而且TOOLS字典可以直接序列化成提示詞里的工具清單不用手動(dòng)同步。4.3 執(zhí)行工具時(shí)必須做的三件事校驗(yàn)、限時(shí)、兜底工具執(zhí)行是 Agent 里最容易出問(wèn)題的環(huán)節(jié)因?yàn)樗钦嬲屯獠渴澜缃换サ牡胤健N铱偨Y(jié)了三條必須做的防護(hù)。第一是參數(shù)校驗(yàn)。模型生成的參數(shù)不一定合法比如路徑不存在、參數(shù)類(lèi)型不對(duì)。執(zhí)行前一定要校驗(yàn)校驗(yàn)失敗就返回一個(gè)清晰的錯(cuò)誤信息給模型讓它自己糾正。我見(jiàn)過(guò)直接open(path)結(jié)果拋異常把整個(gè)循環(huán)搞崩的寫(xiě)法這是大忌。第二是超時(shí)控制。有些工具可能卡住比如網(wǎng)絡(luò)請(qǐng)求、大文件讀取。如果不加超時(shí)整個(gè) Agent 就掛在那里了。我的做法是給每個(gè)工具執(zhí)行包一層超時(shí)超過(guò)閾值就中斷并返回超時(shí)錯(cuò)誤。第三是異常兜底。任何工具執(zhí)行都要包在 try-except 里把異常轉(zhuǎn)成字符串返回給模型而不是讓異常往上拋。因?yàn)槟P涂吹藉e(cuò)誤信息后往往能自己調(diào)整策略比如換個(gè)路徑重試。def execute_tool(name, params): if name not in TOOLS: return f錯(cuò)誤工具 {name} 不存在 try: result TOOLS[name][func](**params) return str(result)[:2000] # 截?cái)喾乐菇Y(jié)果過(guò)長(zhǎng) except Exception as e: return f工具執(zhí)行出錯(cuò){str(e)}注意那個(gè)[:2000]截?cái)噙@也是踩坑得來(lái)的。有一次工具返回了一個(gè)幾萬(wàn)字的文件內(nèi)容直接塞進(jìn)上下文下一輪調(diào)用就超了 token 限制。截?cái)嚯m然會(huì)丟信息但比整個(gè)流程崩掉強(qiáng)。5. 記憶部分上下文管理才是 Agent 的隱形戰(zhàn)場(chǎng)5.1 記憶不是全都塞進(jìn)去而是該記的記該丟的丟很多人以為記憶就是把所有歷史消息都拼起來(lái)發(fā)給模型簡(jiǎn)單粗暴。但實(shí)際跑起來(lái)你會(huì)發(fā)現(xiàn)上下文增長(zhǎng)得非??鞄纵喼缶涂赡艹瞿P偷拇翱谙拗贫?token 成本也扛不住。記憶管理的核心是取舍。哪些信息必須保留我的經(jīng)驗(yàn)是三類(lèi)用戶(hù)最初的任務(wù)描述、最近幾輪的決策和結(jié)果、以及任何被標(biāo)記為關(guān)鍵的中間結(jié)論。哪些可以丟重復(fù)的工具調(diào)用結(jié)果、冗長(zhǎng)的原始數(shù)據(jù)、已經(jīng)消化過(guò)的中間過(guò)程。pi-agent 在這一點(diǎn)上的處理比較務(wù)實(shí)它會(huì)對(duì)歷史做一定程度的壓縮。我自己的實(shí)現(xiàn)用了一個(gè)簡(jiǎn)單的滑動(dòng)窗口保留最前面的系統(tǒng)提示和用戶(hù)任務(wù)保留最近 N 輪的消息中間的老消息如果太多就做摘要。5.2 滑動(dòng)窗口 摘要一個(gè)夠用又不復(fù)雜的方案滑動(dòng)窗口的邏輯很直白維護(hù)一個(gè)消息列表當(dāng)長(zhǎng)度超過(guò)閾值時(shí)把中間部分的消息合并成一條摘要消息。摘要可以用模型生成也可以用簡(jiǎn)單的規(guī)則拼接。def manage_memory(messages, max_len20): if len(messages) max_len: return messages # 保留頭部系統(tǒng)提示 用戶(hù)任務(wù) head messages[:2] # 保留尾部最近的消息 tail messages[-(max_len - 3):] # 中間部分做摘要 middle messages[2:-(max_len - 3)] summary summarize(middle) return head [{role: system, content: f歷史摘要{summary}}] tail這個(gè)方案不完美比如摘要可能丟信息但勝在簡(jiǎn)單可控。我實(shí)測(cè)下來(lái)對(duì)于大多數(shù)中小型任務(wù)這個(gè)策略足夠用了。如果你的任務(wù)特別復(fù)雜可以考慮更精細(xì)的記憶方案比如向量檢索但那是另一個(gè)話題了。5.3 一個(gè)容易被忽略的細(xì)節(jié)工具結(jié)果的格式統(tǒng)一記憶里存的東西格式要統(tǒng)一否則模型讀起來(lái)會(huì)混亂。我早期犯的錯(cuò)是工具結(jié)果有時(shí)候是字符串、有時(shí)候是字典、有時(shí)候是列表模型看到之后經(jīng)常理解錯(cuò)。后來(lái)我定了個(gè)規(guī)矩所有工具結(jié)果在寫(xiě)入記憶前統(tǒng)一轉(zhuǎn)成帶前綴的字符串。比如工具 read_file 返回內(nèi)容。這樣模型一眼就能看出這是哪個(gè)工具的結(jié)果不會(huì)和用戶(hù)消息混淆。這個(gè)小小的格式統(tǒng)一對(duì)提升多輪連貫性幫助很大。6. 把循環(huán)跑起來(lái)主流程的組裝與調(diào)試6.1 主循環(huán)的骨架其實(shí)就二十行前面幾塊都準(zhǔn)備好之后主循環(huán)本身反而很簡(jiǎn)單。核心邏輯就是不斷重復(fù)決策-執(zhí)行-記錄這個(gè)過(guò)程def run_agent(task, max_turns10): messages [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: task} ] for turn in range(max_turns): messages manage_memory(messages) decision call_llm(messages) if decision[action] finish: return decision[final_answer] result execute_tool(decision[tool_name], decision[tool_input]) messages.append({role: assistant, content: str(decision)}) messages.append({role: user, content: f工具結(jié)果{result}}) return 達(dá)到最大輪數(shù)任務(wù)未完成這二十行就是 Agent 的心臟。看起來(lái)簡(jiǎn)單但每一行背后都有前面講的那些設(shè)計(jì)考量。我建議你先把這二十行跑通再往上加?xùn)|西。6.2 調(diào)試 Agent 的正確姿勢(shì)把每一輪都打出來(lái)Agent 調(diào)試和普通程序調(diào)試不一樣因?yàn)樗男袨橛须S機(jī)性出錯(cuò)的時(shí)候你很難一眼看出是哪一步的問(wèn)題。我的做法是把每一輪的完整信息都打印出來(lái)模型看到了什么、輸出了什么決策、工具返回了什么。def call_llm(messages): print( * 50) print(當(dāng)前上下文) for m in messages: print(f[{m[role]}] {m[content][:200]}) response client.chat(...) print(模型決策, response) return parse(response)這個(gè)日志看起來(lái)啰嗦但排查問(wèn)題時(shí)非常有用。我遇到過(guò)好幾次Agent 行為詭異的情況都是靠這個(gè)日志定位到根因的——有時(shí)候是提示詞有歧義有時(shí)候是工具返回格式不對(duì)有時(shí)候是記憶里混進(jìn)了臟數(shù)據(jù)。6.3 常見(jiàn)故障與對(duì)應(yīng)排查方向跑起來(lái)之后你會(huì)遇到各種問(wèn)題。我把最常見(jiàn)的幾類(lèi)整理成一張表方便對(duì)照排查現(xiàn)象可能原因排查方向模型不調(diào)工具直接編答案提示詞沒(méi)強(qiáng)調(diào)必須用工具檢查系統(tǒng)提示詞的決策原則反復(fù)調(diào)用同一個(gè)工具工具結(jié)果沒(méi)讓模型滿意或陷入循環(huán)看工具返回是否清晰加輪數(shù)上限解析 JSON 失敗模型輸出格式不穩(wěn)定用結(jié)構(gòu)化輸出 重試兜底上下文超限記憶沒(méi)做壓縮檢查滑動(dòng)窗口和截?cái)噙壿嫻ぞ邎?zhí)行報(bào)錯(cuò)參數(shù)不合法或環(huán)境問(wèn)題看參數(shù)校驗(yàn)和異常兜底這張表里的每一條我都是真金白銀踩出來(lái)的。特別是反復(fù)調(diào)用同一個(gè)工具這條早期沒(méi)加輪數(shù)上限的時(shí)候模型能在一個(gè)工具上死磕十幾輪token 嘩嘩地?zé)?. 從能跑到好用幾個(gè)提升 Agent 質(zhì)量的經(jīng)驗(yàn)7.1 給模型思考的空間但別讓它想太多前面提到 schema 里有個(gè)thought字段這個(gè)設(shè)計(jì)很關(guān)鍵。讓模型在行動(dòng)前先輸出一段思考能顯著提升決策質(zhì)量。但要注意思考不能太長(zhǎng)否則會(huì)擠占上下文也會(huì)拖慢速度。我的做法是在提示詞里限制思考控制在兩句話以?xún)?nèi)。這個(gè)thought還有個(gè)額外好處調(diào)試的時(shí)候你能直接看到模型為什么做這個(gè)決策比只看動(dòng)作要清楚得多。很多時(shí)候 Agent 行為不對(duì)看它的 thought 就能明白問(wèn)題出在哪。7.2 工具描述要寫(xiě)得像給新人的說(shuō)明書(shū)工具描述的質(zhì)量直接影響模型能不能正確使用工具。我見(jiàn)過(guò)寫(xiě)得很敷衍的比如read_file: 讀文件模型看了根本不知道參數(shù)該怎么填。好的工具描述應(yīng)該像給新人的說(shuō)明書(shū)說(shuō)清楚這個(gè)工具干什么、參數(shù)是什么格式、有沒(méi)有注意事項(xiàng)。比如read_file的描述我會(huì)寫(xiě)成讀取指定路徑的文本文件內(nèi)容。參數(shù) path 是文件的完整路徑必須是字符串。如果文件不存在會(huì)返回錯(cuò)誤信息。這樣模型一看就知道怎么用出錯(cuò)率大大降低。7.3 別追求一步到位先讓最小閉環(huán)跑通最后一條也是最重要的一條經(jīng)驗(yàn)不要一上來(lái)就追求完美。我見(jiàn)過(guò)太多人一開(kāi)始就想搞一個(gè)支持多 Agent 協(xié)作、帶向量記憶、能自我反思的復(fù)雜系統(tǒng)結(jié)果卡在第一步就放棄了。正確的做法是先讓最小閉環(huán)跑通——哪怕它只能讀文件、只能跑十輪、只能處理簡(jiǎn)單任務(wù)。跑通之后你自然會(huì)發(fā)現(xiàn)哪里不夠用然后有針對(duì)性地加?xùn)|西。我自己的 Agent 就是從只能讀文件開(kāi)始的后來(lái)才慢慢加了執(zhí)行代碼、目錄列舉這些能力。每一步都是被真實(shí)需求推著走的而不是憑空設(shè)計(jì)出來(lái)的。這個(gè)思路其實(shí)也是 pi-agent 給我的啟發(fā)它的結(jié)構(gòu)之所以清晰就是因?yàn)槊恳粔K都只解決一個(gè)具體問(wèn)題沒(méi)有為了看起來(lái)強(qiáng)大而堆砌功能。剝開(kāi)它、理解它、再自己實(shí)現(xiàn)一遍這個(gè)過(guò)程本身就是最好的學(xué)習(xí)。如果你也照著這個(gè)思路走一遍我保證你對(duì) Agent 的理解會(huì)比看十篇概念文章都深。跑通之后你可以試著加一個(gè)新工具或者改一改記憶策略觀察 Agent 行為的變化——這種改一點(diǎn)、看效果的循環(huán)才是真正把知識(shí)變成自己的過(guò)程。