入門 LLM 開發(fā) · Day 8】:Function Calling——讓 AI 會“用“工具)
【零基礎(chǔ)入門 LLM 開發(fā) · Day 8】Function Calling——讓 AI 會用工具先糾正一個常見誤解Function Calling不是AI 自己去執(zhí)行函數(shù)。AI 是個活在服務(wù)器里的大腦它碰不到你的電腦。它真正能做的是告訴你我想調(diào)用 get_weather參數(shù)是 location北京然后——由你的代碼替它執(zhí)行再把結(jié)果喂回給它。一句話總結(jié)AI 出主意你動手結(jié)果再匯報給 AI。完整流程圖先看懂再寫代碼用戶提問 ──? 第一次請求帶上工具說明書 tools │ ▼ AI 返回 tool_calls想調(diào)用什么函數(shù)參數(shù) │ ▼ 你的代碼本地執(zhí)行真正的 Python 函數(shù) │ ▼ 把執(zhí)行結(jié)果以 role:tool 塞回 messages │ ▼ 第二次請求 ──? AI 結(jié)合結(jié)果生成最終回答完整代碼importosimportjsonfromdotenvimportload_dotenvfromopenaiimportOpenAI load_dotenv()clientOpenAI(api_keyos.getenv(YUMC_MODEL_API_KEY),base_urlos.getenv(YUMC_MODEL_BASE_URL),)# 1. 定義一個普通的 Python 函數(shù)就是本地工具defget_weather(location:str)-str:if北京inlocation:return晴天25度elif上海inlocation:return雷陣雨28度return未知天氣# 2. 告訴大模型有這個工具可用JSON Schema 說明書tools[{type:function,function:{name:get_weather,description:獲取指定城市的當(dāng)前天氣,parameters:{type:object,properties:{location:{type:string,description:城市名稱:如北京}},required:[location],},},}]# 3. 用戶提問messages[{role:user,content:今天北京和上海的天氣怎么樣}]# 4. 第一次請求AI 決定要不要調(diào)用工具responseclient.chat.completions.create(modelyumcode-pro,messagesmessages,toolstools,tool_choiceauto,# 讓 AI 自己決定用不用工具)ai_messageresponse.choices[0].message messages.append(ai_message)# 把 AI 決定調(diào)用工具的記錄存入歷史# 5. 檢查 AI 是否要調(diào)用工具ifai_message.tool_calls:fortool_callinai_message.tool_calls:func_nametool_call.function.name func_argsjson.loads(tool_call.function.arguments)# 參數(shù)是 JSON 字符串print(fAI 想調(diào)用{func_name}({func_args}))# 6. 本地真正執(zhí)行函數(shù)iffunc_nameget_weather:resultget_weather(**func_args)print(f本地函數(shù)執(zhí)行結(jié)果:{result})# 7. 把執(zhí)行結(jié)果塞回 messages匯報給 AImessages.append({role:tool,tool_call_id:tool_call.id,content:result})# 8. 第二次請求AI 根據(jù)工具結(jié)果生成最終人類可讀的回答final_responseclient.chat.completions.create(modelyumcode-pro,messagesmessages)print(\nAI 最終回復(fù):,final_response.choices[0].message.content)逐段拆解最容易懵的 4 個點(diǎn)① tools 里的 JSON Schema 是什么是寫給 AI 看的工具說明書函數(shù)叫什么、干什么用、需要哪些參數(shù)、哪些必填。AI 靠讀這份說明決定要不要用、怎么用。說明書怎么寫才好用明天專門講。②tool_choiceauto讓 AI 自己判斷需要工具就用閑聊就直接答。不要看到查天氣四個字就無腦調(diào)用。③tool_call.function.arguments是字符串AI 返回的參數(shù)是 JSON字符串{location: 北京}必須json.loads()轉(zhuǎn)成字典才能get_weather(**func_args)這樣展開傳參。④ 回傳結(jié)果時的三個講究role必須是tooltool_call_id必須對應(yīng)上AI 才知道這份結(jié)果是誰要的有幾個tool_calls就回傳幾份結(jié)果用戶問了兩個城市AI 會一次性發(fā)起兩次調(diào)用。運(yùn)行效果AI 想調(diào)用get_weather ({location: 北京}) 本地函數(shù)執(zhí)行結(jié)果:晴天25度 AI 想調(diào)用get_weather ({location: 上海}) 本地函數(shù)執(zhí)行結(jié)果:雷陣雨28度 AI 最終回復(fù): 北京今天是晴天25度上海有雷陣雨28度。出行記得帶傘這就是 Agent 的原子操作。Day 14-15 的多 Agent 系統(tǒng)不過是把這個流程套了好幾層。今日踩坑點(diǎn)忘 append AI 的 tool_calls 消息第二次請求會報錯——messages 必須完整連貫。arguments 沒json.loads拿到的是字符串**展開會炸。result必須是字符串函數(shù)返回了字典/對象先str()或json.dumps()再塞回去。安全提醒AI 只是建議調(diào)用執(zhí)行權(quán)和參數(shù)校驗(yàn)永遠(yuǎn)在你手里絕不要把 AI 的輸出直接拼進(jìn) SQL 或 shell 命令。今日小練習(xí)必做新增一個get_current_time()工具返回當(dāng)前時間跑通現(xiàn)在幾點(diǎn)了。進(jìn)階讓 AI 同時查三個城市觀察tool_calls列表的長度。明日預(yù)告Day 9同一個工具說明書換個寫法AI 的行為天差地別——description 是門手藝。附錄完整練習(xí)代碼openAITools.pyimportosimportjsonfromdotenvimportload_dotenvfromopenaiimportOpenAI load_dotenv()clientOpenAI(api_keyos.getenv(YUMC_MODEL_API_KEY),base_urlos.getenv(YUMC_MODEL_BASE_URL),)# 1.定義一個普通的python 函數(shù)defget_weather(location:str)-str:模擬獲取天氣的函數(shù)if北京inlocation:return晴天25度elif上海inlocation:return雷陣雨28度return未知天氣# 2. 告訴大模型有這個工具可用tools[{type:function,function:{name:get_weather,description:獲取指定城市的當(dāng)前天氣,parameters:{type:object,properties:{location:{type:string,description:城市名稱:如北京}},required:[location],},},}]# 3.用戶提問messages[{role:user,content:今天北京和上海的天氣怎么樣}]# 4. 第一次請求AI 決定調(diào)用工具responseclient.chat.completions.create(modelyumcode-pro,messagesmessages,toolstools,tool_choiceauto,# 讓AI 自己決定用不用工具)ai_messageresponse.choices[0].message messages.append(ai_message)# 把AI 決定調(diào)用工具的記錄存入歷史# 5.檢查AI 是否要調(diào)用工具ifai_message.tool_calls:fortool_callinai_message.tool_calls:func_nametool_call.function.name func_argsjson.loads(tool_call.function.arguments)print(fAI 想調(diào)用{func_name}({func_args}))# 實(shí)際執(zhí)行我們的python 函數(shù)iffunc_nameget_weather:resultget_weather(**func_args)print(f本地函數(shù)執(zhí)行結(jié)果:{result})# 6.把函數(shù)執(zhí)行的結(jié)果塞回messages 里告訴AImessages.append({role:tool,tool_call_id:tool_call.id,content:result})# 7.第二次請求AI 根據(jù)工具結(jié)果生成最終人類可讀的回答final_responseclient.chat.completions.create(modelyumcode-pro,messagesmessages)print(\nAI 最終回復(fù):,final_response.choices[0].message.content)