Agent开发第2步:定义工具抽象 (Tools)

在第1步中,我们通过 Model Adapter 赋予了 Agent "思考"和"交流"的能力。然而,纯粹的语言模型只能基于训练数据回答问题,无法获取实时信息或操作外部系统。为了让 Agent 真正变得强大,我们需要为它装上"手和脚"------这就是**工具(Tools)**的作用。

1. 什么是工具抽象?

大语言模型通常支持 Function Calling(函数调用)机制。这意味着模型可以决定何时调用某个特定函数,并要求我们(客户端)执行该函数并将结果返回给它。

为了让 Agent 能够动态加载、管理和执行不同的函数,我们需要定义一套标准的工具抽象(Tool Interface)。每个工具都应该包含:

  1. 工具名称 (Name)
  2. 工具描述 (Description):告诉 LLM 这个工具是干什么的。
  3. 参数 Schema (Parameters):告诉 LLM 调用该工具需要提供哪些参数。
  4. 执行逻辑 (Run/Execute):实际运行的 Python 代码。

2. 工具调用工作流

3. Python 代码实现

我们先定义一个基础的工具类 BaseTool,然后实现具体的工具,例如一个查询天气的工具和一个计算器工具。

定义基础抽象类

python 复制代码
from abc import ABC, abstractmethod
from typing import Dict, Any, Type
from pydantic import BaseModel, Field

class BaseTool(ABC):
    name: str
    description: str
    args_schema: Type[BaseModel]

    @abstractmethod
    def run(self, **kwargs) -> str:
        """执行工具的核心逻辑"""
        pass
    
    def get_function_declaration(self) -> Dict[str, Any]:
        """将工具转换为 LLM 认识的 JSON Schema 格式"""
        return {
            "type": "function",
            "function": {
                "name": self.name,
                "description": self.description,
                "parameters": self.args_schema.model_json_schema()
            }
        }

实现具体工具:天气查询与计算器

python 复制代码
class WeatherArgs(BaseModel):
    location: str = Field(..., description="城市名称,例如:北京, 上海")

class WeatherTool(BaseTool):
    name = "get_weather"
    description = "获取指定城市的当前天气情况"
    args_schema = WeatherArgs

    def run(self, location: str) -> str:
        # 这里可以接入真实的第三方天气 API
        # 为了演示,我们返回 mock 数据
        mock_weather = {
            "北京": "晴朗,25度",
            "上海": "小雨,22度"
        }
        return mock_weather.get(location, f"无法获取 {location} 的天气信息")


class CalculatorArgs(BaseModel):
    expression: str = Field(..., description="数学表达式,例如:2 + 2 * 3")

class CalculatorTool(BaseTool):
    name = "calculator"
    description = "计算数学表达式的结果"
    args_schema = CalculatorArgs

    def run(self, expression: str) -> str:
        try:
            # 警告:实际生产环境中请使用安全的 eval 替代方案
            result = eval(expression)
            return str(result)
        except Exception as e:
            return f"计算错误: {str(e)}"

工具注册与管理

我们需要一个统一的地方来管理这些工具,并在 LLM 请求调用时找到对应的工具实例。

python 复制代码
class ToolRegistry:
    def __init__(self):
        self._tools: Dict[str, BaseTool] = {}

    def register(self, tool: BaseTool):
        self._tools[tool.name] = tool

    def get_all_declarations(self) -> list:
        """获取所有工具的声明,传给 LLM"""
        return [tool.get_function_declaration() for tool in self._tools.values()]

    def execute_tool(self, name: str, kwargs: dict) -> str:
        """根据 LLM 的指令执行对应工具"""
        if name not in self._tools:
            return f"Error: Tool {name} not found."
        
        tool = self._tools[name]
        try:
            # 使用 Pydantic 验证参数
            validated_args = tool.args_schema(**kwargs)
            # 执行工具
            return tool.run(**validated_args.model_dump())
        except Exception as e:
            return f"Tool Execution Error: {str(e)}"

# 初始化注册表并注册工具
registry = ToolRegistry()
registry.register(WeatherTool())
registry.register(CalculatorTool())

# 打印生成的 JSON Schema 给 LLM 看
import json
print(json.dumps(registry.get_all_declarations(), indent=2, ensure_ascii=False))

总结

通过抽象出 BaseTool 和 ToolRegistry,我们极大地方便了后续工具的扩展。开发者只需要继承基础类并定义参数 Schema,即可快速将新的能力接入到 Agent 中。

有了大脑(Model Adapter)和手脚(Tools),下一步就是将它们结合起来,让 Agent 自主地进行"思考、调用工具、观察结果、回答"的循环------这就是我们在下一篇要实现的 Agent Loop。

相关推荐
Navicat中国13 分钟前
Navicat 18 内置 AI 助手让数据库开发从繁琐操作迈向智能协作
大数据·人工智能·数据库开发
4SAPI35 分钟前
多模型请求路由怎么设计?成本、速度和能力如何平衡
人工智能·python·gateway·php
魔乐社区1 小时前
翼芯・智算测试与适配优化专区,让国产算力“选得准、跑得通、用得好“
人工智能·开源·大模型
XCDoris3 小时前
郴州logo设计机构
大数据·人工智能·python
Goboy3 小时前
一个人带三个Agent,我用全新TRAE从0到1搭了个资讯周刊站
人工智能·trae
俊哥V3 小时前
每日 AI 研究简报 · 2026-10-19
人工智能·ai
AI_AGENT_DEV_AI3 小时前
AI英语教培智能体的开发
人工智能
物联网软硬件开发-轨物科技3 小时前
【技术白皮书】光伏清检一体化机器人系统解决方案技术白皮书
大数据·运维·网络·人工智能·机器人
海宇数据3 小时前
零信任架构实战:基于海宇网上踪迹欺诈行为识别构建自动化信贷资信评估网关
运维·人工智能·架构·自动化
冬奇Lab4 小时前
开源项目第242期:HyperFrames —— 写 HTML 就能渲染视频,专为 AI Agent 设计的确定性视频框架
人工智能·开源·音视频开发