AI Agent 从入门到封神:24 讲打造你的超级智能体~系列文章07:Agent调用工具的底层原理与代码实战
·
Function Calling深度解析:Agent调用工具的底层原理与代码实战 🔧
导读:Function Calling是AI Agent的核心能力——没有它,Agent就只是一个"只会说不会做"的聊天机器人。今天我们从底层原理到代码实战,彻底搞懂Function Calling的工作机制。学完这篇,你就能自己设计任何复杂的工具系统!💪
一、Function Calling是什么?一句话讲透 🎯
Function Calling = 让大模型能够"结构化地"调用外部函数/工具的能力。
什么意思?看这个对比:
| 方式 | 示例 | 问题 |
|---|---|---|
| ❌ 没有Function Calling | 模型输出:“我建议你去搜索一下北京天气” | 只是文字建议,不会真的去搜索 |
| ✅ 有Function Calling | 模型输出:{"name": "get_weather", "args": {"city": "北京"}} |
结构化指令,系统会真的调用天气API |
二、Function Calling的完整工作流程 🔄
2.1 六步工作流
2.2 每一步详解
| 步骤 | 执行者 | 动作 | 关键技术 |
|---|---|---|---|
| 1 | 用户 | 发送自然语言请求 | - |
| 2 | 大模型 | 判断是否需要工具 | 意图识别 |
| 3 | 大模型 | 生成结构化调用请求 | JSON Schema |
| 4 | 系统 | 解析并执行函数 | 函数路由 |
| 5 | 外部API | 返回执行结果 | API调用 |
| 6 | 大模型 | 基于结果生成回答 | 结果整合 |
三、工具定义的JSON Schema详解 📋
Function Calling的核心是工具定义。模型通过阅读工具定义来了解:
- 有哪些工具可用
- 每个工具做什么
- 需要什么参数
3.1 一个完整的工具定义
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的当前天气信息,包括温度、天气状况、湿度和风速。",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如'北京'、'上海'"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位,默认为celsius"
}
},
"required": ["city"]
}
}
}
3.2 Schema各字段说明
| 字段 | 作用 | 重要程度 | 说明 |
|---|---|---|---|
| name | 工具名称 | ⭐⭐⭐⭐⭐ | 模型通过名称选择工具,必须简洁明确 |
| description | 工具描述 | ⭐⭐⭐⭐⭐ | 模型通过描述理解工具用途,越详细越好 |
| parameters | 参数定义 | ⭐⭐⭐⭐⭐ | 模型根据参数定义生成正确的调用参数 |
| required | 必填参数 | ⭐⭐⭐⭐ | 告诉模型哪些参数是必须的 |
| enum | 参数取值范围 | ⭐⭐⭐ | 限制参数取值,减少错误 |
⭐ 重点:description是灵魂! 模型完全靠description来决定什么时候用这个工具。写得不好,模型就选不对。
四、代码实战:从零实现Function Calling 💻
4.1 原生OpenAI API实现
import json
from openai import OpenAI
client = OpenAI()
# Step 1: 定义工具
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": "数学表达式,如 '2 + 3 * 4'"
}
},
"required": ["expression"]
}
}
}
]
# Step 2: 定义实际的函数实现
def get_weather(city: str) -> str:
"""实际的天气查询逻辑(这里简化为模拟)"""
weather_data = {
"北京": "晴天,25°C,湿度40%",
"上海": "多云,22°C,湿度65%",
"广州": "小雨,28°C,湿度80%",
}
return weather_data.get(city, f"暂无{city}的天气数据")
def calculate(expression: str) -> str:
"""实际的计算逻辑"""
try:
result = eval(expression, {"__builtins__": {}}, {})
return f"{expression} = {result}"
except Exception as e:
return f"计算错误: {e}"
# 函数映射表
function_map = {
"get_weather": get_weather,
"calculate": calculate,
}
# Step 3: 发送请求
messages = [{"role": "user", "content": "北京今天天气怎么样?顺便帮我算一下25摄氏度等于多少华氏度"}]
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
)
# Step 4: 处理工具调用
message = response.choices[0].message
if message.tool_calls:
# 将模型的回复加入消息历史
messages.append(message)
# 逐个执行工具调用
for tool_call in message.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
# 调用对应的函数
result = function_map[func_name](**func_args)
# 将工具结果返回给模型
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
# Step 5: 让模型基于工具结果生成最终回答
final_response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
)
print(final_response.choices[0].message.content)
# 输出:北京今天是晴天,气温25°C。25°C等于77°F。
4.2 LangChain方式实现(更简洁)
from langchain.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
# 用@tool装饰器定义工具(更Pythonic)
@tool
def get_weather(city: str) -> str:
"""获取指定城市的天气信息。当用户询问天气时使用。
Args:
city: 城市名称,如'北京'、'上海'
"""
weather_data = {
"北京": "晴天,25°C,湿度40%",
"上海": "多云,22°C,湿度65%",
}
return weather_data.get(city, f"暂无{city}的天气数据")
@tool
def calculate(expression: str) -> str:
"""执行数学计算。当需要精确计算时使用。
Args:
expression: 数学表达式
"""
return f"{expression} = {eval(expression, {'__builtins__': {}}, {})}"
# 创建Agent(自动处理Function Calling的整个流程)
agent = create_react_agent(
model=ChatOpenAI(model="gpt-4o"),
tools=[get_weather, calculate],
)
# 直接调用,框架自动处理工具调用循环
result = agent.invoke({
"messages": [("user", "北京天气怎么样?算一下25°C等于多少°F")]
})
💡 对比:LangChain帮你封装了所有繁琐的循环逻辑,你只需要定义工具和Agent,剩下的框架自动搞定。
五、并行工具调用 ⚡
当用户的一个请求需要调用多个工具时,模型可以一次性返回多个工具调用请求:
5.1 并行调用流程
5.2 并行调用代码
# 模型可能一次返回多个tool_calls
# message.tool_calls = [
# ToolCall(name="get_weather", args={"city": "北京"}, id="call_1"),
# ToolCall(name="get_weather", args={"city": "上海"}, id="call_2"),
# ]
# 并行执行所有工具调用
import concurrent.futures
def execute_tool_calls(tool_calls):
"""并行执行多个工具调用"""
with concurrent.futures.ThreadPoolExecutor() as executor:
futures = {}
for tc in tool_calls:
func = function_map[tc.function.name]
args = json.loads(tc.function.arguments)
futures[tc.id] = executor.submit(func, **args)
results = {}
for tc_id, future in futures.items():
results[tc_id] = future.result()
return results
六、高级技巧:动态工具注册 🔄
6.1 根据上下文动态选择工具
def get_tools_for_context(user_role):
"""根据用户角色动态选择可用工具"""
base_tools = [search, calculate] # 所有人都有
role_tools = {
"admin": [delete_data, manage_users], # 管理员额外工具
"analyst": [query_db, export_report], # 分析师额外工具
"viewer": [], # 访客无额外工具
}
return base_tools + role_tools.get(user_role, [])
# 使用
admin_agent = create_react_agent(
model=llm,
tools=get_tools_for_context("admin"),
)
6.2 工具注册策略对比
| 策略 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 静态注册 | 工具数量少(<10) | 简单直接 | 工具多了模型选不准 |
| 动态注册 | 工具数量多(>10) | 按需加载,准确率高 | 需要额外的路由逻辑 |
| 分层注册 | 复杂系统 | 结构清晰 | 实现复杂 |
七、常见问题与解决方案 🐛
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 🔴 模型不调用工具 | 工具描述不够明确 | 在description中加"当…时使用" |
| 🔴 模型选错工具 | 工具描述太相似 | 让每个工具的描述更独特 |
| 🔴 参数格式错误 | 参数描述不清晰 | 在description中给出示例 |
| 🔴 无限循环调用 | 缺少终止条件 | 设置max_iterations |
| 🔴 工具返回太长 | 没有限制输出 | 在工具中截断输出 |
八、本期小结 📝
| 知识点 | 核心内容 |
|---|---|
| 什么是Function Calling | 让模型结构化地调用外部工具 |
| 工作流程 | 用户提问→模型判断→生成调用→执行→返回结果→生成回答 |
| 工具定义 | name + description + parameters(JSON Schema) |
| 关键要点 | description是灵魂,required要标对,enum限制取值 |
| 框架选择 | 原生API灵活但繁琐,LangChain简洁且高效 |
🔥 Function Calling是Agent从"能说"到"能做"的关键桥梁。掌握它,你就掌握了Agent开发的核心技能!
📢 下期预告:《多模态Agent来了!让你的智能体同时"看"图、"听"音、"读"视频》—— Agent不只是处理文字,还能看图片、听语音!下期解锁多模态Agent!🖼️🎵
📌 三连走起!Function Calling,Agent的灵魂技能! 💪
📚 专栏第7/24期,大模型基座篇接近尾声!
作者:高炉炼铁智能化技术研究者,专注钢铁冶金与人工智能 交叉领域。
👍 如果觉得有帮助,请点赞、收藏、转发!
版权归作者所有,未经许可请勿抄袭,套用,商用(或其它具有利益性行为)。
🔔 关注专栏,不错过后续精彩内容
更多推荐


所有评论(0)