Skip to content
Back to skills

1850 Tool Cf3974f2

ASecurity

SimpleLLMFunc 的工具系统为大语言模型提供了调用外部函数和 API 的能力,让 LLM 能够执行计算、查询数据、调用服务等操作。工具系统支持两种创建方式,并能自动将 Python 函数转换为 LLM 可理解的工具描述格式。

  • 9 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 31, 2026
ai-agentspythonexpressgitapi

Works with

  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned May 31, 2026

npx -y skills add tools-only/X-Skills --skill 1850-tool_cf3974f2 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 1850 Tool Cf3974f2?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 1850 Tool Cf3974f2
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-1850-tool-cf3974f2/badge)](https://www.skillsdirectory.com/skills/tools-only-1850-tool-cf3974f2)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# Tool 工具系统

## 实现功能

SimpleLLMFunc 的工具系统为大语言模型提供了调用外部函数和 API 的能力,让 LLM 能够执行计算、查询数据、调用服务等操作。工具系统支持两种创建方式,并能自动将 Python 函数转换为 LLM 可理解的工具描述格式。

### 核心功能特性
- **智能类型推断**: 自动从函数签名中提取参数类型和描述信息
- **文档字符串解析**: 支持从 docstring 中解析参数描述
- **JSON Schema 生成**: 自动生成符合 OpenAI Function Calling API 的工具描述
- **类型安全**: 支持基本类型、容器类型、Pydantic 模型等多种类型
- **灵活创建**: 支持装饰器和继承两种创建方式
- **批量序列化**: 支持将多个工具一次性序列化为 API 格式

### 支持的数据类型(参数类型)
- **基本类型**: `str`, `int`, `float`, `bool`
- **容器类型**: `List[T]`, `Dict[K, V]`
- **Pydantic 模型**: 自动解析模型字段和验证规则
- **可选参数**: 支持带默认值的可选参数
- **复杂嵌套**: 支持嵌套的容器类型和复杂对象

**⚠️ 注意: 由于LLM提供给工具的参数只能是json支持的类型,所以实际上`Tuple`, `Set`等容器是无法作为工具参数的**

### 支持的返回类型
工具函数可以返回多种数据格式,系统会自动处理这些返回值并将其传递给 LLM:

#### 基本返回类型
- **字符串 (`str`)**: 直接作为文本内容返回给 LLM
- **JSON 可序列化对象**: 包括 `dict`, `list`, `int`, `float`, `bool`, `None`
- **Pydantic 模型**: 自动序列化为 JSON 格式

#### 多模态返回类型
- **图片URL (`ImgUrl`)**: 返回网络图片链接,LLM 可以"看到"图片内容
- **本地图片 (`ImgPath`)**: 返回本地图片文件路径,自动转换为 base64 格式
- **文本+图片组合 (`Tuple[str, ImgUrl]` 或 `Tuple[str, ImgPath]`)**: 同时返回文本说明和图片

#### 返回类型示例

```python
from SimpleLLMFunc import tool
from SimpleLLMFunc.llm_decorator import ImgUrl, ImgPath
from typing import Dict, List, Tuple, Any

# 1. 基本类型返回
@tool(name="calculate", description="执行数学计算")
async def calculate(expression: str) -> float:
    """返回计算结果(浮点数)"""
    return eval(expression)

@tool(name="get_status", description="获取系统状态")
async def get_status() -> str:
    """返回状态信息(字符串)"""
    return "系统运行正常"

# 2. JSON 对象返回
@tool(name="get_user_info", description="获取用户信息")
async def get_user_info(user_id: int) -> Dict[str, Any]:
    """返回用户信息(字典)"""
    return {
        "id": user_id,
        "name": "张三",
        "age": 25,
        "skills": ["Python", "AI", "数据分析"]
    }

@tool(name="search_results", description="搜索并返回结果列表")
async def search_results(query: str) -> List[Dict[str, str]]:
    """返回搜索结果(字典列表)"""
    return [
        {"title": "结果1", "url": "https://example1.com"},
        {"title": "结果2", "url": "https://example2.com"}
    ]

# 3. 多模态返回 - 单独图片
@tool(name="get_chart", description="生成数据图表")
async def get_chart(data: List[float]) -> ImgPath:
    """返回图表图片(本地文件)"""
    # 在chart path下有一个对应的图片文件
    chart_path = "/path/to/generated/chart.png"
    return ImgPath(chart_path)

@tool(name="fetch_image", description="获取网络图片")
async def fetch_image(image_url: str) -> ImgUrl:
    """返回网络图片URL"""
    return ImgUrl(image_url)

# 4. 多模态返回 - 文本+图片组合
@tool(name="analyze_image", description="分析图片并生成报告")
async def analyze_image(image_path: str) -> Tuple[str, ImgPath]:
    """返回分析报告和标注后的图片"""
    analysis_text = "检测到3个对象:2个人、1辆汽车"
    annotated_image = ImgPath("/path/to/annotated_image.png")
    return (analysis_text, annotated_image)
```

#### 返回类型处理机制

1. **基本类型**: 直接序列化为 JSON 字符串传递给 LLM
2. **图片类型**: 
   - `ImgUrl`: 直接使用网络 URL
   - `ImgPath`: 自动转换为 base64 编码的 data URL
3. **组合类型**: 将文本和图片组合成多模态消息,LLM 可以同时看到文本说明和图片内容
4. **错误处理**: 不支持的返回类型会自动转换为字符串格式

**⚠️ 返回类型注意事项**:
- 确保本地图片文件路径存在且可读
- 网络图片 URL 应该是公开可访问的
- 组合类型的元组必须是 `(str, ImgPath)` 或 `(str, ImgUrl)` 格式, 不能交换`str`和`ImgPath`/`ImgUrl`的顺序
- 避免返回过大的数据结构,以免影响 LLM 处理效率

**⚠️ 注意:`@tool` 装饰器要求被装饰的函数本身定义为 `async def`,以便在异步执行链路中无缝协作。**

## 使用方法

### 基本语法

#### 方式一:装饰器方式(推荐)

```python
from SimpleLLMFunc import tool

@tool(name="工具名称", description="工具简短描述")
async def your_function(param1: Type1, param2: Type2 = default_value) -> ReturnType:
    """
    详细的函数说明,这部分会被包含在工具描述中
    
    Args:
        param1: 参数1的详细描述
        param2: 参数2的详细描述
        
    Returns:
        返回值描述
    """
    # 函数实现
    pass
```

#### 方式二:继承方式(兼容旧版本)

```python
from SimpleLLMFunc import Tool

class YourTool(Tool):
    def __init__(self):
        super().__init__(
            name="工具名称",
            description="工具描述"
        )
    
    def run(self, *args, **kwargs):
        # 工具执行逻辑
        pass
```

### 参数说明

#### @tool 装饰器参数
- **name** (必需): 工具名称,应该简洁明了,符合函数命名规范
- **description** (必需): 工具的简短描述,说明工具的主要功能

#### 函数要求
- **类型标注**: 建议为所有参数添加类型标注,以便自动生成准确的 JSON Schema
- **文档字符串**: 建议编写详细的 docstring,特别是 Args 部分的参数描述
- **返回类型**: 建议添加返回类型标注

### 工具调用流程

1. **工具注册**: 使用 `@tool` 装饰器或继承 `Tool` 类创建工具
2. **参数解析**: 系统自动从函数签名中提取参数信息
3. **Schema 生成**: 自动生成符合 OpenAI API 的工具描述
4. **LLM 调用**: LLM 根据工具描述决定是否调用工具
5. **参数验证**: 系统验证 LLM 提供的参数是否符合要求
6. **函数执行**: 调用原始 Python 函数并返回结果

## 实现方法

### 核心类结构

#### Parameter 类
```python
class Parameter:
    """工具参数的包装类"""
    def __init__(self, name, description, type_annotation, required, default=None, example=None):
        self.name = name                    # 参数名
        self.description = description      # 参数描述
        self.type_annotation = type_annotation  # Python 类型标注
        self.required = required            # 是否必需
        self.default = default             # 默认值
        self.example = example             # 示例值
```

#### Tool 类
```python
class Tool(ABC):
    """抽象工具基类"""
    def __init__(self, name, description, func=None):
        self.name = name
        self.description = description
        self.func = func                   # 关联的函数
        self.parameters = self._extract_parameters()  # 参数列表
    
    def run(self, *args, **kwargs):
        """执行工具"""
        
    def to_openai_tool(self):
        """转换为 OpenAI 工具格式"""
        
    @staticmethod
    def serialize_tools(tools):
        """批量序列化工具"""
```

### 关键实现细节

#### 参数提取机制
系统通过以下步骤提取函数参数信息:

1. **签名分析**: 使用 `inspect.signature()` 获取函数签名
2. **类型提示**: 使用 `get_type_hints()` 获取类型标注
3. **文档解析**: 使用正则表达式解析 docstring 中的参数描述
4. **默认值处理**: 识别可选参数和默认值

#### 类型转换规则
```python
# 基本类型映射
str  -> {"type": "string"}
int  -> {"type": "integer"}
float -> {"type": "number"}
bool -> {"type": "boolean"}

# 容器类型
List[T] -> {"type": "array", "items": schema_of_T}
Dict[K, V] -> {"type": "object", "additionalProperties": schema_of_V}

# Pydantic 模型
BaseModel -> {"type": "object", "properties": model_json_schema}
```

#### 文档字符串解析
系统支持标准的 docstring 格式:

```python
def example_function(param1: str, param2: int = 10):
    """
    函数的主要描述
    
    Args:
        param1: 第一个参数的描述
        param2: 第二个参数的描述,可选
        
    Returns:
        返回值描述
    """
```

## 兼容写法

### 装饰器方式示例

```python
from SimpleLLMFunc import tool
from typing import List, Dict, Any, Optional
from pydantic import BaseModel, Field

# 示例1:基本数据类型
@tool(name="calculate", description="执行数学计算")
async def calculate(expression: str) -> float:
    """
    计算数学表达式的值
    
    Args:
        expression: 要计算的数学表达式,如 "2 + 3 * 4"
        
    Returns:
        计算结果
    """
    return eval(expression)

# 示例2:带可选参数
@tool(name="search_web", description="搜索网络信息")
async def search_web(query: str, max_results: int = 10, language: str = "zh") -> List[Dict[str, str]]:
    """
    在网络上搜索信息
    
    Args:
        query: 搜索关键词
        max_results: 最大返回结果数量,默认10条
        language: 搜索语言,默认中文
        
    Returns:
        搜索结果列表,每个结果包含标题和链接
    """
    # 模拟搜索实现
    return [
        {"title": f"搜索结果 {i}", "url": f"http://example.com/{i}"} 
        for i in range(max_results)
    ]

# 示例3:使用 Pydantic 模型
class Location(BaseModel):
    latitude: float = Field(..., description="纬度")
    longitude: float = Field(..., description="经度")
    name: Optional[str] = Field(None, description="位置名称")

@tool(name="get_weather", description="获取天气信息")
async def get_weather(location: Location, days: int = 1) -> Dict[str, Any]:
    """
    获取指定位置的天气预报
    
    Args:
        location: 位置信息,包含经纬度坐标
        days: 预报天数,1-7天,默认1天
        
    Returns:
        天气预报数据,包含温度、湿度、天气状况等
    """
    return {
        "location": location.name or f"{location.latitude},{location.longitude}",
        "forecast": [
            {
                "day": i + 1,
                "temperature": 25,
                "humidity": 60,
                "condition": "晴朗"
            } for i in range(days)
        ]
    }

# 示例4:复杂数据处理
@tool(name="analyze_data", description="分析数据集")
async def analyze_data(
    data: List[Dict[str, Any]], 
    analysis_type: str,
    include_charts: bool = False
) -> Dict[str, Any]:
    """
    对数据集进行统计分析
    
    Args:
        data: 要分析的数据集,每个元素是一个包含字段的字典
        analysis_type: 分析类型,可选值:summary, trend, correlation
        include_charts: 是否包含图表数据,默认否
        
    Returns:
        分析结果,包含统计信息和可选的图表数据
    """
    result = {
        "type": analysis_type,
        "record_count": len(data),
        "summary": "数据分析完成"
    }
    
    if include_charts:
        result["charts"] = {"type": "bar", "data": "chart_data"}
    
    return result

# 示例5:多模态返回类型
from SimpleLLMFunc import ImgUrl, ImgPath
from typing import Tuple

@tool(name="generate_chart", description="生成数据图表")
async def generate_chart(data: List[float], chart_type: str = "bar") -> ImgPath:
    """
    根据数据生成图表并保存为本地文件
    
    Args:
        data: 数据列表
        chart_type: 图表类型,如 bar、line、pie
        
    Returns:
        生成的图表文件路径
    """
    # 模拟图表生成
    import matplotlib.pyplot as plt
    import tempfile
    import os
    
    plt.figure(figsize=(10, 6))
    if chart_type == "bar":
        plt.bar(range(len(data)), data)
    elif chart_type == "line":
        plt.plot(data)
    
    # 保存到临时文件
    temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.png')
    plt.savefig(temp_file.name)
    plt.close()
    
    return ImgPath(temp_file.name)

@tool(name="fetch_web_image", description="获取网络图片")
async def fetch_web_image(image_url: str) -> ImgUrl:
    """
    验证并返回网络图片URL
    
    Args:
        image_url: 图片的网络地址
        
    Returns:
        验证后的图片URL对象
    """
    # 可以添加URL验证逻辑
    return ImgUrl(image_url, detail="high")

@tool(name="analyze_image_with_report", description="分析图片并生成详细报告")
async def analyze_image_with_report(image_path: str) -> Tuple[str, ImgPath]:
    """
    分析图片内容并生成带标注的图片
    
    Args:
        image_path: 要分析的图片路径
        
    Returns:
        分析报告文本和标注后的图片路径
    """
    # 模拟图像分析
    analysis_report = """
    图像分析报告:
    - 检测到 3 个对象
    - 主要颜色:蓝色、绿色
    - 场景类型:户外风景
    - 置信度:95%
    """
    
    # 模拟生成标注图片
    annotated_image_path = "/path/to/annotated_image.png"
    
    return (analysis_report.strip(), ImgPath(annotated_image_path))

@tool(name="create_data_visualization", description="创建在线数据可视化")
async def create_data_visualization(dataset: Dict[str, Any]) -> Tuple[str, ImgUrl]:
    """
    创建数据可视化并上传到云端
    
    Args:
        dataset: 包含数据和配置的字典
        
    Returns:
        可视化说明和在线图片URL
    """
    # 模拟数据可视化处理
    description = f"""
    数据可视化已创建:
    - 数据点数量:{len(dataset.get('data', []))}
    - 图表类型:{dataset.get('chart_type', '未指定')}
    - 创建时间:刚刚
    """
    
    # 模拟上传到云端并获取URL
    visualization_url = ImgUrl("https://example.com/visualizations/chart_12345.png")
    
    return (description.strip(), visualization_url)
```

### 继承方式示例

```python
from SimpleLLMFunc import Tool
import requests
from typing import Dict, Any, List

class WebSearchTool(Tool):
    """网络搜索工具的继承实现方式"""
    
    def __init__(self):
        super().__init__(
            name="web_search",
            description="在网络上搜索信息并返回相关结果"
        )
    
    def run(self, query: str, max_results: int = 5) -> List[Dict[str, str]]:
        """
        执行网络搜索
        
        Args:
            query: 搜索关键词
            max_results: 最大结果数量
            
        Returns:
            搜索结果列表
        """
        # 实际的搜索逻辑
        results = []
        for i in range(max_results):
            results.append({
                "title": f"搜索结果 {i+1}: {query}",
                "url": f"https://example.com/result/{i+1}",
                "snippet": f"关于{query}的相关信息..."
            })
        return results

class APICallTool(Tool):
    """API 调用工具"""
    
    def __init__(self, api_base_url: str):
        super().__init__(
            name="api_call",
            description="调用外部 API 获取数据"
        )
        self.api_base_url = api_base_url
    
    def run(self, endpoint: str, method: str = "GET", data: Dict[str, Any] = None) -> Dict[str, Any]:
        """
        调用 API 端点
        
        Args:
            endpoint: API 端点路径
            method: HTTP 方法
            data: 请求数据
            
        Returns:
            API 响应数据
        """
        url = f"{self.api_base_url}/{endpoint.lstrip('/')}"
        
        if method.upper() == "GET":
            response = requests.get(url, params=data)
        elif method.upper() == "POST":
            response = requests.post(url, json=data)
        else:
            raise ValueError(f"不支持的 HTTP 方法: {method}")
        
        return response.json()
```

### 工具使用示例

```python
import asyncio
from SimpleLLMFunc import llm_function, llm_chat, OpenAICompatible

# 初始化 LLM(从配置文件加载)
models = OpenAICompatible.load_from_json_file("provider.json")
llm = models["openai"]["gpt-3.5-turbo"]

# 在 llm_function 中使用工具
@llm_function(
    llm_interface=llm,
    toolkit=[calculate, search_web, get_weather]
)
async def intelligent_assistant(query: str) -> str:
    """
    智能助手,可以进行计算、搜索和查询天气。
    根据用户查询的内容,选择合适的工具来提供准确的答案。
    """
    pass

# 在 llm_chat 中使用工具
@llm_chat(
    llm_interface=llm,
    toolkit=[calculate, search_web, get_weather, analyze_data]
)
async def chat_with_tools(message: str, history: List[Dict[str, str]] | None = None):
    """
    支持工具调用的聊天助手。
    可以执行计算、搜索网络、查询天气和分析数据。
    """
    yield "", history or []

# 使用示例
async def main():
    # 使用 llm_function
    result = await intelligent_assistant("帮我计算 25 * 4 + 18 的结果")
    print(f"计算结果: {result}")

    # 使用 llm_chat
    history = []
    async for response, updated_history in chat_with_tools("北京今天天气怎么样?", history):
        if response:
            print(response, end="")
        history = updated_history

if __name__ == "__main__":
    asyncio.run(main())
```

### 高级用法

#### 工具序列化和检查

```python
from SimpleLLMFunc import Tool
import json

# 创建工具列表
tools = [calculate, search_web, get_weather]

# 序列化为 OpenAI 格式
openai_tools = Tool.serialize_tools(tools)

# 查看生成的工具描述
for tool_spec in openai_tools:
    print(json.dumps(tool_spec, indent=2, ensure_ascii=False))
```

#### 动态工具创建

```python
def create_tool_from_config(config: Dict[str, Any]):
    """根据配置动态创建工具"""

    @tool(name=config["name"], description=config["description"])
    async def dynamic_tool(**kwargs):
        # 根据配置执行相应逻辑
        return config["handler"](kwargs)

    return dynamic_tool

# 配置示例
tool_config = {
    "name": "custom_processor",
    "description": "自定义数据处理器",
    "handler": lambda data: {"processed": True, "data": data}
}

custom_tool = create_tool_from_config(tool_config)
```

#### 工具链组合

```python
@tool(name="multi_step_analysis", description="多步骤数据分析")
async def multi_step_analysis(data: List[Dict[str, Any]], steps: List[str]) -> Dict[str, Any]:
    """
    执行多步骤数据分析流程
    
    Args:
        data: 原始数据
        steps: 分析步骤列表,如 ["clean", "analyze", "visualize"]
        
    Returns:
        分析结果
    """
    results = {"steps_completed": []}
    
    for step in steps:
        if step == "clean":
            # 数据清洗
            results["cleaned_records"] = len(data)
        elif step == "analyze":
            # 数据分析
            results["analysis"] = {"mean": 0, "std": 0}
        elif step == "visualize":
            # 数据可视化
            results["charts"] = ["bar", "line", "pie"]
        
        results["steps_completed"].append(step)
    
    return results
```

### 返回类型最佳实践

#### 选择合适的返回类型

1. **文本输出优先**: 如果工具主要产生文本结果,使用 `str` 或结构化的 `Dict`
2. **结构化数据**: 复杂数据使用 `Dict` 或 `List`,便于 LLM 理解和处理
3. **多模态内容**: 需要展示图片时使用 `ImgPath`、`ImgUrl` 或组合类型
4. **组合输出**: 需要同时提供说明和图片时使用 `Tuple[str, ImgPath/ImgUrl]`

#### 性能优化建议

```python
# ✅ 推荐:结构化返回,便于LLM理解
@tool(name="search_products", description="搜索商品")
async def search_products(query: str) -> Dict[str, Any]:
    return {
        "total": 10,
        "products": [
            {"name": "商品1", "price": 99.9, "in_stock": True},
            {"name": "商品2", "price": 149.9, "in_stock": False}
        ],
        "query_time": "2024-01-01 12:00:00"
    }

# ✅ 推荐:多模态组合返回
@tool(name="generate_report", description="生成分析报告")
async def generate_report(data: List[Dict]) -> Tuple[str, ImgPath]:
    summary = f"分析了 {len(data)} 条记录,发现 3 个关键趋势"
    chart_path = ImgPath("/tmp/analysis_chart.png")
    return (summary, chart_path)

# ❌ 避免:返回过大的数据结构
def bad_example() -> Dict:
    return {
        "huge_data": list(range(10000)),  # 过大的数据
        "binary_content": b"..."  # 二进制数据无法JSON序列化
    }
```

#### 错误处理模式

```python
@tool(name="safe_division", description="安全除法运算")
async def safe_division(a: float, b: float) -> Dict[str, Any]:
    """
    安全的除法运算,包含错误处理
    
    Returns:
        包含结果或错误信息的字典
    """
    if b == 0:
        return {
            "success": False,
            "error": "除数不能为零",
            "result": None
        }
    
    return {
        "success": True,
        "error": None,
        "result": a / b
    }

@tool(name="robust_image_tool", description="鲁棒的图像处理工具")
async def robust_image_tool(image_path: str) -> Tuple[str, ImgPath]:
    """
    带错误处理的图像工具
    """
    try:
        # 图像处理逻辑
        processed_image = process_image(image_path)
        return ("图像处理成功", ImgPath(processed_image))
    except Exception as e:
        # 返回错误信息和默认图片
        error_msg = f"图像处理失败: {str(e)}"
        default_img = ImgPath("/path/to/error_placeholder.png")
        return (error_msg, default_img)
```

#### 多模态类型详细说明

```python
from SimpleLLMFunc import ImgUrl, ImgPath

# ImgPath 使用示例
img_local = ImgPath(
    path="/path/to/image.jpg",
    detail="high"  # 可选:图片细节级别 low/high
)

# ImgUrl 使用示例  
img_url = ImgUrl(
    url="https://example.com/image.jpg",
    detail="low"  # 网络图片建议使用low以节省token
)

# 组合类型使用
def complex_analysis() -> Tuple[str, ImgPath]:
    analysis = """
    检测结果:
    - 人数:3人
    - 车辆:1辆
    - 置信度:92%
    """
    annotated_img = ImgPath("/tmp/detection_result.jpg")
    return (analysis.strip(), annotated_img)
```

---

工具系统提供了强大而灵活的扩展机制,让 LLM 能够调用各种外部功能。通过装饰器方式,开发者可以轻松地将现有函数转换为 LLM 可用的工具,而继承方式则提供了更多的自定义控制。系统自动处理类型转换和参数验证,确保工具调用的安全性和准确性。

**关键要点总结**:
- 支持多种返回类型:基本类型、JSON对象、多模态内容
- 多模态支持:单独图片或文本+图片组合
- 自动类型转换:本地图片转base64,网络图片直接使用URL
- 错误处理:推荐返回结构化的错误信息
- 性能考虑:避免返回过大数据,网络图片使用低细节级别

Files in this skill

  • README.md1 KB
  • skill.md23.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.