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

# 6. Tool Subclassing BaseTool

> Define advanced custom tools by subclassing BaseTool and implementing the _run method

In this section, you will learn how to define custom tools by subclassing LangChain's base `BaseTool` class, which offers the highest level of control over tool metadata, schemas, and custom internal executions.

## Objectives

1. Define custom tools by subclassing the core abstract class `BaseTool`.
2. Implement schema enforcement using Pydantic classes assigned to `args_schema`.
3. Implement execution pathways by overriding the synchronous `_run` method.

## Implementation Plan

#### Goal

Subclass `BaseTool` to build a Tavily search tool and a multiplier tool, bind them to an agent, and execute queries.

#### Sample Input

```python theme={null}
"Multiply 10 and 20"
```

#### Sample Output

```python theme={null}
"The product of 10.0 and 20.0 is 200.0"
```

#### Plan

1. Define input validation Pydantic classes: `SimpleSearchInput` and `MultiplyNumbersArgs`.
2. Subclass `BaseTool` to define `SimpleSearchTool`. Declare `name`, `description`, `args_schema`, and override `_run` to execute queries using the `TavilyClient`.
3. Subclass `BaseTool` to define `MultiplyNumbersTool`. Declare properties and override `_run` to multiply two floats.
4. Instantiate subclasses: `tools = [SimpleSearchTool(), MultiplyNumbersTool()]`.
5. Pull the prompt `hwchase17/openai-tools-agent`, create the agent executor, and run test queries.

## Step-by-Step Implementation

### Step 1: Define Schemas

We structure the validation schemas using Pydantic models.

```python theme={null}
from langchain.pydantic_v1 import BaseModel, Field

class SimpleSearchInput(BaseModel):
    query: str = Field(description="should be a search query")

class MultiplyNumbersArgs(BaseModel):
    x: float = Field(description="First number to multiply")
    y: float = Field(description="Second number to multiply")
```

### Step 2: Subclass BaseTool

We define the custom classes inheriting from `BaseTool`, specifying properties and overriding the internal `_run` method.

```python theme={null}
import os
from typing import Type
from langchain_core.tools import BaseTool

class SimpleSearchTool(BaseTool):
    name = "simple_search"
    description = "useful for when you need to answer questions about current events"
    args_schema: Type[BaseModel] = SimpleSearchInput

    def _run(self, query: str) -> str:
        from tavily import TavilyClient
        api_key = os.getenv("TAVILY_API_KEY")
        client = TavilyClient(api_key=api_key)
        results = client.search(query=query)
        return f"Search results for: {query}\n\n{results}\n"

class MultiplyNumbersTool(BaseTool):
    name = "multiply_numbers"
    description = "useful for multiplying two numbers"
    args_schema: Type[BaseModel] = MultiplyNumbersArgs

    def _run(self, x: float, y: float) -> str:
        result = x * y
        return f"The product of {x} and {y} is {result}"
```

### Step 3: Run Subclassed Tools with Agent

We instantiate the custom classes and execute the agent loop.

```python theme={null}
from langchain import hub
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain.chat_models import init_chat_model

tools = [SimpleSearchTool(), MultiplyNumbersTool()]

llm = init_chat_model("llama-3.3-70b-versatile", model_provider="groq")
prompt = hub.pull("hwchase17/openai-tools-agent")
agent = create_tool_calling_agent(llm=llm, tools=tools, prompt=prompt)
agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True)
```

## Complete Combined Code

Below is the complete, consolidated Python script uniting all of the steps above:

```python theme={null}
# Import necessary libraries
import os
from typing import Type

from dotenv import load_dotenv
from langchain import hub
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain.pydantic_v1 import BaseModel, Field
from langchain_core.tools import BaseTool
from langchain.chat_models import init_chat_model

load_dotenv()

# Pydantic models for tool arguments
class SimpleSearchInput(BaseModel):
    query: str = Field(description="should be a search query")


class MultiplyNumbersArgs(BaseModel):
    x: float = Field(description="First number to multiply")
    y: float = Field(description="Second number to multiply")


# Custom tool with only custom input
class SimpleSearchTool(BaseTool):
    name = "simple_search"
    description = "useful for when you need to answer questions about current events"
    args_schema: Type[BaseModel] = SimpleSearchInput

    def _run(
        self,
        query: str,
    ) -> str:
        """Use the tool."""
        from tavily import TavilyClient

        api_key = os.getenv("TAVILY_API_KEY")
        client = TavilyClient(api_key=api_key)
        results = client.search(query=query)
        return f"Search results for: {query}\n\n\n{results}\n"


# Custom tool with custom input and output
class MultiplyNumbersTool(BaseTool):
    name = "multiply_numbers"
    description = "useful for multiplying two numbers"
    args_schema: Type[BaseModel] = MultiplyNumbersArgs

    def _run(
        self,
        x: float,
        y: float,
    ) -> str:
        """Use the tool."""
        result = x * y
        return f"The product of {x} and {y} is {result}"


# Create tools using the Pydantic subclass approach
tools = [
    SimpleSearchTool(),
    MultiplyNumbersTool(),
]

# Initialize a Groq model using core abstractions
llm = init_chat_model("llama-3.3-70b-versatile", model_provider="groq")

# Pull the prompt template from the hub
prompt = hub.pull("hwchase17/openai-tools-agent")

# Create the ReAct agent using the create_tool_calling_agent function
agent = create_tool_calling_agent(
    llm=llm,
    tools=tools,
    prompt=prompt,
)

# Create the agent executor
agent_executor = AgentExecutor.from_agent_and_tools(
    agent=agent,
    tools=tools,
    verbose=True,
    handle_parsing_errors=True,
)

# Test the agent with sample queries
response = agent_executor.invoke({"input": "Search for Apple Intelligence"})
print("Response for 'Search for LangChain updates':", response)

response = agent_executor.invoke({"input": "Multiply 10 and 20"})
print("Response for 'Multiply 10 and 20':", response)
```

## Practice & Exercises

To practice subclassing tools, open the interactive notebook:

<CardGroup cols={1}>
  <Card title="Practice & Exercises" icon="laptop-code">
    Practice subclassing BaseTool and customizing execution functions.

    [💻 VS Code](vscode://file/Users/sivaprasad/Downloads/GenAI%20With%20Python/public/notebooks/langchain/6_tool_base_tool.ipynb) | [🚀 Colab](https://colab.research.google.com/github/prasad230776/genai-course/blob/master/public/notebooks/langchain/6_tool_base_tool.ipynb) | <a href="/public/notebooks/langchain/6_tool_base_tool.ipynb" download>📥 Download</a>
  </Card>
</CardGroup>
