大模型 Function Call 原理与应用全景解读

本文基于智谱AI ChatGLM 模型,结合真实代码示例,系统讲解 Function Call 的实现原理与三种典型应用场景,含详细代码解析与注意事项。


一、什么是 Function Call?—— 连接大模型与现实世界的桥梁

Function Call(函数调用)是 OpenAI 于 2023 年 6 月 13 日推出的一项重要功能。它让大语言模型具备了调用外部函数或 API 的能力,从而突破训练数据局限,获取实时信息、执行具体任务。


二、为什么需要 Function Call?—— 解决三大核心问题

问题类型详细说明应用场景举例
信息实时性大模型训练数据存在滞后性,无法获取最新信息实时股价、最新新闻、即时天气
数据局限性模型无法覆盖所有专业领域深度知识医学诊断、法律咨询、金融分析
功能扩展性模型无法执行复杂计算或操作系统功能数学计算、数据分析、文件操作

三、Function Call 工作原理深度解析

3.1 无 Function Call 的传统模式

text

用户 → 应用服务器 → 大模型 → 生成回复

局限性:模型只能基于训练数据生成回复,无法获取最新信息或执行具体操作。

3.2 有 Function Call 的创新模式

  1. 用户请求:发送 prompt 和可用函数定义给应用服务器

  2. 模型判断:GPT 分析是否需要调用函数,返回函数名和参数JSON(不实际执行)

  3. 函数执行:应用服务器根据参数执行相应函数

  4. 结果返回:将函数执行结果返回给 GPT 模型

  5. 最终生成:GPT 结合函数结果生成自然语言回复

关键特点:模型只决定调用什么函数及参数,不实际执行函数,保障了安全性。


四、实战案例一:天气查询机器人(单一函数应用)

4.1 项目结构

text

weather/
├── tools.py                 # 函数实现
├── weather_zhipu.py         # 主逻辑
├── cityCode_use.json        # 城市编码表
└── .env                     # 环境变量(存储API密钥)

4.2 核心代码详解

4.2.1 天气查询函数实现 (tools.py)

python

import json
import requests

def get_current_weather(location):
    """获取指定城市的当前天气信息"""
    # 读取城市编码表
    with open('./cityCode_use.json', 'r') as file:
        data = json.load(file)
    
    city_code = None
    # 匹配城市编码
    for loc in data:
        if location == loc["市名"]:
            city_code = loc["编码"]
            break
    
    # 调用天气API
    if city_code:
        weather_url = f"http://t.weather.itboy.net/api/weather/city/{city_code}"
        response = requests.get(weather_url)
        result = response.json()
        forecast = result["data"]["forecast"][0]
        
        weather_info = {
            "location": location,
            "high_temperature": forecast["high"],
            "low_temperature": forecast["low"],
            "week": forecast["week"],
            "type": forecast["type"],
        }
        return json.dumps(weather_info, ensure_ascii=False)
    else:
        return json.dumps({"error": "城市不存在"}, ensure_ascii=False)
4.2.2 函数描述定义 (tools.py)

python

tools = [
    {
        'type': 'function',
        'function': {
            'name': 'get_current_weather',
            'description': '获取给定位置的当前天气',
            'parameters': {
                'type': 'object',
                'properties': {
                    'location': {
                        'type': 'string',
                        'description': '城市或区,例如北京、海淀',
                    },
                },
                'required': ['location'],
            },
        }
    }
]
4.2.3 主逻辑实现 (weather_zhipu.py)

python

import os
from dotenv import load_dotenv, find_dotenv
from tools import *
from zhipuai import ZhipuAI

# 加载环境变量
_ = load_dotenv(find_dotenv())
zhupu_ak = os.environ['zhupu_api']
client = ZhipuAI(api_key=zhupu_ak)
ChatGLM = "glm-4"

def chat_completion_request(messages, tools=None, tool_choice=None, model=ChatGLM):
    """调用智谱AI聊天 completion API"""
    try:
        response = client.chat.completions.create(
            model=model,
            messages=messages,
            tools=tools,
            tool_choice=tool_choice
        )
        return response
    except Exception as e:
        print(f"Unable to generate ChatCompletion response: {e}")
        return None

def main():
    """主函数"""
    messages = [
        {"role": "system", "content": "你是一个天气播报小助手,你需要根据用户提供的地址来回答当地的天气情况。"},
        {"role": "user", "content": "今天北京的天气如何"}
    ]
    
    # 第一次调用模型
    response = chat_completion_request(messages, tools=tools, tool_choice="auto")
    
    # 解析模型响应,执行函数
    if response and response.choices[0].message.tool_calls:
        function_response = parse_response(response)
        
        # 将函数结果添加到消息中
        tool_call = response.choices[0].message.tool_calls[0]
        messages.append({
            "role": "tool",
            "tool_call_id": tool_call.id,
            "name": tool_call.function.name,
            "content": function_response
        })
        
        # 第二次调用模型,生成最终回复
        last_response = chat_completion_request(messages, tools=tools, tool_choice="auto")
        print(f"最终回复: {last_response.choices[0].message.content}")

if __name__ == "__main__":
    main()

4.3 实际运行效果

text

用户:今天北京的天气如何?
模型:根据您的查询,我获取到了北京市当前的天气情况。今天是星期一,北京的天气情况是晴天,最高气温为33℃,最低气温为17℃。请注意天气变化,做好防晒和保暖措施。

五、实战案例二:航班查询系统(多函数应用)

5.1 项目结构

text

airplane/
├── muti_utils.py                 # 多个函数实现
├── airplane_function_tools.py    # 函数描述定义
└── muti_function_zhipu.py        # 主逻辑

5.2 核心代码详解

5.2.1 多函数实现 (muti_utils.py)

python

import json

def get_plane_number(date, start, end):
    """根据日期、出发地、目的地查询航班号"""
    # 模拟航班数据(实际应用中应调用航班API)
    plane_number = {
        "北京": {"深圳": "126", "广州": "356"},
        "郑州": {"北京": "1123", "天津": "3661"}
    }
    
    return {"date": date, "number": plane_number[start][end]}

def get_ticket_price(date, number):
    """根据日期和航班号查询票价"""
    # 模拟票价查询(实际应用中应调用票价API)
    print(f"查询日期: {date}, 航班号: {number}")
    return {"ticket_price": "668"}

def parse_function_call(model_response):
    """解析模型响应,执行相应函数"""
    function_result = ""
    if model_response.choices[0].message.tool_calls:
        tool_call = model_response.choices[0].message.tool_calls[0]
        args = json.loads(tool_call.function.arguments)
        
        if tool_call.function.name == "get_plane_number":
            function_result = get_plane_number(**args)
        elif tool_call.function.name == "get_ticket_price":
            function_result = get_ticket_price(**args)
            
    return function_result
5.2.2 多函数描述定义 (airplane_function_tools.py)

python

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_plane_number",
            "description": "根据出发地、目的地和日期,查询对应日期的航班号",
            "parameters": {
                "type": "object",
                "properties": {
                    "start": {"type": "string", "description": "出发地"},
                    "end": {"type": "string", "description": "目的地"},
                    "date": {"type": "string", "description": "日期"}
                },
                "required": ["start", "end", "date"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "get_ticket_price",
            "description": "查询某航班在某日的价格",
            "parameters": {
                "type": "object",
                "properties": {
                    "number": {"type": "string", "description": "航班号"},
                    "date": {"type": "string", "description": "日期"}
                },
                "required": ["number", "date"]
            }
        }
    }
]

5.3 实际运行效果

text

用户:帮我查询2024年4月2日,郑州到北京的航班的票价
模型:2024年4月2日,郑州到北京的航班号为1123,票价为668元。

六、实战案例三:数据库查询助手(SQL连接应用)

6.1 项目结构

text

sql/
├── sql_function_tools.py    # 数据库查询函数
└── sql_zhipu.py            # 主逻辑

6.2 核心代码详解

6.2.1 数据库查询函数 (sql_function_tools.py)

python

import json
import pymysql

# 数据库表结构描述
database_schema_string = """
CREATE TABLE `emp` (
  `empno` int DEFAULT NULL, --员工编号
  `ename` varchar(50) DEFAULT NULL, --员工姓名
  `job` varchar(50) DEFAULT NULL, --员工工作
  `mgr` int DEFAULT NULL, --员工领导
  `hiredate` date DEFAULT NULL, --入职日期
  `sal` int DEFAULT NULL, --月薪
  `comm` int DEFAULT NULL, --年终奖
  `deptno` int DEFAULT NULL --部门编号
)"""

def ask_database(query):
    """执行SQL查询并返回结果"""
    try:
        # 连接MySQL数据库
        conn = pymysql.connect(
            host='localhost',
            port=3306,
            user='root',
            password='123456',
            database='it_heima',
            charset='utf8mb4'
        )
        
        # 执行查询
        cursor = conn.cursor()
        cursor.execute(query)
        result = cursor.fetchall()
        
        # 关闭连接
        cursor.close()
        conn.close()
        
        return str(result)
    except Exception as e:
        return f"查询错误: {str(e)}"

# 函数描述
tools = [
    {
        "type": "function",
        "function": {
            "name": "ask_database",
            "description": "使用此函数回答业务问题,要求输出是一个SQL查询语句",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": f"SQL查询语句,基于以下数据库结构:{database_schema_string}"
                    }
                },
                "required": ["query"]
            }
        }
    }
]

6.3 实际运行效果

text

用户:查询一下最高工资的员工姓名及对应的工资
模型:根据您的查询,我已经为您找到了工资最高的员工。这位员工的姓名是KING,他的工资是5000元。

七、开发注意事项与最佳实践

7.1 安全性考虑

  1. 函数执行权限控制:确保模型只能调用允许的函数

  2. 参数验证:对所有函数参数进行严格验证,防止注入攻击

  3. API密钥管理:使用环境变量或密钥管理服务,不要硬编码在代码中

7.2 性能优化

  1. 函数调用缓存:对相同参数的函数调用结果进行缓存

  2. 超时处理:设置函数调用超时时间,避免长时间阻塞

  3. 批量处理:尽可能批量处理数据,减少API调用次数

7.3 错误处理

  1. 函数执行失败:提供有意义的错误信息返回给模型

  2. 网络异常:实现重试机制处理网络波动

  3. 模型理解偏差:通过提示工程优化函数描述,提高模型理解准确性


八、总结与展望

Function Call 技术极大地扩展了大模型的能力边界,使其从单纯的文本生成工具转变为能够连接现实世界数据与服务的智能助手。通过本文介绍的三种典型应用场景,开发者可以快速掌握这一技术的核心原理与实践方法。

未来,随着多模态模型和工具调用能力的进一步发展,Function Call 将在更多领域发挥重要作用,如物联网控制、自动化工作流、智能决策支持等。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐