工具库设计:构建可复用的 AI Agent 工具
前言
工具是 AI Agent 能力的重要延伸。设计一个良好的工具库,能让 Agent 方便地调用各种功能,如搜索、计算、数据处理等。
我在多个项目中设计过工具库,今天分享一些设计经验和实现。
工具基类设计
from abc import ABC, abstractmethod from typing import Dict, Any, List, Optional from dataclasses import dataclass @dataclass class ToolResult: """工具执行结果""" success: bool content: str metadata: Dict[str, Any] = None error: str = None class BaseTool(ABC): """工具基类""" name: str description: str def __init__(self): pass @abstractmethod def execute(self, params: Dict[str, Any]) -> ToolResult: """执行工具""" pass def get_schema(self) -> Dict[str, Any]: """获取工具参数 schema""" return { "type": "object", "properties": {} }搜索工具示例
import requests from typing import Dict, Any class SearchTool(BaseTool): """搜索工具""" name = "web_search" description = "搜索网页信息" def __init__(self, api_key: str = None): super().__init__() self.api_key = api_key def execute(self, params: Dict[str, Any]) -> ToolResult: """执行搜索""" query = params.get("query", "") if not query: return ToolResult( success=False, content="", error="查询不能为空" ) try: # 实际搜索逻辑 # 这里使用示例搜索 search_results = [ { "title": f"关于 {query} 的搜索结果", "snippet": "这是搜索结果的摘要信息...", "url": "https://example.com/result" } ] content = "\n".join([ f"标题: {r['title']}\n摘要: {r['snippet']}\n链接: {r['url']}" for r in search_results ]) return ToolResult( success=True, content=content, metadata={"query": query, "count": len(search_results)} ) except Exception as e: return ToolResult( success=False, content="", error=str(e) ) def get_schema(self) -> Dict[str, Any]: """获取参数 schema""" return { "type": "object", "properties": { "query": { "type": "string", "description": "搜索关键词" } }, "required": ["query"] }计算器工具
import math from typing import Dict, Any class CalculatorTool(BaseTool): """计算器工具""" name = "calculator" description = "执行数学计算" def __init__(self): super().__init__() def execute(self, params: Dict[str, Any]) -> ToolResult: """执行计算""" try: expression = params.get("expression", "") # 安全计算(简化版) # 实际项目中应使用更安全的计算方式 result = self._safe_calculate(expression) return ToolResult( success=True, content=str(result), metadata={"expression": expression, "result": result} ) except Exception as e: return ToolResult( success=False, content="", error=str(e) ) def _safe_calculate(self, expr: str): """安全计算""" # 使用安全的求值方式 allowed = { 'math': math, 'abs': abs, 'min': min, 'max': max, 'sum': sum } try: return eval(expr, {"__builtins__": None}, allowed) except: raise ValueError("计算错误") def get_schema(self) -> Dict[str, Any]: return { "type": "object", "properties": { "expression": { "type": "string", "description": "数学表达式" } }, "required": ["expression"] }工具注册与管理
from typing import Dict, List, Optional class ToolRegistry: """工具注册表""" def __init__(self): self.tools: Dict[str, BaseTool] = {} def register(self, tool: BaseTool): """注册工具""" self.tools[tool.name] = tool def unregister(self, name: str): """注销工具""" if name in self.tools: del self.tools[name] def get(self, name: str) -> Optional[BaseTool]: """获取工具""" return self.tools.get(name) def list_tools(self) -> List[Dict[str, Any]]: """列出所有工具""" return [ { "name": tool.name, "description": tool.description, "schema": tool.get_schema() } for tool in self.tools.values() ] def execute_tool(self, name: str, params: Dict[str, Any]) -> ToolResult: """执行工具""" tool = self.get(name) if not tool: return ToolResult( success=False, content="", error=f"工具 {name} 不存在" ) return tool.execute(params)工具调用
from typing import Dict, Any import json class ToolCaller: """工具调用器""" def __init__(self, registry: ToolRegistry): self.registry = registry self.history = [] def call_tool(self, tool_name: str, params: Dict[str, Any]) -> ToolResult: """调用工具""" result = self.registry.execute_tool(tool_name, params) # 记录历史 self.history.append({ "tool": tool_name, "params": params, "result": result, "timestamp": None # 可添加时间戳 }) return result def parse_and_call(self, json_str: str) -> ToolResult: """解析 JSON 并调用""" try: call = json.loads(json_str) tool_name = call.get("name") params = call.get("params", {}) return self.call_tool(tool_name, params) except json.JSONDecodeError as e: return ToolResult( success=False, content="", error=f"JSON 解析错误: {str(e)}" )完整工具库示例
# 创建并注册工具 registry = ToolRegistry() registry.register(SearchTool()) registry.register(CalculatorTool()) # 使用工具 caller = ToolCaller(registry) # 调用搜索 search_result = caller.call_tool("web_search", {"query": "Python 教程"}) print(search_result) # 调用计算器 calc_result = caller.call_tool("calculator", {"expression": "2 * math.pi"}) print(calc_result)总结
工具库设计要点:
- 基类抽象:统一的工具接口
- 注册管理:方便的工具管理
- 安全执行:输入验证和沙箱
- 结果标准化:统一的结果格式
- 可扩展性:易于添加新工具
实践建议:
- 从简单工具开始
- 逐步完善工具库
- 添加工具文档和示例
- 监控工具使用情况