hugs 文档

函数调用

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

函数调用

函数调用是一项强大的功能,它使大型语言模型 (LLM) 能够以结构化的方式与你的代码和外部系统进行交互。LLM 不仅仅是生成文本响应,还可以理解何时调用特定函数并提供必要的参数来执行现实世界的操作。

函数调用如何工作

该过程遵循以下步骤

Function Calling

这个周期可以根据需要继续进行,从而允许应用程序和 LLM 之间进行复杂的多步交互。

示例用例

函数调用在许多实际应用中非常有用,例如

  1. 数据检索:将自然语言查询转换为 API 调用以获取数据 (例如,“显示我最近的订单”会触发数据库查询)
  2. 执行操作:将用户请求转换为特定的函数调用 (例如,“安排会议”会变成日历 API 调用)
  3. 计算任务:通过专用函数处理数学或逻辑运算 (例如,计算复利或进行统计分析)
  4. 数据处理管道:将多个函数调用链接在一起 (例如,获取数据 → 解析 → 转换 → 存储)
  5. UI/UX 集成:根据用户交互触发界面更新 (例如,更新地图标记或显示图表)

使用工具 (函数定义)

工具是为你的 LLM 定义可调用函数的主要方式。每个工具都需要

  • 一个唯一的名称
  • 一个清晰的描述
  • 一个定义预期参数的 JSON schema

下面是一个定义天气相关函数的示例

from huggingface_hub import InferenceClient

client = InferenceClient("https://:8080") # Replace with your HUGS host
messages = [
    {
        "role": "system",
        "content": "Don't make assumptions about values. Ask for clarification if needed.",
    },
    {
        "role": "user",
        "content": "What's the weather like the next 3 days in San Francisco, CA?",
    },
]

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_n_day_weather_forecast",
            "description": "Get an N-day weather forecast",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "The city and state, e.g. San Francisco, CA",
                    },
                    "format": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "The temperature unit to use",
                    },
                    "num_days": {
                        "type": "integer",
                        "description": "The number of days to forecast",
                    },
                },
                "required": ["location", "format", "num_days"],
            },
        },
    }
]

response = client.chat_completion(
    messages=messages,
    tools=tools,
    tool_choice="auto",
    max_tokens=500,
)
print(response.choices[0].message.tool_calls[0].function)
# ChatCompletionOutputFunctionDefinition(arguments={'format': 'celsius', 'location': 'San Francisco, CA', 'num_days': 3}, name='get_n_day_weather_forecast', description=None)

模型将分析用户的请求并生成对相应函数的结构化调用,同时提供正确的参数。

使用 Pydantic 模型实现结构化输出

为了获得更好的类型安全性和验证,你可以使用 Pydantic 模型来定义你的函数 schema。这种方法提供了

  • 运行时类型检查
  • 自动验证
  • 更好的 IDE 支持
  • 通过 Python 类型提供清晰的文档

以下是如何使用 Pydantic 模型进行函数调用

from pydantic import BaseModel, Field
from typing import List


class ParkObservation(BaseModel):
    location: str = Field(..., description="Where the observation took place")
    activity: str = Field(..., description="What activity was being done")
    animals_seen: int = Field(..., description="Number of animals spotted", ge=1, le=5)
    animals: List[str] = Field(..., description="List of animals observed")


client = InferenceClient("https://:8080")  # Replace with your HUGS host
response_format = {"type": "json", "value": ParkObservation.model_json_schema()}


messages = [
    {
        "role": "user",
        "content": "I saw a puppy, a cat and a raccoon during my bike ride in the park.",
    },
]


response = client.chat_completion(
    messages=messages,
    response_format=response_format,
    max_tokens=500,
)
print(response.choices[0].message.content)
# {   "activity": "bike ride",
#     "animals": ["puppy", "cat", "raccoon"],
#     "animals_seen": 3,
#     "location": "the park"
# }

这将返回一个与你的 schema 相匹配的 JSON 对象,使其在你的应用程序中易于解析和使用。

高级用法模式

链式函数调用

LLM 可以协调多个函数调用以完成复杂任务

tools = [
    {
        "type": "function",
        "function": {
            "name": "search_products",
            "description": "Search product catalog",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string"},
                    "category": {"type": "string", "enum": ["electronics", "clothing", "books"]}
                }
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "create_order",
            "description": "Create a new order",
            "parameters": {
                "type": "object",
                "properties": {
                    "product_id": {"type": "string"},
                    "quantity": {"type": "integer", "minimum": 1}
                }
            }
        }
    }
]

错误处理和执行

在执行前务必验证函数调用

import json

def get_n_day_weather_forecast(location, format, num_days):
    return '{"temperature": 70, "condition": "sunny"}'

def handle_tool_call(tool_call):
    try:
        args = tool_call.function.arguments
        # Validate required parameters
        if tool_call.function.name == "get_n_day_weather_forecast":
            if not all(k in args for k in ["location", "format", "num_days"]):
                raise ValueError("Missing required parameters")
            # Only pass arguments that match the function's parameters
            valid_args = {k: v for k, v in args.items() 
                         if k in get_n_day_weather_forecast.__code__.co_varnames}
            return get_n_day_weather_forecast(**valid_args)
    except json.JSONDecodeError:
        return {"error": "Invalid function arguments"}
    except Exception as e:
        return {"error": str(e)}

res = handle_tool_call(response.choices[0].message.tool_calls[0])
print(res)
# {"temperature": 70, "condition": "sunny"}

最佳实践

  1. 函数设计

    • 保持函数名称清晰具体
    • 为函数和参数使用详细的描述
    • 包含参数约束 (最小值/最大值、枚举等)
  2. 错误处理

    • 验证所有函数输入
    • 为失败的函数调用实现适当的错误处理
    • 考虑为暂时性故障设置重试逻辑
  3. 安全

    • 在执行前验证并清理所有输入
    • 实施速率限制和访问控制
    • 根据用户上下文考虑函数调用权限
切勿直接通过函数调用暴露敏感操作。务必实施适当的验证和授权检查。

有关基本推理功能的更多信息,请参阅我们的推理指南

< > 在 GitHub 上更新