大模型工具调用能力之一——FunctionCalling:大模型的外部能力接口,实现工具调用与任务执行
Function Calling(函数调用)是LLM 工程化、AI 智能体的核心基石。
如果大模型是大脑,那 Function Calling 就是让大脑「指挥手脚干活」的标准协议——它规定了大模型如何描述工具、如何输出调用指令、程序如何执行、如何回传结果。
一、Function Calling 是什么?
一句话定义:
Function Calling 是一套固定的 JSON 数据协议,让大模型以结构化格式告诉程序:我需要调用哪个函数、传什么参数。
它的核心分工:
- LLM:理解意图 → 生成规范的调用格式
- 程序:解析格式 → 执行函数 → 返回结果
- LLM:整合结果 → 生成最终回答
二、Function Calling 标准格式拆解
Function Calling 两套核心格式:
- 工具定义格式(告诉 LLM 有什么函数可用)
- 模型返回格式(LLM 告诉程序要调用什么)
2.1 格式1:工具定义格式
传给大模型的格式,描述函数的名字、功能、参数。
完整标准结构
[
{
"type": "function",
"function": {
"name": "函数名称(英文,程序中真实存在)",
"description": "函数功能描述(LLM靠这个判断是否调用)",
"parameters": {
"type": "object",
"properties": {
"参数1": {
"type": "参数类型(string/number/boolean)",
"description": "参数说明"
},
"参数2": {
"type": "string",
"description": "参数说明"
}
},
"required": ["必填参数1"]
}
}
}
]
|
字段 |
作用 |
必须? |
|
|
函数名,程序与模型的唯一对应标识 |
✅ 必须 |
|
|
功能描述,LLM 调用的依据 |
✅ 必须(写不清楚就调用失败) |
|
|
参数定义容器 |
✅ 必须 |
|
|
所有参数的详细描述 |
✅ 必须 |
|
|
声明哪些参数必填 |
✅ 推荐 |
2.2 格式2:模型返回格式
LLM 接收到工具描述后,需要调用时,会返回固定 JSON 格式:
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"function": {
"name": "调用的函数名",
"arguments": "{\"参数1\":\"值1\",\"参数2\":\"值2\"}"
}
}
]
}
关键字段
name:模型选择的函数arguments:模型生成的参数(JSON 字符串)
三、Function Calling 怎么用?
5 步法:
- 定义工具函数(写业务代码:计算器/查天气/查数据库)
- 封装为标准 FC 格式(上文的工具格式)
- 传给 LLM,让模型知道可用工具
- LLM 返回调用指令,程序解析并执行函数
- 把结果回传给 LLM,生成最终答案
四、JSON 工具封装
1. 手动封装 JSON
步骤 1:定义原始函数
# 原始业务函数
def calculator(num1: float, num2: float, operator: str) -> str:
if operator == "+": return f"结果:{num1+num2}"
if operator == "-": return f"结果:{num1-num2}"
if operator == "*": return f"结果:{num1*num2}"
if operator == "/": return f"结果:{num1/num2}"
return "无效运算符"
步骤 2:严格按照标准封装 JSON
# 手动封装:计算器工具 JSON
tool_json = [
{
"type": "function",
"function": {
"name": "calculator", # 对应函数名
"description": "计算器工具,支持加减乘除计算", # 功能描述
"parameters": {
"type": "object",
"properties": {
"num1": {
"type": "number",
"description": "第一个计算数字"
},
"num2": {
"type": "number",
"description": "第二个计算数字"
},
"operator": {
"type": "string",
"description": "运算符,支持+ - * /"
}
},
"required": ["num1", "num2", "operator"] # 必填参数
}
}
}
]
步骤 3:多工具合并封装
如果有多个工具,直接放在数组里即可:
# 双工具封装:计算器 + 天气查询
tools_json = [
# 计算器工具
{
"type": "function",
"function": {"name": "calculator", "...": "..."}
},
# 天气查询工具
{
"type": "function",
"function": {"name": "weather_query", "...": "..."}
}
]
步骤 4:原生调用验证(无框架)
直接把 JSON 传给模型,完成调用。
4.2 LangChain 自动封装
核心原理:函数与JSON 映射关系
|
Python 函数元素 |
自动封装为 JSON 字段 |
|
函数名 |
|
|
函数注释(docstring) |
|
|
参数类型注解 |
|
|
参数说明 |
|
查看 LangChain 自动生成的 JSON
这是最直观的验证方式,运行代码就能看到封装结果:
from langchain.tools import tool
# 1. 定义工具函数
@tool
def calculator(num1: float, num2: float, operator: str) -> str:
"""计算器工具,支持加减乘除计算"""
if operator == "+": return f"结果:{num1+num2}"
return "计算失败"
# 2. 打印自动封装的 JSON 格式
print("===== LangChain 自动封装的工具 JSON =====")
print(calculator.args_schema.model_json_schema())
===== LangChain 自动封装的工具 JSON =====
{'description': '计算器工具,支持加减乘除计算', 'properties': {'num1': {'title': 'Num1', 'type': 'number'}, 'num2': {'title': 'Num2', 'type': 'number'}, 'operator': {'title': 'Operator', 'type': 'string'}}, 'required': ['num1', 'num2', 'operator'], 'title': 'calculator', 'type': 'object'}
五、实战代码(可直接运行)
用 双工具(计算器+天气查询) 完整演示,框架使用 LangChain,自动处理格式,无需手写 JSON。
1. 完整可执行代码
from langchain_openai import ChatOpenAI
from langchain.tools import tool
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain.prompts import ChatPromptTemplate
import os
from dotenv import load_dotenv
# 加载配置
load_dotenv()
# ===================== 1. 初始化模型 =====================
llm = ChatOpenAI(
model="qwen3.5-flash",
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
temperature=0.1,
)
# ===================== 2. 定义工具(自动封装FC格式) =====================
# 工具1:计算器
@tool
def calculator(num1: float, num2: float, operator: str) -> str:
"""
计算器工具,执行加减乘除
参数:
num1: 数字1
num2: 数字2
operator: 运算符(+ - * /)
"""
if operator == "+": return f"结果:{num1+num2}"
if operator == "-": return f"结果:{num1-num2}"
if operator == "*": return f"结果:{num1*num2}"
if operator == "/": return f"结果:{num1/num2}"
return "无效运算符"
# 工具2:天气查询
@tool
def weather_query(city: str) -> str:
"""
查询城市天气
city: 城市名称
"""
data = {"北京":"晴 25℃","上海":"多云 28℃","广州":"小雨 26℃"}
return data.get(city, "暂无数据")
# 工具列表
tools = [calculator, weather_query]
# ===================== 3. 构建调用流程 =====================
prompt = ChatPromptTemplate.from_messages([
("system", "你是工具调用助手,必须严格按格式调用工具"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
# 创建智能体(自动处理FC格式)
agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True, # 打印完整格式日志
max_iterations=3
)
# ===================== 4. 执行测试 =====================
if __name__ == "__main__":
# 测试1:计算
print("=== 测试1:10乘以6.5 ===")
print(executor.invoke({"input": "10乘以6.5等于多少?"})["output"])
# 测试2:天气
print("\n=== 测试2:查询北京天气 ===")
print(executor.invoke({"input": "北京今天天气怎么样?"})["output"])
3. 运行日志
=== 测试1:10乘以6.5 ===
> Entering new AgentExecutor chain...
Invoking: `calculator` with `{'num1': 10, 'num2': 6.5, 'operator': '*'}`
结果:65.010乘以6.5等于65。
> Finished chain.
10乘以6.5等于65。
=== 测试2:查询北京天气 ===
> Entering new AgentExecutor chain...
Invoking: `weather_query` with `{'city': '北京'}`
晴 25℃北京今天天气晴朗,气温25℃。
> Finished chain.
北京今天天气晴朗,气温25℃。
五、Function Calling 用法核心规则
1. 工具描述决定调用成功率
LLM 不看代码,只看描述!
描述越清晰,调用越准确。
2. 参数类型必须严格定义
数字、字符串不能混淆,否则格式解析失败。
3. 必须限制调用次数
防止无限循环,生产环境必加 max_iterations。
六、总结
- Function Calling = 一套固定 JSON 协议
- 两个核心格式:工具定义格式 + 模型返回格式
- 5步固定用法:定义工具→封装格式→传给LLM→执行→回传
- 工程落地:工具描述是关键,框架自动处理格式
更多推荐


所有评论(0)