# Connect to external functions using LangChain tools

Use LangChain and the Python Pydantic library to connect models to external tools and systems to provide AI assistants with additional capabilities, or to build integrations between your applications and the models. See [LangChain tools](https://docs.langchain.com/oss/python/langchain/tools) for details on LangChain tools and tool calling.

The following example shows how to use `ImagineChat` for tool calling. It defines two schemas (`GetWeather` and `GetPopulation`) and binds them to the LLM to make the tools available to the LLM. The code then sends the `messages` to the LLM for processing. Because the LLM recognizes that the `HumanMessage` is about “weather in NY,” the LLM calls the `GetWeather` tool and displays the response.

from langchain_core.messages import HumanMessage, SystemMessage
    from pydantic import BaseModel, Field
    from rich.pretty import pprint
    
    from imagine.langchain import ImagineChat

    llm = ImagineChat(model="Llama-3.1-8B", max_tokens=512)

    class GetWeather(BaseModel):
        """Get the current weather in a given location"""
    
        location: str = Field(..., description="The city and state, e.g. San Francisco, CA")

    class GetPopulation(BaseModel):
        """Get the current population in a given location"""
    
        location: str = Field(..., description="The city and state, e.g. San Francisco, CA")

    model_with_tools = llm.bind_tools([GetWeather, GetPopulation])

    messages = [
        SystemMessage(
            content="You are a helpful assistant that can access external functions. The responses from these function calls will be appended to this dialogue. Please provide responses based on the information from these function calls."
        ),
        # HumanMessage(content="What is the population of NY?"),
        HumanMessage(content="What is the current weather in NY?"),
    ]

    response_message = model_with_tools.invoke(messages)
    # response_tool_calls = model_with_tools.invoke(messages).tool_calls

    pprint(response_message)
    Copy to clipboard

## Approaches for tools specification

This code demonstrates the flexibility of LangChain in defining tools by showing four different approaches for specifying the tools:

- Pydantic class (`multiply`)
- LangChain tool (`@tool`)
- Standard Python function (`subtract`)
- OpenAI-format (`add`)

As with the previous example, the code binds the tools to the LLM to make the tools available to the LLM.
When the LLM receives the “human” messages, it analyzes if any of the tools are relevant to the prompt. If yes, the code calls the tool and prints the response. If no, model uses its own data to generate a response. In this example, the LLM would most likely call `multiply` to generate a response.

from langchain_core.pydantic_v1 import BaseModel, Field
    from langchain_core.tools import tool
    from rich.pretty import pprint
    
    from imagine.langchain import ImagineChat

    # Pydantic class
    class multiply(BaseModel):
        """Return product of 'x' and 'y'."""
    
        x: float = Field(..., description="First factor")
        y: float = Field(..., description="Second factor")

    # LangChain tool
    @tool
    def exponentiate(x: float, y: float) -> float:
        """Raise 'x' to the 'y'."""
        return x**y

    # Function
    def subtract(x: float, y: float) -> float:
        """Subtract 'x' from 'y'."""
        return y - x

    # OpenAI-format dict
    add = {
        "name": "add",
        "description": "Add 'x' and 'y'.",
        "parameters": {
            "type": "object",
            "properties": {
                "x": {"type": "number", "description": "First number to add"},
                "y": {"type": "number", "description": "Second number to add"},
            },
            "required": ["x", "y"],
        },
    }
    
    llm = ImagineChat(model="Llama-3.1-8B", temperature=0)

    llm_with_tools = llm.bind_tools([multiply, exponentiate, add, subtract])
    
    response = llm_with_tools.invoke(
        [
            ("system", "You're a helpful assistant"),
            # ("human", "what's 5 raised to the 2.743"),
            # ("human", "what's 5 minus 56"),
            ("human", "What is 100 into 35"),
        ]
    )

    pprint(response)
    Copy to clipboard

## Create an agent and execute agent tasks (multi-step)

This code creates a LangChain agent that performs multi-step reasoning and uses multiple tools to answer questions. This code does the following:

- Uses the LangChain `@tool` decorator to convert Python functions for `multiply`, `exponentiate`, and `add` into LangChain tools.
- Initializes an `ImagineChat` model, specifically Llama-3.1-70B.
- Creates an agent using `create_tool_calling_agent` and combines the LLM, the list of tools, and the prompt into the agent
- Uses `AgentExecutor` to create a runtime environment for the agent.
- When `agent_executor.iter()` is called with the input “what’s 3 plus 5. Get me the 5th power of result,” the agent calls the
appropriate tools at each step of the process then prints the result.

from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.tools import tool
    
    from imagine.langchain import ImagineChat
    from langchain.agents import AgentExecutor, create_tool_calling_agent

    @tool
    def multiply(x: float, y: float) -> float:
        """Multiply 'x' times 'y'."""
        return x * y

    @tool
    def exponentiate(x: float, y: float) -> float:
        """Raise 'x' to the 'y'."""
        return x**y

    @tool
    def add(x: float, y: float) -> float:
        """Add 'x' and 'y'."""
        return x + y

    prompt = ChatPromptTemplate.from_messages(
        [
            ("system", "you're a helpful assistant"),
            ("human", "{input}"),
            ("placeholder", "{agent_scratchpad}"),
        ]
    )
    
    tools = [multiply, exponentiate, add]

    llm = ImagineChat(model="Llama-3.1-70B", temperature=0)

    agent = create_tool_calling_agent(llm, tools, prompt)
    agent_executor = AgentExecutor(
        agent=agent, tools=tools, verbose=True, stream_runnable=False
    )
    
    for step in agent_executor.iter(
        {"input": "what's 3 plus 5. Get me the 5th power of result"}
    ):
        print(step)
    Copy to clipboard

## Create an agent and execute agent tasks (single step)

This code creates a LangChain agent that performs single step reasoning and invokes one tool to answer the question. This code does the following:

- Uses the LangChain `@tool` decorator to convert a Python function for [magic\_functon] into a LangChain tool.
- Initializes an `ImagineChat` model, specifically Llama-3.1-70B.
- Creates an agent using `create_tool_calling_agent` and combines the LLM, tool, and the prompt into the agent.
- Uses `AgentExecutor` to create a runtime environment for the agent.
- When `agent_executor.invoke` is called, the agent runs the query and prints the results.

from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.tools import tool
    from rich.pretty import pprint
    
    from imagine.langchain import ImagineChat
    from langchain.agents import AgentExecutor, create_tool_calling_agent

    model = ImagineChat(model="Llama-3.1-70B", temperature=0)
    
    query = "what is the value of magic_function(3)?"
    
    prompt = ChatPromptTemplate.from_messages(
        [
            ("system", "You are a helpful assistant."),
            ("human", "{input}"),
            # Placeholders fill up a **list** of messages
            ("placeholder", "{agent_scratchpad}"),
        ]
    )

    @tool
    def magic_function(input: int) -> int:
        """Applies a magic function to an input."""
        return input + 2

    tools = [magic_function]
    
    agent = create_tool_calling_agent(model, tools, prompt=prompt)
    agent_executor = AgentExecutor(agent=agent, tools=tools, stream_runnable=False)
    
    response = agent_executor.invoke({"input": query})
    
    pprint(response)
    Copy to clipboard

## Return an LLM response as structured output

This example shows how to define a structured output for the LLM to use when it returns its responses rather than conversational text. Structured outputs are useful for predictable, reliable output formats and for integrating outputs into downstream applications or databases. The code defines a class `AnswerWithJustification` to be the blueprint for the structured output. The code includes examples with three different `llm.with_structured_output` functions to show different ways to return the structured output.

from pydantic import BaseModel, Field
    from rich.pretty import pprint
    
    from imagine.langchain import ImagineChat

    llm = ImagineChat(model="Llama-3.1-70B", max_tokens=512)

    class AnswerWithJustification(BaseModel):
        """An answer to the user question along with justification for the answer."""
    
        answer: str
    
        # If we provide default values and/or descriptions for fields, these will be passed
        # to the model. This is an important part of improving a model's ability to correctly return structured outputs.
        justification: str | None = Field(
            default=None, description="A justification for the answer."
        )

    # ---------------------------
    
    # include_raw is False
    structured_model = llm.with_structured_output(AnswerWithJustification)
    response = structured_model.invoke(
        "What weighs more a pound of bricks or a pound of feathers"
    )
    pprint(response)
    
    # ---------------------------
    
    structured_model = llm.with_structured_output(AnswerWithJustification, include_raw=True)
    response = structured_model.invoke(
        "What weighs more a pound of bricks or a pound of feathers"
    )
    pprint(response)

    # ---------------------------
    
    oai_schema = {
        "name": "AnswerWithJustification",
        "description": "An answer to the user question along with justification for the answer.",
        "parameters": {
            "type": "object",
            "properties": {
                "answer": {"type": "string"},
                "justification": {
                    "description": "A justification for the answer.",
                    "type": "string",
                },
            },
            "required": ["answer"],
        },
    }
    
    structured_model = llm.with_structured_output(oai_schema)
    response = structured_model.invoke(
        "What weighs more a pound of bricks or a pound of feathers"
    )
    pprint(response)
    
    # ---------------------------
    Copy to clipboard

## Next steps

- Review how to [connect models to external systems with tool calling](https://docs.qualcomm.com/doc/80-88545-1/topic/2_0_tool_calling.html).
- [Create custom tools](https://docs.qualcomm.com/doc/80-88545-1/topic/3_2_langchain_custom_tools.html) with LangChain.

Last Published: Apr 17, 2026