Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/QwenLM/Qwen-Agent/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Tools are the building blocks that enable agents to interact with external systems, execute code, generate images, or perform any custom operation. Qwen-Agent provides a flexible tool system based on the BaseTool class.

Quick Start

Here’s a simple custom tool example from the codebase (examples/assistant_add_custom_tool.py:30):
from qwen_agent.tools.base import BaseTool, register_tool
import json

@register_tool('my_image_gen')
class MyImageGen(BaseTool):
    description = 'AI painting service that generates images from text descriptions.'
    parameters = [{
        'name': 'prompt',
        'type': 'string',
        'description': 'Detailed description of the desired image content, in English',
        'required': True,
    }]

    def call(self, params: str, **kwargs) -> str:
        import json5
        prompt = json5.loads(params)['prompt']
        # Your implementation here
        return json.dumps(
            {'image_url': f'https://image.pollinations.ai/prompt/{prompt}'},
            ensure_ascii=False,
        )

Understanding BaseTool

The BaseTool class (qwen_agent/tools/base.py:109) defines the interface all tools must implement:
class BaseTool(ABC):
    name: str = ''  # Tool identifier
    description: str = ''  # What the tool does
    parameters: Union[List[dict], dict] = []  # Tool parameters schema
    
    @abstractmethod
    def call(self, params: Union[str, dict], **kwargs) -> Union[str, list, dict]:
        """Execute the tool"""
        raise NotImplementedError

Creating a Custom Tool

1
Step 1: Define the Tool Class
2
Inherit from BaseTool and use the @register_tool decorator:
3
from qwen_agent.tools.base import BaseTool, register_tool

@register_tool('weather_query')
class WeatherTool(BaseTool):
    description = 'Get current weather for a city'
    parameters = [{
        'name': 'city',
        'type': 'string',
        'description': 'City name',
        'required': True
    }, {
        'name': 'units',
        'type': 'string',
        'description': 'Temperature units (celsius/fahrenheit)',
        'required': False
    }]
4
Step 2: Implement the call Method
5
    def call(self, params: str, **kwargs) -> str:
        # Parse parameters
        params_dict = self._verify_json_format_args(params)
        city = params_dict['city']
        units = params_dict.get('units', 'celsius')
        
        # Your logic here
        weather_data = fetch_weather(city, units)
        
        # Return result as string or JSON
        return json.dumps(weather_data, ensure_ascii=False)
6
Step 3: Use in an Agent
7
from qwen_agent.agents import Assistant

agent = Assistant(
    llm={'model': 'qwen-max'},
    function_list=['weather_query']  # Use your registered tool
)

messages = [{'role': 'user', 'content': 'What is the weather in Beijing?'}]
for response in agent.run(messages):
    print(response)

Parameter Schema Formats

Qwen-Agent supports two parameter schema formats:

List Format (Simple)

parameters = [{
    'name': 'param_name',
    'type': 'string',
    'description': 'Parameter description',
    'required': True
}]

OpenAI JSON Schema Format (Advanced)

parameters = {
    'type': 'object',
    'properties': {
        'location': {
            'type': 'string',
            'description': 'The city and state, e.g. San Francisco, CA'
        },
        'unit': {
            'type': 'string',
            'enum': ['celsius', 'fahrenheit']
        }
    },
    'required': ['location']
}
The OpenAI JSON Schema format provides better validation and is recommended for complex tools. It must conform to the OpenAI function calling specification.

Real-World Examples

Example 1: Database Query Tool

import json
import sqlite3
from qwen_agent.tools.base import BaseTool, register_tool

@register_tool('database_query')
class DatabaseQuery(BaseTool):
    description = 'Execute SQL queries on the database'
    parameters = {
        'type': 'object',
        'properties': {
            'query': {
                'type': 'string',
                'description': 'SQL query to execute'
            }
        },
        'required': ['query']
    }
    
    def __init__(self, cfg=None):
        super().__init__(cfg)
        self.db_path = cfg.get('db_path', 'database.db') if cfg else 'database.db'
    
    def call(self, params: str, **kwargs) -> str:
        params_dict = self._verify_json_format_args(params)
        query = params_dict['query']
        
        try:
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()
            cursor.execute(query)
            results = cursor.fetchall()
            conn.close()
            
            return json.dumps({
                'success': True,
                'data': results
            })
        except Exception as e:
            return json.dumps({
                'success': False,
                'error': str(e)
            })

Example 2: API Integration Tool

import requests
from qwen_agent.tools.base import BaseTool, register_tool

@register_tool('github_search')
class GitHubSearch(BaseTool):
    description = 'Search GitHub repositories'
    parameters = [{
        'name': 'query',
        'type': 'string',
        'description': 'Search query',
        'required': True
    }, {
        'name': 'language',
        'type': 'string',
        'description': 'Programming language filter',
        'required': False
    }]
    
    def call(self, params: str, **kwargs) -> str:
        import json5
        params_dict = json5.loads(params)
        query = params_dict['query']
        language = params_dict.get('language', '')
        
        search_query = f"{query} language:{language}" if language else query
        
        response = requests.get(
            'https://api.github.com/search/repositories',
            params={'q': search_query, 'sort': 'stars', 'order': 'desc'},
            headers={'Accept': 'application/vnd.github.v3+json'}
        )
        
        if response.status_code == 200:
            data = response.json()
            repos = [{
                'name': repo['full_name'],
                'stars': repo['stargazers_count'],
                'url': repo['html_url']
            } for repo in data['items'][:5]]
            return json.dumps(repos, ensure_ascii=False)
        else:
            return f"Error: {response.status_code}"

Example 3: File Processing Tool

import os
from qwen_agent.tools.base import BaseToolWithFileAccess, register_tool

@register_tool('csv_analyzer')
class CSVAnalyzer(BaseToolWithFileAccess):
    description = 'Analyze CSV files and return statistics'
    parameters = [{
        'name': 'file_path',
        'type': 'string',
        'description': 'Path to CSV file',
        'required': True
    }]
    
    def call(self, params: str, files=None, **kwargs) -> str:
        # BaseToolWithFileAccess automatically handles file downloads
        super().call(params, files=files)
        
        params_dict = self._verify_json_format_args(params)
        file_path = params_dict['file_path']
        
        # Process file in self.work_dir
        local_path = os.path.join(self.work_dir, os.path.basename(file_path))
        
        import pandas as pd
        df = pd.read_csv(local_path)
        
        stats = {
            'rows': len(df),
            'columns': len(df.columns),
            'column_names': df.columns.tolist(),
            'summary': df.describe().to_dict()
        }
        
        return json.dumps(stats, ensure_ascii=False, indent=2)

Tool Configuration

Pass configuration when initializing tools:
# Use default configuration
agent = Assistant(
    llm={'model': 'qwen-max'},
    function_list=['code_interpreter']
)

Built-in Tools

Qwen-Agent includes several powerful built-in tools:
  • code_interpreter: Execute Python code in a sandboxed environment
  • image_gen: Generate images (integration point)
  • doc_parser: Parse and extract content from documents
See the Code Interpreter guide for detailed usage.

Helper Methods

The BaseTool class provides useful helper methods (qwen_agent/tools/base.py:140):

_verify_json_format_args(params, strict_json=False)

Validate and parse tool parameters:
def call(self, params: str, **kwargs) -> str:
    # Automatically validates against self.parameters schema
    params_dict = self._verify_json_format_args(params)
    # Use params_dict...

function Property

Get OpenAI-compatible function definition:
tool = MyTool()
function_def = tool.function
# Returns: {'name': '...', 'description': '...', 'parameters': ...}

Best Practices

Tool Design Guidelines
  • Keep tools focused on a single responsibility
  • Provide clear, detailed descriptions for better LLM understanding
  • Use descriptive parameter names and descriptions
  • Return structured JSON for complex data
  • Handle errors gracefully and return informative error messages
Security Considerations
  • Validate all inputs thoroughly
  • Use BaseToolWithFileAccess for tools that need file operations
  • Be cautious with tools that execute code or make system calls
  • Consider rate limiting for API-based tools
  • Never expose sensitive credentials in tool responses

Troubleshooting

Tool Not Found Error

# Make sure to import the file where @register_tool is called
import my_tools  # This registers the tool

agent = Assistant(
    function_list=['my_custom_tool']  # Now it's available
)

Parameter Validation Errors

# Use json5 for more flexible parsing
import json5

def call(self, params: str, **kwargs):
    params_dict = json5.loads(params)  # Handles trailing commas, comments, etc.

Next Steps