Machine Learning Spot

An Awesome Practical Guide to LangChain Tool Calling (2024)

Feature Image of LangChain Tool Calling

LangChain Tool Calling is a great way to connect your LLM to the information that LLM doesn’t have, i.e to connect your LLM with the real world, the world that is still working and updating itself daily, making LangChain tool calling an essential tool for us to use with LLM.

Why tool-calling? is tool-calling important? Indeed, it’s a good question our LLMs have limited and frozen-in-time knowledge for example, some LLMs are trained up to 2023; how can they know what happened in 2024? who won the election held in some country in 2024? Especially, how can an LLM access information that is continuously variable? like weather updates, job openings available in your city, currency exchange rates, and many others, we can’t know any of it using just LLM as they are frozen in time, having limited knowledge.

Some tools are already available out there that we can use directly using agents, but today we will learn how to define our own tools and how to bind them with the LLM that we are using.
So what will LLM do with our tool? It will just come up with the tool and tell us which one we should use and then it is up to us which one we should use as developers to answer certain questions.

Now let’s see how to define a tool.

How To Define a Tool: The First Lesson in LangChain Tool Calling

To get started with the LangChain tool calling, we first need to know how to define a tool. There are two ways that we are going to discuss about LangChain tool calling using a Pydantic class and using a simple function. If you are wondering why we use classes and functions? Then yes, LangChain tool calling is nothing but binding a function or class to the LLM and using it, that’s it.
let’s see some examples

Decorating The Tool Using Tool Decorator

This involves 3 main steps

  1. Decorating the first line of the function with a decorator, i.e. @tool.
  2. Defining a Function
  3. Give a description in the form of a docstring the more detailed, the better.

Now let’s start coding.

starting by importing the essentials for our function definition the tool from langchain.tools is a decorator.
Dict and Any are not needed here. However, importing them prepares the script for potentially more complex type annotations in other functions.


from langchain.tools import tool
from typing import Dict, Any

Now creating dummy data although it won’t work right now but just to be as realistic as we can I am defining this dummy data for which function has to work.
This data deals with the number of job vacancies available in different cities of Pakistan.

# Dummy data
data = {
    "Karachi": 1000,
    "Lahore": 1500,
    "Islamabad": 2000,
    "Faisalabad": 1200,
    "Peshawar": 800
}

Now let’s define a function and use tool decorator @tool to declare that function as a tool.
After the tool decorator and function definition, it is the docstring’s turn. The more detailed the docstring is, the better.

In the end, we will tell what to return and when to return, thus ending our function definition for LangChain Tool Calling.

@tool
def job_vacancy(city: str) -> str:

  #Defining Docstring  

  """
This tool provides the number of job vacancies in specified cities of Pakistan. 

Usage: 

- Input a city name as a string (e.g., 'Karachi', 'Lahore'). 

- The tool will return the number of job vacancies in that city if available. 

- If the city is not recognized or data is not available, the tool will return a message indicating so. 

Example: 

- If you input 'Karachi', the tool may return 'There are 1000 job vacancies in Karachi.' - If you input 'Quetta', which is not in the data, the tool may return 'Sorry, I don't have information about job vacancies in Quetta.' 

Note: - The tool only has data for a predefined list of cities. - The data is static and does not reflect real-time job vacancy numbers.

"""
    if city in data:
        return f"There are {data[city]} job vacancies in {city}."
    else:
        return f"Sorry, I don't have information about job vacancies in {city}."

To Learn LangChain Tool Calling even better, let’s see another example of tool definition and this time we will use real API.
In this second example, the API of the website we use will fetch the model’s current exchange rates, making a good choice for LangChain Tool Calling when we want exchange rates.

The methodology will be the same as above, we have just not made any dummy data here.


@tool
def get_exchange_rate(currency_code: str) -> str:
    
    """
    Retrieves the current exchange rate for a specified currency using an external API.

    This tool queries an external API to fetch the latest exchange rate for the given currency code.
    It handles basic error checking but may not cover all possible API response scenarios.

    Args:
        currency_code (str): The three-letter ISO currency code for the desired currency (e.g., 'USD', 'EUR').

    Returns:
        str: A string containing the current exchange rate for the specified currency, or an error message if the currency is not found or if there is an API error.

    Example:
        If you query for 'USD', the tool may return '1.0' (assuming USD is the base currency).
        If you query for 'XYZ', which is not a recognized currency, the tool may return 'Currency not found or API error.'

    Note:
        - The tool relies on an external API for data, which may have rate limits or downtime.
        - The accuracy and timeliness of the data depend on the API's reliability.
        - The tool assumes that the API response is in a specific format; changes to the API may require updates to this function.
    """
   
    url = f'https://api.exchangerate-api.com/v4/latest/{currency_code}'
    response = requests.get(url)
    data = response.json()

    # Assuming the response is in a specific format, adjust as necessary
    if 'rates' in data and currency_code in data['rates']:
        return str(data['rates'][currency_code])
    else:
        return "Currency not found or API error."

Tool Definition Using Pydantic

The Pydant tool definition is more beneficial when the input is more complex. To define the tool for LangChain tool calling with Pydant, follow these three steps.

  1. Create a Pydantic Model: We create a class inherited from BaseModel, which we will import from Pydantic in the examples. This model defines the data structure that the tool expects as input. Right after creating the Pydantic model, we write a docstring.
  2. Design Structure of Model: In a Pydantic model, each attribute represents a tool parameter. The Field function is used to provide additional information about each parameter. The ... (ellipsis) indicates that the field is required. The description parameter is used to describe the parameter, as shown in the examples.
  3. Giving Tool Some Logic: In the third step, we provide some logic. We define a function that takes an instance of the input model as an argument.

Now let’s apply all three steps shown above

To make learning easier Both examples shown will be the same as those we designed using the tool decorator earlier in this blog on LangChain tool calling. Starting with the job vacancy tool. So use the same data as you used for the tool that we created using the tool decorator. The docstring can be the same as before here too but you will have to decide according to your tool mine might be slightly different than before, but it would be fine here if it were the same.

Remember, docstring goes to the LLM too, so it helps them understand your tool better. In the below example, the docstring is written almost the same as written while using the tool decorator for the LangChain tool calling



#Importing required Modules first 
from langchain_core.pydantic_v1 import BaseModel, Field

#Creating a pydantic model

class JobVacancyTool(BaseModel):
    """
    This tool provides the number of job vacancies in specified cities of Pakistan.

    Usage:

    - Input a city name as a string (e.g., 'Karachi', 'Lahore').

    - The tool will return the number of job vacancies in that city if available.

    - If the city is not recognized or data is not available, the tool will return a message indicating so.

    Example:

    - If you input 'Karachi', the tool may return 'There are 1000 job vacancies in Karachi.' - If you input 'Quetta', which is not in the data, the tool may return 'Sorry, I don't have information about job vacancies in Quetta.'

    Note: - The tool only has data for a predefined list of cities. - The data is static and does not reflect real-time job vacancy numbers.

    """

Now coming to step 2, step 2 will be in a single line as it will need only one attribute, ‘city’.

city: str = Field(…, description="The name of the city in Pakistan.")

Step 3 is where we define logic, typically encapsulated in a function.

def execute(self):
        if self.city in data:
            return f"There are {data[self.city]} job vacancies in {self.city}."
        else:
            return f"Sorry, I don't have information about job vacancies in {self.city}.

Woohoo! You defined a tool using Pydantic too. Now let’s look at one more example. This is going to be the same as the tool decorator, but this time I will keep it in a single code block so that you can directly copy it in one shot, not in three pieces.

#Importing essentials
import requests
from langchain_core.pydantic_v1 import BaseModel, Field

#Creating Pydantic Model
class GetExchangeRateTool(BaseModel):
    """
    Retrieves the current exchange rate for a specified currency using an external API.

    This tool queries an external API to fetch the latest exchange rate for the given currency code.
    It handles basic error checking but may not cover all possible API response scenarios.

    Args:
        currency_code (str): The three-letter ISO currency code for the desired currency (e.g., 'USD', 'EUR').

    Returns:
        str: A string containing the current exchange rate for the specified currency, or an error message if the currency is not found or if there is an API error.

    Example:
        If you query for 'USD', the tool may return '1.0' (assuming USD is the base currency).
        If you query for 'XYZ', which is not a recognized currency, the tool may return 'Currency not found or API error.'

    Note:
        - The tool relies on an external API for data, which may have rate limits or downtime.
        - The accuracy and timeliness of the data depend on the API's reliability.
        - The tool assumes that the API response is in a specific format; changes to the API may require updates to this function.
    """

#Design Structure of Model

    currency_code: str = Field(..., description="The three-letter ISO currency code for the desired currency (e.g., 'USD', 'EUR').")
#Giving Tool Some Logic:
    def execute(self):
        url = f'https://api.exchangerate-api.com/v4/latest/{self.currency_code}'
        response = requests.get(url)
        data = response.json()

        # Assuming the response is in a specific format, adjust as necessary
        if 'rates' in data and self.currency_code in data['rates']:
            return str(data['rates'][self.currency_code])
        else:
            return "Currency not found or API error."

Combining The Language Model With Tool

To bind a tool with an LLM, we need an LLM in the first place, so we have to initialize one. Here, I am using Anthropic’s LLM to bind our tools, but any LLM can be used. You can get the API of Anthropic from here.

My_API = "Paste your API here"
from langchain_anthropic import ChatAnthropic
chat = ChatAnthropic(temperature=0, api_key= My_API , model_name="claude-3-opus-20240229")

Now, to combine our tools with the LLM, we have bind tools, as their names suggest, to bind the tools to the LLM.
We created two tools using Pydantic and a tool decorator. No matter how it was created, the method to invoke and bind will remain the same so let’s look at an example of how would we do that.

tools = [GetExchangeRateTool, JobVacancyTool]
llmwithtools= chat.bind_tools(tools)
ans= llmwithtools.invoke("What is rate of Euro")
print(ans)

The Output:

AIMessage(content=[{'text': "<thinking>\nThe GetExchangeRateTool seems relevant to answer this question, as it can retrieve the current exchange rate for a specified currency code.\n\nThe tool requires a single parameter:\n- currency_code (str): The three-letter ISO currency code for the desired currency\n\nThe user has requested the exchange rate for Euro. The ISO currency code for Euro is 'EUR'. So we have the necessary parameter to call the GetExchangeRateTool.\n\nNo other tools seem necessary to answer this specific request. The JobVacancyTool is not relevant.\n</thinking>", 'type': 'text'}, {'id': 'toolu_012Seb9ZAzd5paA6fJGmcp1n', 'input': {'currency_code': 'EUR'}, 'name': 'GetExchangeRateTool', 'type': 'tool_use'}], response_metadata={'id': 'msg_01QZpGavMK1R8kR4STLgvZSQ', 'model': 'claude-3-opus-20240229', 'stop_reason': 'tool_use', 'stop_sequence': None, 'usage': {'input_tokens': 1172, 'output_tokens': 187}}, id='run-4217c280-3617-4b87-ac52-1178d26010dc-0', tool_calls=[{'name': 'GetExchangeRateTool', 'args': {'currency_code': 'EUR'}, 'id': 'toolu_012Seb9ZAzd5paA6fJGmcp1n'}], usage_metadata={'input_tokens': 1172, 'output_tokens': 187, 'total_tokens': 1359})

Conclusion:

Congratulations readers! I am sure now you must have seen how easy is to make a LangChain Tool Call If you want to read similar articles like LangChain Tool Call, then read my other articles, and if you have any questions or feedback, feel free to contact us

Liked the Post?  You can share as well

Facebook
Twitter
LinkedIn

More From Machine Learning Spot

Get The Latest AI News and Insights

Directly To Your Inbox
Subscribe

Signup ML Spot Newsletter

What Will You Get?

Bonus

Get A Free Workshop on
AI Development