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

# 4. Tool Constructor

> Define custom tools using Tool and StructuredTool constructors with Pydantic validation schemas

In this section, you will learn how to define custom tools using LangChain's core constructors: `Tool` for simple single-argument inputs, and `StructuredTool` for complex multi-argument configurations validated with Pydantic.

## Objectives

1. Define custom functions for greeting users, reversing strings, and concatenating values.
2. Formulate Pydantic schemas using `BaseModel` and `Field` to describe and validate tool inputs.
3. Instantiate `Tool` and `StructuredTool` classes and bind them to a tool-calling agent.

## Implementation Plan

#### Goal

Construct a set of custom utility tools using constructors, compile them within an OpenAI tools agent, and verify executions on text inputs.

#### Sample Input

```python theme={null}
"Concatenate 'hello' and 'world'"
```

#### Sample Output

```python theme={null}
"helloworld"
```

#### Plan

1. Define functions: `greet_user`, `reverse_string`, and `concatenate_strings`.
2. Define a Pydantic class `ConcatenateStringsArgs` containing validation schemas for parameters `a` and `b`.
3. Wrap greeting and reversing functions inside the `Tool(...)` class constructor.
4. Wrap string concatenation inside `StructuredTool.from_function(...)` mapping the arguments schema.
5. Load the prompt `hwchase17/openai-tools-agent` and initialize the agent executor with `create_tool_calling_agent`.
6. Invoke the agent with query strings.

## Step-by-Step Implementation

### Step 1: Define Functions and Pydantic Schema

We write our Python operations and define the Pydantic validation schema for multiple arguments.

```python theme={null}
def greet_user(name: str) -> str:
    return f"Hello, {name}!"

def reverse_string(text: str) -> str:
    return text[::-1]

def concatenate_strings(a: str, b: str) -> str:
    return a + b

from langchain.pydantic_v1 import BaseModel, Field

class ConcatenateStringsArgs(BaseModel):
    a: str = Field(description="First string")
    b: str = Field(description="Second string")
```

### Step 2: Instantiate Constructors

We wrap the functions into `Tool` and `StructuredTool` objects.

```python theme={null}
from langchain_core.tools import Tool, StructuredTool

tools = [
    Tool(
        name="GreetUser",
        func=greet_user,
        description="Greets the user by name.",
    ),
    Tool(
        name="ReverseString",
        func=reverse_string,
        description="Reverses the given string.",
    ),
    StructuredTool.from_function(
        func=concatenate_strings,
        name="ConcatenateStrings",
        description="Concatenates two strings.",
        args_schema=ConcatenateStringsArgs,
    ),
]
```

### Step 3: Create and Invoke Tool-Calling Agent

We pull the specialized tools-agent prompt, initialize the model, build the agent executor, and run tests.

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

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)

# Example invocations
# agent_executor.invoke({"input": "Greet Alice"})
```

## Complete Combined Code

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

```python theme={null}
# Import necessary libraries
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 StructuredTool, Tool
from langchain.chat_models import init_chat_model


# Functions for the tools
def greet_user(name: str) -> str:
    """Greets the user by name."""
    return f"Hello, {name}!"


def reverse_string(text: str) -> str:
    """Reverses the given string."""
    return text[::-1]


def concatenate_strings(a: str, b: str) -> str:
    """Concatenates two strings."""
    return a + b


# Pydantic model for tool arguments
class ConcatenateStringsArgs(BaseModel):
    a: str = Field(description="First string")
    b: str = Field(description="Second string")


# Create tools using the Tool and StructuredTool constructor approach
tools = [
    # Use Tool for simpler functions with a single input parameter.
    Tool(
        name="GreetUser",  # Name of the tool
        func=greet_user,  # Function to execute
        description="Greets the user by name.",  # Description of the tool
    ),
    # Use Tool for another simple function with a single input parameter.
    Tool(
        name="ReverseString",  # Name of the tool
        func=reverse_string,  # Function to execute
        description="Reverses the given string.",  # Description of the tool
    ),
    # Use StructuredTool for more complex functions that require multiple input parameters.
    StructuredTool.from_function(
        func=concatenate_strings,  # Function to execute
        name="ConcatenateStrings",  # Name of the tool
        description="Concatenates two strings.",  # Description of the tool
        args_schema=ConcatenateStringsArgs,  # Schema defining the tool's input arguments
    ),
]

# 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,  # Language model to use
    tools=tools,  # List of tools available to the agent
    prompt=prompt,  # Prompt template to guide the agent's responses
)

# Create the agent executor
agent_executor = AgentExecutor.from_agent_and_tools(
    agent=agent,  # The agent to execute
    tools=tools,  # List of tools available to the agent
    verbose=True,  # Enable verbose logging
    handle_parsing_errors=True,  # Handle parsing errors gracefully
)

# Test the agent with sample queries
response = agent_executor.invoke({"input": "Greet Alice"})
print("Response for 'Greet Alice':", response)

response = agent_executor.invoke({"input": "Reverse the string 'hello'"})
print("Response for 'Reverse the string hello':", response)

response = agent_executor.invoke({"input": "Concatenate 'hello' and 'world'"})
print("Response for 'Concatenate hello and world':", response)
```

## Practice & Exercises

To practice setting up tools using standard constructors, open the interactive notebook:

<CardGroup cols={1}>
  <Card title="Practice & Exercises" icon="laptop-code">
    Practice initializing Tool and StructuredTool constructor wrappers.

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