工厂基类

目录

统一注册工具函数、统一调用执行的框架,就像你现在做的那样 —— 类似于一个「工具工厂」。

from typing import Dict, Callable, Any
import inspect
import json

# 工具工厂基类
class BaseTool:
    registry: Dict[str, Callable] = {}

    @classmethod
    def register(cls, fn: Callable):
        """注册工具函数到工厂"""
        cls.registry[fn.__name__] = fn
        return fn

    @classmethod
    def get_tools(cls):
        """返回所有注册的工具定义(给 OpenAI)"""
        tools = []
        for name, fn in cls.registry.items():
            sig = inspect.signature(fn)
            parameters = {
                "type": "object",
                "properties": {},
                "required": [],
            }
            for param in sig.parameters.values():
                parameters["properties"][param.name] = {
                    "type": "string",
                    "description": f"{param.name} 参数"
                }
                parameters["required"].append(param.name)

            tools.append({
                "type": "function",
                "function": {
                    "name": name,
                    "description": fn.__doc__ or "无描述",
                    "parameters": parameters
                }
            })
        return tools

    @classmethod
    def call(cls, name: str, args: Dict[str, Any]) -> str:
        """根据名称调用工具函数"""
        if name not in cls.registry:
            raise ValueError(f"未注册的工具函数: {name}")
        return cls.registry[name](**args)

# ==============================

# 子类工具集:自动注册
class MyTools(BaseTool):

    @BaseTool.register
    def get_weather(location: str) -> str:
        """获取城市天气信息"""
        return f"☀️ 当前 {location} 晴天,温度 25°C"

    @BaseTool.register
    def get_time(city: str) -> str:
        """获取当前时间"""
        return f"🕒 当前 {city} 时间为 12:00"

# ==============================

# 🧪 测试工厂调用
if __name__ == "__main__":
    tools = BaseTool.get_tools()
    print("注册的工具定义(可传给 OpenAI 的 tools):")
    print(json.dumps(tools, indent=2, ensure_ascii=False))

    print("\n✅ 工厂调用 get_weather:")
    result = BaseTool.call("get_weather", {"location": "北京"})
    print(result)

    print("\n✅ 工厂调用 get_time:")
    result = BaseTool.call("get_time", {"city": "上海"})
    print(result)
机制 作用
@BaseTool.register 自动注册工具函数进工厂
BaseTool.call(name, args) 根据名字自动找到函数并执行
BaseTool.get_tools() 生成 OpenAI 所需的 tools 描述

🔁 @BaseTool.register 是什么?

它是一个类方法装饰器,装饰的作用是把函数注册到 BaseTool.registry 这个字典中,供后续统一调用。

这个 @classmethod 的作用是——将一个函数 fn 注册进当前类的 registry 字典中,键是函数名,值是函数本体。

class MyTools(BaseTool):

    @BaseTool.register
    def get_weather(location: str) -> str:
        return f"{location} 今天晴,25°C"

等价于:

def get_weather(location: str) -> str:
    return f"{location} 今天晴,25°C"

BaseTool.register(get_weather)

{
  "get_weather": <function get_weather(...)>,
  "get_time": <function get_time(...)>
}

当你执行:

for name, fn in cls.registry.items():
name fn
“get_weather”
“get_time”

Python 的 inspect.signature(fn) 是标准库中的函数,用来获取函数的参数信息

def get_weather(location: str):
    pass

sig = inspect.signature(get_weather)
print(sig)  # (location: str)
代码 作用
cls.registry.items() 获取注册的所有函数名和函数本体
inspect.signature(fn) 获取函数的参数定义
构建 parameters 字典 转成 OpenAI tools 能识别的格式

点赞一下

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦