HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //opt/PraisonAI/docs/tools/tools_class.mdx
---
title: "Tools as Class"
sidebarTitle: "Tools as Class"
description: "Learn how to create and use class-based tools with AI agents for enhanced functionality."
icon: "toolbox"
---

```mermaid
flowchart LR
    In[In] --> Agent[AI Agent]
    Agent --> Tool[Tool Call]
    Tool --> Agent
    Agent --> Out[Out]
    
    style In fill:#8B0000,color:#fff
    style Agent fill:#2E8B57,color:#fff
    style Tool fill:#2E8B57,color:#fff
    style Out fill:#8B0000,color:#fff
```

A workflow demonstrating how to create and use class-based tools that can be integrated with AI agents to extend their capabilities with custom functionality.

## Quick Start

<Steps>
    <Step title="Install Package">
        First, install the PraisonAI Agents package:
        ```bash
        pip install praisonaiagents
        ```
    </Step>

    <Step title="Set API Key">
        Set your OpenAI API key and EXA API key as environment variables in your terminal:
        ```bash
        export OPENAI_API_KEY=your_api_key_here
        export EXA_API_KEY=your_exa_api_key_here
        ```
    </Step>

    <Step title="Create a file">
        Create a new file `app.py` with the basic setup:
        ```python
        from praisonaiagents import Agent, Task, PraisonAIAgents
        import os
        import requests
        from typing import Any, Dict, List, Optional
        from pydantic import BaseModel, Field

        class EXASearchTool(BaseModel):
            """Wrapper for EXA Search API."""
            search_url: str = "https://api.exa.ai/search"
            headers: Dict = {
                "accept": "application/json",
                "content-type": "application/json",
            }
            max_results: Optional[int] = None

            def run(self, query: str) -> str:
                """Run query through EXA and return concatenated results."""
                payload = {
                    "query": query,
                    "type": "magic",
                }

                headers = self.headers.copy()
                headers["x-api-key"] = os.environ['EXA_API_KEY']

                response = requests.post(self.search_url, json=payload, headers=headers)
                results = response.json()
                
                if 'results' in results:
                    return self._parse_results(results['results'])
                return ""

            def results(self, query: str, max_results: Optional[int] = None) -> List[Dict[str, Any]]:
                """Run query through EXA and return metadata."""
                payload = {
                    "query": query,
                    "type": "magic",
                }

                headers = self.headers.copy()
                headers["x-api-key"] = os.environ['EXA_API_KEY']

                response = requests.post(self.search_url, json=payload, headers=headers)
                results = response.json()
                
                if 'results' in results:
                    return results['results'][:max_results] if max_results else results['results']
                return []

            def _parse_results(self, results: List[Dict[str, Any]]) -> str:
                """Parse results into a readable string format."""
                strings = []
                for result in results:
                    try:
                        strings.append('\n'.join([
                            f"Title: {result['title']}",
                            f"Score: {result['score']}",
                            f"Url: {result['url']}",
                            f"ID: {result['id']}",
                            "---"
                        ]))
                    except KeyError:
                        continue

                content = '\n'.join(strings)
                return f"\nSearch results: {content}\n"

        # Create an agent with the tool
        agent = Agent(
            name="SearchAgent",
            role="Research Assistant",
            goal="Search for information about 'AI Agents Framework'",
            backstory="I am an AI assistant that can search GitHub.",
            tools=[EXASearchTool],
            self_reflect=False
        )

        # Create task to demonstrate the tool
        task = Task(
            name="search_task",
            description="Search for information about 'AI Agents Framework'",
            expected_output="Information about AI Agents Framework",
            agent=agent
        )

        # Create and start the workflow
        agents = PraisonAIAgents(
            agents=[agent],
            tasks=[task],
            verbose=True
        )

        agents.start()
        ```
    </Step>

    <Step title="Start Agents">
        Type this in your terminal to run your agents:
        ```bash
        python app.py
        ```
    </Step>
</Steps>

<Note>
  **Requirements**
  - Python 3.10 or higher
  - OpenAI API key. Generate OpenAI API key [here](https://platform.openai.com/api-keys)
  - EXA API key for search functionality
  - Basic understanding of Python and Pydantic
</Note>

## Understanding Tools as Class

<Card title="What are Class-based Tools?" icon="question">
  Class-based tools enable:
  - Custom functionality encapsulation
  - Reusable tool components
  - Type-safe tool interfaces
  - Complex API integrations
</Card>

## Features

<CardGroup cols={2}>
  <Card title="Pydantic Integration" icon="check-square">
    Built-in validation and type safety with Pydantic models.
  </Card>
  <Card title="API Wrapping" icon="globe">
    Easily wrap external APIs as agent tools.
  </Card>
  <Card title="Method Flexibility" icon="code">
    Support for multiple methods within a single tool.
  </Card>
  <Card title="Type Hints" icon="brackets-curly">
    Strong typing for better code reliability.
  </Card>
</CardGroup>

## Configuration Options

```python
# Create a custom tool class
class CustomTool(BaseModel):
    """Custom tool with configuration options."""
    api_url: str = Field(default="https://api.example.com")
    headers: Dict[str, str] = Field(default_factory=dict)
    max_retries: int = Field(default=3)

    def run(self, input_data: str) -> str:
        """Main execution method."""
        # Tool implementation
        return "Result"

    def configure(self, **kwargs):
        """Update tool configuration."""
        for key, value in kwargs.items():
            if hasattr(self, key):
                setattr(self, key, value)

# Use the tool with an agent
agent = Agent(
    name="CustomAgent",
    role="Tool User",
    goal="Use custom tool functionality",
    tools=[CustomTool],
    verbose=True
)
```

## Troubleshooting

<CardGroup cols={2}>
  <Card title="Tool Issues" icon="triangle-exclamation">
    If tool execution fails:
    - Check API credentials
    - Verify network connectivity
    - Enable verbose logging
  </Card>

  <Card title="Type Errors" icon="bug">
    If type validation fails:
    - Review input types
    - Check Pydantic model
    - Verify method signatures
  </Card>
</CardGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Function Tools" icon="function" href="./function-tools">
    Learn about function-based tools
  </Card>
  <Card title="API Tools" icon="cloud" href="./api-tools">
    Explore API integration tools
  </Card>
</CardGroup>

<Note>
  For optimal results, ensure your tool classes are well-documented and follow Pydantic best practices for model definition.
</Note>