文章目录
- [【42.Python+AI】大模型Function Calling:让AI调用你的Python函数,从聊天机器人到智能助手](#【42.Python+AI】大模型Function Calling:让AI调用你的Python函数,从聊天机器人到智能助手)
-
- 导入语
- [1 ~> Function Calling的核心流程](#1 ~> Function Calling的核心流程)
- [2 ~> 定义Tool:告诉AI你有哪些函数](#2 ~> 定义Tool:告诉AI你有哪些函数)
-
- [2.1 JSON Schema规范](#2.1 JSON Schema规范)
- [2.2 实际实现函数](#2.2 实际实现函数)
- [3 ~> 完整实现:处理Function Calling循环](#3 ~> 完整实现:处理Function Calling循环)
- [4 ~> 实战:AI助手------查数据库+发邮件](#4 ~> 实战:AI助手——查数据库+发邮件)
-
- [4.1 定义多个Tool](#4.1 定义多个Tool)
- [4.2 实现函数](#4.2 实现函数)
- [4.3 完整对话处理](#4.3 完整对话处理)
- [思考 && 总结](#思考 && 总结)
- 结尾
【42.Python+AI】大模型Function Calling:让AI调用你的Python函数,从聊天机器人到智能助手
📖 文章简介: 本文深入拆解大模型Function Calling(函数调用)的完整机制。从Tool定义的JSON Schema规范讲起,到单轮与多轮对话中的函数调用链实现,再到一个可自动查数据库+发送邮件的AI助手完整实战。文中包含Mermaid时序图展示Function Calling的请求-响应-执行-反馈全链路,并对比了不同国产模型对Function Calling的支持现状,适合想让AI从"只会聊天"升级为"能执行操作"的开发者。

🎬 个人主页: 源码骑士
❄ 专栏传送门: 《Android开发基础》《python基础课程》
⭐️热衷从源码视角拆解技术底层原理,将复杂架构讲得通俗易懂
🎬 源码骑士的简介:
5年Android Framework系统开发经验,曾主导多项系统级性能优化专项
技术栈覆盖Android系统全链路(Binder/Handler/AMS/WMS/启动流程)及Java后端全家桶(Spring + MyBatis + Redis + Oracle)
累计产出原创技术文章100+篇,文章以流程图为特色,被读者评价为"看一篇胜过啃一周源码"
导入语
你花了两周搭了一个AI客服Bot,效果不错。但老板问:"它能查订单状态吗?能帮用户修改收货地址吗?"------你沉默了。
如果AI只能聊天、不能执行操作,它永远是一个"有趣的玩具"而不是"有用的工具"。Function Calling就是解决这个痛点的关键能力------让大模型决定"该调用哪个函数",你来实现这个函数,把结果返回给模型,模型再用自然语言告诉用户。
这篇文章就是带你从零实现一个能查数据库、发邮件的AI助手。整个过程你会彻底理解Function Calling的请求-响应-执行循环。
1 ~> Function Calling的核心流程
数据库/API 大模型 你的AI应用 用户 数据库/API 大模型 你的AI应用 用户 #mermaid-svg-3KPdVy2AK2sVDdMH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-3KPdVy2AK2sVDdMH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3KPdVy2AK2sVDdMH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3KPdVy2AK2sVDdMH .error-icon{fill:#552222;}#mermaid-svg-3KPdVy2AK2sVDdMH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3KPdVy2AK2sVDdMH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3KPdVy2AK2sVDdMH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3KPdVy2AK2sVDdMH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3KPdVy2AK2sVDdMH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3KPdVy2AK2sVDdMH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3KPdVy2AK2sVDdMH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3KPdVy2AK2sVDdMH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3KPdVy2AK2sVDdMH .marker.cross{stroke:#333333;}#mermaid-svg-3KPdVy2AK2sVDdMH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3KPdVy2AK2sVDdMH p{margin:0;}#mermaid-svg-3KPdVy2AK2sVDdMH .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-3KPdVy2AK2sVDdMH text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-3KPdVy2AK2sVDdMH .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-3KPdVy2AK2sVDdMH .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-3KPdVy2AK2sVDdMH .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-3KPdVy2AK2sVDdMH .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-3KPdVy2AK2sVDdMH #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-3KPdVy2AK2sVDdMH .sequenceNumber{fill:white;}#mermaid-svg-3KPdVy2AK2sVDdMH #sequencenumber{fill:#333;}#mermaid-svg-3KPdVy2AK2sVDdMH #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-3KPdVy2AK2sVDdMH .messageText{fill:#333;stroke:none;}#mermaid-svg-3KPdVy2AK2sVDdMH .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-3KPdVy2AK2sVDdMH .labelText,#mermaid-svg-3KPdVy2AK2sVDdMH .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-3KPdVy2AK2sVDdMH .loopText,#mermaid-svg-3KPdVy2AK2sVDdMH .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-3KPdVy2AK2sVDdMH .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-3KPdVy2AK2sVDdMH .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-3KPdVy2AK2sVDdMH .noteText,#mermaid-svg-3KPdVy2AK2sVDdMH .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-3KPdVy2AK2sVDdMH .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-3KPdVy2AK2sVDdMH .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-3KPdVy2AK2sVDdMH .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-3KPdVy2AK2sVDdMH .actorPopupMenu{position:absolute;}#mermaid-svg-3KPdVy2AK2sVDdMH .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-3KPdVy2AK2sVDdMH .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-3KPdVy2AK2sVDdMH .actor-man circle,#mermaid-svg-3KPdVy2AK2sVDdMH line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-3KPdVy2AK2sVDdMH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 模型判断:需要调用 get_order_status函数 "帮我查订单 发送消息 + 可用函数列表 返回函数调用请求 function_name="get_order_status" arguments={"order_id":"12345"} 执行 get_order_status("12345") 返回 {"status":"已发货","tracking":"SF123456"} 把函数执行结果发送给模型 "您的订单 "您的订单
2 ~> 定义Tool:告诉AI你有哪些函数
2.1 JSON Schema规范
python
# 定义一个"查天气"的函数描述
weather_tool = {
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气信息。使用此函数当用户询问天气相关问题。",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如'北京'、'上海'",
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位",
}
},
"required": ["city"],
}
}
}
2.2 实际实现函数
python
def get_weather(city: str, unit: str = "celsius") -> dict:
"""实际查询天气的函数(这里用模拟数据)"""
# 真实场景:调用天气API
weather_data = {
"北京": {"temp": 28, "humidity": 65, "condition": "晴"},
"上海": {"temp": 32, "humidity": 80, "condition": "多云"},
}
data = weather_data.get(city, {"temp": 25, "humidity": 50, "condition": "未知"})
return {
"city": city,
"temperature": data["temp"],
"humidity": data["humidity"],
"condition": data["condition"],
"unit": unit,
}
3 ~> 完整实现:处理Function Calling循环
python
import json
from openai import OpenAI
client = OpenAI()
# 函数注册表
AVAILABLE_FUNCTIONS = {
"get_weather": get_weather,
}
def run_conversation(user_message: str):
"""处理一轮对话,自动判断是否需要调用函数"""
messages = [{"role": "user", "content": user_message}]
tools = [weather_tool]
# 第一轮:把用户消息和可用工具发给模型
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages,
tools=tools,
tool_choice="auto", # 让模型自己决定是否调用函数
)
response_message = response.choices[0].message
tool_calls = response_message.tool_calls
# 检查模型是否决定调用函数
if tool_calls:
# 把模型的回复加入消息历史
messages.append(response_message)
for tool_call in tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
print(f"🔧 调用函数: {function_name}")
print(f" 参数: {function_args}")
# 执行函数
function_to_call = AVAILABLE_FUNCTIONS[function_name]
function_result = function_to_call(**function_args)
# 把函数执行结果加入消息历史
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"name": function_name,
"content": json.dumps(function_result, ensure_ascii=False),
})
# 第二轮:把函数结果发给模型,让它生成最终回答
second_response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages,
)
return second_response.choices[0].message.content
# 模型不调用函数,直接返回
return response_message.content
# 测试
print(run_conversation("北京今天天气怎么样?"))
print("---")
print(run_conversation("上海的温度是多少华氏度?"))
4 ~> 实战:AI助手------查数据库+发邮件
4.1 定义多个Tool
python
import sqlite3
import smtplib
from email.mime.text import MIMEText
# Tool 1: 查询订单
order_tool = {
"type": "function",
"function": {
"name": "query_order",
"description": "根据订单号查询订单信息,包括状态、金额、收货地址",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string", "description": "订单号"}
},
"required": ["order_id"],
}
}
}
# Tool 2: 发送邮件
email_tool = {
"type": "function",
"function": {
"name": "send_email",
"description": "发送邮件给指定收件人",
"parameters": {
"type": "object",
"properties": {
"to": {"type": "string", "description": "收件人邮箱"},
"subject": {"type": "string", "description": "邮件主题"},
"body": {"type": "string", "description": "邮件正文"},
},
"required": ["to", "subject", "body"],
}
}
}
4.2 实现函数
python
def query_order(order_id: str) -> dict:
"""从数据库查询订单"""
conn = sqlite3.connect("orders.db")
cursor = conn.execute(
"SELECT * FROM orders WHERE id = ?", (order_id,)
)
row = cursor.fetchone()
conn.close()
if row:
return {
"order_id": row[0],
"status": row[1],
"amount": row[2],
"address": row[3],
}
return {"error": f"订单{order_id}不存在"}
def send_email(to: str, subject: str, body: str) -> dict:
"""发送邮件"""
try:
msg = MIMEText(body, "plain", "utf-8")
msg["Subject"] = subject
msg["To"] = to
# 实际发送(此处为示例,需配置SMTP)
# with smtplib.SMTP("smtp.example.com") as server:
# server.send_message(msg)
return {"success": True, "message": f"邮件已发送至 {to}"}
except Exception as e:
return {"success": False, "error": str(e)}
AVAILABLE_FUNCTIONS = {
"query_order": query_order,
"send_email": send_email,
}
ALL_TOOLS = [order_tool, email_tool]
4.3 完整对话处理
python
def ai_assistant(user_message: str) -> str:
"""AI助手入口"""
messages = [{"role": "user", "content": user_message}]
# 循环处理:因为一个请求可能需要多次函数调用
while True:
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages,
tools=ALL_TOOLS,
tool_choice="auto",
)
msg = response.choices[0].message
# 没有函数调用 → 模型给出了最终回答
if not msg.tool_calls:
return msg.content
# 有函数调用 → 执行并继续循环
messages.append(msg)
for tool_call in msg.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
result = AVAILABLE_FUNCTIONS[func_name](**func_args)
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"name": func_name,
"content": json.dumps(result, ensure_ascii=False),
})
# 使用示例
print(ai_assistant("查一下订单#12345的状态,然后发邮件到admin@test.com通知负责人"))
思考 && 总结
- Function Calling把AI从"嘴"升级成"手": 模型只负责"决策"------调用哪个函数、传什么参数,函数的实际执行完全在你的控制之下。
- Tool定义的质量决定调用准确率:
description不仅要写清楚函数做什么,还要告诉模型"什么时候该用"。写得模糊 → 模型乱调用。 - 函数调用可以串联: 上面的例子中,AI自动完成"先查订单→再发邮件"的串联操作。关键在于你用while True循环让模型多轮调用。
- 国产模型支持差异大: GPT和DeepSeek的Function Calling比较成熟,通义千问和GLM的支持在快速追赶。上线前务必测试目标模型的调用准确率。
- 安全是第一优先级: 模型调用什么函数、传什么参数完全是"AI决定"的。对敏感操作(删除、转账)必须加人工确认或权限校验。
Function Calling是AI应用从Demo走向Product的分水岭。
结尾
各位小伙伴,本文的内容到这里就全部结束了,源码骑士在这里再次感谢您的阅读!
源码骑士 --- Android Framework & 全栈开发
👀 关注:跟博主一起从源码视角深耕底层原理,见证每一次成长
❤️ 点赞:让优质内容被更多人看见,让知识传递更有力量
⭐ 收藏:BatchProcessor代码存好,下个批量任务直接复用
💬 评论:你批量调API最高用过多少并发?评论区交流
🔄 一键四连:不要忘记给博主"一键四连"哦!今日并发调优达成!
🗡️ 寄语:慢不是模型的问题,是你的调用方式没有发挥它的并发能力。
结语:现在就把本文的Function Calling循环代码拷进你的项目,给你的AI装上第一个"技能"------查天气也好,查数据库也好。一旦跑通,你会打开一个全新的世界。不要忘记给博主"一键四连"哦!