LangChain Agents: Tools, Agents & LCEL

Master LangChain agents with Module 3. Learn to use, build custom tools, and integrate them into advanced workflows with LCEL for LLM power.

Module 3: Working with Tools and Agents

This module delves into the powerful capabilities of LangChain agents, focusing on how to leverage and develop tools to enhance their functionality. We will explore different agent types, understand built-in tools and toolkits, learn to create custom tools, and integrate them into sophisticated agent workflows. Finally, we'll introduce the basics of the LangChain Expression Language (LCEL) for building complex agent logic.

Agent Types

LangChain offers a variety of agent types, each designed for specific interaction patterns and reasoning capabilities:

  • Zero-shot ReAct agents: These agents utilize the ReAct (Reasoning and Acting) framework, enabling them to generate intermediate thoughts and actions based on input. They are "zero-shot" as they don't require explicit examples for new tasks.
  • Conversational agents: Designed for interactive dialogues, these agents maintain conversation history and context, allowing for more natural and coherent multi-turn interactions.
  • Tool-using agents: These agents are explicitly built to interact with external tools, allowing them to fetch information, perform actions, and execute logic beyond their LLM's inherent knowledge.

Built-in Tools and Toolkits

LangChain provides a rich ecosystem of pre-built tools and toolkits that can be readily integrated with agents. These tools abstract complex operations, making it easier for agents to interact with external services and functionalities.

Common Built-in Tools:

  • Search Tools: For accessing information from various search engines (e.g., Google Search, DuckDuckGo).
  • Calculator Tools: To perform mathematical computations.
  • Code Interpreter Tools: To execute Python code and process data.
  • LLM Chain Tool: To encapsulate LLM calls as tools.
  • RequestsWrapper: For making HTTP requests to APIs.

Toolkits:

Toolkits often group related tools together, providing convenient ways to access and manage them. Examples include:

  • Wikipedia Toolkit: For searching and retrieving information from Wikipedia.
  • Pandas DataFrame Toolkit: For enabling agents to interact with Pandas DataFrames.
  • SQL Toolkit: For querying SQL databases.

Custom Tool Development

Beyond built-in options, you can create custom tools to extend agent capabilities to your specific needs. This is essential for integrating with proprietary APIs, accessing local files, or performing unique operations.

Developing Custom Tools:

Custom tools can be developed by:

  1. Defining a Python function: This function will encapsulate the logic of your tool.
  2. Adding a descriptive docstring: The docstring should clearly explain what the tool does, its arguments, and what it returns. This is crucial for LLM understanding.
  3. Decorating the function: Use the @tool decorator from langchain_core.tools to register your function as a LangChain tool.

Example: A Simple File Reading Tool

from langchain.tools import tool
import os

@tool
def read_file_content(file_path: str) -> str:
    """
    Reads and returns the content of a given file.
    Ensure the file_path is correctly specified and accessible.
    """
    if not os.path.exists(file_path):
        return f"Error: File not found at '{file_path}'"
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            return f.read()
    except Exception as e:
        return f"Error reading file '{file_path}': {e}"

# Example usage (for testing the tool directly)
# print(read_file_content("/path/to/your/file.txt"))

Custom Tool for API Calls

You can create tools to interact with any RESTful API. This typically involves using libraries like requests.

Example: A Weather API Tool

from langchain.tools import tool
import requests
import os

@tool
def get_weather(city: str, api_key: str) -> str:
    """
    Fetches the current weather information for a given city using a weather API.
    Requires a valid API key and the city name.
    """
    base_url = "http://api.openweathermap.org/data/2.5/weather?"
    complete_url = base_url + "appid=" + api_key + "&q=" + city
    response = requests.get(complete_url)
    data = response.json()

    if data["cod"] != "404":
        main_data = data["main"]
        current_temperature = main_data["temp"]
        current_pressure = main_data["pressure"]
        current_humidity = main_data["humidity"]
        weather_description = data["weather"][0]["description"]

        return (f"Temperature in {city}: {current_temperature} K\n"
                f"Atmospheric pressure in {city}: {current_pressure} hPa\n"
                f"Humidity in {city}: {current_humidity}%\n"
                f"Description: {weather_description}")
    else:
        return f"Error: City '{city}' not found."

# To use this tool, you would need an API key, e.g., from OpenWeatherMap
# weather_api_key = os.environ.get("OPENWEATHERMAP_API_KEY")
# if weather_api_key:
#     print(get_weather("London", weather_api_key))

Implementing Tool-Augmented Agents

Tool-augmented agents are agents that have access to one or more tools. When faced with a task, the agent can reason about which tool to use, prepare the necessary arguments for the tool, execute the tool, and then process the tool's output to generate a final response.

Steps to Implement a Tool-Augmented Agent:

  1. Initialize an LLM: Choose your preferred language model (e.g., from ChatOpenAI).
  2. Instantiate Tools: Create instances of the tools you want the agent to use (either built-in or custom).
  3. Create an Agent Executor: Combine the LLM, the tools, and an agent type (e.g., create_react_agent or create_openai_functions_agent) to form an AgentExecutor. The executor handles the agent's execution loop.
  4. Invoke the Agent Executor: Pass your prompt to the agent_executor.invoke().

Example: Agent using the File Reading Tool

from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_react_agent
from langchain import hub
from langchain.tools import tool
import os

# Assume read_file_content tool is defined as above

# 1. Initialize LLM
llm = ChatOpenAI(model="gpt-4o", temperature=0)

# 2. Instantiate Tools
tools = [read_file_content]

# 3. Create Agent Executor
# Get a pre-defined prompt template for ReAct agents
prompt = hub.pull("hwchase17/react")
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# 4. Invoke the Agent Executor
# Create a dummy file for demonstration
with open("my_document.txt", "w") as f:
    f.write("This is the content of my test document.\nIt contains important information.")

# Ensure the file exists before calling the agent
if os.path.exists("my_document.txt"):
    result = agent_executor.invoke({"input": "What is the content of my_document.txt?"})
    print("\n--- Agent Result ---")
    print(result["output"])
else:
    print("Error: my_document.txt was not created successfully.")

# Clean up the dummy file
# if os.path.exists("my_document.txt"):
#     os.remove("my_document.txt")

In this example, the agent will:

  1. Receive the input "What is the content of my_document.txt?".
  2. Reason that it needs to read a file.
  3. Select the read_file_content tool.
  4. Determine the file_path argument to be "my_document.txt".
  5. Execute read_file_content("my_document.txt").
  6. Receive the file's content as the tool's output.
  7. Format the output to answer the user's question.

LangChain Expression Language (LCEL) Basics

LangChain Expression Language (LCEL) is a declarative way to compose chains. It offers a powerful and flexible way to build complex LLM applications, including sophisticated agent logic, by combining components like LLMs, prompts, and parsers.

Key Concepts in LCEL:

  • Chains: LCEL allows you to chain components together using the | operator. For example, prompt | llm | output_parser.
  • Streaming: LCEL supports streaming outputs from LLMs, enabling more interactive user experiences.
  • Asynchronous Support: LCEL is designed with async operations in mind.
  • Runnable Interface: All LCEL components implement the Runnable interface, which defines a common set of methods for invocation, streaming, and batching.

Using LCEL for Agents:

LCEL can be used to define the core logic of agents. For instance, the create_react_agent and create_openai_functions_agent functions often return LCEL-compatible runnables. You can then integrate these runnable agents into larger LCEL workflows.

Simple LCEL Example (Not directly an agent, but illustrates composition):

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

# 1. Define a Prompt Template
prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant."),
    ("user", "{input}")
])

# 2. Initialize an LLM
llm = ChatOpenAI(model="gpt-4o", temperature=0)

# 3. Define an Output Parser
output_parser = StrOutputParser()

# 4. Compose the chain using LCEL
chain = prompt | llm | output_parser

# 5. Invoke the chain
# result = chain.invoke({"input": "What is the capital of France?"})
# print(result)

LCEL provides a robust foundation for building advanced agent behaviors and integrating them seamlessly with other LLM operations. By understanding these concepts, you can create highly capable and customized AI agents.