Hugging Face 生成式 AI 服务 (HUGS) 文档

函数调用

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

函数调用

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

函数调用工作原理

该过程遵循以下步骤

Function Calling

此循环可以根据需要继续进行,从而允许应用程序和 LLM 之间进行复杂的多步骤交互。

用例示例

函数调用对于许多实际应用都很有用,例如

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

使用工具(函数定义)

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

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

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

from huggingface_hub import InferenceClient

client = InferenceClient("http://localhost: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 模型来定义函数模式。这种方法提供:

  • 运行时类型检查
  • 自动验证
  • 更好的 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("http://localhost: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"
# }

这将返回一个与您的模式匹配的 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 上更新