LLM 应用开发实战 #6:Function Calling 让大模型拥有"超能力"

本系列文章将系统讲解如何从零开始构建基于大语言模型的应用程序,涵盖 Prompt Engineering、RAG、Agent、微调等核心技术。

什么是 Function Calling?

Function Calling(函数调用)是 OpenAI 在 2023 年 6 月推出的革命性功能,它让大语言模型能够**识别何时需要调用外部工具**,并生成符合函数签名的结构化参数。

简单来说,Function Calling 让 LLM 从"只会聊天"变成了"能动手做事":

  • 🌤️ 查询实时天气
  • 📊 操作数据库
  • 🔍 搜索互联网
  • 📧 发送邮件
  • 🧮 执行复杂计算
  • 核心原理

    Function Calling 的工作流程分为三步:

    1. **定义工具**:向模型描述可用的函数及其参数

    2. **模型决策**:模型判断是否需要调用函数,以及调用哪个函数

    3. **执行反馈**:程序执行函数,将结果返回给模型生成最终回复

    
    用户提问 → LLM 分析 → 需要工具?→ 生成函数调用 → 执行函数 → 返回结果 → LLM 生成回复
                    ↓
                  不需要 → 直接回答
    

    实战代码演示

    基础示例:天气查询助手

    
    import json
    import openai
    
    # 1. 定义可用函数
    functions = [
        {
            "name": "get_weather",
            "description": "获取指定城市的当前天气信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "城市名称,如\"北京\"、\"上海\""
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "温度单位"
                    }
                },
                "required": ["city"]
            }
        }
    ]
    
    # 2. 模拟天气查询函数
    def get_weather(city: str, unit: str = "celsius"):
        """模拟天气API调用"""
        weather_data = {
            "北京": {"temp": 22, "condition": "晴朗"},
            "上海": {"temp": 25, "condition": "多云"},
            "广州": {"temp": 28, "condition": "小雨"}
        }
        data = weather_data.get(city, {"temp": 20, "condition": "未知"})
        return json.dumps(data, ensure_ascii=False)
    
    # 3. 主对话流程
    def chat_with_functions(user_message):
        messages = [
            {"role": "system", "content": "你是一个 helpful 的助手,可以使用工具帮助用户。"},
            {"role": "user", "content": user_message}
        ]
        
        # 第一次调用:让模型决定是否使用工具
        response = openai.chat.completions.create(
            model="gpt-4o",
            messages=messages,
            functions=functions,
            function_call="auto"
        )
        
        message = response.choices[0].message
        
        # 检查是否需要调用函数
        if message.function_call:
            function_name = message.function_call.name
            function_args = json.loads(message.function_call.arguments)
            
            print(f"🤖 模型决定调用函数: {function_name}")
            print(f"📋 参数: {function_args}")
            
            # 执行函数
            if function_name == "get_weather":
                result = get_weather(**function_args)
                
                # 将函数结果返回给模型
                messages.append(message)
                messages.append({
                    "role": "function",
                    "name": function_name,
                    "content": result
                })
                
                # 第二次调用:让模型生成最终回复
                final_response = openai.chat.completions.create(
                    model="gpt-4o",
                    messages=messages
                )
                return final_response.choices[0].message.content
        
        return message.content
    
    # 测试
    print(chat_with_functions("北京今天天气怎么样?"))
    

    输出:

    
    🤖 模型决定调用函数: get_weather
    📋 参数: {"city": "北京"}
    北京今天天气晴朗,气温 22°C,是个出门的好日子!
    

    进阶示例:多函数智能助手

    
    functions = [
        {
            "name": "search_products",
            "description": "搜索商品信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "keyword": {"type": "string", "description": "搜索关键词"},
                    "category": {"type": "string", "description": "商品类别"},
                    "max_price": {"type": "number", "description": "最高价格"}
                },
                "required": ["keyword"]
            }
        },
        {
            "name": "create_order",
            "description": "创建订单",
            "parameters": {
                "type": "object",
                "properties": {
                    "product_id": {"type": "string"},
                    "quantity": {"type": "integer"},
                    "address": {"type": "string"}
                },
                "required": ["product_id", "quantity"]
            }
        },
        {
            "name": "calculate_shipping",
            "description": "计算运费",
            "parameters": {
                "type": "object",
                "properties": {
                    "weight_kg": {"type": "number"},
                    "destination": {"type": "string"}
                },
                "required": ["weight_kg", "destination"]
            }
        }
    ]
    

    Function Calling vs RAG

    | 特性 | Function Calling | RAG |

    |------|------------------|-----|

    | **数据来源** | 实时 API、数据库、外部服务 | 预处理的文档向量库 |

    | **响应时效** | 实时获取 | 基于已有知识 |

    | **适用场景** | 动态数据、操作执行 | 静态知识问答 |

    | **实现复杂度** | 需要开发接口 | 需要构建向量库 |

    | **典型应用** | 天气查询、订单管理、数据分析 | 客服问答、文档检索 |

    两者可以结合使用:先用 RAG 检索相关知识,再用 Function Calling 执行具体操作。

    最佳实践

    1. 函数描述要清晰

    
    # ❌ 不好的描述
    {"name": "get_data", "description": "获取数据"}
    
    # ✅ 好的描述
    {
        "name": "query_user_orders",
        "description": "查询指定用户在最近30天内的订单列表,支持按状态筛选。需要用户授权后才能调用。"
    }
    

    2. 参数设计要精确

    
    {
        "parameters": {
            "properties": {
                "date_range": {
                    "type": "string",
                    "description": "日期范围,格式:YYYY-MM-DD to YYYY-MM-DD,如 '2024-01-01 to 2024-01-31'"
                }
            }
        }
    }
    

    3. 错误处理要完善

    
    def safe_function_call(func_name, args):
        try:
            if func_name not in available_functions:
                return json.dumps({"error": f"Unknown function: {func_name}"})
            
            result = available_functions[func_name](**args)
            return json.dumps({"success": True, "data": result})
        except Exception as e:
            return json.dumps({"success": False, "error": str(e)})
    

    4. 控制函数调用频率

    
    # 限制每轮最多调用3个函数
    MAX_FUNCTION_CALLS = 3
    call_count = 0
    
    while call_count < MAX_FUNCTION_CALLS:
        response = openai.chat.completions.create(...)
        if not response.choices[0].message.function_call:
            break
        call_count += 1
    

    主流模型支持情况

    | 模型 | Function Calling | 特点 |

    |------|------------------|------|

    | GPT-4/GPT-4o | ✅ 原生支持 | 最成熟稳定 |

    | Claude 3 | ✅ 原生支持 | tool_use 功能 |

    | Gemini Pro | ✅ 原生支持 | function_declarations |

    | Llama 3 | ⚠️ 需引导 | 通过 prompt 模拟 |

    | Qwen | ✅ 原生支持 | 国产模型表现优秀 |

    实际应用场景

    1. 智能客服机器人

  • 查询订单状态
  • 修改配送地址
  • 申请退款退货
  • 2. 数据分析助手

  • 连接数据库执行 SQL
  • 生成可视化图表
  • 导出报表文件
  • 3. 个人效率工具

  • 添加日历事件
  • 发送邮件/消息
  • 管理待办事项
  • 4. 企业级 Agent

  • 审批工作流
  • 跨系统数据同步
  • 自动化运维操作
  • 下节预告

    在下一篇文章中,我们将深入探讨 **Agent 架构设计**,学习如何让多个 Function 协同工作,构建真正自主决策的智能代理系统。

    ---

    *本文是《LLM 应用开发实战》系列第6篇,系列文章持续更新中...*

    *相关阅读:*

  • *#5: Embedding 与向量数据库入门*
  • *#7: Agent 架构设计与实现(即将发布)*
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐