Now that you understand how Chains link components in a predefined sequence, let's move to a more dynamic approach: Agents. Unlike Chains, where the developer defines the exact order of operations, Agents use an LLM as a reasoning engine to decide which actions to take and in what order, based on a set of available Tools
. This allows them to handle more complex, unpredictable tasks where the path to the solution isn't known beforehand.
Creating a basic agent involves bringing together a few specific components:
For a basic agent, we can start with simple, pre-built tools provided by LangChain. Let's consider an agent that needs to perform mathematical calculations. LangChain offers a load_tools
function that simplifies loading common tools. We'll load the llm-math
tool, which uses an LLM to perform calculations.
from langchain.agents import load_tools
from langchain_openai import OpenAI # Or your preferred LLM provider
# Assume llm object is already initialized (e.g., llm = OpenAI(temperature=0))
# Tool names are specific strings recognized by LangChain
tool_names = ["llm-math"]
tools = load_tools(tool_names, llm=llm)
print(f"Loaded tool: {tools[0].name}")
print(f"Tool description: {tools[0].description}")
The load_tools
function returns a list of Tool
objects. Each tool has a name
(used by the agent to identify it) and a description
(crucial for the LLM to understand what the tool does and when to use it).
LangChain supports several agent types, each employing different prompting strategies. A common and effective type for beginners is the ReAct (Reasoning and Acting) agent. ReAct prompts instruct the LLM to follow a specific thought process:
LangChain provides standardized prompts for different agent types. We typically don't need to craft these complex prompts manually for basic agents.
With the LLM and tools ready, we initialize the agent. We use the create_react_agent
function (or similar functions for other agent types), passing the LLM, the list of tools, and a pre-defined prompt structure suitable for ReAct agents. LangChain often pulls the correct prompt automatically based on the agent type you are creating.
from langchain import hub
from langchain.agents import create_react_agent
# Pull a standard ReAct prompt template
# This prompt is designed to work with the ReAct agent logic
prompt = hub.pull("hwchase17/react")
# Create the ReAct agent
agent = create_react_agent(llm, tools, prompt)
# Note: The 'agent' object itself contains the logic blueprint,
# but it needs the AgentExecutor to actually run.
This agent
object now bundles the LLM, the available tools, and the specific instructions (the prompt) on how the LLM should use those tools to reason and act.
The final piece is the AgentExecutor
. This is the runtime that actually executes the agent's reasoning loop. It takes the agent
object and the tools
as input.
from langchain.agents import AgentExecutor
# Create the Agent Executor
# verbose=True allows us to see the agent's thought process
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, max_iterations=5)
# max_iterations prevents potential infinite loops
The verbose=True
argument is highly recommended during development, as it prints the agent's internal monologue (Thoughts, Actions, Observations), making it much easier to understand its behavior and debug issues. max_iterations
is a safety measure to prevent the agent from getting stuck in a loop.
The agent execution loop can be visualized as follows:
Diagram illustrating the flow within the Agent Executor. The LLM reasons, proposes an action, the executor parses this, runs the tool if specified, gets the result (observation), adds it to the scratchpad, and feeds it back to the LLM until a final answer is determined.
Now, we can invoke the agent with a specific task using the invoke
method of the AgentExecutor
.
# Example query for our math agent
query = "What is 25 percent of 300?"
# Run the agent executor
response = agent_executor.invoke({"input": query})
print("\nFinal Response:")
print(response)
# A more complex calculation
query_complex = "If a train travels at 60 km/h for 2.5 hours, how far does it travel?"
# Note: The basic 'llm-math' tool might struggle with unit conversions or physics implicitly.
# It's primarily designed for arithmetic/algebraic calculations.
# A more sophisticated agent might need specific physics tools or better reasoning.
response_complex = agent_executor.invoke({"input": query_complex})
print("\nFinal Response (Complex Query):")
print(response_complex)
If verbose=True
was set, you will see output similar to this during execution:
> Entering new AgentExecutor chain...
Thought: The user wants to calculate 25% of 300. I can use the calculator tool for this. The calculation is 0.25 * 300.
Action: Calculator
Action Input: 0.25 * 300
Observation: Answer: 75.0
Thought: I have the result from the calculator. The answer is 75.0. I can now provide the final answer to the user.
Final Answer: 25 percent of 300 is 75.0.
> Finished chain.
Final Response:
{'input': 'What is 25 percent of 300?', 'output': '25 percent of 300 is 75.0.'}
# ... (similar output for the second query, likely involving 60 * 2.5)
This output clearly shows the ReAct process: the agent's thought, the chosen action and its input, the observation received from the tool, and the final thought leading to the answer.
This example demonstrates the core process of creating and running a basic agent. You initialize an LLM, load necessary tools, combine them with an appropriate agent prompt using a creation function (like create_react_agent
), wrap everything in an AgentExecutor
, and then invoke it with your query. The executor handles the interaction loop, leveraging the LLM's reasoning ability to decide how to use the tools effectively. In the next section, we'll look at techniques for debugging when things don't go as planned.
© 2025 ApX Machine Learning