AI大模型小白手册 | Function Calling-大模型与真实世界交互的桥梁

前言

2023 年之前,大模型是"关在笼子里的天才大脑"------它能写诗、能编程、能回答问题,但它的世界止步于训练数据的截止日期。你不知道今天的天气,查不了实时的股票,动不了数据库里的一行记录。

Function Calling 的出现,打破了这堵墙。

它给大模型装上了"手":模型不再只是"想",还能"做"。当用户说"明天北京适合爬山吗",模型可以调用天气 API 查预报、调用地图 API 查路况、调用笔记工具查你的日程,然后把所有信息整合成一句有温度的建议。

这听起来很美,但真正落地时,你会遇到一连串实际问题:该如何定义工具描述?模型什么时候该调用、什么时候不该调用?多个函数链式调用怎么管理?数据量太大怎么办?模型生成 SQL 不准确怎么优化?

大模型系列目录(持续更新):

AI大模型小白手册|基础原理篇

AI大模型小白手册 | API调用的魔法指南

AI大模型小白手册|如何像工程师一样写Prompt

AI大模型小白手册|Embedding 与向量数据库

AI大模型小白手册 | RAG技术与应用

AI大模型小白手册 | RAG进阶:从胡说八道到引经据典

一、为什么需要 Function Calling?

大模型擅长理解和生成自然语言,但它无法直接操作外部世界。比如:

  • 查询实时天气、股票价格、最新新闻
  • 访问和操作数据库
  • 执行复杂计算
  • 发送邮件或控制智能设备

Function Calling(函数调用) 正是大模型与真实世界交互的"桥梁"------它将大模型从"语言理解"扩展到"具体行动"。

Function Calling 的核心能力

  1. 扩展模型能力:大模型通过调用预设函数,完成自身无法直接完成的任务

  2. 结构化输出:模型将用户的自然语言请求转化为结构化的函数参数。例如:

    1. 用户说"明天北京天气如何?" → 模型调用 get_weather(location="北京", date="2025-05-06")
  3. 动态决策:模型根据上下文自主决定是否调用函数、调用哪个函数,甚至链式调用多个函数(如先查天气再推荐穿搭)


二、Function Calling vs MCP:同与不同

MCP(Model Context Protocol,模型上下文协议)是近年来兴起的一种开放协议,与 Function Calling 作用类似,但定位不同。

维度 Function Calling MCP
定位 模型厂商私有接口(OpenAI、Qwen 等各自实现) 开放协议(类似 HTTP / USB-C 标准)
扩展性 需为每个模型单独适配 一次开发,多模型兼容
复杂性 适合简单、单次调用任务 支持多轮对话与复杂上下文管理
生态依赖 依赖特定模型(如 GPT-4、Qwen) 跨模型跨平台(Claude、Cursor 等均可使用)
安全性 依赖云端 API 密钥 支持本地化数据控制

有了 MCP,还需要 Function Calling 吗?

答案是:两者会共存。

MCP 可能成为主流协议,但 Function Calling 作为大模型的底层标配能力,仍然不可或缺。对于简单、原子化的任务,Function Calling 更加便捷:

  • 查询天气:get_weather(city="北京")
  • 数学计算:calculate(expression="3+5")
  • 发送通知:send_email(to="``user@example.com``")

Function Calling 的优势在于开发快捷(无需配置 MCP Server)、低延迟(单次请求-响应,无协议层开销)。当你只需要让大模型调用一个自己写的函数时,Function Calling 是更直接的选择。


三、Qwen3:本次实战的模型基座

阿里于 2025 年 4 月 29 日发布了 Qwen3 系列模型,包含 8 种不同规模,涵盖密集(Dense)和混合专家(MoE)两种架构,全部基于 Apache 2.0 开源协议,支持免费商用。

MoE 模型(高效推理)

模型 总参数 激活参数 备注
Qwen3-235B-A22B 2350 亿 220 亿 旗舰级,性能接近 Gemini 2.5 Pro
Qwen3-30B-A3B 300 亿 30 亿 仅 10% 激活参数即超越前代 QwQ-32B

Dense 模型(全参数激活)

包括 Qwen3-32B、14B、8B、4B 、1.7B、0.6B。其中 Qwen3-4B 尤其值得关注------它以 4B 的参数量达到了前代 Qwen2.5-72B 的性能水平。这意味着:

  • 推理成本大幅降低(一张 RTX 4090 即可运行)
  • 端侧部署成为可能(手机、IoT 设备)

Qwen3 引入了混合推理模式,模型会自动根据问题决定是否先进行"思考"(thinking)再给出答案,这是小模型性能大幅提升的关键。


四、实战案例一:天气查询助手

整体架构

复制代码
用户提问 → Qwen3 解析意图 → 调用 get_current_weather 工具
→ 高德天气 API → 返回数据 → Qwen3 组织回复 → 展示给用户

Step 1:定义 Function Tool

我们需要定义一个 JSON 格式的工具描述,告诉大模型"你有这么一个函数可以用":

makefile 复制代码
weather_tool = {
    "type": "function",
    "function": {
        "name": "get_current_weather",
        "description": "获取指定地点的当前天气",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "城市名称,如北京"
                },
                "adcode": {
                    "type": "string",
                    "description": "城市编码,如 110000(北京)"
                }
            },
            "required": ["location"]
        }
    }
}

注意name 用英文(因为它是程序中的函数名),description 用中文完全没问题------大模型可以理解中文描述。

Step 2:实现工具函数

python 复制代码
def get_weather_from_gaode(location: str, adcode: str = None):
    """调用高德地图 API 查询天气"""
    gaode_api_key = "你的高德API Key"
    base_url = "https://restapi.amap.com/v3/weather/weatherInfo"
    params = {
        "key": gaode_api_key,
        "city": adcode if adcode else location,
        "extensions": "base",
    }
    response = requests.get(base_url, params=params)
    if response.status_code == 200:
        return response.json()
    else:
        return {"error": f"请求失败: {response.status_code}"}

Step 3:主流程------两次调用大模型

这里有一个关键设计:为什么需要调用大模型两次?

ini 复制代码
def run_weather_query():
    messages = [
        {"role": "system", "content": "你是一个智能助手,可以查询天气信息。"},
        {"role": "user", "content": "北京现在天气怎么样?"}
    ]

    # 第一次调用:让大模型决定是否调用工具
    response = dashscope.Generation.call(
        model="qwen-plus-2025-04-28",
        messages=messages,
        tools=[weather_tool],
        tool_choice="auto",
    )

    if "tool_calls" in response.output.choices[0].message:
        tool_call = response.output.choices[0].message.tool_calls[0]
        if tool_call["function"]["name"] == "get_current_weather":
            import json
            args = json.loads(tool_call["function"]["arguments"])
            location = args.get("location", "北京")
            adcode = args.get("adcode", None)

            # 执行工具函数
            weather_data = get_weather_from_gaode(location, adcode)

            # 第二次调用:将工具结果传给大模型,让它组织自然语言回复
            messages.append({
                "role": "tool",
                "content": json.dumps(weather_data, ensure_ascii=False)
            })
            response2 = dashscope.Generation.call(
                model="qwen-plus-2025-04-28",
                messages=messages,
                tools=[weather_tool],
            )
            print(response2.output.choices[0].message.content)
    else:
        print(response.output.choices[0].message.content)

两次调用的作用

  1. 第一次 :大模型解析用户意图 → 决定调用工具 → 返回 tool_calls(包含参数)
  2. 执行工具:我们拿到参数后调用高德 API,获取天气数据
  3. 第二次:将工具返回的原始数据(JSON)传给大模型 → 大模型将其组织成友好的自然语言回复

"北京现在天气晴朗,温度 17°C,西南风,风力小于 3 级,湿度 44%。"

高德地图 API Key 申请

  1. 登录高德开放平台
  2. 进入「应用管理」→「创建应用」
  3. 选择「出行」类型,添加 Key
  4. 选择「Web 服务」类型,提交后保存 Key

⚠️ 注意:高德 API 有调用频率限制,频繁调用可能被封禁账号。


五、实战案例二:门票业务助手(Text-to-SQL)

这个案例展示了 Function Calling 在企业数据分析中的典型应用:通过自然语言查询数据库。

需求场景

对门票业务数据进行查询,例如:

  • "2023 年 4、5、6 月一日门票和二日门票的销量是多少?按周统计"
  • "2023 年 7 月不同省份的入园人数统计"
  • "2023 年 10 月 1 日至 7 日销售渠道订单金额排名"

搭建流程

Step 1:系统 Prompt --- 给大模型" metadata"

要让大模型写出正确的 SQL,必须先告诉它数据库结构:

scss 复制代码
system_prompt = """我是门票助手,以下是门票订单表相关的字段,我可能会编写对应的SQL进行查询

-- 门票订单表
CREATE TABLE tkt_orders (
    order_time DATETIME,       -- 订单日期
    account_id INT,            -- 预定用户ID
    gov_id VARCHAR(18),        -- 商品使用人身份证号
    gender VARCHAR(10),        -- 使用人性别
    age INT,                   -- 年龄
    province VARCHAR(30),      -- 使用人省份
    SKU VARCHAR(100),          -- 商品SKU名
    product_serial_no VARCHAR(30), -- 商品ID
    eco_main_order_id VARCHAR(20), -- 订单ID
    sales_channel VARCHAR(20), -- 销售渠道
    status VARCHAR(30),        -- 商品状态
    order_value DECIMAL(10,2), -- 订单金额
    quantity INT,              -- 商品数量
    ...
);
"""

除了表结构,业务术语也很关键。比如数据库里"两人门票"可能存的是"1.5 倍",如果你不告诉大模型,它可能写出错误的 SQL。

Step 2:注册工具

使用 Qwen-Agent 框架注册一个执行 SQL 的工具:

python 复制代码
from qwen_agent.tools.base import BaseTool, register_tool

@register_tool('exc_sql')
class ExcSQLTool(BaseTool):
    description = '对生成的SQL进行查询'
    parameters = [{
        'name': 'sql_input',
        'type': 'string',
        'description': '生成的SQL语句',
        'required': True
    }]

    def call(self, params: str, **kwargs) -> str:
        import json
        args = json.loads(params)
        sql_input = args['sql_input']
        database = args.get('database', 'ubr')

        # 创建数据库连接
        engine = create_engine(f"mysql+pymysql://user:pass@host/{database}")
        try:
            df = pd.read_sql(sql_input, engine)
            return df.head(10).to_markdown(index=False)  # 截断行,防止数据过多
        except Exception as e:
            return f"SQL执行出错: {str(e)}"
Step 3:初始化 Assistant 并启动 Web UI
ini 复制代码
from qwen_agent.agents import Assistant

def init_agent_service():
    llm_cfg = {
        'model': 'qwen-turbo-2025-04-28',
        'timeout': 30,
        'retry_count': 3,
    }
    bot = Assistant(
        llm=llm_cfg,
        name='门票助手',
        description='门票查询与订单分析',
        system_message=system_prompt,
        function_list=['exc_sql'],  # 传入已注册的工具名
    )
    return bot

def app_gui():
    bot = init_agent_service()
    chatbot_config = {
        'prompt.suggestions': [
            '2023年4、5、6月一日门票,二日门票的销量多少?按周统计',
            '2023年7月不同省份的入园人数统计',
            '2023年10月1-7日销售渠道订单金额排名',
        ]
    }
    WebUI(bot, chatbot_config=chatbot_config).run()

Qwen-Agent 的 Assistant 会自动处理多轮对话和工具调用的控制逻辑,无需我们自己写复杂的流程管理代码。


六、进阶:数据可视化

在门票助手的基础上,我们还想实现:查询数据后自动生成图表。

方案对比

方案一:单独写一个 plot_data 函数

  • 优点:功能解耦,可复用
  • 缺点:Markdown 传参可能过大;X/Y 轴参数不易传递准确;需先将 Markdown 转回 DataFrame

方案二:在 exc_sql 中集成绘图功能

  • 优点:数据无需二次传递;自动推断图表字段;一次调用完成查询+可视化
  • 最终选择方案二

自动推断逻辑

X 轴:优先选择第一个字符串类型(日期或分类名称)的列

Y 轴:选择所有数值类型的列,支持多系列数据

ini 复制代码
# 自动推断 x/y 字段
x_candidates = df.select_dtypes(include=['object']).columns.tolist()
x = x_candidates[0] if x_candidates else df.columns.tolist()[0]
y_fields = df.select_dtypes(include=['number']).columns.tolist()

# 绘制柱状图
plt.figure(figsize=(8, 5))
bar_width = 0.35 if len(y_fields) > 1 else 0.6
x_labels = df[x].astype(str)
x_pos = range(len(df))

for idx, y_col in enumerate(y_fields):
    plt.bar([p + idx * bar_width for p in x_pos], df[y_col],
            width=bar_width, label=y_col)

版本迭代

整个开发过程经历了三个版本:

版本 功能 说明
assistant_ticket_bot-1 基本查询 Function Calling + exc_sql
assistant_ticket_bot-2 查询+绘图 增加柱状图绘制
assistant_ticket_bot-3 多类别可视化 支持分组与透视(pivot_table)

第三个版本引入了 pivot_table 支持多类别变量的透视图可视化------比如同时按"日期"和"销售渠道"两个维度展示数据。


七、避坑指南与最佳实践

上下文干扰

当连续提问时,大模型可能会受到前文影响。例如,问完"4、5、6 月数据"后再问"第 13 周数据",模型可能会错误地将第 13 周限制在 4-6 月范围内。解决方案是明确指定时间范围

arduino 复制代码
✅ "我看到第13周(2023年3月27日-4月2日)数据有异常..."

数据量过大

  • 查询结果可能多达几十万行,返回给大模型会超出上下文限制
  • 建议对返回结果做截断(如 head(10)),或只返回聚合统计信息

多表关联场景

  • 如果涉及上百张表,不可能把所有 metadata 都塞给大模型
  • 采用两阶段策略:先让大模型根据表名初筛 → 再将被选中的表的 DDL 传给模型生成 SQL

准确性优化

  • 提供业务术语说明(如 SKU 含义、特定的编码规则)
  • 给一些示例 SQL 让大模型模仿
  • 先做测试,定位错误集中在哪里(是大模型 Text-to-SQL 能力不足,还是上下文信息缺失)

八、总结

Function Calling 是大模型的底层标配能力,它让大模型从"只能聊天"进化为"能执行任务"的智能体。无论 MCP 如何发展,Function Calling 作为最直接的工具调用方式,仍是每位 AI 应用开发者必须掌握的技能。

相关推荐
幻奏岚音1 小时前
AI模型用户画像分析_new
人工智能·算法·计算机视觉·数据挖掘
XD7429716361 小时前
科技早报晚报|2026年5月16日:本地化闸门、训练前优化与设备信任栈,今天更值得跟进的 3 个技术机会
人工智能·科技·科技新闻·开发者工具·工程质量·科技早报
hu9245195591 小时前
基于阻尼能量的 P波初至 自动拾取算法
人工智能
fpcc1 小时前
AI和大模型——梯度和梯度下降
人工智能
深度学习lover1 小时前
<数据集>yolo 笔识别<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·笔识别
熊猫钓鱼>_>1 小时前
Q-Learning详解:从理论到实战的完整指南
人工智能·python·架构·大模型·llm·machine learning·q-learning
iskyseraph1 小时前
开源 Skills 全生命周期创造平台
llm·agent·skill
落羽的落羽1 小时前
【项目】C++从零实现JsonRpc框架——项目引入
linux·服务器·开发语言·c++·人工智能·算法·机器学习
pngyul1 小时前
后端微服务的 monorepo-like workspace 方案
ai编程