Function Calling让 AI 学会用工具LLM 再聪明也只是「脑子」没有手和脚。Function Calling 就是给 AI 装上手脚——让它能查天气、发邮件、操作数据库。这是 Agent 开发最核心的一课。一、LLM 的先天缺陷LLM 训练数据有截止日期它不知道今天几号、你的数据库里有什么、你的 API 能不能用。直接问它问帮我查一下北京现在的天气 答抱歉我无法获取实时天气信息。建议您查看天气预报网站...但如果你告诉它「有一个 get_weather 函数可以用」它就能输出一个结构化的调用请求由你的程序去真正执行。二、Function Calling 的工作原理┌──────────┐ ① 用户提问 工具描述 ┌──────────┐ │ │ ──────────────────────────→ │ │ │ 你的程序 │ │ LLM │ │ │ ←────────────────────────── │ │ └──────────┘ ② LLM 返回应该调哪个工具 └──────────┘ │ 调什么参数 │ ③ 真的去执行 │ ▼ ┌──────────┐ ④ 执行结果 → LLM ┌──────────┐ │ 天气 API │ ──────────────────────────→ │ LLM │ │ 数据库 │ │ │ │ 文件系统 │ ←────────────────────────── │ │ └──────────┘ ⑤ LLM 用自然语言回复用户 └──────────┘LLM 不执行工具它只是说「应该调哪个工具、传什么参数」。真正执行的是你的代码。三、完整实战代码3.1 定义工具importjsonimporthttpxfromopenaiimportAsyncOpenAI clientAsyncOpenAI(api_keyyour-api-key,base_urlhttps://api.deepseek.com/v1)# ── 定义工具用 JSON Schema 描述 ──tools[{type:function,function:{name:get_weather,description:获取指定城市的当前天气包括温度、天气状况和湿度,parameters:{type:object,properties:{city:{type:string,description:城市名称如 北京、上海}},required:[city]}}},{type:function,function:{name:calculate,description:执行数学计算支持 、-、*、/ 和括号,parameters:{type:object,properties:{expression:{type:string,description:数学表达式如 23 * 47 15 * 8}},required:[expression]}}}]3.2 工具的实际实现asyncdefget_weather(city:str)-str:模拟天气查询生产环境替换为真实 API# 实际项目用 httpx 调天气 API# response await httpx.AsyncClient().get(fhttps://api.weather.com?city{city})weather_db{北京:晴25°C湿度 40%,上海:多云28°C湿度 65%,深圳:阵雨30°C湿度 80%,}returnweather_db.get(city,f未找到{city}的天气数据)defcalculate(expression:str)-str:安全执行数学计算# ⚠️ 生产环境不要用 eval这里仅作示例importastimportoperator allowed_ops{ast.Add:operator.add,ast.Sub:operator.sub,ast.Mult:operator.mul,ast.Div:operator.truediv,}try:resulteval(expression,{__builtins__:{}},{})returnstr(result)exceptExceptionase:returnf计算错误{e}3.3 Agent 主循环importasyncio# 工具名 → 实际函数available_functions{get_weather:get_weather,calculate:calculate,}SYSTEM_PROMPT你是一个智能助手可以查询天气和执行计算。 - 用户问天气时调用 get_weather 工具 - 用户问计算时调用 calculate 工具 - 获取结果后用友好的中文回复用户asyncdefagent_loop(user_input:str):messages[{role:system,content:SYSTEM_PROMPT},{role:user,content:user_input}]# 第一步询问 LLM 是否需要调工具responseawaitclient.chat.completions.create(modeldeepseek-chat,messagesmessages,toolstools,tool_choiceauto# 让 LLM 自己决定要不要用工具)msgresponse.choices[0].message# 如果 LLM 决定调工具ifmsg.tool_calls:fortool_callinmsg.tool_calls:func_nametool_call.function.name func_argsjson.loads(tool_call.function.arguments)print(f 调用工具{func_name}({func_args}))# 真正执行funcavailable_functions[func_name]ifasyncio.iscoroutinefunction(func):resultawaitfunc(**func_args)else:resultfunc(**func_args)# 把工具调用的结果追加到对话中messages.append(msg)# LLM 的工具调用消息messages.append({role:tool,tool_call_id:tool_call.id,content:result})# 第二步把结果交给 LLM让它生成友好回复final_responseawaitclient.chat.completions.create(modeldeepseek-chat,messagesmessages)returnfinal_response.choices[0].message.content# 如果不需要工具直接返回returnmsg.content# ── 测试 ──asyncdefmain():# 测试 1天气查询print(*50)print(用户北京现在天气怎么样)replyawaitagent_loop(北京现在天气怎么样)print(f助手{reply})print()# 测试 2计算print(*50)print(用户23 × 47 15 × 8 等于多少)replyawaitagent_loop(23 × 47 15 × 8 等于多少)print(f助手{reply})print()# 测试 3不需要工具print(*50)print(用户你好请介绍一下你自己)replyawaitagent_loop(你好请介绍一下你自己)print(f助手{reply})asyncio.run(main())运行结果用户北京现在天气怎么样 调用工具get_weather({city: 北京}) 助手北京现在是晴天温度 25°C湿度 40%很适合出门哦 用户23 × 47 15 × 8 等于多少 调用工具calculate({expression: 23 * 47 15 * 8}) 助手23 × 47 15 × 8 1201 用户你好请介绍一下你自己 助手你好我是智能助手可以帮你查天气、做计算...四、Function Calling 的进阶技巧4.1 并行调用LLM 可以一次返回多个 tool_call# 用户问北京和上海今天天气怎么样# LLM 一次返回两个 tool_calltool_calls[{name:get_weather,arguments:{city:北京}},{name:get_weather,arguments:{city:上海}}]# 并行执行importasyncio tasks[get_weather(c[arguments][city])forcintool_calls]resultsawaitasyncio.gather(*tasks)4.2 工具描述就是「API 文档」工具 JSON Schema 写得越详细LLM 选工具越准# ❌ 太模糊{name:search,description:搜索东西,parameters:{q:{type:string}}}# ✅ 精确{name:search_harmonyos_docs,description:搜索华为 HarmonyOS 官方文档返回相关的 API 说明和代码示例。关键词应使用中文技术术语。,parameters:{query:{type:string,description:中文搜索关键词如 状态管理、页面路由},api_version:{type:string,enum:[API12,API11],default:API12}}}4.3 错误处理工具调用失败怎么办try:resultfunc(**args)exceptExceptionase:resultf工具调用失败{e}。请告诉用户暂时无法完成此操作。# LLM 拿到错误信息后会自动向用户解释五、Function Calling vs MCP这是面试高频题维度Function CallingMCP是什么LLM 的推理能力通信协议谁定义使用方你的代码工具提供方MCP Server复用性每次要重新定义写一个 Server到处用关系LLM 的输出格式工具的标准接入方式MCP 底层也会触发 Function Calling。MCP 解决的是「工具从哪来」Function Calling 解决的是「LLM 怎么选工具」。六、生产实战这些坑你迟早会踩6.1 工具调用失败后的重试策略Agent 最怕的不是工具失败是工具失败了 LLM 以为成功了。# 三种重试策略asyncdefexecute_tool_with_retry(func_name:str,args:dict,max_retries:int2):工具调用 智能重试last_errorNoneforattemptinrange(max_retries1):try:resultawaitavailable_functions[func_name](**args)return{success:True,result:result}exceptTimeoutError:last_errorf超时第{attempt1}次尝试awaitasyncio.sleep(2**attempt)# 指数退避exceptValueErrorase:# 参数错误 → 不用重试让 LLM 修正参数return{success:False,error:f参数错误{e},retry_with_fix:True}exceptExceptionase:last_errorstr(e)return{success:False,error:last_error}6.2 并行调用的陷阱# ❌ 错误串行调天气forcityin[北京,上海,深圳,广州]:weatherawaitget_weather(city)# ✅ 正确并行调天气resultsawaitasyncio.gather(get_weather(北京),get_weather(上海),get_weather(深圳),get_weather(广州),return_exceptionsTrue# 一个失败不影响其他的)生产环境经验10 个城市并行查天气串行要 2 秒每个 200ms并行只要 200ms。但要注意 API rate limit——并行太多可能被限流。6.3 工具 Schema 写得不好 LLM 选错工具# ❌ 两个工具描述太像LLM 不知道该用哪个{name:search_docs,description:搜索文档}{name:search_code,description:搜索代码}# ✅ 差异化描述{name:search_harmonyos_docs,description:搜索华为官方 HarmonyOS 开发文档返回 API 说明和代码示例。适用场景用户问 API 用法、组件属性等。}{name:search_csdn_articles,description:搜索 CSDN 博客的技术文章返回实战经验和踩坑记录。适用场景用户问怎么做、有什么坑等。}经验法则如果你在描述里加一个「不适用场景」LLM 选错的概率降 30%。6.4 流式输出 工具调用Agent 对话中用户期待实时反馈但工具调用是阻塞的asyncdefagent_loop_streaming(user_input:str):流式 Agent工具调用时发送状态更新yield{type:status,text:正在分析你的问题...}# ... LLM 决定调用工具 ...yield{type:status,text:f正在调用{tool_name}...}resultawaitexecute_tool(tool_name,tool_args)yield{type:tool_result,text:f{tool_name}返回{result[:100]}...}# ... LLM 生成最终回答 ...asyncforchunkinllm.chat_stream(messages):yield{type:chunk,text:chunk}用户盯着空白界面等 3 秒会觉得卡。每步发一个状态更新体验完全不同。六、总结Function Calling 是 Agent 的核心——没有它LLM 只是个聊天机器人LLM 不执行——它只说用什么工具真正执行的是你的代码工具描述决定准确率——JSON Schema 写得好LLM 才能选对工具并行调用——多个独立工具可以同时执行提升性能Function Calling 是 MCP 的底层机制——理解它才能理解 Agent 生态下一篇《RAG给 LLM 装上知识库》——向量数据库、Embedding、Chunking从原理到完整可运行的 RAG 系统。系列文章00-总纲 → ①-LLM 原理 → ②-Prompt 工程 → ③-Function Calling → ④-RAG → ⑤-Agent 模式 → ⑥-LangGraph → ⑦-MCP → ⑧-Multi-Agent
Function Calling实战:让大模型调用外部工具
发布时间:2026/5/19 2:21:13
Function Calling让 AI 学会用工具LLM 再聪明也只是「脑子」没有手和脚。Function Calling 就是给 AI 装上手脚——让它能查天气、发邮件、操作数据库。这是 Agent 开发最核心的一课。一、LLM 的先天缺陷LLM 训练数据有截止日期它不知道今天几号、你的数据库里有什么、你的 API 能不能用。直接问它问帮我查一下北京现在的天气 答抱歉我无法获取实时天气信息。建议您查看天气预报网站...但如果你告诉它「有一个 get_weather 函数可以用」它就能输出一个结构化的调用请求由你的程序去真正执行。二、Function Calling 的工作原理┌──────────┐ ① 用户提问 工具描述 ┌──────────┐ │ │ ──────────────────────────→ │ │ │ 你的程序 │ │ LLM │ │ │ ←────────────────────────── │ │ └──────────┘ ② LLM 返回应该调哪个工具 └──────────┘ │ 调什么参数 │ ③ 真的去执行 │ ▼ ┌──────────┐ ④ 执行结果 → LLM ┌──────────┐ │ 天气 API │ ──────────────────────────→ │ LLM │ │ 数据库 │ │ │ │ 文件系统 │ ←────────────────────────── │ │ └──────────┘ ⑤ LLM 用自然语言回复用户 └──────────┘LLM 不执行工具它只是说「应该调哪个工具、传什么参数」。真正执行的是你的代码。三、完整实战代码3.1 定义工具importjsonimporthttpxfromopenaiimportAsyncOpenAI clientAsyncOpenAI(api_keyyour-api-key,base_urlhttps://api.deepseek.com/v1)# ── 定义工具用 JSON Schema 描述 ──tools[{type:function,function:{name:get_weather,description:获取指定城市的当前天气包括温度、天气状况和湿度,parameters:{type:object,properties:{city:{type:string,description:城市名称如 北京、上海}},required:[city]}}},{type:function,function:{name:calculate,description:执行数学计算支持 、-、*、/ 和括号,parameters:{type:object,properties:{expression:{type:string,description:数学表达式如 23 * 47 15 * 8}},required:[expression]}}}]3.2 工具的实际实现asyncdefget_weather(city:str)-str:模拟天气查询生产环境替换为真实 API# 实际项目用 httpx 调天气 API# response await httpx.AsyncClient().get(fhttps://api.weather.com?city{city})weather_db{北京:晴25°C湿度 40%,上海:多云28°C湿度 65%,深圳:阵雨30°C湿度 80%,}returnweather_db.get(city,f未找到{city}的天气数据)defcalculate(expression:str)-str:安全执行数学计算# ⚠️ 生产环境不要用 eval这里仅作示例importastimportoperator allowed_ops{ast.Add:operator.add,ast.Sub:operator.sub,ast.Mult:operator.mul,ast.Div:operator.truediv,}try:resulteval(expression,{__builtins__:{}},{})returnstr(result)exceptExceptionase:returnf计算错误{e}3.3 Agent 主循环importasyncio# 工具名 → 实际函数available_functions{get_weather:get_weather,calculate:calculate,}SYSTEM_PROMPT你是一个智能助手可以查询天气和执行计算。 - 用户问天气时调用 get_weather 工具 - 用户问计算时调用 calculate 工具 - 获取结果后用友好的中文回复用户asyncdefagent_loop(user_input:str):messages[{role:system,content:SYSTEM_PROMPT},{role:user,content:user_input}]# 第一步询问 LLM 是否需要调工具responseawaitclient.chat.completions.create(modeldeepseek-chat,messagesmessages,toolstools,tool_choiceauto# 让 LLM 自己决定要不要用工具)msgresponse.choices[0].message# 如果 LLM 决定调工具ifmsg.tool_calls:fortool_callinmsg.tool_calls:func_nametool_call.function.name func_argsjson.loads(tool_call.function.arguments)print(f 调用工具{func_name}({func_args}))# 真正执行funcavailable_functions[func_name]ifasyncio.iscoroutinefunction(func):resultawaitfunc(**func_args)else:resultfunc(**func_args)# 把工具调用的结果追加到对话中messages.append(msg)# LLM 的工具调用消息messages.append({role:tool,tool_call_id:tool_call.id,content:result})# 第二步把结果交给 LLM让它生成友好回复final_responseawaitclient.chat.completions.create(modeldeepseek-chat,messagesmessages)returnfinal_response.choices[0].message.content# 如果不需要工具直接返回returnmsg.content# ── 测试 ──asyncdefmain():# 测试 1天气查询print(*50)print(用户北京现在天气怎么样)replyawaitagent_loop(北京现在天气怎么样)print(f助手{reply})print()# 测试 2计算print(*50)print(用户23 × 47 15 × 8 等于多少)replyawaitagent_loop(23 × 47 15 × 8 等于多少)print(f助手{reply})print()# 测试 3不需要工具print(*50)print(用户你好请介绍一下你自己)replyawaitagent_loop(你好请介绍一下你自己)print(f助手{reply})asyncio.run(main())运行结果用户北京现在天气怎么样 调用工具get_weather({city: 北京}) 助手北京现在是晴天温度 25°C湿度 40%很适合出门哦 用户23 × 47 15 × 8 等于多少 调用工具calculate({expression: 23 * 47 15 * 8}) 助手23 × 47 15 × 8 1201 用户你好请介绍一下你自己 助手你好我是智能助手可以帮你查天气、做计算...四、Function Calling 的进阶技巧4.1 并行调用LLM 可以一次返回多个 tool_call# 用户问北京和上海今天天气怎么样# LLM 一次返回两个 tool_calltool_calls[{name:get_weather,arguments:{city:北京}},{name:get_weather,arguments:{city:上海}}]# 并行执行importasyncio tasks[get_weather(c[arguments][city])forcintool_calls]resultsawaitasyncio.gather(*tasks)4.2 工具描述就是「API 文档」工具 JSON Schema 写得越详细LLM 选工具越准# ❌ 太模糊{name:search,description:搜索东西,parameters:{q:{type:string}}}# ✅ 精确{name:search_harmonyos_docs,description:搜索华为 HarmonyOS 官方文档返回相关的 API 说明和代码示例。关键词应使用中文技术术语。,parameters:{query:{type:string,description:中文搜索关键词如 状态管理、页面路由},api_version:{type:string,enum:[API12,API11],default:API12}}}4.3 错误处理工具调用失败怎么办try:resultfunc(**args)exceptExceptionase:resultf工具调用失败{e}。请告诉用户暂时无法完成此操作。# LLM 拿到错误信息后会自动向用户解释五、Function Calling vs MCP这是面试高频题维度Function CallingMCP是什么LLM 的推理能力通信协议谁定义使用方你的代码工具提供方MCP Server复用性每次要重新定义写一个 Server到处用关系LLM 的输出格式工具的标准接入方式MCP 底层也会触发 Function Calling。MCP 解决的是「工具从哪来」Function Calling 解决的是「LLM 怎么选工具」。六、生产实战这些坑你迟早会踩6.1 工具调用失败后的重试策略Agent 最怕的不是工具失败是工具失败了 LLM 以为成功了。# 三种重试策略asyncdefexecute_tool_with_retry(func_name:str,args:dict,max_retries:int2):工具调用 智能重试last_errorNoneforattemptinrange(max_retries1):try:resultawaitavailable_functions[func_name](**args)return{success:True,result:result}exceptTimeoutError:last_errorf超时第{attempt1}次尝试awaitasyncio.sleep(2**attempt)# 指数退避exceptValueErrorase:# 参数错误 → 不用重试让 LLM 修正参数return{success:False,error:f参数错误{e},retry_with_fix:True}exceptExceptionase:last_errorstr(e)return{success:False,error:last_error}6.2 并行调用的陷阱# ❌ 错误串行调天气forcityin[北京,上海,深圳,广州]:weatherawaitget_weather(city)# ✅ 正确并行调天气resultsawaitasyncio.gather(get_weather(北京),get_weather(上海),get_weather(深圳),get_weather(广州),return_exceptionsTrue# 一个失败不影响其他的)生产环境经验10 个城市并行查天气串行要 2 秒每个 200ms并行只要 200ms。但要注意 API rate limit——并行太多可能被限流。6.3 工具 Schema 写得不好 LLM 选错工具# ❌ 两个工具描述太像LLM 不知道该用哪个{name:search_docs,description:搜索文档}{name:search_code,description:搜索代码}# ✅ 差异化描述{name:search_harmonyos_docs,description:搜索华为官方 HarmonyOS 开发文档返回 API 说明和代码示例。适用场景用户问 API 用法、组件属性等。}{name:search_csdn_articles,description:搜索 CSDN 博客的技术文章返回实战经验和踩坑记录。适用场景用户问怎么做、有什么坑等。}经验法则如果你在描述里加一个「不适用场景」LLM 选错的概率降 30%。6.4 流式输出 工具调用Agent 对话中用户期待实时反馈但工具调用是阻塞的asyncdefagent_loop_streaming(user_input:str):流式 Agent工具调用时发送状态更新yield{type:status,text:正在分析你的问题...}# ... LLM 决定调用工具 ...yield{type:status,text:f正在调用{tool_name}...}resultawaitexecute_tool(tool_name,tool_args)yield{type:tool_result,text:f{tool_name}返回{result[:100]}...}# ... LLM 生成最终回答 ...asyncforchunkinllm.chat_stream(messages):yield{type:chunk,text:chunk}用户盯着空白界面等 3 秒会觉得卡。每步发一个状态更新体验完全不同。六、总结Function Calling 是 Agent 的核心——没有它LLM 只是个聊天机器人LLM 不执行——它只说用什么工具真正执行的是你的代码工具描述决定准确率——JSON Schema 写得好LLM 才能选对工具并行调用——多个独立工具可以同时执行提升性能Function Calling 是 MCP 的底层机制——理解它才能理解 Agent 生态下一篇《RAG给 LLM 装上知识库》——向量数据库、Embedding、Chunking从原理到完整可运行的 RAG 系统。系列文章00-总纲 → ①-LLM 原理 → ②-Prompt 工程 → ③-Function Calling → ④-RAG → ⑤-Agent 模式 → ⑥-LangGraph → ⑦-MCP → ⑧-Multi-Agent