5.1 工具抽象接口设计

工具抽象接口是工具系统的核心基础,需要在通用性、类型安全、可观测性和性能间取得平衡。本节介绍Claude Code的泛型设计、工具实现示例、注册中心机制,以及权限管理策略。

5.1.1 统一工具接口的设计目标

工具抽象接口的设计需要平衡以下目标:

  1. 通用性:支持各种异构工具(文件、网络、计算、数据库等)

  2. 类型安全:在编译时(或运行时)检查参数和返回值类型

  3. 可观测性:支持进度报告、事件发射、日志记录

  4. 可扩展性:易于添加新工具类型

  5. 性能:最小化开销,支持并发执行

  6. 安全性:权限检查、资源限制、错误隔离

5.1.2 Claude Code 的 Tool<Input,Output,Progress> 泛型设计

Claude Code 采用泛型 Tool 接口,明确定义输入、输出和进度类型:

"""
Claude Code 风格的工具接口
"""

from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Generic, TypeVar, Optional, Dict, Any, List
import asyncio

# 类型变量
InputType = TypeVar('InputType')
OutputType = TypeVar('OutputType')
ProgressType = TypeVar('ProgressType')

@dataclass
class ToolProgress:
    """工具执行进度"""
    step: int              # 当前步骤号
    total_steps: int       # 总步骤数
    current_status: str    # 当前状态描述
    estimated_time_remaining: Optional[float] = None  # 剩余时间(秒)

    def percentage(self) -> float:
        """进度百分比"""
        return (self.step / self.total_steps * 100) if self.total_steps > 0 else 0

class Tool(ABC, Generic[InputType, OutputType]):
    """通用工具抽象"""

    @abstractmethod
    async def call(self, input_data: InputType) -> OutputType:
        """
        执行工具

        Args:
            input_data: 工具输入,已验证和类型检查过

        Returns:
            工具执行结果

        Raises:
            ToolExecutionError: 工具执行失败
        """
        pass

    @abstractmethod
    def name(self) -> str:
        """工具名称"""
        pass

    @abstractmethod
    def description(self) -> str:
        """工具描述"""
        pass

    @abstractmethod
    def input_schema(self) -> Dict[str, Any]:
        """输入的 JSON Schema"""
        pass

    def check_permissions(self, context: Any) -> bool:
        """
        检查当前上下文是否有权限调用此工具

        Args:
            context: 执行上下文(包含用户、会话信息等)

        Returns:
            是否有权限
        """
        return True  # 默认允许

    async def get_progress(self) -> Optional[ToolProgress]:
        """
        获取工具执行进度

        Returns:
            进度对象,如果工具不支持进度报告则返回 None
        """
        return None

    def supports_streaming(self) -> bool:
        """工具是否支持流式输出"""
        return False

    async def stream_output(self, input_data: InputType):
        """
        流式输出(可选)

        Yields:
            OutputType: 逐个产生的输出
        """
        if not self.supports_streaming():
            output = await self.call(input_data)
            yield output

⚠️ 类型系统说明:上述 Tool[InputType, OutputType] 的泛型注解为设计理想。在 Python 运行时,由于动态类型特性,实际实现常使用 Dict[str,Any] 承载参数和返回值。这是 Python 动态类型系统与静态类型检查间的权衡——静态分析可以验证泛型约束,但运行时仍需灵活处理异构数据。关于完整的类型安全实现,请参考第 5.3 节和附录 D (MiniHarness 类型体系)。

本节展示了工具的核心设计模式与流程。为了更好地理解如何将这些模式应用于实践,下面我们通过具体的实现示例来演示工具的常见用法。

5.1.3 工具实现示例

1. 简单工具:Bash 执行

一个简单的Bash命令执行工具的实现如下:

2. 支持进度报告的工具:文件复制

一个支持进度报告的文件复制工具,展示如何在长时间运行的操作中提供实时反馈:

3. 流式输出工具:数据库查询

一个支持流式输出的数据库查询工具,展示如何处理大结果集:

💡 类型参数说明:以下示例中 Tool<I,O,P> 的类型参数为概念占位符。运行时实现使用 Dict[str,Any] 承载动态数据。如需真正的静态类型约束,可改用 Pydantic BaseModelTypedDict(见附录 D MiniHarness 实现)。

5.1.4 buildTool() 工厂函数

Claude Code 使用工厂函数动态构造工具,支持参数化和延迟初始化:

5.1.5 工具注册中心

工具注册中心是所有工具的中枢,负责工具的注册、发现和管理。下面的流程图展示了工具的注册、发现和查询的完整流程:

图 5-1:工具注册与发现流程

5.1.6 OpenClaw 的工具策略模型

OpenClaw 支持更细粒度的权限管理:

5.1.7 本节小结

工具抽象接口的设计决定了整个工具系统的质量和可维护性:

  1. Claude Code 的 Tool<I,O,P> 泛型设计 提供了强类型检查,但需要 Python 的高级类型系统支持

  2. 工具工厂函数 支持动态工具构造和参数化配置

  3. 工具注册中心 管理工具的生命周期和 Schema 缓存

  4. 权限检查 在工具调用前进行,可以是简单的 boolean 也可以是复杂的策略模型

  5. OpenClaw 的工具策略模型 提供更细粒度的权限管理,支持不同智能体的不同权限

好的工具抽象应该既通用又灵活,既简单又强大。在实践中,需要根据具体场景选择合适的抽象级别。

最后更新于