> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Tools as Class

> Learn how to create and use class-based tools with AI agents for enhanced functionality.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Tools as Class"
        Request[📋 User Request] --> Process[⚙️ Tools as Class]
        Process --> Result[✅ Result]
    end

    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef process fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef output fill:#10B981,stroke:#7C90A0,color:#fff

    class Request input
    class Process process
    class Result output
```

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant Agent
    participant Feature as Tools as Class

    User->>Agent: Request
    Agent->>Feature: Process request
    Feature-->>Agent: Result
    Agent-->>User: Response
```

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent
from pydantic import BaseModel

class CustomTool(BaseModel):
    def run(self, query: str) -> str:
        return f"Processed: {query}"

agent = Agent(name="CustomAgent", tools=[CustomTool])
agent.start("Run the custom tool on sample data")
```

The user wraps behaviour in a class-based tool; the agent invokes it like any other capability.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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:#8B0000,color:#fff
    style Tool fill:#189AB4,color:#fff
    style Out fill:#8B0000,color:#fff

    classDef agent fill:#8B0000,color:#fff
    classDef tool fill:#189AB4,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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonaiagents import Agent, Task, AgentTeam
    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],
        reflection=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 = AgentTeam(
        agents=[agent],
        tasks=[task]
    )

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

  <Step title="Start Agents">
    Type this in your terminal to run your agents:

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# 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]
)
```

## 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>

## Best Practices

<AccordionGroup>
  <Accordion title="Keep tools focused on one task">
    Each tool should do one thing well - this makes agent behavior more predictable.
  </Accordion>

  <Accordion title="Return descriptive strings">
    Return human-readable strings from tools so the agent can understand and relay results.
  </Accordion>

  <Accordion title="Include error messages in returns">
    On failure, return a descriptive error string rather than raising an exception.
  </Accordion>

  <Accordion title="Add docstrings to tools">
    The agent uses tool docstrings to decide when to call a tool - write clear, specific descriptions.
  </Accordion>
</AccordionGroup>

## Related

<CardGroup cols={2}>
  <Card title="Custom Tools" icon="wrench" href="/docs/tools/custom">
    Build your own agent tools
  </Card>

  <Card title="Tools Overview" icon="toolbox" href="/docs/tools/tools">
    Browse PraisonAI tool documentation
  </Card>
</CardGroup>
