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