Skip to content

27.2 工具呼叫機制

工具呼叫機制概述

工具呼叫(Tool Calling)是Agentic AI系統的核心能力之一,它允許AI模型透過呼叫外部工具來擴充套件其能力,執行實際的操作,而不僅僅是生成文字。

工具调用的基本概念

1. 什么是工具调用

工具呼叫是指AI模型根據使用者的請求,識別需要使用的工具,生成工具呼叫引數,執行工具呼叫,並將結果整合到最終響應中的過程。

工具调用的特点 :

  • 結構化輸出 : 模型輸出結構化的工具呼叫指令
  • 引數驗證 : 驗證工具呼叫引數的有效性
  • 結果整合 : 將工具執行結果整合到響應中
  • 錯誤處理 : 處理工具呼叫失敗的情況

2. 工具呼叫流程

使用者請求 ↓ 意圖識別 ↓ 工具選擇 ↓ 引數生成 ↓ 工具執行 ↓ 結果處理 ↓ 響應生成

python
## 工具定义与注册

### 1\. 工具定义

    python


    python

    # 示例:工具定义

    用户请求:
    "定义一个文件读取工具"

    Claude Code 生成的代码:

    ```python

    ```python

    from typing import Dict, Any, Optional
    import json
    from dataclasses import dataclass, asdict
    from enum import Enum

    class ToolType(Enum):
        """工具类型"""
        FILE_OPERATION = "file_operation"
        CODE_EXECUTION = "code_execution"
        API_CALL = "api_call"
        SEARCH = "search"
        CALCULATION = "calculation"

    @dataclass
    class ToolParameter:
        """工具参数"""
        name: str
        type: str
        description: str
        required: bool
        default: Optional[Any] = None

    @dataclass
    class ToolDefinition:
        """工具定义"""
        name: str
        description: str
        type: ToolType
        parameters: list[ToolParameter]
        function: callable

        def to_dict(self) -> Dict[str, Any]:
            """转换为字典"""
            return {
                'name': self.name,
                'description': self.description,
                'type': self.type.value,
                'parameters': [asdict(param) for param in self.parameters]
            }

    # 文件读取工具
    def read_file(file_path: str) -> str:
        """读取文件内容"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                return f.read()
        except FileNotFoundError:
            return f"Error: File not found: {file_path}"
        except Exception as e:
            return f"Error: {str(e)}"

    read_file_tool = ToolDefinition(
        name="read_file",
        description="读取指定文件的内容",
        type=ToolType.FILE_OPERATION,
        parameters=[
            ToolParameter(
                name="file_path",
                type="string",
                description="要读取的文件路径",
                required=True
            )
        ],
        function=read_file
    )

    # 文件写入工具
    def write_file(file_path: str, content: str) -> str:
        """写入内容到文件"""
        try:
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(content)
            return f"Success: File written to {file_path}"
        except Exception as e:
            return f"Error: {str(e)}"

    write_file_tool = ToolDefinition(
        name="write_file",
        description="将内容写入到指定文件",
        type=ToolType.FILE_OPERATION,
        parameters=[
            ToolParameter(
                name="file_path",
                type="string",
                description="要写入的文件路径",
                required=True
            ),
            ToolParameter(
                name="content",
                type="string",
                description="要写入的内容",
                required=True
            )
        ],
        function=write_file
    )

    # 代码执行工具
    def execute_code(code: str, language: str = "python") -> str:
        """执行代码"""
        try:
            if language == "python":
                import subprocess
                result = subprocess.run(
                    ['python', '-c', code],
                    capture_output=True,
                    text=True,
                    timeout=10
                )
                if result.returncode == 0:
                    return result.stdout
                else:
                    return f"Error: {result.stderr}"
            else:
                return f"Error: Unsupported language: {language}"
        except subprocess.TimeoutExpired:
            return "Error: Code execution timeout"
        except Exception as e:
            return f"Error: {str(e)}"

    execute_code_tool = ToolDefinition(
        name="execute_code",
        description="执行代码并返回结果",
        type=ToolType.CODE_EXECUTION,
        parameters=[
            ToolParameter(
                name="code",
                type="string",
                description="要执行的代码",
                required=True
            ),
            ToolParameter(
                name="language",
                type="string",
                description="编程语言",
                required=False,
                default="python"
            )
        ],
        function=execute_code
    )

    ### 2. 工具注册

    ```python

```python
    # 示例:工具注册

    用户请求:
    "实现一个工具注册系统"

    Claude Code 生成的代码:

    ```python

    ```python

    from typing import Dict, List, Optional

    class ToolRegistry:
        """工具注册表"""

        def __init__(self):
            self.tools: Dict[str, ToolDefinition] = {}
            self.categories: Dict[str, List[str]] = {}

        def register(self, tool: ToolDefinition, category: Optional[str] = None):
            """注册工具"""
            self.tools[tool.name] = tool

            if category:
                if category not in self.categories:
                    self.categories[category] = []
                self.categories[category].append(tool.name)

        def unregister(self, tool_name: str):
            """注销工具"""
            if tool_name in self.tools:
                del self.tools[tool_name]

                for category, tools in self.categories.items():
                    if tool_name in tools:
                        tools.remove(tool_name)

        def get_tool(self, tool_name: str) -> Optional[ToolDefinition]:
            """获取工具"""
            return self.tools.get(tool_name)

        def list_tools(self, category: Optional[str] = None) -> List[ToolDefinition]:
            """列出工具"""
            if category:
                tool_names = self.categories.get(category, [])
                return [self.tools[name] for name in tool_names]
            else:
                return list(self.tools.values())

        def search_tools(self, keyword: str) -> List[ToolDefinition]:
            """搜索工具"""
            results = []
            keyword = keyword.lower()

            for tool in self.tools.values():
                if (keyword in tool.name.lower() or
                    keyword in tool.description.lower()):
                    results.append(tool)

            return results

        def get_tool_schema(self, tool_name: str) -> Optional[Dict[str, Any]]:
            """获取工具schema"""
            tool = self.get_tool(tool_name)
            if tool:
                return tool.to_dict()
            return None

        def get_all_schemas(self) -> Dict[str, Dict[str, Any]]:
            """获取所有工具schema"""
            return {
                name: tool.to_dict()
                for name, tool in self.tools.items()
            }

    # 使用示例
    registry = ToolRegistry()

    # 注册工具
    registry.register(read_file_tool, category="file_operations")
    registry.register(write_file_tool, category="file_operations")
    registry.register(execute_code_tool, category="code_execution")

    # 列出所有工具
    print("All tools:")
    for tool in registry.list_tools():
        print(f"  - {tool.name}: {tool.description}")

    # 列出特定类别的工具
    print("\nFile operation tools:")
    for tool in registry.list_tools(category="file_operations"):
        print(f"  - {tool.name}: {tool.description}")

    # 搜索工具
    print("\nSearch results for 'file':")
    for tool in registry.search_tools("file"):
        print(f"  - {tool.name}: {tool.description}")

    # 获取工具schema
    print("\nTool schema for read_file:")
    print(json.dumps(registry.get_tool_schema("read_file"), indent=2))

    ## 工具调用执行

    ### 1. 工具调用解析

    # 示例:工具调用解析
    用户请求:
    "实现工具调用解析器"
    Claude Code 生成的代码:

    ````python

    `python

    import re
    from typing import Dict, Any, List, Optional
    import json

    class ToolCallParser:
    """工具呼叫解析器"""

    def __init__(self, registry: ToolRegistry):
    self.registry = registry

    def parse_tool_calls(self, text: str) -> List[Dict[str, Any]]:
    """解析工具呼叫"""
    tool_calls = []

     # 匹配工具呼叫模式

    pattern = r'<tool_call>\s*<name>(.*?)</name>\s*<parameters>(.*?)</parameters>\s*</tool_call>'
    matches = re.finditer(pattern, text, re.DOTALL)

    for match in matches:
    tool_name = match.group(1).strip()
    parameters_str = match.group(2).strip()

     # 解析引數

    try:
    parameters = json.loads(parameters_str)
    except json.JSONDecodeError:
    parameters = self._parse_parameters(parameters_str)

    tool_calls.append({
    'tool': tool_name,
    'parameters': parameters
    })

    return tool_calls

    def _parse_parameters(self, parameters_str: str) -> Dict[str, Any]:
    """解析引數字串"""
    parameters = {}

     # 匹配引數

    param_pattern = r'<(\w+)>(.*?)</\1>'
    matches = re.findall(param_pattern, parameters_str, re.DOTALL)

    for name, value in matches:
    parameters[name] = value.strip()

    return parameters

    def validate_tool_call(self, tool_call: Dict[str, Any]) -> tuple[bool, Optional[str]]:
    """驗證工具呼叫"""
    tool_name = tool_call['tool']
    parameters = tool_call['parameters']

     # 檢查工具是否存在

    tool = self.registry.get_tool(tool_name)
    if not tool:
    return False, f"Tool not found: {tool_name}"

     # 檢查必需引數

    for param in tool.parameters:
    if param.required and param.name not in parameters:
    return False, f"Missing required parameter: {param.name}"

     # 檢查引數型別

    for param in tool.parameters:
    if param.name in parameters:
    value = parameters[param.name]
    if not self._check_parameter_type(value, param.type):
    return False, f"Invalid type for parameter {param.name}: expected {param.type}"

    return True, None

    def _check_parameter_type(self, value: Any, expected_type: str) -> bool:
    """檢查引數型別"""
    type_mapping = {
    'string': str,
    'integer': int,
    'float': float,
    'boolean': bool,
    'array': list,
    'object': dict
    }

    expected_python_type = type_mapping.get(expected_type)
    if expected_python_type:
    return isinstance(value, expected_python_type)

    return True

    # 使用示例

    parser = ToolCallParser(registry)

    # 解析工具呼叫

    text = """
    I'll read the file for you.

    <tool_call>
    <name>read_file</name>
    <parameters>{"file_path": "/path/to/file.txt"}</parameters>
    </tool_call>
    """

    tool_calls = parser.parse_tool_calls(text)
    print("Parsed tool calls:")
    for tool_call in tool_calls:
    print(f"  Tool: {tool_call['tool']}")
    print(f"  Parameters: {tool_call['parameters']}")

     # 驗證工具呼叫

    is_valid, error = parser.validate_tool_call(tool_call)
    if is_valid:
    print(f"  Status: Valid")
    else:
    print(f"  Status: Invalid - {error}")

    ```### 2. 工具调用执行
python

# 示例:工具调用执行

用户请求: "实现工具调用执行器"

Claude Code 生成的代码:

from typing import Dict, Any, List import asyncio from concurrent.futures import ThreadPoolExecutor

class ToolExecutor: """工具执行器"""

def **init**(self, registry: ToolRegistry): self.registry = registry self.executor = ThreadPoolExecutor(max_workers=4)

async def execute_tool_call(self, tool_call: Dict[str, Any]) -> Dict[str, Any]: """执行工具调用""" tool_name = tool_call['tool'] parameters = tool_call['parameters']

# 获取工具

tool = self.registry.get_tool(tool_name) if not tool: return { 'success': False, 'error': f"Tool not found: {tool_name}", 'tool': tool_name }

try:

# 执行工具

loop = asyncio.get_event_loop() result = await loop.run_in_executor( self.executor, tool.function, **parameters )

return { 'success': True, 'result': result, 'tool': tool_name }

except Exception as e: return { 'success': False, 'error': str(e), 'tool': tool_name }

async def execute_tool_calls(self, tool_calls: List[Dict[str, Any]]) -> List[Dict[str, Any]]: """执行多个工具调用""" tasks = [ self.execute_tool_call(tool_call) for tool_call in tool_calls ]

results = await asyncio.gather(*tasks, return_exceptions=True)

return results

def execute_tool_call_sync(self, tool_call: Dict[str, Any]) -> Dict[str, Any]: """同步执行工具调用""" tool_name = tool_call['tool'] parameters = tool_call['parameters']

# 获取工具

tool = self.registry.get_tool(tool_name) if not tool: return { 'success': False, 'error': f"Tool not found: {tool_name}", 'tool': tool_name }

try:

# 执行工具

result = tool.function(**parameters)

return { 'success': True, 'result': result, 'tool': tool_name }

except Exception as e: return { 'success': False, 'error': str(e), 'tool': tool_name }

# 使用示例

executor = ToolExecutor(registry)

# 执行工具调用

tool_calls = [ { 'tool': 'read_file', 'parameters': {'file_path': '/path/to/file.txt'} }, { 'tool': 'execute_code', 'parameters': {'code': 'print("Hello, World!")', 'language': 'python'} } ]

# 异步执行

async def main(): results = await executor.execute_tool_calls(tool_calls)

print("Execution results:") for result in results: if result['success']: print(f" {result['tool']}: Success") print(f" Result: {result['result']}") else: print(f" {result['tool']}: Failed") print(f" Error: {result['error']}")

# 同步执行

def main_sync(): for tool_call in tool_calls: result = executor.execute_tool_call_sync(tool_call)

if result['success']: print(f"{result['tool']}: Success") print(f" Result: {result['result']}") else: print(f"{result['tool']}: Failed") print(f" Error: {result['error']}")

`> >

## 工具调用优化

### 1\. 缓存机制

    python


    python

    # 示例:工具调用缓存

    用户请求:
    "实现工具调用缓存"

    Claude Code 生成的代码:

    ```python

    ```python

    from typing import Dict, Any, Optional
    import hashlib
    import json
    from datetime import datetime, timedelta

    class ToolCallCache:
        """工具调用缓存"""

        def __init__(self, ttl: int = 3600):
            self.cache: Dict[str, Dict[str, Any]] = {}
            self.ttl = ttl

        def _generate_key(self, tool_name: str, parameters: Dict[str, Any]) -> str:
            """生成缓存键"""
            key_data = {
                'tool': tool_name,
                'parameters': parameters
            }
            key_str = json.dumps(key_data, sort_keys=True)
            return hashlib.md5(key_str.encode()).hexdigest()

        def get(self, tool_name: str, parameters: Dict[str, Any]) -> Optional[Dict[str, Any]]:
            """获取缓存"""
            key = self._generate_key(tool_name, parameters)

            if key in self.cache:
                cached = self.cache[key]

                # 检查是否过期
                if datetime.utcnow() - cached['timestamp'] < timedelta(seconds=self.ttl):
                    return cached['result']
                else:
                    del self.cache[key]

            return None

        def set(self, tool_name: str, parameters: Dict[str, Any], result: Dict[str, Any]):
            """设置缓存"""
            key = self._generate_key(tool_name, parameters)

            self.cache[key] = {
                'result': result,
                'timestamp': datetime.utcnow()
            }

        def clear(self):
            """清空缓存"""
            self.cache.clear()

        def cleanup(self):
            """清理过期缓存"""
            current_time = datetime.utcnow()
            expired_keys = [
                key for key, cached in self.cache.items()
                if current_time - cached['timestamp'] >= timedelta(seconds=self.ttl)
            ]

            for key in expired_keys:
                del self.cache[key]

    class CachedToolExecutor(ToolExecutor):
        """带缓存的工具执行器"""

        def __init__(self, registry: ToolRegistry, cache: ToolCallCache):
            super().__init__(registry)
            self.cache = cache

        async def execute_tool_call(self, tool_call: Dict[str, Any]) -> Dict[str, Any]:
            """执行工具调用(带缓存)"""
            tool_name = tool_call['tool']
            parameters = tool_call['parameters']

            # 检查缓存
            cached_result = self.cache.get(tool_name, parameters)
            if cached_result:
                return cached_result

            # 执行工具调用
            result = await super().execute_tool_call(tool_call)

            # 缓存结果
            if result['success']:
                self.cache.set(tool_name, parameters, result)

            return result

    ### 2. 批量执行

    ```python

```python
    # 示例:批量工具调用

    用户请求:
    "实现批量工具调用"

    Claude Code 生成的代码:

    ```python

    ```python

    from typing import Dict, Any, List
    import asyncio

    class BatchToolExecutor(ToolExecutor):
        """批量工具执行器"""

        async def execute_batch(self, batch: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
            """批量执行工具调用"""
            # 按工具类型分组
            tool_groups = {}
            for tool_call in batch:
                tool_name = tool_call['tool']
                if tool_name not in tool_groups:
                    tool_groups[tool_name] = []
                tool_groups[tool_name].append(tool_call)

            # 并行执行不同工具的调用
            tasks = [
                self._execute_tool_group(tool_name, tool_calls)
                for tool_name, tool_calls in tool_groups.items()
            ]

            results = await asyncio.gather(*tasks, return_exceptions=True)

            # 合并结果
            all_results = []
            for result_list in results:
                if isinstance(result_list, list):
                    all_results.extend(result_list)

            return all_results

        async def _execute_tool_group(self, tool_name: str, tool_calls: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
            """执行同一工具的多个调用"""
            tool = self.registry.get_tool(tool_name)
            if not tool:
                return [
                    {
                        'success': False,
                        'error': f"Tool not found: {tool_name}",
                        'tool': tool_name
                    }
                    for _ in tool_calls
                ]

            results = []
            for tool_call in tool_calls:
                result = await super().execute_tool_call(tool_call)
                results.append(result)

            return results

## 总结

工具呼叫機制包括:

  1. 工具呼叫的基本概念 : 什麼是工具呼叫、工具呼叫流程
  2. 工具定義與註冊 : 工具定義、工具註冊
  3. 工具呼叫執行 : 工具呼叫解析、工具呼叫執行
  4. 工具呼叫最佳化 : 快取機制、批次執行

透過工具呼叫機制,Claude Code可以執行各種實際操作,大大擴充套件了其能力。

在下一節中,我們將探討自主規劃演算法。

基于 MIT 许可发布 | 永久导航