知识模块
🤖 Agent 知识模块
九、工具模块
工具定义与注册

工具定义与注册

工具定义是 Agent 工具系统的基石。一个好的工具定义能让 LLM 准确理解工具的用途、正确构建参数、避免误用。本章详细介绍工具定义的标准、注册机制和设计原则。


一、核心原理

1.1 工具定义的组成要素

一个完整的工具定义包含以下核心要素:

┌─────────────────────────────────────────────────────────────┐
│                    工具定义组成要素                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌─────────────────────────────────────────────────────┐  │
│   │                    Tool Definition                   │  │
│   ├─────────────────────────────────────────────────────┤  │
│   │                                                      │  │
│   │  1. 元数据 (Metadata)                                │  │
│   │     • name: 工具唯一标识符                           │  │
│   │     • description: 自然语言描述                      │  │
│   │     • version: 版本号                                │  │
│   │     • category: 分类标签                             │  │
│   │                                                      │  │
│   │  2. 参数模式 (Parameter Schema)                      │  │
│   │     • type: 参数类型 (object)                        │  │
│   │     • properties: 各参数定义                         │  │
│   │     • required: 必填参数列表                         │  │
│   │     • definitions: 共享类型定义                      │  │
│   │                                                      │  │
│   │  3. 行为配置 (Behavior Config)                       │  │
│   │     • timeout: 超时时间                              │  │
│   │     • retry_policy: 重试策略                         │  │
│   │     • permission: 权限等级                           │  │
│   │     • side_effects: 副作用标记                       │  │
│   │                                                      │  │
│   │  4. 返回模式 (Return Schema)                         │  │
│   │     • type: 返回值类型                               │  │
│   │     • properties: 返回字段定义                       │  │
│   │                                                      │  │
│   └─────────────────────────────────────────────────────┘  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 JSON Schema 基础

工具参数使用 JSON Schema 定义,这是工具定义的核心:

{
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "description": "搜索关键词"
    },
    "limit": {
      "type": "integer",
      "description": "返回结果数量限制",
      "default": 10,
      "minimum": 1,
      "maximum": 100
    },
    "filters": {
      "type": "object",
      "description": "过滤条件",
      "properties": {
        "date_range": {
          "type": "object",
          "properties": {
            "start": {"type": "string", "format": "date"},
            "end": {"type": "string", "format": "date"}
          }
        },
        "source": {
          "type": "string",
          "enum": ["web", "news", "academic"]
        }
      }
    }
  },
  "required": ["query"]
}

1.3 JSON Schema 类型系统

类型说明示例
string字符串"hello"
integer整数42
number数字(含浮点)3.14
boolean布尔值true
array数组[1, 2, 3]
object对象{"key": "value"}
null空值null

二、工具定义标准

2.1 OpenAI Function Calling 格式

"""
OpenAI Function Calling 工具定义格式
"""
 
# 标准格式
openai_tool_format = {
    "type": "function",
    "function": {
        "name": "search_web",              # 工具名称
        "description": "搜索互联网获取信息,适用于需要实时数据或最新信息的场景",  # 工具描述
        "parameters": {                    # 参数 Schema
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "搜索关键词,建议使用简洁精确的词语"
                },
                "num_results": {
                    "type": "integer",
                    "description": "返回结果数量",
                    "default": 5,
                    "minimum": 1,
                    "maximum": 20
                },
                "search_type": {
                    "type": "string",
                    "enum": ["web", "news", "images", "videos"],
                    "description": "搜索类型"
                }
            },
            "required": ["query"]
        }
    }
}

2.2 Anthropic Tool Use 格式

"""
Anthropic Claude Tool Use 工具定义格式
"""
 
anthropic_tool_format = {
    "name": "search_web",
    "description": "搜索互联网获取信息,适用于需要实时数据或最新信息的场景",
    "input_schema": {  # Anthropic 使用 input_schema 而非 parameters
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "搜索关键词"
            },
            "num_results": {
                "type": "integer",
                "description": "返回结果数量",
                "default": 5
            }
        },
        "required": ["query"]
    }
}

2.3 LangChain Tool 格式

"""
LangChain 工具定义方式
"""
 
from langchain.tools import BaseTool, tool
from pydantic import BaseModel, Field
from typing import Optional, Literal
 
 
# 方式 1: 使用 @tool 装饰器(推荐)
@tool
def search_web(
    query: str,
    num_results: int = 5,
    search_type: Literal["web", "news", "images"] = "web"
) -> str:
    """
    搜索互联网获取信息
    
    Args:
        query: 搜索关键词,建议使用简洁精确的词语
        num_results: 返回结果数量,默认5条
        search_type: 搜索类型,可选 web/news/images
        
    Returns:
        搜索结果摘要
    """
    # 实现逻辑...
    return f"搜索 '{query}' 的结果..."
 
 
# 方式 2: 使用 Pydantic 定义输入模型
class SearchWebInput(BaseModel):
    """搜索工具输入参数"""
    query: str = Field(description="搜索关键词")
    num_results: int = Field(default=5, ge=1, le=20, description="返回结果数量")
    search_type: Literal["web", "news", "images"] = Field(default="web", description="搜索类型")
 
 
# 方式 3: 继承 BaseTool 类
class SearchWebTool(BaseTool):
    """搜索工具类"""
    
    name = "search_web"
    description = "搜索互联网获取信息"
    args_schema = SearchWebInput
    
    def _run(
        self,
        query: str,
        num_results: int = 5,
        search_type: str = "web"
    ) -> str:
        """执行搜索"""
        # 实现逻辑...
        return f"搜索 '{query}' 的结果..."
    
    async def _arun(
        self,
        query: str,
        num_results: int = 5,
        search_type: str = "web"
    ) -> str:
        """异步执行搜索"""
        # 异步实现...
        return f"搜索 '{query}' 的结果..."

2.4 MCP 工具定义格式

"""
MCP (Model Context Protocol) 工具定义格式
"""
 
mcp_tool_format = {
    "name": "search_web",
    "description": "搜索互联网获取信息",
    "inputSchema": {  # MCP 使用 inputSchema
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "搜索关键词"
            }
        },
        "required": ["query"]
    },
    # MCP 特有的元数据
    "annotations": {
        "title": "Web Search",
        "readOnlyHint": True,       # 只读操作
        "destructiveHint": False,   # 非破坏性操作
        "idempotentHint": True      # 幂等操作
    }
}

三、工具注册中心

3.1 注册中心架构

┌─────────────────────────────────────────────────────────────┐
│                    工具注册中心架构                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌─────────────────────────────────────────────────────┐  │
│   │                  Tool Registry                       │  │
│   ├─────────────────────────────────────────────────────┤  │
│   │                                                      │  │
│   │  ┌──────────────┐    ┌──────────────┐              │  │
│   │  │  工具索引    │    │  分类目录    │              │  │
│   │  │              │    │              │              │  │
│   │  │ • 名称索引   │    │ • 信息获取   │              │  │
│   │  │ • 功能索引   │    │ • 数据处理   │              │  │
│   │  │ • 语义索引   │    │ • 系统操作   │              │  │
│   │  └──────────────┘    └──────────────┘              │  │
│   │                                                      │  │
│   │  ┌──────────────┐    ┌──────────────┐              │  │
│   │  │  元数据存储  │    │  权限管理    │              │  │
│   │  │              │    │              │              │  │
│   │  │ • 版本信息   │    │ • 权限等级   │              │  │
│   │  │ • 依赖关系   │    │ • 访问控制   │              │  │
│   │  │ • 统计数据   │    │ • 审计日志   │              │  │
│   │  └──────────────┘    └──────────────┘              │  │
│   │                                                      │  │
│   └─────────────────────────────────────────────────────┘  │
│                             │                               │
│                             ↓                               │
│   ┌─────────────────────────────────────────────────────┐  │
│   │                    工具实例池                        │  │
│   │                                                      │  │
│   │  ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐          │  │
│   │  │搜索 │ │计算 │ │文件 │ │API  │ │代码 │          │  │
│   │  │工具 │ │工具 │ │工具 │ │工具 │ │执行 │          │  │
│   │  └─────┘ └─────┘ └─────┘ └─────┘ └─────┘          │  │
│   │                                                      │  │
│   └─────────────────────────────────────────────────────┘  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

3.2 注册中心实现

"""
工具注册中心实现
支持工具注册、检索、权限管理
"""
 
from typing import Dict, List, Optional, Callable, Any
from dataclasses import dataclass, field
from enum import Enum
import json
 
 
class PermissionLevel(Enum):
    """权限等级"""
    READ_ONLY = 1      # 只读操作
    LIMITED_WRITE = 2  # 有限写入
    FULL_ACCESS = 3    # 完全访问
    SYSTEM = 4         # 系统级操作
 
 
@dataclass
class ToolMetadata:
    """工具元数据"""
    name: str
    description: str
    parameters: Dict[str, Any]
    version: str = "1.0.0"
    category: str = "general"
    permission_level: PermissionLevel = PermissionLevel.READ_ONLY
    timeout: int = 30  # 秒
    has_side_effects: bool = False
    tags: List[str] = field(default_factory=list)
    examples: List[Dict] = field(default_factory=list)
 
 
class ToolRegistry:
    """
    工具注册中心
    
    功能:
    - 工具注册与注销
    - 工具检索(名称、功能、语义)
    - 权限检查
    - 版本管理
    """
    
    def __init__(self):
        self._tools: Dict[str, ToolMetadata] = {}
        self._functions: Dict[str, Callable] = {}
        self._categories: Dict[str, List[str]] = {}
        self._tags: Dict[str, List[str]] = {}
    
    def register(
        self,
        name: str,
        function: Callable,
        description: str,
        parameters: Dict[str, Any],
        **kwargs
    ) -> None:
        """
        注册工具
        
        Args:
            name: 工具名称(唯一标识)
            function: 执行函数
            description: 工具描述
            parameters: 参数 Schema
            **kwargs: 其他元数据
        """
        if name in self._tools:
            raise ValueError(f"工具 '{name}' 已存在")
        
        # 创建元数据
        metadata = ToolMetadata(
            name=name,
            description=description,
            parameters=parameters,
            **kwargs
        )
        
        # 存储
        self._tools[name] = metadata
        self._functions[name] = function
        
        # 更新分类索引
        category = metadata.category
        if category not in self._categories:
            self._categories[category] = []
        self._categories[category].append(name)
        
        # 更新标签索引
        for tag in metadata.tags:
            if tag not in self._tags:
                self._tags[tag] = []
            self._tags[tag].append(name)
        
        print(f"[注册] 工具 '{name}' 注册成功")
    
    def unregister(self, name: str) -> bool:
        """注销工具"""
        if name not in self._tools:
            return False
        
        metadata = self._tools[name]
        
        # 从分类索引中移除
        if metadata.category in self._categories:
            self._categories[metadata.category].remove(name)
        
        # 从标签索引中移除
        for tag in metadata.tags:
            if tag in self._tags:
                self._tags[tag].remove(name)
        
        # 删除工具
        del self._tools[name]
        del self._functions[name]
        
        return True
    
    def get_tool(self, name: str) -> Optional[ToolMetadata]:
        """获取工具元数据"""
        return self._tools.get(name)
    
    def get_function(self, name: str) -> Optional[Callable]:
        """获取工具执行函数"""
        return self._functions.get(name)
    
    def list_tools(
        self,
        category: Optional[str] = None,
        tags: Optional[List[str]] = None
    ) -> List[ToolMetadata]:
        """
        列出工具
        
        Args:
            category: 按分类过滤
            tags: 按标签过滤
            
        Returns:
            工具元数据列表
        """
        if category:
            names = self._categories.get(category, [])
            return [self._tools[n] for n in names if n in self._tools]
        
        if tags:
            names = set()
            for tag in tags:
                names.update(self._tags.get(tag, []))
            return [self._tools[n] for n in names if n in self._tools]
        
        return list(self._tools.values())
    
    def get_openai_tools(self) -> List[Dict]:
        """获取 OpenAI 格式的工具定义列表"""
        return [
            {
                "type": "function",
                "function": {
                    "name": tool.name,
                    "description": tool.description,
                    "parameters": tool.parameters
                }
            }
            for tool in self._tools.values()
        ]
    
    def check_permission(
        self,
        name: str,
        required_level: PermissionLevel
    ) -> bool:
        """检查权限"""
        tool = self._tools.get(name)
        if not tool:
            return False
        return tool.permission_level.value >= required_level.value
 
 
# 使用示例
if __name__ == "__main__":
    registry = ToolRegistry()
    
    # 注册工具
    registry.register(
        name="search_web",
        function=lambda query: f"搜索结果: {query}",
        description="搜索互联网获取信息",
        parameters={
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "搜索关键词"}
            },
            "required": ["query"]
        },
        category="information",
        tags=["search", "web"],
        permission_level=PermissionLevel.READ_ONLY
    )
    
    registry.register(
        name="delete_file",
        function=lambda path: f"删除文件: {path}",
        description="删除指定文件",
        parameters={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "文件路径"}
            },
            "required": ["path"]
        },
        category="system",
        tags=["file", "delete"],
        permission_level=PermissionLevel.SYSTEM,
        has_side_effects=True
    )
    
    # 列出工具
    print("\n所有工具:")
    for tool in registry.list_tools():
        print(f"  - {tool.name}: {tool.description}")
    
    # 按分类查询
    print("\n信息类工具:")
    for tool in registry.list_tools(category="information"):
        print(f"  - {tool.name}")
    
    # 获取 OpenAI 格式
    print("\nOpenAI 工具定义:")
    print(json.dumps(registry.get_openai_tools(), indent=2, ensure_ascii=False))

3.3 大规模工具注册策略

当工具数量从 10 个增加到 1000+ 个时,需要采用分层注册策略:

┌─────────────────────────────────────────────────────────────┐
│                    大规模工具注册策略                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  问题:工具数量过多导致                                      │
│  • 上下文爆炸(Token 消耗)                                 │
│  • 工具选择准确率下降                                       │
│  • 注册和维护困难                                           │
│                                                             │
│  解决方案:分层注册 + 按需加载                              │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐  │
│  │                    全局注册中心                      │  │
│  │                                                      │  │
│  │  ┌─────────┐   ┌─────────┐   ┌─────────┐           │  │
│  │  │ 信息层  │   │ 处理层  │   │ 系统层  │           │  │
│  │  │ Registry│   │ Registry│   │ Registry│           │  │
│  │  └────┬────┘   └────┬────┘   └────┬────┘           │  │
│  │       │             │             │                 │  │
│  │       ↓             ↓             ↓                 │  │
│  │  ┌─────────┐   ┌─────────┐   ┌─────────┐           │  │
│  │  │搜索工具 │   │计算工具 │   │文件工具 │           │  │
│  │  │查询工具 │   │分析工具 │   │进程工具 │           │  │
│  │  │API工具  │   │转换工具 │   │网络工具 │           │  │
│  │  └─────────┘   └─────────┘   └─────────┘           │  │
│  │                                                      │  │
│  └─────────────────────────────────────────────────────┘  │
│                                                             │
│  流程:                                                     │
│  1. 意图分类 → 确定哪个层级                                  │
│  2. 加载对应层级的工具定义                                   │
│  3. 在该层级内选择具体工具                                   │
│                                                             │
│  示例:                                                     │
│  用户: "搜索 Python 教程"                                   │
│  → 意图分类: 信息获取                                       │
│  → 加载: 信息层 Registry (搜索、查询工具)                   │
│  → 工具选择: search_web                                     │
│                                                             │
└─────────────────────────────────────────────────────────────┘
"""
分层工具注册实现
"""
 
class HierarchicalToolRegistry:
    """分层工具注册中心"""
    
    def __init__(self):
        self.registries: Dict[str, ToolRegistry] = {
            "information": ToolRegistry(),
            "processing": ToolRegistry(),
            "system": ToolRegistry()
        }
        self.classifier = None  # 意图分类器
    
    def register_tool(
        self,
        layer: str,
        name: str,
        function: Callable,
        **kwargs
    ):
        """在指定层级注册工具"""
        if layer not in self.registries:
            raise ValueError(f"未知层级: {layer}")
        self.registries[layer].register(name, function, **kwargs)
    
    def get_tools_for_intent(self, intent: str) -> List[Dict]:
        """根据意图获取相关工具"""
        # 意图到层级的映射
        intent_to_layer = {
            "search": "information",
            "query": "information",
            "calculate": "processing",
            "analyze": "processing",
            "file": "system",
            "process": "system"
        }
        
        # 确定层级
        layer = intent_to_layer.get(intent, "information")
        
        # 返回该层级的工具
        return self.registries[layer].get_openai_tools()

四、工具设计最佳实践

4.1 描述设计原则

┌─────────────────────────────────────────────────────────────┐
│                    工具描述设计原则                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 功能明确                                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ ❌ 模糊描述:                                        │   │
│  │    "处理数据"                                        │   │
│  │                                                      │   │
│  │ ✅ 明确描述:                                        │   │
│  │    "将 JSON 数据转换为 CSV 格式,支持嵌套结构展开"   │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
│  2. 适用场景                                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ ✅ 包含使用场景说明:                                │   │
│  │    "搜索互联网获取实时信息,适用于:                 │   │
│  │     • 需要最新数据(如股价、天气)                   │   │
│  │     • 训练数据截止后的信息                           │   │
│  │     • 实时变化的动态内容"                            │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
│  3. 限制说明                                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ ✅ 说明工具的限制:                                  │   │
│  │    "注意:此工具仅支持公开可访问的网页,             │   │
│  │     无法访问需要登录的页面或内网资源"                │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
│  4. 使用示例                                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ ✅ 在参数描述中包含示例:                            │   │
│  │    "city: 城市名称,如 '北京'、'Shanghai'"          │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

4.2 参数设计原则

# 好的参数设计示例
good_parameters = {
    "type": "object",
    "properties": {
        "query": {
            "type": "string",
            "description": "搜索关键词,如 'Python教程' 或 'machine learning'"
        },
        "date_range": {
            "type": "object",
            "description": "时间范围过滤,可选",
            "properties": {
                "start": {
                    "type": "string",
                    "format": "date",
                    "description": "起始日期,格式 YYYY-MM-DD"
                },
                "end": {
                    "type": "string",
                    "format": "date",
                    "description": "结束日期,格式 YYYY-MM-DD"
                }
            }
        },
        "language": {
            "type": "string",
            "enum": ["zh", "en", "ja"],
            "description": "语言过滤,默认不限",
            "default": None
        },
        "num_results": {
            "type": "integer",
            "description": "返回结果数量,1-20之间",
            "default": 10,
            "minimum": 1,
            "maximum": 20
        }
    },
    "required": ["query"]
}
 
# 差的参数设计示例(避免)
bad_parameters = {
    "type": "object",
    "properties": {
        "q": {  # 参数名不清晰
            "type": "string"
            # 缺少 description
        },
        "n": {  # 参数名缩写过度
            "type": "integer"
            # 缺少范围限制
        }
    }
    # 缺少 required
}

4.3 常见工具类型模板

"""
常用工具类型模板
"""
 
# 1. 搜索类工具
SEARCH_TOOL_TEMPLATE = {
    "name": "search",
    "description": "搜索{source}获取信息",
    "parameters": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "搜索关键词"
            },
            "filters": {
                "type": "object",
                "description": "过滤条件"
            }
        },
        "required": ["query"]
    }
}
 
# 2. 计算/处理类工具
CALCULATOR_TOOL_TEMPLATE = {
    "name": "calculate",
    "description": "执行数学计算或数据处理",
    "parameters": {
        "type": "object",
        "properties": {
            "expression": {
                "type": "string",
                "description": "计算表达式或处理指令"
            },
            "precision": {
                "type": "integer",
                "description": "结果精度(小数位数)",
                "default": 2
            }
        },
        "required": ["expression"]
    }
}
 
# 3. 文件操作类工具
FILE_TOOL_TEMPLATE = {
    "name": "file_operation",
    "description": "{operation}文件",
    "parameters": {
        "type": "object",
        "properties": {
            "path": {
                "type": "string",
                "description": "文件路径"
            },
            "content": {
                "type": "string",
                "description": "文件内容(写入时)"
            },
            "encoding": {
                "type": "string",
                "enum": ["utf-8", "gbk", "ascii"],
                "default": "utf-8"
            }
        },
        "required": ["path"]
    }
}
 
# 4. API 调用类工具
API_TOOL_TEMPLATE = {
    "name": "api_call",
    "description": "调用{service} API",
    "parameters": {
        "type": "object",
        "properties": {
            "endpoint": {
                "type": "string",
                "description": "API 端点路径"
            },
            "method": {
                "type": "string",
                "enum": ["GET", "POST", "PUT", "DELETE"],
                "default": "GET"
            },
            "params": {
                "type": "object",
                "description": "请求参数"
            },
            "body": {
                "type": "object",
                "description": "请求体(POST/PUT)"
            }
        },
        "required": ["endpoint"]
    }
}

五、面试高频问题

Q1: 如何设计一个好的工具描述?

答案要点

  1. 功能明确:清晰说明工具能做什么
  2. 适用场景:说明何时应该使用此工具
  3. 限制说明:说明工具不能做什么
  4. 使用示例:在参数描述中包含典型值

Q2: 工具数量很多时,如何解决上下文爆炸问题?

答案要点

策略说明
分层注册按功能分类,按需加载
Tool RAG语义检索相关工具
工具摘要压缩工具描述
动态加载根据意图动态注入工具定义

Q3: JSON Schema 中如何表示复杂参数类型?

答案要点

{
  "type": "object",
  "properties": {
    "nested_object": {
      "type": "object",
      "properties": {
        "field": {"type": "string"}
      }
    },
    "array_field": {
      "type": "array",
      "items": {"type": "string"}
    },
    "enum_field": {
      "type": "string",
      "enum": ["option1", "option2"]
    },
    "union_type": {
      "oneOf": [
        {"type": "string"},
        {"type": "integer"}
      ]
    }
  }
}

Q4: 如何防止 Agent 调用破坏性工具?

答案要点

  1. 权限分级:工具设置权限等级,高风险工具需要更高权限
  2. 人类确认:破坏性操作需要人工确认
  3. 沙箱执行:在隔离环境中执行
  4. 审计日志:记录所有操作,便于追溯

Q5: 工具注册中心需要哪些核心功能?

答案要点

功能说明
工具注册支持动态添加/删除工具
工具检索按名称、分类、标签检索
格式转换输出不同平台的工具定义格式
权限管理检查工具调用权限
版本管理支持工具版本控制

六、小结

概念一句话总结
工具定义包含元数据、参数 Schema、行为配置的完整描述
JSON Schema标准化的参数类型定义语言
注册中心管理工具生命周期、提供检索和权限控制
设计原则功能明确、适用场景、限制说明、使用示例
大规模策略分层注册 + 按需加载 + Tool RAG

一句话总结:好的工具定义是 Agent 正确使用工具的前提,需要关注描述清晰、参数完整、权限分级和大规模场景下的分层管理。


最后更新:2026年3月18日