知识模块
🤖 Agent 知识模块
九、工具模块
Function Calling 机制

Function Calling 机制

Function Calling 是 OpenAI 于 2023 年 6 月推出的原生工具调用能力,标志着工具调用从 Prompt Hacking 进入标准化阶段。理解 Function Calling 的原理和实践,是掌握现代 Agent 开发的关键。


一、核心原理

1.1 什么是 Function Calling?

Function Calling 是 OpenAI 提供的一种机制,允许 LLM 输出结构化的函数调用请求,而不是自由文本:

┌─────────────────────────────────────────────────────────────┐
│                    Function Calling 工作原理                 │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   输入阶段:                                                │
│   ┌─────────────────────────────────────────────────────┐  │
│   │ 用户消息 + 工具定义(JSON Schema)                   │  │
│   │                                                      │  │
│   │ tools = [{                                           │  │
│   │   type: "function",                                  │  │
│   │   function: {                                        │  │
│   │     name: "get_weather",                             │  │
│   │     description: "获取城市天气",                     │  │
│   │     parameters: {                                    │  │
│   │       type: "object",                                │  │
│   │       properties: {                                  │  │
│   │         city: { type: "string" }                     │  │
│   │       }                                              │  │
│   │     }                                                │  │
│   │   }                                                  │  │
│   │ }]                                                   │  │
│   └──────────────────────┬───────────────────────────────┘  │
│                          │                                  │
│                          ↓                                  │
│   LLM 处理阶段:                                            │
│   ┌─────────────────────────────────────────────────────┐  │
│   │ 模型内部推理:                                       │  │
│   │ • 分析用户意图                                       │  │
│   │ • 匹配可用工具                                       │  │
│   │ • 生成结构化输出(非自由文本)                       │  │
│   └──────────────────────┬───────────────────────────────┘  │
│                          │                                  │
│                          ↓                                  │
│   输出阶段:                                                │
│   ┌─────────────────────────────────────────────────────┐  │
│   │ tool_calls: [{                                       │  │
│   │   id: "call_xxx",                                    │  │
│   │   type: "function",                                  │  │
│   │   function: {                                        │  │
│   │     name: "get_weather",                             │  │
│   │     arguments: '{"city": "北京"}'                    │  │
│   │   }                                                  │  │
│   │ }]                                                   │  │
│   └─────────────────────────────────────────────────────┘  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 核心概念详解

概念说明示例
Tool Schema工具的结构化定义JSON Schema 格式
tool_choice控制工具调用行为auto / none / required / specific
tool_callsLLM 输出的工具调用列表包含 id、name、arguments
parallel_tool_calls是否允许多工具并行调用true / false

1.3 tool_choice 参数详解

┌─────────────────────────────────────────────────────────────┐
│                    tool_choice 参数说明                      │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. "auto"(默认)                                          │
│     ┌─────────────────────────────────────────────────┐    │
│     │ • 模型自动决定是否调用工具                        │    │
│     │ • 可能调用,也可能直接回答                        │    │
│     │ • 适合:通用场景                                  │    │
│     └─────────────────────────────────────────────────┘    │
│                                                             │
│  2. "none"                                                  │
│     ┌─────────────────────────────────────────────────┐    │
│     │ • 强制模型不调用任何工具                          │    │
│     │ • 即使提供了工具定义                              │    │
│     │ • 适合:只需要文本回答的场景                      │    │
│     └─────────────────────────────────────────────────┘    │
│                                                             │
│  3. "required"                                              │
│     ┌─────────────────────────────────────────────────┐    │
│     │ • 强制模型必须调用至少一个工具                    │    │
│     │ • 不能直接给出文本回答                            │    │
│     │ • 适合:必须执行操作的场景                        │    │
│     └─────────────────────────────────────────────────┘    │
│                                                             │
│  4. {"type": "function", "function": {"name": "xxx"}}       │
│     ┌─────────────────────────────────────────────────┐    │
│     │ • 强制调用指定的工具                              │    │
│     │ • 模型只能选择这个工具                            │    │
│     │ • 适合:明确知道需要哪个工具的场景                │    │
│     └─────────────────────────────────────────────────┘    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

二、工作流程

2.1 完整调用流程

┌─────────────────────────────────────────────────────────────┐
│                    Function Calling 完整流程                 │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   Step 1: 准备工具定义                                      │
│   ┌─────────────────────────────────────────────────────┐  │
│   │ tools = [                                            │  │
│   │   {                                                  │  │
│   │     "type": "function",                              │  │
│   │     "function": {                                    │  │
│   │       "name": "get_weather",                         │  │
│   │       "description": "获取城市天气",                 │  │
│   │       "parameters": {                                │  │
│   │         "type": "object",                            │  │
│   │         "properties": {...},                         │  │
│   │         "required": ["city"]                         │  │
│   │       }                                              │  │
│   │     }                                                │  │
│   │   }                                                  │  │
│   │ ]                                                    │  │
│   └─────────────────────────────────────────────────────┘  │
│                          │                                  │
│                          ↓                                  │
│   Step 2: 发送请求                                          │
│   ┌─────────────────────────────────────────────────────┐  │
│   │ response = client.chat.completions.create(           │  │
│   │     model="gpt-4",                                   │  │
│   │     messages=[{"role": "user", "content": "..."}],   │  │
│   │     tools=tools,                                     │  │
│   │     tool_choice="auto"                               │  │
│   │ )                                                    │  │
│   └─────────────────────────────────────────────────────┘  │
│                          │                                  │
│                          ↓                                  │
│   Step 3: 检查是否需要工具调用                              │
│   ┌─────────────────────────────────────────────────────┐  │
│   │ message = response.choices[0].message                │  │
│   │                                                      │  │
│   │ if message.tool_calls:                               │  │
│   │     # 需要执行工具                                   │  │
│   │ else:                                                │  │
│   │     # 直接返回文本回答                               │  │
│   └─────────────────────────────────────────────────────┘  │
│                          │                                  │
│                          ↓                                  │
│   Step 4: 执行工具                                          │
│   ┌─────────────────────────────────────────────────────┐  │
│   │ for tool_call in message.tool_calls:                 │  │
│   │     function_name = tool_call.function.name          │  │
│   │     arguments = json.loads(tool_call.function.args)  │  │
│   │     result = execute_function(function_name, args)   │  │
│   │                                                      │  │
│   │     # 添加工具结果到消息历史                         │  │
│   │     messages.append({                                │  │
│   │         "role": "tool",                              │  │
│   │         "tool_call_id": tool_call.id,                │  │
│   │         "content": str(result)                       │  │
│   │     })                                               │  │
│   └─────────────────────────────────────────────────────┘  │
│                          │                                  │
│                          ↓                                  │
│   Step 5: 获取最终回答                                      │
│   ┌─────────────────────────────────────────────────────┐  │
│   │ final_response = client.chat.completions.create(     │  │
│   │     model="gpt-4",                                   │  │
│   │     messages=messages                                │  │
│   │ )                                                    │  │
│   └─────────────────────────────────────────────────────┘  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2.2 多轮工具调用流程

┌─────────────────────────────────────────────────────────────┐
│                    多轮工具调用示例                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   用户问题:                                                │
│   "北京现在天气怎么样?如果温度超过25度,                   │
│    推荐一个适合户外的活动,否则推荐室内活动。"              │
│                                                             │
│   ┌─────────────────────────────────────────────────────┐  │
│   │ 第 1 轮:调用天气工具                                │  │
│   │                                                      │  │
│   │ Tool Call: get_weather(city="北京")                  │  │
│   │ Observation: {"temp": 18, "condition": "晴"}         │  │
│   └─────────────────────────────────────────────────────┘  │
│                          │                                  │
│                          ↓                                  │
│   ┌─────────────────────────────────────────────────────┐  │
│   │ 第 2 轮:根据温度条件判断                            │  │
│   │                                                      │  │
│   │ Thought: 温度18度,不超过25度,需要推荐室内活动      │  │
│   │ Tool Call: search_activity(type="indoor")            │  │
│   │ Observation: ["阅读", "看电影", "桌游"]              │  │
│   └─────────────────────────────────────────────────────┘  │
│                          │                                  │
│                          ↓                                  │
│   ┌─────────────────────────────────────────────────────┐  │
│   │ 最终回答                                             │  │
│   │                                                      │  │
│   │ 北京现在天气晴朗,气温18度,不超过25度。             │  │
│   │ 推荐以下室内活动:                                   │  │
│   │ 1. 阅读 - 享受安静的时光                             │  │
│   │ 2. 看电影 - 不错的选择                               │  │
│   │ 3. 桌游 - 适合和朋友一起                             │  │
│   └─────────────────────────────────────────────────────┘  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

三、代码实现

3.1 基础 Function Calling

"""
OpenAI Function Calling 基础实现
"""
 
import json
from openai import OpenAI
 
client = OpenAI()
 
 
def basic_function_calling():
    """基础 Function Calling 示例"""
    
    # 1. 定义工具
    tools = [
        {
            "type": "function",
            "function": {
                "name": "get_current_weather",
                "description": "获取指定位置的当前天气",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "location": {
                            "type": "string",
                            "description": "城市和省份,如:北京、上海浦东"
                        },
                        "unit": {
                            "type": "string",
                            "enum": ["celsius", "fahrenheit"],
                            "description": "温度单位,默认摄氏度"
                        }
                    },
                    "required": ["location"]
                }
            }
        }
    ]
    
    # 2. 发送请求
    messages = [
        {"role": "user", "content": "北京现在的天气怎么样?"}
    ]
    
    response = client.chat.completions.create(
        model="gpt-4",
        messages=messages,
        tools=tools,
        tool_choice="auto"
    )
    
    # 3. 处理响应
    message = response.choices[0].message
    
    if message.tool_calls:
        print("模型决定调用工具:")
        for tool_call in message.tool_calls:
            print(f"  - 工具名: {tool_call.function.name}")
            print(f"  - 参数: {tool_call.function.arguments}")
    else:
        print("模型直接回答:")
        print(message.content)
 
 
if __name__ == "__main__":
    basic_function_calling()

3.2 完整的 Agent 实现

"""
完整的 Function Calling Agent 实现
包含工具执行、多轮调用、错误处理
"""
 
import json
from typing import Callable, Dict, Any, List
from openai import OpenAI
 
 
class FunctionCallingAgent:
    """
    Function Calling Agent
    支持多轮工具调用、并行执行、错误处理
    """
    
    def __init__(
        self,
        model: str = "gpt-4",
        max_iterations: int = 10,
        verbose: bool = True
    ):
        self.client = OpenAI()
        self.model = model
        self.max_iterations = max_iterations
        self.verbose = verbose
        self.tools: List[Dict] = []
        self.functions: Dict[str, Callable] = {}
    
    def register_function(
        self,
        name: str,
        func: Callable,
        description: str,
        parameters: Dict
    ):
        """
        注册工具函数
        
        Args:
            name: 工具名称
            func: 实际执行的函数
            description: 工具描述
            parameters: 参数 Schema (JSON Schema)
        """
        # 注册工具定义
        self.tools.append({
            "type": "function",
            "function": {
                "name": name,
                "description": description,
                "parameters": parameters
            }
        })
        
        # 注册执行函数
        self.functions[name] = func
        
        if self.verbose:
            print(f"[注册工具] {name}: {description}")
    
    def _execute_function(self, name: str, arguments: Dict) -> Any:
        """执行工具函数"""
        if name not in self.functions:
            return {"error": f"未知工具: {name}"}
        
        try:
            result = self.functions[name](**arguments)
            return result
        except Exception as e:
            return {"error": f"执行错误: {str(e)}"}
    
    def run(self, user_input: str) -> str:
        """
        运行 Agent
        
        Args:
            user_input: 用户输入
            
        Returns:
            最终回答
        """
        messages = [{"role": "user", "content": user_input}]
        
        for iteration in range(self.max_iterations):
            if self.verbose:
                print(f"\n{'='*50}")
                print(f"第 {iteration + 1} 轮")
                print('='*50)
            
            # 调用 LLM
            response = self.client.chat.completions.create(
                model=self.model,
                messages=messages,
                tools=self.tools,
                tool_choice="auto"
            )
            
            message = response.choices[0].message
            
            # 检查是否需要工具调用
            if not message.tool_calls:
                # 没有工具调用,返回最终答案
                if self.verbose:
                    print(f"\n[最终答案]\n{message.content}")
                return message.content
            
            # 将助手消息添加到历史
            messages.append(message)
            
            # 执行所有工具调用
            for tool_call in message.tool_calls:
                function_name = tool_call.function.name
                arguments = json.loads(tool_call.function.arguments)
                
                if self.verbose:
                    print(f"\n[工具调用] {function_name}")
                    print(f"[参数] {json.dumps(arguments, ensure_ascii=False)}")
                
                # 执行函数
                result = self._execute_function(function_name, arguments)
                
                if self.verbose:
                    print(f"[结果] {json.dumps(result, ensure_ascii=False)}")
                
                # 添加工具结果
                messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "content": json.dumps(result, ensure_ascii=False)
                })
        
        return "达到最大迭代次数,未能完成任务"
 
 
# 使用示例
if __name__ == "__main__":
    # 定义工具函数
    def get_weather(location: str, unit: str = "celsius") -> Dict:
        """模拟天气 API"""
        weather_data = {
            "北京": {"temp": 18, "condition": "晴", "humidity": 45},
            "上海": {"temp": 22, "condition": "多云", "humidity": 60},
            "广州": {"temp": 28, "condition": "雨", "humidity": 80}
        }
        result = weather_data.get(location, {"temp": 20, "condition": "未知"})
        
        if unit == "fahrenheit":
            result["temp"] = result["temp"] * 9/5 + 32
        
        return result
    
    def calculate(expression: str) -> Dict:
        """计算器"""
        try:
            result = eval(expression)
            return {"expression": expression, "result": result}
        except Exception as e:
            return {"error": str(e)}
    
    def search(query: str) -> Dict:
        """搜索工具"""
        # 模拟搜索结果
        results = {
            "Python": "Python 是一种高级编程语言",
            "AI": "AI 是人工智能的缩写"
        }
        for key, value in results.items():
            if key.lower() in query.lower():
                return {"query": query, "answer": value}
        return {"query": query, "answer": "未找到相关信息"}
    
    # 创建 Agent
    agent = FunctionCallingAgent(verbose=True)
    
    # 注册工具
    agent.register_function(
        name="get_weather",
        func=get_weather,
        description="获取指定城市的当前天气",
        parameters={
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "城市名称"
                },
                "unit": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "温度单位"
                }
            },
            "required": ["location"]
        }
    )
    
    agent.register_function(
        name="calculate",
        func=calculate,
        description="执行数学计算",
        parameters={
            "type": "object",
            "properties": {
                "expression": {
                    "type": "string",
                    "description": "数学表达式"
                }
            },
            "required": ["expression"]
        }
    )
    
    agent.register_function(
        name="search",
        func=search,
        description="搜索互联网获取信息",
        parameters={
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "搜索关键词"
                }
            },
            "required": ["query"]
        }
    )
    
    # 运行
    result = agent.run("北京和上海现在的天气对比一下,计算两地的温差")
    print(f"\n\n最终结果:{result}")

3.3 并行工具调用

"""
并行工具调用示例
OpenAI 支持在一次响应中返回多个工具调用
"""
 
import json
import asyncio
from openai import OpenAI
 
 
async def execute_tool_async(name: str, arguments: dict) -> dict:
    """异步执行工具"""
    # 模拟异步操作
    await asyncio.sleep(0.5)
    
    # 模拟天气 API
    if name == "get_weather":
        weather_data = {
            "北京": {"temp": 18, "condition": "晴"},
            "上海": {"temp": 22, "condition": "多云"}
        }
        city = arguments.get("city")
        return weather_data.get(city, {"temp": 20, "condition": "未知"})
    
    return {"error": f"未知工具: {name}"}
 
 
async def parallel_tool_calling():
    """并行执行多个工具调用"""
    client = OpenAI()
    
    tools = [
        {
            "type": "function",
            "function": {
                "name": "get_weather",
                "description": "获取城市天气",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "city": {"type": "string"}
                    },
                    "required": ["city"]
                }
            }
        }
    ]
    
    # 用户问题需要多个城市天气
    messages = [
        {"role": "user", "content": "北京、上海、广州三个城市的天气怎么样?"}
    ]
    
    # 第一次调用
    response = client.chat.completions.create(
        model="gpt-4",
        messages=messages,
        tools=tools,
        tool_choice="auto",
        parallel_tool_calls=True  # 允许并行调用
    )
    
    message = response.choices[0].message
    
    if message.tool_calls:
        print(f"模型请求调用 {len(message.tool_calls)} 个工具")
        
        # 并行执行所有工具
        tasks = []
        for tool_call in message.tool_calls:
            args = json.loads(tool_call.function.arguments)
            print(f"  - {tool_call.function.name}({args})")
            tasks.append(execute_tool_async(
                tool_call.function.name,
                args
            ))
        
        # 等待所有工具完成
        results = await asyncio.gather(*tasks)
        
        print("\n执行结果:")
        for tool_call, result in zip(message.tool_calls, results):
            print(f"  - {tool_call.function.name}: {result}")
 
 
# 运行
asyncio.run(parallel_tool_calling())

3.4 流式工具调用

"""
流式工具调用示例
支持实时输出工具调用过程
"""
 
from openai import OpenAI
 
 
def streaming_tool_calling():
    """流式工具调用"""
    client = OpenAI()
    
    tools = [
        {
            "type": "function",
            "function": {
                "name": "get_weather",
                "description": "获取城市天气",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "city": {"type": "string"}
                    },
                    "required": ["city"]
                }
            }
        }
    ]
    
    messages = [
        {"role": "user", "content": "北京天气怎么样?"}
    ]
    
    # 流式调用
    stream = client.chat.completions.create(
        model="gpt-4",
        messages=messages,
        tools=tools,
        stream=True
    )
    
    tool_calls = {}
    
    for chunk in stream:
        delta = chunk.choices[0].delta
        
        if delta.tool_calls:
            for tool_call_delta in delta.tool_calls:
                idx = tool_call_delta.index
                
                if idx not in tool_calls:
                    tool_calls[idx] = {
                        "id": "",
                        "name": "",
                        "arguments": ""
                    }
                
                # 累积工具调用信息
                if tool_call_delta.id:
                    tool_calls[idx]["id"] = tool_call_delta.id
                if tool_call_delta.function:
                    if tool_call_delta.function.name:
                        tool_calls[idx]["name"] = tool_call_delta.function.name
                        print(f"\n[工具调用] {tool_call_delta.function.name}")
                    if tool_call_delta.function.arguments:
                        tool_calls[idx]["arguments"] += tool_call_delta.function.arguments
                        print(tool_call_delta.function.arguments, end="", flush=True)
    
    print("\n\n完整的工具调用:")
    for idx, tc in tool_calls.items():
        print(f"  {tc['name']}({tc['arguments']})")
 
 
if __name__ == "__main__":
    streaming_tool_calling()

四、高级特性

4.1 工具调用控制

"""
tool_choice 高级用法
"""
 
from openai import OpenAI
 
client = OpenAI()
 
tools = [
    {
        "type": "function",
        "function": {
            "name": "search",
            "description": "搜索信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string"}
                }
            }
        }
    }
]
 
# 场景 1: 强制调用特定工具
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "今天新闻"}],
    tools=tools,
    tool_choice={"type": "function", "function": {"name": "search"}}
    # 强制使用 search 工具
)
 
# 场景 2: 强制必须调用某个工具
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "你好"}],
    tools=tools,
    tool_choice="required"
    # 必须调用工具,但可以选择哪个
)
 
# 场景 3: 禁止工具调用
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "什么是 AI?"}],
    tools=tools,
    tool_choice="none"
    # 即使有工具定义,也不调用
)

4.2 结构化输出与 JSON Mode

"""
结构化输出与 JSON Mode
确保输出格式符合预期
"""
 
from openai import OpenAI
 
client = OpenAI()
 
# 方法 1: JSON Mode
response = client.chat.completions.create(
    model="gpt-4",
    messages=[
        {"role": "system", "content": "你是一个数据提取助手,总是返回 JSON 格式。"},
        {"role": "user", "content": "提取以下文本中的实体:张三,28岁,北京人"}
    ],
    response_format={"type": "json_object"}
)
 
print(response.choices[0].message.content)
# 输出: {"name": "张三", "age": 28, "city": "北京"}
 
# 方法 2: Function Calling 获取结构化数据
tools = [
    {
        "type": "function",
        "function": {
            "name": "extract_entities",
            "description": "从文本中提取实体信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "name": {"type": "string", "description": "人名"},
                    "age": {"type": "integer", "description": "年龄"},
                    "city": {"type": "string", "description": "城市"}
                },
                "required": ["name", "age", "city"]
            }
        }
    }
]
 
response = client.chat.completions.create(
    model="gpt-4",
    messages=[
        {"role": "user", "content": "提取以下文本中的实体:张三,28岁,北京人"}
    ],
    tools=tools,
    tool_choice={"type": "function", "function": {"name": "extract_entities"}}
)
 
import json
entities = json.loads(response.choices[0].message.tool_calls[0].function.arguments)
print(entities)
# 输出: {"name": "张三", "age": 28, "city": "北京"}

五、最佳实践

5.1 工具设计原则

┌─────────────────────────────────────────────────────────────┐
│                    工具设计最佳实践                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 描述清晰                                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ ❌ 差的描述:                                        │   │
│  │    "description": "搜索"                             │   │
│  │                                                      │   │
│  │ ✅ 好的描述:                                        │   │
│  │    "description": "搜索互联网获取实时信息,          │   │
│  │                    适用于需要最新数据或              │   │
│  │                    训练数据截止后的信息"             │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
│  2. 参数完整                                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ • 所有参数都有 description                           │   │
│  │ • required 列表完整                                  │   │
│  │ • 使用 enum 约束可选值                               │   │
│  │ • 提供默认值建议                                     │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
│  3. 粒度适中                                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ ❌ 过于宽泛:                                        │   │
│  │    "do_something" - 做任何事情                       │   │
│  │                                                      │   │
│  │ ❌ 过于细碎:                                        │   │
│  │    "get_first_char", "get_second_char"...            │   │
│  │                                                      │   │
│  │ ✅ 适中粒度:                                        │   │
│  │    "search_web", "calculate", "read_file"            │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
│  4. 幂等设计                                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ • 相同输入 → 相同输出                                │   │
│  │ • 支持重试而不产生副作用                             │   │
│  │ • 读操作优先于写操作                                 │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

5.2 错误处理策略

def execute_tool_safely(name: str, arguments: dict, func: Callable) -> dict:
    """
    安全执行工具,包含完整的错误处理
    """
    import traceback
    
    try:
        # 1. 参数验证
        if not isinstance(arguments, dict):
            return {
                "success": False,
                "error": "参数必须是字典类型",
                "error_type": "validation_error"
            }
        
        # 2. 执行超时控制
        import signal
        
        def timeout_handler(signum, frame):
            raise TimeoutError("工具执行超时")
        
        # 设置 30 秒超时
        signal.signal(signal.SIGALRM, timeout_handler)
        signal.alarm(30)
        
        try:
            result = func(**arguments)
        finally:
            signal.alarm(0)  # 取消超时
        
        # 3. 结果验证
        if result is None:
            return {
                "success": True,
                "data": None,
                "message": "工具执行成功,无返回值"
            }
        
        return {
            "success": True,
            "data": result
        }
        
    except TimeoutError as e:
        return {
            "success": False,
            "error": str(e),
            "error_type": "timeout"
        }
    except TypeError as e:
        return {
            "success": False,
            "error": f"参数类型错误: {str(e)}",
            "error_type": "type_error"
        }
    except Exception as e:
        return {
            "success": False,
            "error": str(e),
            "error_type": "execution_error",
            "traceback": traceback.format_exc()
        }

六、面试高频问题

Q1: Function Calling 的工作原理是什么?

答案要点

  1. 工具定义注入:将工具的 JSON Schema 作为特殊 token 注入 prompt
  2. 模型推理:模型被训练成在需要工具时输出结构化 JSON
  3. 输出解析:API 层解析模型输出,返回标准化的 tool_calls 结构
  4. 执行循环:开发者执行工具,将结果返回给模型继续对话

Q2: tool_choice 参数各有什么用途?

答案要点

用途适用场景
auto模型自动决定通用场景
none禁止工具调用只需要文本回答
required必须调用工具强制执行操作
指定工具强制调用特定工具明确知道需要哪个工具

Q3: 如何处理工具调用失败的情况?

答案要点

  1. 返回错误信息:将错误作为 Observation 返回给模型
  2. 自动重试:对可重试错误(网络超时)自动重试
  3. 降级处理:提供备选工具或直接回答
  4. 用户确认:高风险操作失败后询问用户

Q4: parallel_tool_calls 是什么?有什么限制?

答案要点

  1. 定义:允许模型在一次响应中返回多个工具调用
  2. 优势:减少交互轮数,提高效率
  3. 限制:所有工具调用必须是独立的,无依赖关系
  4. 实现:使用 asyncio.gather 或线程池并行执行

Q5: Function Calling 与 ReAct 模式有什么关系?

答案要点

  1. ReAct 是框架:定义了 Thought-Action-Observation 的循环模式
  2. Function Calling 是实现:提供了 Action 阶段的结构化输出能力
  3. 互补关系:ReAct 提供推理框架,Function Calling 提供技术实现
  4. 现代实践:大多数 Agent 系统结合使用两者

七、小结

概念一句话总结
Function CallingLLM 原生支持的结构化工具调用能力
核心优势结构化输出可靠,参数类型安全
tool_choice控制模型是否以及如何调用工具
并行调用一次响应多个工具调用,提高效率
最佳实践描述清晰、参数完整、粒度适中、幂等设计

一句话总结:Function Calling 是现代 Agent 工具调用的基石,理解其原理和最佳实践是构建可靠 Agent 系统的关键。


最后更新:2026年3月18日