Function Calling(函数调用)是LLM 工程化、AI 智能体的核心基石。
如果大模型是大脑,那 Function Calling 就是让大脑「指挥手脚干活」的标准协议——它规定了大模型如何描述工具、如何输出调用指令、程序如何执行、如何回传结果

一、Function Calling 是什么?

一句话定义:

Function Calling 是一套固定的 JSON 数据协议,让大模型以结构化格式告诉程序:我需要调用哪个函数、传什么参数。

它的核心分工:

  • LLM:理解意图 → 生成规范的调用格式
  • 程序:解析格式 → 执行函数 → 返回结果
  • LLM:整合结果 → 生成最终回答

二、Function Calling 标准格式拆解

Function Calling 两套核心格式

  1. 工具定义格式(告诉 LLM 有什么函数可用)
  2. 模型返回格式(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"]
      }
    }
  }
]

字段

作用

必须?

name

函数名,程序与模型的唯一对应标识

✅ 必须

description

功能描述,LLM 调用的依据

✅ 必须(写不清楚就调用失败)

parameters

参数定义容器

✅ 必须

properties

所有参数的详细描述

✅ 必须

required

声明哪些参数必填

✅ 推荐

2.2 格式2:模型返回格式

LLM 接收到工具描述后,需要调用时,会返回固定 JSON 格式:

{
  "role": "assistant",
  "content": null,
  "tool_calls": [
    {
      "function": {
        "name": "调用的函数名",
        "arguments": "{\"参数1\":\"值1\",\"参数2\":\"值2\"}"
      }
    }
  ]
}
关键字段
  • name:模型选择的函数
  • arguments:模型生成的参数(JSON 字符串)

三、Function Calling 怎么用?

5 步法

  1. 定义工具函数(写业务代码:计算器/查天气/查数据库)
  2. 封装为标准 FC 格式(上文的工具格式)
  3. 传给 LLM,让模型知道可用工具
  4. LLM 返回调用指令,程序解析并执行函数
  5. 把结果回传给 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 字段

函数名

function.name

函数注释(docstring)

function.description

参数类型注解

properties.type

参数说明

properties.description

查看 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

六、总结

  1. Function Calling = 一套固定 JSON 协议
  2. 两个核心格式:工具定义格式 + 模型返回格式
  3. 5步固定用法:定义工具→封装格式→传给LLM→执行→回传
  4. 工程落地:工具描述是关键,框架自动处理格式

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐