用:從API自動(dòng)化到智能體架構(gòu)的工程實(shí)踐)
1. 從“缸中大腦”到“世界之手”LLM工具調(diào)用的本質(zhì)躍遷想象一下你有一個(gè)知識(shí)淵博、思維敏捷的助手他上知天文下知地理能寫(xiě)詩(shī)、能編程、能解答你的任何疑問(wèn)。但當(dāng)你讓他幫你訂一張機(jī)票、查一下明天的天氣或者把一份報(bào)告里的數(shù)據(jù)整理成圖表時(shí)他卻只能抱歉地告訴你“對(duì)不起我無(wú)法執(zhí)行這個(gè)操作?!?這就是當(dāng)前大多數(shù)大型語(yǔ)言模型LLM的現(xiàn)狀——一個(gè)被困在數(shù)字世界里的“缸中大腦”。它擁有海量的知識(shí)和強(qiáng)大的推理能力卻缺乏與現(xiàn)實(shí)世界交互的“手”和“眼”。而“工具調(diào)用”Tool Calling這項(xiàng)技術(shù)正是為這個(gè)超級(jí)大腦裝上操控現(xiàn)實(shí)世界的“神經(jīng)接口”和“機(jī)械臂”的關(guān)鍵。簡(jiǎn)單來(lái)說(shuō)LLM工具調(diào)用就是讓模型學(xué)會(huì)識(shí)別用戶的意圖并調(diào)用預(yù)先定義好的外部工具如API、函數(shù)、命令行來(lái)完成任務(wù)。這不僅僅是“API調(diào)用”的自動(dòng)化而是一次認(rèn)知架構(gòu)的升級(jí)。它標(biāo)志著LLM從純粹的文本生成器向能夠感知、決策并作用于外部環(huán)境的“智能體”Agent的轉(zhuǎn)變。無(wú)論是通過(guò)API查詢實(shí)時(shí)天氣、調(diào)用代碼解釋器執(zhí)行計(jì)算、操控瀏覽器進(jìn)行網(wǎng)頁(yè)操作還是整合企業(yè)內(nèi)部系統(tǒng)工具調(diào)用都讓LLM突破了自身訓(xùn)練數(shù)據(jù)的靜態(tài)邊界獲得了動(dòng)態(tài)獲取信息和執(zhí)行動(dòng)作的能力。對(duì)于開(kāi)發(fā)者、產(chǎn)品經(jīng)理乃至普通用戶而言理解這一機(jī)制意味著能夠真正將AI的“思考力”轉(zhuǎn)化為解決實(shí)際問(wèn)題的“生產(chǎn)力”。2. 核心架構(gòu)拆解LLM如何“思考”并“行動(dòng)”工具調(diào)用并非一個(gè)簡(jiǎn)單的“if-else”觸發(fā)器而是一個(gè)涉及規(guī)劃、決策與執(zhí)行的復(fù)雜認(rèn)知循環(huán)。其核心架構(gòu)可以分解為幾個(gè)關(guān)鍵環(huán)節(jié)共同構(gòu)成了LLM與外部世界交互的“神經(jīng)系統(tǒng)”。2.1 意圖識(shí)別與工具匹配從“想做什么”到“用什么做”當(dāng)用戶提出一個(gè)請(qǐng)求如“幫我查一下上海明天下午的天氣并建議我是否需要帶傘”時(shí)LLM首先需要理解這個(gè)請(qǐng)求背后的復(fù)合意圖。這個(gè)過(guò)程遠(yuǎn)不止于關(guān)鍵詞匹配。深度解析模型會(huì)基于其龐大的預(yù)訓(xùn)練知識(shí)對(duì)查詢進(jìn)行語(yǔ)義解析。它需要識(shí)別出核心動(dòng)作“查詢天氣”、關(guān)鍵參數(shù)地點(diǎn)“上海”時(shí)間“明天下午”以及隱含需求“判斷是否需要帶傘”意味著需要降水概率信息。這一步考驗(yàn)的是模型的基礎(chǔ)語(yǔ)言理解能力。緊接著模型需要將解析出的意圖與它“已知”的工具庫(kù)進(jìn)行匹配。這個(gè)工具庫(kù)通常以結(jié)構(gòu)化描述如函數(shù)名、功能描述、參數(shù)格式的形式提供給模型。例如工具庫(kù)中可能有一個(gè)名為get_weather的函數(shù)描述為“獲取指定城市和時(shí)間的天氣預(yù)報(bào)信息”參數(shù)包括city字符串和date字符串格式Y(jié)YYY-MM-DD。模型的任務(wù)是判斷用戶的請(qǐng)求是否可以通過(guò)調(diào)用這個(gè)或這些工具來(lái)滿足。注意工具描述的清晰度和準(zhǔn)確性至關(guān)重要。模糊的描述如“獲取天氣信息”可能導(dǎo)致模型誤匹配或無(wú)法匹配。最佳實(shí)踐是為每個(gè)工具提供詳盡、無(wú)歧義的自然語(yǔ)言描述并明確參數(shù)的類型和約束。2.2 參數(shù)提取與結(jié)構(gòu)化將自然語(yǔ)言轉(zhuǎn)化為機(jī)器指令匹配到合適的工具后LLM需要從用戶的自然語(yǔ)言陳述中精確地提取出調(diào)用該工具所需的參數(shù)。這是工具調(diào)用中最具挑戰(zhàn)性的環(huán)節(jié)之一因?yàn)樗竽P途邆鋸?qiáng)大的信息抽取和上下文理解能力。以天氣查詢?yōu)槔脩粽f(shuō)“明天下午上海天氣怎么樣”模型需要推斷出city參數(shù)應(yīng)為 “上?!薄?duì)于date參數(shù)模型需要理解“明天”指的是相對(duì)于當(dāng)前日期的下一天并將其轉(zhuǎn)換為 “2024-05-28” 這樣的標(biāo)準(zhǔn)格式假設(shè)今天是2024-05-27。對(duì)于“下午”這可能是一個(gè)需要進(jìn)一步處理的模糊時(shí)間范圍或者工具本身只支持到“天”的粒度模型需要忽略或做默認(rèn)處理。技術(shù)實(shí)現(xiàn)層面在如 OpenAI 的 Function Calling 或 ReAct 等框架中這一步通常由模型生成一個(gè)結(jié)構(gòu)化的 JSON 對(duì)象。例如{ “tool_call”: { “name”: “get_weather”, “arguments”: { “city”: “上?!?“date”: “2024-05-28” } } }這個(gè) JSON 對(duì)象就是模型“思考”后輸出的“行動(dòng)指令”。后端系統(tǒng)在收到這個(gè)指令后才會(huì)去實(shí)際執(zhí)行對(duì)應(yīng)的函數(shù)或API調(diào)用。2.3 執(zhí)行與反饋循環(huán)完成動(dòng)作并學(xué)習(xí)結(jié)果工具被調(diào)用后會(huì)返回一個(gè)執(zhí)行結(jié)果。這個(gè)結(jié)果可能是成功的數(shù)據(jù)如{“temperature”: 25, “condition”: “多云” “precipitation_prob”: 10%}也可能是一個(gè)錯(cuò)誤如{“error”: “City not found”}或網(wǎng)絡(luò)超時(shí)。反饋的重要性LLM 并不會(huì)在發(fā)出指令后就結(jié)束工作。它必須接收并理解這個(gè)執(zhí)行結(jié)果然后決定下一步行動(dòng)。這構(gòu)成了一個(gè)“感知-思考-行動(dòng)”的循環(huán)Perception-Reasoning-Action Loop。感知結(jié)果模型讀取工具返回的原始數(shù)據(jù)或錯(cuò)誤信息。思考分析模型分析結(jié)果是否滿足了用戶的原始請(qǐng)求。如果天氣數(shù)據(jù)已獲取它需要結(jié)合“是否需要帶傘”的隱含需求進(jìn)行推理“降水概率10%建議不帶傘”。如果調(diào)用失敗它需要分析錯(cuò)誤原因是參數(shù)錯(cuò)誤還是服務(wù)不可用并決定是重試、換用其他工具還是向用戶請(qǐng)求澄清。生成響應(yīng)或新行動(dòng)最終模型將分析結(jié)果轉(zhuǎn)化為面向用戶的自然語(yǔ)言回答或者生成一個(gè)新的工具調(diào)用指令來(lái)繼續(xù)完成任務(wù)。這個(gè)循環(huán)是智能體Agent能力的核心體現(xiàn)使得LLM能夠處理多步驟、有條件分支的復(fù)雜任務(wù)。3. 主流實(shí)現(xiàn)方案與框架實(shí)戰(zhàn)理解了原理我們來(lái)看看如何在實(shí)際項(xiàng)目中實(shí)現(xiàn)它。目前市場(chǎng)上有多種成熟的方案從云服務(wù)商提供的原生能力到開(kāi)源框架各有側(cè)重。3.1 云服務(wù)商的原生工具調(diào)用以O(shè)penAI為例OpenAI的GPT系列模型通過(guò)“Function Calling”功能原生支持工具調(diào)用。這是目前最直接、集成度最高的方案之一。實(shí)操步驟定義工具函數(shù)在調(diào)用Chat Completions API時(shí)在tools參數(shù)中提供一個(gè)函數(shù)列表。每個(gè)函數(shù)需要定義name名稱、description描述和parameters遵循JSON Schema格式的參數(shù)定義。模型決策將用戶消息和工具定義一起發(fā)送給API。模型會(huì)根據(jù)對(duì)話上下文判斷是否需要調(diào)用工具。如果需要它會(huì)在響應(yīng)中返回一個(gè)或多個(gè)tool_calls包含要調(diào)用的函數(shù)名和提取出的參數(shù)。本地執(zhí)行你的應(yīng)用程序收到響應(yīng)后解析tool_calls在本地代碼中執(zhí)行對(duì)應(yīng)的真實(shí)函數(shù)。提交結(jié)果將函數(shù)執(zhí)行的結(jié)果作為一條新的“工具”角色消息追加到對(duì)話歷史中再次調(diào)用API。模型會(huì)基于這個(gè)結(jié)果生成面向用戶的最終回答。示例代碼片段概念性import openai # 1. 定義工具 tools [ { “type”: “function” “function”: { “name”: “get_weather” “description”: “獲取指定城市的天氣預(yù)報(bào)” “parameters”: { “type”: “object” “properties”: { “city”: {“type”: “string” “description”: “城市名如‘上海’”} “date”: {“type”: “string” “description”: “日期格式Y(jié)YYY-MM-DD”} } “required”: [“city”] } } } ] # 2. 用戶請(qǐng)求 messages [{“role”: “user” “content”: “明天上海天氣如何”}] # 3. 首次調(diào)用模型可能決定調(diào)用工具 response openai.chat.completions.create( model“gpt-4” messagesmessages toolstools tool_choice“auto” # 讓模型自行決定 ) # 4. 檢查并執(zhí)行工具調(diào)用 if response.choices[0].message.tool_calls: tool_call response.choices[0].message.tool_calls[0] if tool_call.function.name “get_weather”: import json args json.loads(tool_call.function.arguments) weather_result your_weather_function(args[“city”] args.get(“date”)) # 5. 將結(jié)果提交給模型 messages.append(response.choices[0].message) # 追加模型的消息包含工具調(diào)用請(qǐng)求 messages.append({ “role”: “tool” “content”: json.dumps(weather_result) “tool_call_id”: tool_call.id }) # 6. 獲取最終回答 second_response openai.chat.completions.create( model“gpt-4” messagesmessages ) final_answer second_response.choices[0].message.content print(final_answer) # 例如“明天上海多云氣溫25度降水概率較低建議不用帶傘。”優(yōu)勢(shì)與局限優(yōu)勢(shì)簡(jiǎn)單易用與OpenAI生態(tài)無(wú)縫集成模型對(duì)工具調(diào)用的理解能力強(qiáng)。局限綁定特定廠商工具執(zhí)行邏輯完全需要開(kāi)發(fā)者自行實(shí)現(xiàn)和托管錯(cuò)誤處理、復(fù)雜流程編排多個(gè)工具順序/并行調(diào)用需要額外開(kāi)發(fā)。3.2 開(kāi)源智能體框架LangChain與LangGraph對(duì)于需要更高靈活性、復(fù)雜工作流編排或希望避免廠商鎖定的項(xiàng)目開(kāi)源框架是更強(qiáng)大的選擇。LangChain 及其擴(kuò)展 LangGraph 是目前最流行的生態(tài)之一。LangChain 的核心抽象LangChain 將工具調(diào)用抽象為Agent和Tool兩個(gè)核心概念。Tool一個(gè)可調(diào)用的功能單元。你可以輕松地將一個(gè)Python函數(shù)、一個(gè)API封裝成一個(gè)Tool只需提供名稱和描述。Agent一個(gè)代理它配備了一系列Tools和一個(gè)LLM。Agent負(fù)責(zé)理解用戶輸入決定使用哪個(gè)Tool或都不使用并處理Tool的返回結(jié)果。LangGraph 的進(jìn)階編排當(dāng)任務(wù)涉及多步驟、有狀態(tài)、帶循環(huán)或條件分支時(shí)基礎(chǔ)的Agent可能不夠用。LangGraph 引入了“圖”的概念來(lái)編排工作流。你可以將整個(gè)任務(wù)流程定義為一個(gè)有向圖節(jié)點(diǎn)是LLM調(diào)用、工具執(zhí)行或條件判斷邊定義了執(zhí)行流向。實(shí)戰(zhàn)構(gòu)建一個(gè)數(shù)據(jù)分析Agent假設(shè)我們要構(gòu)建一個(gè)Agent用戶可以用自然語(yǔ)言要求它分析CSV文件比如“幫我計(jì)算data.csv中‘銷售額’列的平均值并找出最大值對(duì)應(yīng)的日期”。定義工具創(chuàng)建幾個(gè)工具函數(shù)如read_csv(file_path)、calculate_column_stats(data, column_name)、find_row_by_value(data, column_name, value)。創(chuàng)建Agent使用LangChain的create_react_agent或create_openai_tools_agent將LLM如ChatOpenAI和上述Tools綁定。設(shè)計(jì)工作流使用LangGraph節(jié)點(diǎn)1理解意圖LLM解析用戶請(qǐng)求輸出結(jié)構(gòu)化計(jì)劃如[“步驟1讀取文件” “步驟2計(jì)算銷售額統(tǒng)計(jì)” “步驟3查找最大值對(duì)應(yīng)日期”]。節(jié)點(diǎn)2執(zhí)行讀取調(diào)用read_csv工具。節(jié)點(diǎn)3執(zhí)行計(jì)算調(diào)用calculate_column_stats工具。節(jié)點(diǎn)4執(zhí)行查找調(diào)用find_row_by_value工具。節(jié)點(diǎn)5生成報(bào)告LLM匯總所有工具結(jié)果生成最終的自然語(yǔ)言回答。運(yùn)行將用戶查詢輸入這個(gè)圖它會(huì)自動(dòng)按流程執(zhí)行并在需要時(shí)調(diào)用LLM進(jìn)行決策。優(yōu)勢(shì)與心得優(yōu)勢(shì)極度靈活可編排復(fù)雜流程社區(qū)活躍工具生態(tài)豐富已集成數(shù)百個(gè)工具支持本地模型。實(shí)操心得LangChain的學(xué)習(xí)曲線較陡初期需要理解其大量的抽象概念Chains, Agents, Tools, Memory等。建議從簡(jiǎn)單的Agent Tools開(kāi)始再逐步過(guò)渡到LangGraph。另外對(duì)于生產(chǎn)環(huán)境要特別注意錯(cuò)誤處理和流程的穩(wěn)定性圖編排雖然強(qiáng)大但調(diào)試起來(lái)比線性流程復(fù)雜。3.3 低代碼/一體化平臺(tái)Dify、Coze等如果你希望快速搭建一個(gè)具備工具調(diào)用能力的AI應(yīng)用而不想深入編碼和架構(gòu)細(xì)節(jié)那么低代碼平臺(tái)是一個(gè)高效的選擇。這類平臺(tái)通常提供了可視化的工具配置、工作流編排和Agent設(shè)計(jì)界面。以Dify為例工具技能配置在Dify的“技能中心”或“工具”模塊你可以通過(guò)圖形界面配置一個(gè)API工具。填寫(xiě)名稱、描述、API端點(diǎn)、請(qǐng)求方法GET/POST、Headers、Parameters以及如何解析響應(yīng)。平臺(tái)會(huì)自動(dòng)為你生成后端調(diào)用邏輯。工作流編排在“工作流”畫(huà)布中你可以通過(guò)拖拽節(jié)點(diǎn)來(lái)設(shè)計(jì)復(fù)雜的AI流程。節(jié)點(diǎn)類型包括LLM模型、工具調(diào)用、條件判斷、變量賦值、代碼執(zhí)行等。你可以輕松地將配置好的工具節(jié)點(diǎn)拖入畫(huà)布并連接起來(lái)。構(gòu)建Agent你可以創(chuàng)建一個(gè)“智能體”為其選擇基礎(chǔ)模型如GPT-4并關(guān)聯(lián)上一步創(chuàng)建的工作流或者直接為其添加多個(gè)已配置的工具。在Agent的“提示詞”部分你可以精心設(shè)計(jì)系統(tǒng)指令指導(dǎo)它如何以及何時(shí)使用這些工具。發(fā)布與集成完成后你可以將Agent發(fā)布為一個(gè)Web應(yīng)用或API端點(diǎn)直接供用戶使用。適用場(chǎng)景與注意事項(xiàng)適用場(chǎng)景產(chǎn)品原型快速驗(yàn)證、內(nèi)部效率工具開(kāi)發(fā)、對(duì)編程能力要求不高的業(yè)務(wù)團(tuán)隊(duì)自主搭建AI應(yīng)用。注意事項(xiàng)平臺(tái)的靈活性和深度通常不如純代碼方案。對(duì)于需要復(fù)雜業(yè)務(wù)邏輯、自定義數(shù)據(jù)處理或高性能要求的場(chǎng)景可能會(huì)遇到限制。此外需評(píng)估平臺(tái)的長(zhǎng)期成本、數(shù)據(jù)安全性以及是否支持私有化部署。4. 深入原理思維鏈、規(guī)劃與執(zhí)行工具調(diào)用能力并非憑空產(chǎn)生它建立在LLM幾項(xiàng)關(guān)鍵的底層能力之上其中“思維鏈”Chain-of-Thought CoT和“規(guī)劃與執(zhí)行”Planning and Execution范式尤為重要。4.1 思維鏈CoT的賦能讓模型“一步步思考”工具調(diào)用本質(zhì)上是一個(gè)多步推理問(wèn)題。模型不能直接從一個(gè)問(wèn)題跳到調(diào)用某個(gè)具體API它需要中間推理步驟。思維鏈技術(shù)通過(guò)鼓勵(lì)模型在生成最終答案前先輸出其推理的中間步驟極大地提升了其在復(fù)雜任務(wù)上的表現(xiàn)。在工具調(diào)用場(chǎng)景中CoT體現(xiàn)為任務(wù)分解模型先將“訂一張從北京到上海明天最早的經(jīng)濟(jì)艙機(jī)票”分解為1) 查詢明天北京到上海的航班2) 過(guò)濾出經(jīng)濟(jì)艙3) 按時(shí)間排序找到最早的4) 獲取該航班的預(yù)訂信息。工具選擇推理對(duì)于每一步模型需要推理出最適合的工具。例如第一步可能需要調(diào)用“航班查詢API”而不是“天氣查詢API”。模型在內(nèi)部可能會(huì)生成類似“用戶需要航班信息我應(yīng)該使用 search_flights 工具參數(shù)是 origin北京 destination上海 date明天”的“內(nèi)心獨(dú)白”。參數(shù)推導(dǎo)基于上下文和常識(shí)推導(dǎo)參數(shù)。比如從“最早”推導(dǎo)出排序參數(shù)應(yīng)為“departure_time ASC”。ReAct范式將CoT與工具調(diào)用結(jié)合得最經(jīng)典的框架是ReActReason Act。在ReAct中模型的輸出被嚴(yán)格格式化為交替的“思考Thought”、“行動(dòng)Action”、“觀察Observation”步驟。這強(qiáng)制模型進(jìn)行顯式的推理并基于上一步行動(dòng)的觀察結(jié)果決定下一步行動(dòng)非常契合工具調(diào)用的交互特性。4.2 規(guī)劃與執(zhí)行框架從單次調(diào)用到復(fù)雜項(xiàng)目對(duì)于更復(fù)雜的任務(wù)如“研究某個(gè)主題并撰寫(xiě)一份報(bào)告”簡(jiǎn)單的單步或線性工具調(diào)用不夠用了。這就需要更高級(jí)的“規(guī)劃與執(zhí)行”框架。規(guī)劃器Planner通常是一個(gè)LLM它的職責(zé)是接收高層目標(biāo)并生成一個(gè)可執(zhí)行的計(jì)劃或任務(wù)列表。這個(gè)計(jì)劃可能是樹(shù)狀或圖狀的。例如對(duì)于“撰寫(xiě)AI在醫(yī)療領(lǐng)域應(yīng)用的報(bào)告”規(guī)劃器可能輸出1. 搜索“AI 醫(yī)療 最新進(jìn)展”2. 搜索“醫(yī)學(xué)影像 AI 診斷”3. 搜索“藥物發(fā)現(xiàn) AI”4. 匯總資料并起草報(bào)告大綱5. 撰寫(xiě)引言6. 撰寫(xiě)分章節(jié)內(nèi)容7. 撰寫(xiě)結(jié)論。執(zhí)行器Executor負(fù)責(zé)具體執(zhí)行計(jì)劃中的每一個(gè)子任務(wù)。它可能本身就是一個(gè)配備了搜索工具、文檔讀寫(xiě)工具的Agent。執(zhí)行器完成每個(gè)任務(wù)后將結(jié)果返回。監(jiān)督與協(xié)調(diào)一個(gè)頂層的協(xié)調(diào)模塊可能也是LLM負(fù)責(zé)監(jiān)督執(zhí)行進(jìn)度檢查子任務(wù)結(jié)果的質(zhì)量并根據(jù)情況動(dòng)態(tài)調(diào)整計(jì)劃。例如如果搜索“藥物發(fā)現(xiàn) AI”返回的信息太少協(xié)調(diào)器可能會(huì)指示規(guī)劃器重新規(guī)劃改為搜索更具體的“AlphaFold 新藥研發(fā)”。HuggingGPT、AutoGPT等項(xiàng)目都體現(xiàn)了這種思想。它們將LLM作為任務(wù)規(guī)劃和調(diào)度的大腦調(diào)用各種專家模型如圖像識(shí)別、語(yǔ)音合成或工具作為執(zhí)行的手腳來(lái)完成極其復(fù)雜的跨模態(tài)任務(wù)。5. 開(kāi)發(fā)實(shí)戰(zhàn)從零構(gòu)建一個(gè)支持工具調(diào)用的智能體理論說(shuō)再多不如動(dòng)手做一遍。讓我們拋開(kāi)復(fù)雜框架用最基礎(chǔ)的原理從零開(kāi)始構(gòu)建一個(gè)簡(jiǎn)單的命令行智能體它能調(diào)用一個(gè)模擬的“天氣查詢”和“計(jì)算器”工具。5.1 環(huán)境準(zhǔn)備與工具定義我們使用Python并假設(shè)你已經(jīng)有了一個(gè)LLM的API訪問(wèn)權(quán)限這里以O(shè)penAI格式的API為例但原理通用。import openai import json import os # 設(shè)置你的API密鑰示例請(qǐng)?zhí)鎿Q為你的實(shí)際密鑰或從環(huán)境變量讀取 openai.api_key os.getenv(“OPENAI_API_KEY”) # 1. 定義我們的工具庫(kù) def get_current_weather(location: str) - str: “”“模擬獲取天氣的函數(shù)。在實(shí)際應(yīng)用中這里會(huì)調(diào)用真實(shí)的天氣API?!薄啊?# 模擬數(shù)據(jù) weather_data { “北京”: “晴 15°C” “上?!? “多云 20°C” “深圳”: “陣雨 25°C” } return weather_data.get(location f“未找到 {location} 的天氣信息?!? def calculator(expression: str) - str: “”“一個(gè)簡(jiǎn)單的計(jì)算器函數(shù)。注意直接eval有安全風(fēng)險(xiǎn)此處僅用于演示?!薄啊?try: # 警告在生產(chǎn)環(huán)境中應(yīng)對(duì)表達(dá)式進(jìn)行嚴(yán)格的安全檢查和沙箱計(jì)算 result eval(expression) return str(result) except Exception as e: return f“計(jì)算錯(cuò)誤 {e}” # 將工具信息結(jié)構(gòu)化用于提供給LLM tools_metadata [ { “name”: “get_current_weather” “description”: “獲取指定城市的當(dāng)前天氣” “parameters”: { “type”: “object” “properties”: { “l(fā)ocation”: {“type”: “string” “description”: “城市名稱”} } “required”: [“l(fā)ocation”] } } { “name”: “calculator” “description”: “執(zhí)行一個(gè)數(shù)學(xué)計(jì)算表達(dá)式如 ‘(3 5) * 2’” “parameters”: { “type”: “object” “properties”: { “expression”: {“type”: “string” “description”: “數(shù)學(xué)表達(dá)式字符串”} } “required”: [“expression”] } } ]5.2 核心對(duì)話循環(huán)與工具調(diào)用邏輯接下來(lái)我們實(shí)現(xiàn)一個(gè)簡(jiǎn)單的對(duì)話循環(huán)。這個(gè)循環(huán)會(huì)持續(xù)接收用戶輸入讓LLM判斷是否需要調(diào)用工具并處理調(diào)用結(jié)果。def run_conversation(user_input: str conversation_history: list) - (str list): “”“ 運(yùn)行一輪對(duì)話。 返回(AI的回復(fù)文本 更新后的對(duì)話歷史) “”“ # 1. 將工具元數(shù)據(jù)格式化為模型能理解的系統(tǒng)提示或函數(shù)描述 # 這里我們采用一種簡(jiǎn)單的方式將工具描述拼接到系統(tǒng)消息中 system_message f“””你是一個(gè)有幫助的助手可以調(diào)用以下工具 {json.dumps(tools_metadata indent2)} 如果用戶的問(wèn)題需要調(diào)用工具請(qǐng)嚴(yán)格按照以下JSON格式回復(fù)且只回復(fù)這個(gè)JSON {{“action”: “tool_call” “tool_name”: “工具名” “arguments”: {{“arg1”: “value1” ...}}}} 否則請(qǐng)正常用文本回復(fù)。 “”” # 構(gòu)建消息歷史始終以系統(tǒng)消息開(kāi)始 messages [{“role”: “system” “content”: system_message}] conversation_history [{“role”: “user” “content”: user_input}] # 2. 調(diào)用LLM response openai.chat.completions.create( model“gpt-3.5-turbo” # 或 gpt-4 messagesmessages temperature0 max_tokens500 ) ai_message response.choices[0].message.content updated_history conversation_history [{“role”: “user” “content”: user_input}] # 3. 解析AI的回復(fù)判斷是否為工具調(diào)用 try: # 嘗試解析為JSON response_json json.loads(ai_message.strip()) if response_json.get(“action”) “tool_call”: tool_name response_json[“tool_name”] arguments response_json[“arguments”] # 4. 執(zhí)行對(duì)應(yīng)的工具 if tool_name “get_current_weather”: location arguments.get(“l(fā)ocation”) if not location: result “錯(cuò)誤缺少 location 參數(shù)?!?else: result get_current_weather(location) elif tool_name “calculator”: expression arguments.get(“expression”) if not expression: result “錯(cuò)誤缺少 expression 參數(shù)?!?else: result calculator(expression) else: result f“錯(cuò)誤未知工具 ‘{tool_name}’?!?# 5. 將工具執(zhí)行結(jié)果作為新的上下文再次調(diào)用LLM生成最終回復(fù) # 將工具調(diào)用和結(jié)果都加入歷史 updated_history.append({“role”: “assistant” “content”: ai_message}) # AI發(fā)出的工具調(diào)用請(qǐng)求 updated_history.append({“role”: “user” “content”: f“[工具執(zhí)行結(jié)果] {result}”}) # 模擬用戶角色返回結(jié)果 # 重新調(diào)用LLM讓它基于工具結(jié)果生成回復(fù) final_response run_conversation(“請(qǐng)根據(jù)上面的工具結(jié)果回答用戶最初的問(wèn)題。” updated_history) return final_response # 這里遞歸調(diào)用實(shí)際應(yīng)用中可能需要控制深度 except json.JSONDecodeError: # AI的回復(fù)不是JSON說(shuō)明是普通文本回復(fù) updated_history.append({“role”: “assistant” “content”: ai_message}) return ai_message updated_history # 理論上不會(huì)走到這里除非工具調(diào)用后遞歸返回 return ai_message updated_history # 簡(jiǎn)單的交互循環(huán) if __name__ “__main__”: history [] print(“智能體已啟動(dòng)。輸入‘退出’或‘quit’結(jié)束。”) while True: user_input input(“\n你 ”) if user_input.lower() in [“退出” “quit”]: break reply history run_conversation(user_input history) print(f“助手 {reply}”)代碼解析與心得系統(tǒng)提示詞設(shè)計(jì)我們通過(guò)系統(tǒng)消息明確告知了LLM可用的工具及其格式并規(guī)定了當(dāng)它想調(diào)用工具時(shí)必須輸出的嚴(yán)格JSON格式。這是引導(dǎo)模型行為的關(guān)鍵。工具執(zhí)行與上下文管理當(dāng)檢測(cè)到工具調(diào)用時(shí)我們執(zhí)行本地函數(shù)并將結(jié)果以特定格式如[工具執(zhí)行結(jié)果] ...追加到對(duì)話歷史中。然后我們重新調(diào)用LLM讓它看到“自己”發(fā)出的工具調(diào)用指令和“環(huán)境”返回的結(jié)果從而基于此生成面向用戶的最終回答。這個(gè)過(guò)程模擬了ReAct范式中的“Act”和“Observe”步驟。遞歸調(diào)用為了處理工具調(diào)用后的回答生成示例中使用了遞歸。在實(shí)際更復(fù)雜的Agent中這通常是一個(gè)顯式的循環(huán)while循環(huán)直到模型認(rèn)為任務(wù)完成為止。安全性示例中的calculator函數(shù)使用了eval這在生產(chǎn)環(huán)境是極其危險(xiǎn)的因?yàn)樗试S執(zhí)行任意代碼。這里僅用于演示原理。真實(shí)場(chǎng)景中必須使用安全的數(shù)學(xué)表達(dá)式解析庫(kù)如ast.literal_eval配合自定義解析或numexpr等。5.3 錯(cuò)誤處理與魯棒性增強(qiáng)上面的基礎(chǔ)版本非常脆弱。一個(gè)健壯的智能體必須處理各種異常情況。工具調(diào)用格式錯(cuò)誤模型可能返回不符合約定的JSON。需要添加更健壯的解析并提供錯(cuò)誤反饋?zhàn)屇P椭卦?。工具?zhí)行失敗網(wǎng)絡(luò)超時(shí)、API返回錯(cuò)誤、參數(shù)無(wú)效等。需要捕獲異常并將清晰的錯(cuò)誤信息返回給模型讓它決定是重試、換用其他方式還是向用戶求助。模型“幻覺(jué)”調(diào)用不存在的工具在系統(tǒng)提示中清晰界定工具列表并在代碼中做好校驗(yàn)對(duì)未知工具名返回明確錯(cuò)誤。無(wú)限循環(huán)風(fēng)險(xiǎn)模型可能陷入“調(diào)用工具-得到結(jié)果-再次調(diào)用同一工具”的死循環(huán)。需要設(shè)置最大迭代次數(shù)或超時(shí)機(jī)制。上下文長(zhǎng)度管理工具調(diào)用和結(jié)果會(huì)不斷追加到對(duì)話歷史中可能很快耗盡模型的上下文窗口。需要實(shí)現(xiàn)歷史消息的摘要或選擇性遺忘策略。增強(qiáng)后的錯(cuò)誤處理片段示例def safe_execute_tool(tool_name: str arguments: dict) - dict: “”“安全執(zhí)行工具并統(tǒng)一返回格式?!薄啊?try: if tool_name “get_current_weather”: location arguments.get(“l(fā)ocation”) if not location: return {“status”: “error” “message”: “Missing required parameter: location”} result get_current_weather(location) return {“status”: “success” “data”: result} elif tool_name “calculator”: expression arguments.get(“expression”) if not expression: return {“status”: “error” “message”: “Missing required parameter: expression”} # 使用更安全的方式計(jì)算此處為偽代碼 # result safe_calculator(expression) # 為演示暫用eval result eval(expression) return {“status”: “success” “data”: str(result)} else: return {“status”: “error” “message”: f“Unknown tool: {tool_name}”} except Exception as e: # 記錄日志 return {“status”: “error” “message”: f“Tool execution failed: {str(e)}”} # 在主循環(huán)中解析AI響應(yīng)后 tool_result safe_execute_tool(tool_name arguments) # 將統(tǒng)一格式的結(jié)果加入歷史指導(dǎo)模型下一步行動(dòng) if tool_result[“status”] “success”: updated_history.append({“role”: “user” “content”: f“Tool ‘{tool_name}’ returned: {tool_result[‘data’]}”}) else: updated_history.append({“role”: “user” “content”: f“Tool ‘{tool_name}’ failed. Error: {tool_result[‘message’]}. Please adjust your request or inform the user.”})6. 高級(jí)話題與避坑指南當(dāng)你開(kāi)始構(gòu)建更復(fù)雜的、用于生產(chǎn)環(huán)境的LLM智能體時(shí)會(huì)面臨一系列進(jìn)階挑戰(zhàn)。6.1 工具描述的工程藝術(shù)如何讓LLM“懂你”工具描述的質(zhì)量直接決定了模型調(diào)用工具的準(zhǔn)確率。差的描述會(huì)導(dǎo)致誤調(diào)用或漏調(diào)用。優(yōu)秀工具描述的要素功能清晰用一句話準(zhǔn)確概括工具是做什么的。例如“根據(jù)股票代碼查詢?cè)摴善钡膶?shí)時(shí)價(jià)格和今日漲跌幅”而不是“獲取股票信息”。參數(shù)明確每個(gè)參數(shù)都要說(shuō)明其含義、類型、格式和是否必填。對(duì)于枚舉值最好列出選項(xiàng)。例如interval: 字符串 時(shí)間間隔 可選值為 [‘1min’ ‘5min’ ‘15min’ ‘60min’ ‘daily’] 默認(rèn)為 ‘daily’。示例驅(qū)動(dòng)在描述中或通過(guò)少量示例few-shot展示工具的典型用法。例如“例如查詢蘋(píng)果公司的股票symbol‘AAPL’”。邊界條件說(shuō)明工具的局限性。例如“僅支持查詢A股和美股主要上市公司不支持基金和期貨。”一個(gè)對(duì)比示例差的描述工具搜索。描述搜索信息。參數(shù)q查詢?cè)~。好的描述工具網(wǎng)絡(luò)搜索。描述使用搜索引擎在互聯(lián)網(wǎng)上查找最新的公開(kāi)信息適用于回答關(guān)于實(shí)時(shí)事件、新聞、不確定事實(shí)的問(wèn)題。參數(shù)query字符串 必填要搜索的關(guān)鍵詞或問(wèn)題例如‘2024年奧運(yùn)會(huì)舉辦城市’。注意對(duì)于數(shù)學(xué)計(jì)算、內(nèi)部系統(tǒng)狀態(tài)查詢等請(qǐng)勿使用此工具。6.2 復(fù)雜工作流的編排策略當(dāng)任務(wù)需要多個(gè)工具按特定順序、有時(shí)是條件性或并行執(zhí)行時(shí)就需要工作流編排。順序執(zhí)行最簡(jiǎn)單A做完做B。適用于有明確依賴關(guān)系的步驟如先“搜索資料”再“總結(jié)資料”。并行執(zhí)行多個(gè)獨(dú)立任務(wù)同時(shí)進(jìn)行以提高效率如同時(shí)查詢“天氣”和“交通路況”。條件分支根據(jù)上一步的結(jié)果決定下一步走向。例如如果“查詢航班”返回?zé)o票則分支到“查詢高鐵票”否則繼續(xù)“選擇座位”。循環(huán)重復(fù)執(zhí)行某個(gè)步驟直到滿足條件例如“不斷從搜索結(jié)果中提取下一頁(yè)鏈接并獲取內(nèi)容直到收集夠10條結(jié)果或沒(méi)有下一頁(yè)”。實(shí)現(xiàn)建議對(duì)于簡(jiǎn)單流程可以用if-else和循環(huán)在代碼中硬編碼邏輯。對(duì)于中等復(fù)雜度使用LangGraph或微軟的Semantic Kernel等框架提供的圖編排能力是更優(yōu)雅的選擇。對(duì)于高度動(dòng)態(tài)、無(wú)法預(yù)先定義流程的復(fù)雜任務(wù)可以考慮使用一個(gè)“元規(guī)劃”LLM讓它根據(jù)當(dāng)前狀態(tài)動(dòng)態(tài)生成或調(diào)整下一步計(jì)劃。6.3 穩(wěn)定性與安全性的生死線穩(wěn)定性重試與降級(jí)工具調(diào)用尤其是外部API可能失敗。必須實(shí)現(xiàn)帶指數(shù)退避的重試機(jī)制。對(duì)于非核心功能要有降級(jí)方案如搜索API掛了就返回“暫時(shí)無(wú)法獲取網(wǎng)絡(luò)信息但我根據(jù)已有知識(shí)可以告訴你...”。速率限制嚴(yán)格遵守外部API的調(diào)用頻率限制并為自己的Agent設(shè)置全局速率限制防止濫用或意外循環(huán)導(dǎo)致的洪水攻擊。超時(shí)控制為每個(gè)工具調(diào)用設(shè)置合理的超時(shí)時(shí)間避免整個(gè)Agent被一個(gè)慢響應(yīng)拖死。安全性重中之重輸入凈化與校驗(yàn)永遠(yuǎn)不要相信來(lái)自LLM或用戶的輸入直接用于命令執(zhí)行、數(shù)據(jù)庫(kù)查詢或文件操作。對(duì)工具參數(shù)進(jìn)行嚴(yán)格的類型、范圍、格式校驗(yàn)。對(duì)于計(jì)算類工具使用沙箱或安全的解釋器。權(quán)限最小化每個(gè)工具只應(yīng)擁有完成其功能所需的最小權(quán)限。例如一個(gè)“讀取文件”的工具不應(yīng)該有刪除文件的權(quán)限。在系統(tǒng)設(shè)計(jì)上進(jìn)行隔離。敏感信息防護(hù)工具調(diào)用可能泄露API密鑰、訪問(wèn)令牌或內(nèi)部數(shù)據(jù)。確保這些敏感信息不會(huì)通過(guò)提示詞意外泄露給LLM例如不要在系統(tǒng)消息里寫(xiě)完整的數(shù)據(jù)庫(kù)連接字符串。使用環(huán)境變量或安全的密鑰管理服務(wù)。審核與日志記錄所有工具調(diào)用的詳情誰(shuí)、何時(shí)、調(diào)用了什么、參數(shù)是什么、結(jié)果是什么。這對(duì)于調(diào)試、審計(jì)和發(fā)現(xiàn)潛在濫用行為至關(guān)重要。6.4 成本與延遲的優(yōu)化工具調(diào)用會(huì)增加LLM的使用成本因?yàn)槎啻握{(diào)用和響應(yīng)延遲因?yàn)榇袌?zhí)行和網(wǎng)絡(luò)IO。成本優(yōu)化緩存對(duì)相同參數(shù)的、結(jié)果不常變的工具調(diào)用如城市信息查詢、歷史數(shù)據(jù)獲取進(jìn)行緩存。批量處理如果可能將多個(gè)小請(qǐng)求合并為一個(gè)批量請(qǐng)求。例如同時(shí)查詢多個(gè)城市的天氣。選擇性價(jià)比模型在規(guī)劃、推理步驟使用能力強(qiáng)但貴的模型如GPT-4在簡(jiǎn)單的文本生成或格式化步驟使用便宜模型如GPT-3.5-Turbo。延遲優(yōu)化并行調(diào)用對(duì)于無(wú)依賴關(guān)系的工具盡可能并行執(zhí)行。流式響應(yīng)對(duì)于需要長(zhǎng)時(shí)間運(yùn)行的任務(wù)可以先返回一個(gè)“已開(kāi)始處理”的響應(yīng)然后通過(guò)WebSocket或Server-Sent Events (SSE) 逐步推送結(jié)果。預(yù)加載與預(yù)熱對(duì)于常用的、初始化慢的工具可以提前加載。7. 未來(lái)展望從工具調(diào)用到自主智能體工具調(diào)用只是LLM邁向現(xiàn)實(shí)世界的第一步。未來(lái)的方向是構(gòu)建高度自主的智能體Agent它們能夠長(zhǎng)期運(yùn)行持續(xù)感知環(huán)境主動(dòng)規(guī)劃并執(zhí)行復(fù)雜目標(biāo)。記憶與學(xué)習(xí)當(dāng)前的Agent大多是“無(wú)狀態(tài)”的每次對(duì)話相對(duì)獨(dú)立。未來(lái)的Agent需要擁有長(zhǎng)期記憶能夠記住與用戶的交互歷史、從成功和失敗中學(xué)習(xí)并隨著時(shí)間的推移優(yōu)化其工具使用策略。工具發(fā)現(xiàn)與創(chuàng)建不再局限于預(yù)先定義的工具集。智能體應(yīng)該能夠根據(jù)任務(wù)需求自動(dòng)探索可用的API通過(guò)文檔、示例甚至通過(guò)生成代碼來(lái)創(chuàng)建新的臨時(shí)工具。多模態(tài)交互工具調(diào)用將不限于API和函數(shù)。智能體將能直接操控圖形界面GUI、解析圖像和視頻內(nèi)容、與物理機(jī)器人交互實(shí)現(xiàn)真正的“眼手協(xié)調(diào)”。社會(huì)性與協(xié)作多個(gè)智能體之間可以分工協(xié)作共同完成一個(gè)宏大目標(biāo)。它們會(huì)進(jìn)行協(xié)商、任務(wù)分配和信息共享形成多智能體系統(tǒng)。工具調(diào)用技術(shù)正在快速消融數(shù)字智能與物理世界之間的壁壘。作為開(kāi)發(fā)者我們現(xiàn)在掌握的不僅僅是讓AI“說(shuō)話”的技巧更是賦予它“行動(dòng)”能力的方法。從理解用戶意圖到精準(zhǔn)調(diào)用工具從處理錯(cuò)誤到編排復(fù)雜工作流每一步都充滿了工程與設(shè)計(jì)的挑戰(zhàn)也帶來(lái)了前所未有的可能性。開(kāi)始動(dòng)手構(gòu)建你的第一個(gè)智能體吧從讓AI幫你查一次天氣、算一筆賬開(kāi)始你將親手參與到這場(chǎng)讓“缸中大腦”長(zhǎng)出操控世界之手的偉大進(jìn)程之中。