建Agent:工具調(diào)用、記憶與規(guī)劃的學(xué)習(xí)路徑指南)
最近在不少技術(shù)交流群里總能看到同一個問題想從零開始構(gòu)建一個 Agent但資料像一團(tuán)亂麻今天刷到工具調(diào)用明天又看到記憶機(jī)制后天又有人聊多智能體協(xié)作到底按什么順序?qū)W才不繞路我每次的回復(fù)其實(shí)都差不多先別急著寫代碼先把你要做的 Agent 是什么、解決什么問題、需要哪幾個環(huán)節(jié)想清楚。這個順序一旦亂了后面八成要走彎路。這篇內(nèi)容是我?guī)氯藭r反復(fù)驗(yàn)證過的一條路徑把從零構(gòu)建 Agent 的學(xué)習(xí)順序完整梳理一遍。適合剛接觸 Agent、想獨(dú)立做出第一個能跑通的項(xiàng)目的人也適合已經(jīng)寫過簡單 API 調(diào)用但覺得體系混亂的朋友。我不會用一堆術(shù)語堆砌概念更多是講每一步為什么這么做、遇到的問題怎么排查你看完就能照著排自己的學(xué)習(xí)計(jì)劃。1. 先放下代碼把 Agent 的邊界想清楚1.1 到底什么是 Agent別把它當(dāng)成一個智能聊天框很多人會把 Agent 和普通的問答機(jī)器人畫等號這是第一個誤解。普通的聊天機(jī)器人是你問一句大模型回答一句本質(zhì)上是一個帶上下文接口的提示詞應(yīng)用。而 Agent 的核心在于“循環(huán)”接收任務(wù)后由大模型作為決策者判斷下一步該做什么調(diào)用外部工具拿到結(jié)果后再判斷直到任務(wù)完成為止。我比較喜歡用一個極簡循環(huán)來描述 Agent任務(wù)進(jìn)入 - 模型思考 - 如果需要工具輸出一個結(jié)構(gòu)化的調(diào)用指令 - 程序執(zhí)行工具并返回結(jié)果 - 模型結(jié)合結(jié)果繼續(xù)思考 - 重復(fù)直到模型認(rèn)為任務(wù)已經(jīng)完成。理解了這個循環(huán)你后面學(xué)的所有東西——工具調(diào)用、記憶、規(guī)劃、反思——都是在給這個循環(huán)的某一個環(huán)節(jié)加能力。所以第一階段不是學(xué)某個框架而是花點(diǎn)時間把你自己的 Agent 循環(huán)在紙上畫出來。畫不出來說明你對需求還不夠清楚。提示判斷一個系統(tǒng)是不是 Agent關(guān)鍵不是看它能不能聊天而是看它有沒有能力在循環(huán)中自主決策、調(diào)用外部資源并根據(jù)結(jié)果修正下一步。1.2 你想構(gòu)建的 Agent 屬于哪一類為了不讓自己一上來就陷入“什么都想學(xué)”的狀態(tài)我建議先分類。根據(jù)復(fù)雜程度常見的幾種形態(tài)單輪問答型輸入問題直接輸出答案。工具調(diào)用型遇到需要實(shí)時數(shù)據(jù)或計(jì)算的任務(wù)時主動調(diào)用外部 API 或函數(shù)。多步規(guī)劃型先列計(jì)劃再執(zhí)行多個步驟途中根據(jù)結(jié)果調(diào)整方案。多 Agent 協(xié)作型多個角色分工配合處理更復(fù)雜的任務(wù)。從學(xué)習(xí)順序上看我堅(jiān)決推薦從“工具調(diào)用型”起步。為什么因?yàn)樗钅荏w現(xiàn) Agent 的本質(zhì)又不至于復(fù)雜到失控。單輪問答不需要“循環(huán)”多步規(guī)劃又依賴工具調(diào)用之后的反饋多 Agent 協(xié)作更是建立在前幾種能力之上。你在工具調(diào)用型上把循環(huán)跑穩(wěn)了后面升級路徑會非常自然。1.3 一句話定義你的第一個目標(biāo)我在帶人時一定會讓他們用一句話寫出第一個目標(biāo)。舉個例子“一個能根據(jù)用戶提問自動調(diào)用搜索工具和計(jì)算工具最后輸出帶步驟答案的腳本。”這句話看起來簡單但它直接把學(xué)習(xí)范圍框死了你需要會調(diào)大模型 API、會寫兩個工具函數(shù)、會寫循環(huán)、會管理對話上下文。目標(biāo)越具體學(xué)習(xí)順序就越清晰。如果你現(xiàn)在還說不清“我要做的是一個能定時整理報(bào)表的 Agent”還是“一個能跟人聊天時查天氣的小助手”建議先停下來把目標(biāo)寫清楚。別看不起這個小目標(biāo)很多人學(xué)了兩個月還在收藏資料就是因?yàn)橐恢睕]有一個可以對著做的靶子。把第一句話寫出來貼在你的編輯器上方接下來每一周的學(xué)習(xí)都往這個靶子上靠你會發(fā)現(xiàn)很多資料根本不用看因?yàn)槟悴恍枰切┕δ堋?. 寫 Agent 前的地基編程基礎(chǔ)與必備工具箱2.1 三塊編程基礎(chǔ)少一塊都會卡住說到編程基礎(chǔ)先潑一盆冷水你不需要成為資深工程師但至少要有能力把“要做的事”翻譯成函數(shù)調(diào)用。圍繞 Agent 最常用到的其實(shí)只有三塊。第一塊是函數(shù)定義與參數(shù)傳遞。Agent 的工具本質(zhì)就是一組函數(shù)你把函數(shù)列給模型模型決定調(diào)用哪個、傳什么參數(shù)你的代碼再去執(zhí)行。如果函數(shù)寫不清楚模型生成的參數(shù)也會亂七八糟。第二塊是異常處理。工具一定會失敗搜索超時、計(jì)算除零、權(quán)限不足。你需要讓程序在異常時記錄信息并把錯誤反饋給模型而不是直接崩潰。第三塊是列表、字典和 JSON 解析。大模型 API 的請求和響應(yīng)都是結(jié)構(gòu)化數(shù)據(jù)你需要熟練地從嵌套字典里取字段也要會把 Python 的字典正確序列化成 JSON 字符串。很多人一上來就想著學(xué)更高級的并發(fā)、異步、設(shè)計(jì)模式不是不行但那是后面的事。先把這三塊練到位你的 Agent 已經(jīng)能跑了。2.2 API 調(diào)用是第一課必須寫到手熟Agent 的“大腦”通常是大模型 API所以編程基礎(chǔ)練完后第一門專業(yè)課就是 API 調(diào)用。你要理解請求是怎么發(fā)的、響應(yīng)是怎么回來的、有哪些關(guān)鍵參數(shù)。我建議用最簡單的代碼把調(diào)用流程寫一遍不要一開始就套封裝好的客戶端。核心代碼大概長這樣import json import urllib.request def call_llm(messages): payload { model: your-model-name, messages: messages, temperature: 0.2, max_tokens: 1024 } req urllib.request.Request( https://your-llm-endpoint.example/v1/chat, datajson.dumps(payload).encode(), headers{Content-Type: application/json} ) with urllib.request.urlopen(req) as resp: data json.load(resp) return data[choices][0][message][content]這段代碼里messages是對話列表temperature控制隨機(jī)性max_tokens限制返回長度。第一次跑通之后你再去理解那些封裝好的客戶端就很容易了。很多人一開始就使用現(xiàn)成 SDK雖然簡單但遇到報(bào)錯時往往不知道問題出在請求還是響應(yīng)解析上反而是裸調(diào)用能幫你建立正確的心智模型。注意不同模型服務(wù)商的 API 格式會有差異但核心都是“傳消息進(jìn)去拿到文本出來”。第一周內(nèi)不要關(guān)心太多高級參數(shù)能穩(wěn)定拿到一次響應(yīng)就算及格。2.3 結(jié)構(gòu)化數(shù)據(jù)與狀態(tài)管理很多新手栽在這里API 調(diào)用跑通后緊接著就是狀態(tài)管理。普通問答只需要把用戶消息追加進(jìn)messages列表再來回幾次之后列表越來越長這就是最簡單的記憶。但 Agent 的狀態(tài)不只是對話消息它還包括“當(dāng)前任務(wù)進(jìn)度”“已經(jīng)調(diào)用過哪些工具”“工具執(zhí)行結(jié)果是什么”。這些狀態(tài)如果不用結(jié)構(gòu)化方式維護(hù)程序很快就會失控。我的建議是在第二周就學(xué)著把 Agent 的狀態(tài)封裝成一個類例如class SimpleAgent: def __init__(self): self.messages [] self.tools {} def add_tool(self, name, func, description): self.tools[name] {func: func, description: description} def run(self, task): self.messages.append({role: user, content: task}) while True: response call_llm(self.messages) # 解析模型返回判斷是繼續(xù)調(diào)用工具還是結(jié)束 ...先別管細(xì)節(jié)是否優(yōu)雅這樣的結(jié)構(gòu)能讓你明確“狀態(tài)放在哪”“工具在哪注冊”“循環(huán)在哪判斷”。很多新手寫出的 Agent 第一次能跑第二次換個任務(wù)就亂套多半就是狀態(tài)混在全局變量里沒有歸位。狀態(tài)管理這一關(guān)越早重視越好。你甚至可以在這個類里加一個step_count避免無限循環(huán)這也是初見端倪的工程化思維。3. 核心能力的學(xué)習(xí)順序工具調(diào)用、記憶、規(guī)劃怎么排3.1 先學(xué)工具調(diào)用再學(xué)規(guī)劃我見過不少人一上來就研究“怎么讓 Agent 自己拆解任務(wù)、自我反思”結(jié)果連工具都調(diào)不穩(wěn)定。這個順序是反的。規(guī)劃能力依賴一個基礎(chǔ)前提模型知道當(dāng)前有哪些工具、能用什么辦法獲取反饋。沒有工具調(diào)用作為支點(diǎn)規(guī)劃出來的步驟都是空中樓閣執(zhí)行不到任何地方。工具調(diào)用的核心是“讓模型輸出結(jié)構(gòu)化指令”。你有兩個選擇一是讓模型返回 JSON 字符串包含工具名和參數(shù)二是用模型服務(wù)商提供的結(jié)構(gòu)化輸出功能直接把結(jié)果約束成對象。無論哪種代碼里都需要一個分發(fā)器讀取模型輸出找到對應(yīng)的 Python 函數(shù)傳入?yún)?shù)執(zhí)行再把結(jié)果追加回messages。我給你的學(xué)習(xí)目標(biāo)很簡單寫一個工具函數(shù)“獲取當(dāng)前時間”再寫一個“計(jì)算兩個數(shù)的和”讓模型根據(jù)用戶問題選擇調(diào)用哪個并把最終答案整理成自然語言。這個閉環(huán)跑通工具調(diào)用就算入門了。有了這個基礎(chǔ)再去看那些規(guī)劃類的提示詞技巧你會立刻明白模型“列計(jì)劃”和“調(diào)工具”之間是怎么配合的。很多看起來神奇的效果本質(zhì)上是這個簡單閉環(huán)在不同場景下的重復(fù)而已。3.2 記憶機(jī)制從對話上下文開始別一上來就做向量檢索記憶是很多人最感興趣的部分也是最容易過度設(shè)計(jì)的地方。市面上講記憶的內(nèi)容動不動就是向量數(shù)據(jù)庫、Embedding、語義檢索但對新手來說這些先放一邊。你要先搞清楚Agent 的記憶至少有三種短期記憶是當(dāng)前任務(wù)內(nèi)的上下文長期記憶是跨會話可用的事實(shí)還有一個容易被忽視的“工作記憶”指當(dāng)前正在處理的任務(wù)狀態(tài)。學(xué)習(xí)順序應(yīng)該從短期記憶開始。短期記憶的實(shí)現(xiàn)方式就是維護(hù)好messages列表用戶說了什么、模型說過什么、工具返回了什么都在列表里。列表會不斷變長直到碰到上下文窗口限制這時候你再學(xué)怎么截?cái)?、怎么摘要。給一個最樸素的滑動窗口實(shí)現(xiàn)思路設(shè)定一個最大消息數(shù)超過之后把最早的消息丟棄。雖然粗暴但能讓你直觀看到“記憶丟失”對 Agent 行為的影響。等你有經(jīng)驗(yàn)了再考慮用摘要壓縮舊內(nèi)容或者引入向量檢索做真正意義上的長期記憶。直接跳到最后一步不光實(shí)現(xiàn)復(fù)雜還很難定位問題。我?guī)н^的一個新人就是這樣第一版就上了向量庫結(jié)果數(shù)據(jù)沒準(zhǔn)備好跑出來的效果比純文本截?cái)噙€差最后花了整整一周才排查出來是索引更新不及時。3.3 多步驟流程先手寫循環(huán)再考慮編排框架Agent 的核心循環(huán)其實(shí)很簡單模型決定工具調(diào)用 - 執(zhí)行工具 - 結(jié)果返回 - 模型繼續(xù)決定 - 直到結(jié)束。很多人因?yàn)橐婚_始就用某個編排框架反而沒見過這個循環(huán)長什么樣??蚣茈[藏了復(fù)雜度但也隱藏了理解。我強(qiáng)烈建議新手至少用 50 行左右手寫一個循環(huán)哪怕它沒有重試、沒有并發(fā)、沒有美觀的日志。偽代碼邏輯如下for step in range(MAX_STEPS): response call_llm(messages) action parse_action(response) # 模型返回的是繼續(xù)調(diào)用工具還是最終答案 if action[type] finish: return action[answer] tool_result execute_tool(action[name], action[args]) messages.append({role: tool, content: tool_result})這個循環(huán)里有三個關(guān)鍵點(diǎn)怎么判斷要不要結(jié)束、怎么解析工具調(diào)用、怎么把工具結(jié)果放回上下文。你把這個循環(huán)親手實(shí)現(xiàn)一次再去看各種編排框架的文檔會發(fā)現(xiàn)它們無非是在這個循環(huán)外面加了緩存、并行、重試、可視化之類的功能。先底層后封裝是學(xué)習(xí)這類系統(tǒng)最穩(wěn)的路線。4. 四周從零到一一條可直接抄作業(yè)的學(xué)習(xí)路徑4.1 第一周寫一個能自己查資料的 Agent第一周的目標(biāo)不需要太大做一個能根據(jù)用戶問題調(diào)用搜索和計(jì)算工具的腳本。我會建議你準(zhǔn)備兩個工具函數(shù)一個是查詢“某個關(guān)鍵詞的返回結(jié)果”內(nèi)部可以用任意在線接口但為了練習(xí)也可以先用本地模擬數(shù)據(jù)替代一個是計(jì)算器。工具函數(shù)準(zhǔn)備好了再寫工具描述告訴模型這兩個函數(shù)分別能干什么、需要哪些參數(shù)。之后就是實(shí)現(xiàn)循環(huán)把用戶問題放進(jìn) messages調(diào)用大模型讓它返回一個結(jié)構(gòu)化的動作。如果模型判斷需要搜索就執(zhí)行搜索函數(shù)把結(jié)果文本追加到 messages如果模型判斷可以直接回答就退出循環(huán)。第一周最常見的成果是“能跑通幾個固定問題”比如“計(jì)算 123 乘 45”“查一下某個詞的定義”。這里你要有心理準(zhǔn)備模型輸出的 JSON 格式偶爾會不合法需要你寫一點(diǎn)解析容錯不同模型對工具描述的敏感度不同可能需要調(diào)一調(diào)描述措辭。別被這些細(xì)節(jié)勸退這些都是第一周必須經(jīng)歷的基本功。4.2 第二周給 Agent 加記憶和上下文第一周跑通的 Agent 有一個明顯問題當(dāng)工具的返回結(jié)果很長時多輪之后上下文會膨脹模型容易“忘掉”最初的目標(biāo)。第二周我們就來解決這件事。先做一個簡單版本只保留最近 N 條消息超出部分直接截?cái)唷_@個實(shí)現(xiàn)五分鐘就能寫完但它會讓你立刻體會到“截?cái)嗪竽P蛠G失了關(guān)鍵信息”的局限。接著再升級不要簡單丟棄舊消息而是讓大模型對舊消息生成一段摘要把摘要放在 messages 最前面作為系統(tǒng)提示。這一步命令可以是“請把以下歷史對話壓縮成不超過 50 字的摘要保留任務(wù)目標(biāo)、已經(jīng)執(zhí)行過的工具和重要結(jié)果”。做完這個改動之后測試一個多步任務(wù)“先查今天的日期再用日期里的年份計(jì)算某個結(jié)果是幾年后的最后解釋推理過程”。如果 Agent 在第三步仍然能說出年份說明摘要記憶基本可用。記住第一版不要追求完美先讓它“不丟最關(guān)鍵信息”就好。摘要本身也有開銷所以每周都要審視這段記憶對我的任務(wù)真的必要嗎很多時候砍掉冗余比堆更多技巧更有效。4.3 第三周加入規(guī)劃和反思到第三周你可以開始教 Agent 先思考再動手了。這里有一個很好用的模式讓模型在接受任務(wù)后先輸出一個簡短計(jì)劃再開始執(zhí)行工具。實(shí)現(xiàn)倒不復(fù)雜你可以在提示詞里要求模型第一步必須輸出 JSON 格式的計(jì)劃包含 steps 數(shù)組然后你按計(jì)劃逐步執(zhí)行。你甚至不需要寫復(fù)雜的狀態(tài)機(jī)只要把計(jì)劃輸出當(dāng)作一條消息記錄下來然后進(jìn)入原來的工具調(diào)用循環(huán)即可。反思也很重要。一個簡單的反思實(shí)現(xiàn)是在所有工具執(zhí)行完畢后再調(diào)用一次模型輸入“以下是你的推理和執(zhí)行結(jié)果請檢查是否存在錯誤如果發(fā)現(xiàn)問題請重新規(guī)劃并繼續(xù)”。很多第一次跑通規(guī)劃的人會因?yàn)?Agent 能列出步驟而興奮但實(shí)際效果可能依然很差。差別往往就出在缺了反思這一步。反思不一定每次都能糾錯但它能把“模型自己發(fā)現(xiàn)矛盾”的概率拉高不少。我在自己的項(xiàng)目里反思后修正的成功率比不反思高了不少尤其是遇到長鏈條計(jì)算和資料收集類任務(wù)時。4.4 第四周封裝成服務(wù)并處理異常第四周把這個腳本變成可以被外部請求調(diào)用的服務(wù)。我用“任意一個你熟悉的輕量級 Web 框架”來表述因?yàn)槟悴恍枰谶@個階段糾結(jié)技術(shù)選型重要的是理解幾個新問題并發(fā)請求來了怎么排隊(duì)每個用戶會話的狀態(tài)怎么隔離工具超時和失敗怎么重試日志里需要記下每一步調(diào)用耗時。這些工程問題在寫腳本時往往被忽略但一旦對外提供服務(wù)它們是穩(wěn)定性的關(guān)鍵。一個很現(xiàn)實(shí)的問題如果 Agent 內(nèi)部跑了一個永不結(jié)束的循環(huán)你的服務(wù)會被卡死。所以要在循環(huán)里加上最大步數(shù)限制并且給每次工具調(diào)用設(shè)置超時時間。我在實(shí)際項(xiàng)目里吃過這個虧第一次封裝服務(wù)時沒給循環(huán)步數(shù)加上限結(jié)果模型反復(fù)調(diào)用同一個錯工具白白燒掉很多額度。后來我設(shè)了MAX_STEPS并強(qiáng)制要求模型如果連續(xù)兩次調(diào)用同一個工具且結(jié)果相同就必須換個策略或結(jié)束。這個規(guī)則簡單但有效值得你在第四周就加進(jìn)去。5. 學(xué)習(xí) Agent 最容易踩的六個坑與排查實(shí)錄5.1 坑一一上來就套現(xiàn)成編排框架我不反對框架但我反對在循環(huán)都沒手寫過的情況下去用框架。框架會把工具調(diào)度、狀態(tài)管理、上下文處理封裝得看不見一旦出問題你連日志都看不懂。身邊有新人用框架寫了三天的 Agent最后報(bào)錯時只會截圖問人而另一個先手寫循環(huán)的人遇到類似問題能很快判斷是解析問題還是工具執(zhí)行問題。所以我的原則是先手寫一個最小循環(huán)再考慮用框架提升工程效率。5.2 坑二把思維鏈提示當(dāng)成了 Agent很多教程讓模型“讓我們一步步思考”模型確實(shí)輸出了推理過程但這只是提示詞層面的技巧不是 Agent。真正的 Agent 要有外部循環(huán)和工具反饋。如果你的程序只調(diào)用了兩次模型沒有任何工具執(zhí)行那它本質(zhì)上是提示詞工程不是 Agent。搞清楚這個區(qū)別你才知道自己缺的是什么。經(jīng)常有人拿一個“會自己編步驟”的對話機(jī)器人來問我為什么不算 Agent我的回答永遠(yuǎn)是它沒有改變環(huán)境的能力也沒有接收環(huán)境反饋的機(jī)制。5.3 坑三工具函數(shù)報(bào)錯沒有反饋給模型工具執(zhí)行失敗時最忌諱的是直接崩潰或者返回一個空字符串。模型看到空結(jié)果會一本正經(jīng)地編造一個看似合理的答案這是我最常遇到的坑。正確做法是把錯誤信息盡量結(jié)構(gòu)化地放進(jìn)工具返回結(jié)果比如{error: search api timeout, retry_times: 1}并且讓模型根據(jù)錯誤決定是否需要重試或更換策略。這一步能大幅減少幻覺。我在給別人排查時發(fā)現(xiàn)很多“Agent 胡說八道”的問題源頭不是模型變笨了而是工具把錯誤吞掉了。5.4 坑四上下文窗口塞滿關(guān)鍵信息被擠掉上下文窗口不是無限大塞得越多模型對重點(diǎn)的注意力反而會被稀釋。我見過有人為了讓 Agent 記住更多信息把上下文全部塞進(jìn)提示詞結(jié)果任務(wù)目標(biāo)被淹沒在無關(guān)細(xì)節(jié)里。處理方式很簡單能不放上下文的就不放放之前先壓縮重要目標(biāo)可以放在 system 消息里且反復(fù)強(qiáng)調(diào)工具返回的長文本優(yōu)先提取關(guān)鍵段落而不是原封不動塞回去。一個好的經(jīng)驗(yàn)法則是如果一條信息連續(xù)三輪都沒被模型引用它大概率是噪聲可以壓縮掉。5.5 坑五沒有測試集就直接調(diào) Prompt很多人調(diào)提示詞靠感覺改一個詞跑一個案例看到結(jié)果順眼就覺得成功了。但同一個改動可能在另一個案例上反而變差。正確的做法是準(zhǔn)備一份 10 到 20 條的代表性測試集覆蓋常見任務(wù)、邊界情況和典型的錯誤場景然后用腳本批量跑記錄成功率和失敗原因。我自己跑 Agent 項(xiàng)目時一定是先有測試集再動提示詞否則你根本沒法判斷每次改動是真的變好了還是只是運(yùn)氣好。測試集不用一開始就很全先記錄自己最在意的 10 個場景后續(xù)再不斷補(bǔ)充。5.6 坑六硬要一個 Agent 解決所有問題最后一個坑是關(guān)于架構(gòu)的。很多新手喜歡把需求越加越多讓一個 Agent 同時負(fù)責(zé)查資料、算數(shù)據(jù)、做圖表、寫報(bào)告最后提示詞長得嚇人效果卻一塌糊涂。我的經(jīng)驗(yàn)是復(fù)雜任務(wù)拆成多個職責(zé)單一的 Agent 或流程節(jié)點(diǎn)每個 Agent 只做一件事然后用一個調(diào)度邏輯把它們串起來。比起把全部指令塞給一個 Agent讓幾個笨但穩(wěn)定的環(huán)節(jié)協(xié)作往往更容易調(diào)試、也更容易維護(hù)。把大問題拆成小環(huán)節(jié)是工程上最樸素的道理在 Agent 領(lǐng)域同樣適用。如果你正處在從零開始的階段我最大的建議是先給自己定一個極小的閉環(huán)目標(biāo)讓 Agent 調(diào)一次工具、拿到結(jié)果、再回復(fù)你。把這個閉環(huán)跑通后面所有復(fù)雜能力都只是在這個環(huán)上疊加。這條路徑我自己帶不同基礎(chǔ)的新人走過很多次卡點(diǎn)基本都集中在前兩周只要熬過去后面會越來越順。