Function Calling实战:用10行代码让大模型帮你查天气、查股票、调内部API

7 阅读7分钟

Function Calling是大模型从"聊天工具"变成"工作代理"的关键能力。本文通过3个真实场景,带你从原理到落地完整掌握这项技术。


什么是Function Calling?

大模型默认只能处理文字——它接收文本输入,输出文本结果。但现实中的工作往往需要调用外部系统:查实时天气、读数据库、发邮件……

Function Calling(函数调用)  就是让大模型具备"调工具"能力的机制:

  1. 你告诉模型"你可以用这些函数"
  2. 模型判断是否需要调用某个函数
  3. 如果需要,模型返回"我要调用XX函数,参数是XX"
  4. 你的代码执行这个函数,把结果返回给模型
  5. 模型基于真实数据,给出最终回答

这个流程让大模型从静态的知识库变成了能与现实世界交互的智能体。


一、原理图解

用户提问
    ↓
[大模型] → "我需要查天气" → 返回函数调用请求
    ↓
[你的代码] → 调用真实天气API → 获取实时数据
    ↓
[大模型] → 基于真实数据 → 生成自然语言回答
    ↓
返回用户

整个过程对用户来说是透明的,他只问了一句"今天北京天气怎么样",背后发生了完整的"判断→调用→整合→回答"链路。


二、基础实现:查天气示例

下面用 OpenAI API 实现一个完整的天气查询助手:

2.1 定义函数描述

这是Function Calling的核心——你需要用JSON Schema告诉模型每个函数的用途和参数:

import openai
import json
import requests

client = openai.OpenAI(api_key="your-api-key")

# 定义工具列表(告诉模型可以调用哪些函数)
tools = [
    {
        "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"]
            }
        }
    }
]

2.2 实现真实的天气查询函数

def get_weather(city: str, unit: str = "celsius") -> dict:
    """调用真实天气API(以和风天气为例)"""
    # 这里用和风天气API,免费额度每天1000次
    api_key = "your-hefeng-api-key"
    
    # 先获取城市ID
    location_url = f"https://geoapi.qweather.com/v2/city/lookup?location={city}&key={api_key}"
    location_data = requests.get(location_url).json()
    
    if not location_data.get("location"):
        return {"error": f"找不到城市:{city}"}
    
    location_id = location_data["location"][0]["id"]
    
    # 获取实时天气
    weather_url = f"https://devapi.qweather.com/v7/weather/now?location={location_id}&key={api_key}"
    weather_data = requests.get(weather_url).json()
    
    now = weather_data["now"]
    temp = now["temp"]
    
    if unit == "fahrenheit":
        temp = int(temp) * 9/5 + 32
    
    return {
        "city": city,
        "temperature": f"{temp}°{'C' if unit == 'celsius' else 'F'}",
        "condition": now["text"],
        "humidity": f"{now['humidity']}%",
        "wind": f"{now['windDir']} {now['windSpeed']}km/h"
    }

2.3 主对话循环

def chat_with_tools(user_message: str) -> str:
    messages = [{"role": "user", "content": user_message}]
    
    # 第一次请求:让模型判断是否需要调用函数
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        tools=tools,
        tool_choice="auto"  # 让模型自动决定是否调用工具
    )
    
    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)
            
            print(f"🔧 调用函数:{func_name},参数:{func_args}")
            
            # 路由到对应函数
            if func_name == "get_weather":
                result = get_weather(**func_args)
            else:
                result = {"error": f"未知函数:{func_name}"}
            
            # 把函数结果返回给模型
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": json.dumps(result, ensure_ascii=False)
            })
        
        # 第二次请求:让模型基于函数结果生成最终回答
        final_response = client.chat.completions.create(
            model="gpt-4o",
            messages=messages
        )
        return final_response.choices[0].message.content
    
    # 不需要调用函数,直接返回
    return message.content

# 测试
print(chat_with_tools("今天北京天气怎么样?适合出门跑步吗?"))

输出示例:

🔧 调用函数:get_weather,参数:{'city': '北京'}
今天北京天气晴,气温22°C,湿度45%,吹东北风3级。
非常适合出门跑步!温度适宜,风力不大,建议带上太阳镜防紫外线。

三、进阶场景:同时注册多个工具

真实应用中往往需要多个工具协同工作。下面扩展一个可以"查天气 + 查股票"的助手:

# 股票查询函数定义
stock_tool = {
    "type": "function",
    "function": {
        "name": "get_stock_price",
        "description": "获取A股或港股的实时股价和涨跌信息",
        "parameters": {
            "type": "object",
            "properties": {
                "symbol": {
                    "type": "string",
                    "description": "股票代码,如:000001(平安银行)、600519(贵州茅台)"
                }
            },
            "required": ["symbol"]
        }
    }
}

def get_stock_price(symbol: str) -> dict:
    """调用行情数据API"""
    # 使用聚合数据等免费API
    url = f"https://stock.xueqiu.com/v5/stock/quote.json?symbol={symbol}&extend=detail"
    headers = {"Cookie": "your-xueqiu-cookie"}  # 雪球API需要cookie
    
    # 简化示例,实际需要处理认证
    return {
        "symbol": symbol,
        "name": "示例股票",
        "price": "45.23",
        "change": "+1.23%",
        "volume": "12.3亿"
    }

# 把两个工具合并
tools = [tools[0], stock_tool]  # 天气 + 股票

模型会自动判断用户提问需要调用哪个工具,甚至在一次对话中依次调用多个工具。


四、企业实战:接入内部API

Function Calling最大的价值在于连接企业内部系统。以下是一个接入工单系统的例子:

# 工单查询工具
ticket_tools = [
    {
        "type": "function",
        "function": {
            "name": "query_tickets",
            "description": "查询客户工单状态,支持按状态、时间范围过滤",
            "parameters": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "string",
                        "enum": ["open", "processing", "closed", "all"],
                        "description": "工单状态"
                    },
                    "customer_id": {
                        "type": "string",
                        "description": "客户ID(可选)"
                    },
                    "days": {
                        "type": "integer",
                        "description": "查询最近N天的工单,默认7天"
                    }
                },
                "required": ["status"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "create_ticket",
            "description": "创建新工单",
            "parameters": {
                "type": "object",
                "properties": {
                    "title": {"type": "string", "description": "工单标题"},
                    "description": {"type": "string", "description": "问题描述"},
                    "priority": {
                        "type": "string",
                        "enum": ["low", "medium", "high", "urgent"]
                    },
                    "customer_id": {"type": "string"}
                },
                "required": ["title", "description", "priority"]
            }
        }
    }
]

有了这两个工具,客服系统就可以这样工作:

用户:"客户C001最近有什么未处理的工单?"
模型:调用 query_tickets(status="open", customer_id="C001")
模型:"C001客户有3个未处理工单:
  1. 数据库连接超时(高优先级,2天前创建)
  2. 账单金额异常(中优先级,昨天创建)
  3. 功能权限申请(低优先级,今天创建)"

五、各模型对比

不只是OpenAI支持Function Calling,国内主流大模型也已全面支持:

模型是否支持并发函数调用中文支持API价格(输入)
GPT-4o$5/M tokens
GPT-4o-mini$0.15/M tokens
通义千问-Plus⭐⭐⭐¥4/M tokens
文心4.5⭐⭐⭐¥4/M tokens
DeepSeek-V3⭐⭐⭐¥2/M tokens
混元-Large⭐⭐⭐¥4/M tokens

实测建议

  • 国内业务优先用 DeepSeek-V3(价格最低,中文最好)
  • 复杂多步骤任务用 GPT-4o(推理能力更稳定)
  • 高并发低延迟场景用 GPT-4o-mini 或通义千问-Turbo

六、注意事项和常见坑

1. 函数描述要写清楚

模型完全依靠 description 字段来决定调不调这个函数。描述模糊会导致调用错误或不调用。

2. 参数校验不要省

模型填充的参数可能不符合你的预期,一定要在函数内部做验证:

def get_weather(city: str, unit: str = "celsius"):
    if not city or len(city) > 50:
        return {"error": "城市名称无效"}
    if unit not in ["celsius", "fahrenheit"]:
        unit = "celsius"
    # ... 正常逻辑

3. 处理函数调用失败

网络请求可能失败,要给模型一个有意义的错误信息,而不是抛异常:

try:
    result = call_external_api(...)
except Exception as e:
    result = {"error": str(e), "suggestion": "请稍后重试"}

4. 防止无限循环

复杂任务中,模型可能连续调用多个工具。建议设置最大循环次数:

MAX_ITERATIONS = 5
for i in range(MAX_ITERATIONS):
    # ... 处理逻辑
    if not message.tool_calls:
        break

总结

Function Calling 是大模型落地企业应用最重要的基础能力之一:

  • 查询场景:让模型接入实时数据(天气/股票/订单)
  • 操作场景:让模型执行动作(发邮件/创建工单/写数据库)
  • 编排场景:多工具协同,完成复杂任务

核心三步记住了:定义工具 → 执行调用 → 返回结果。代码框架基本固定,换不同的工具只需要替换函数实现即可。


关于作者

长期关注大模型应用落地与云服务器实战,专注技术在企业场景中的落地实践。

个人博客:yunduancloud.icu —— 持续更新云计算、AI大模型实战教程,欢迎访问交流。