LangChain Agents

LangChain agents combine a chat model with tools and a loop: the model decides on an action, a tool runs, the result goes back to the model, and this repeats until the model gives a final answer. In LangChain 1.x you build agents with create_agent, which runs on LangGraph.

Creating an Agent

from langchain.agents import create_agent
from langchain.tools import tool

@tool
def add(a: float, b: float) -> float:
    """Add two numbers."""
    return a + b

@tool
def multiply(a: float, b: float) -> float:
    """Multiply two numbers."""
    return a * b

agent = create_agent(
    model="ollama:llama3.2",
    tools=[add, multiply],
    system_prompt="You are a careful calculator. Always use tools for math.",
)
result = agent.invoke({"messages": [{"role": "user", "content": "What is (3 + 4) * 6?"}]})
print(result["messages"][-1].content)
Sample output:
(3 + 4) * 6 = 42.

The input and output are a state dictionary with a messages list. The last message is the final answer; earlier messages show every tool call and result, which is great for debugging.

Inspecting the Steps

for m in result["messages"]:
    print(type(m).__name__, getattr(m, "tool_calls", None) or m.content)
Sample output:
HumanMessage What is (3 + 4) * 6?
AIMessage [{'name': 'add', 'args': {'a': 3, 'b': 4}, ...}]
ToolMessage 7.0
AIMessage [{'name': 'multiply', 'args': {'a': 7, 'b': 6}, ...}]
ToolMessage 42.0
AIMessage (3 + 4) * 6 = 42.

Using a Model Object and Structured Responses

from pydantic import BaseModel
from langchain_ollama import ChatOllama

class MathAnswer(BaseModel):
    expression: str
    value: float

agent = create_agent(
    model=ChatOllama(model="qwen3", temperature=0),
    tools=[add, multiply],
    response_format=MathAnswer,
)
out = agent.invoke({"messages": [{"role": "user", "content": "2 * 9 + 1"}]})
print(out["structured_response"])
Sample output:
expression='2 * 9 + 1' value=19.0

LangGraph Basics

Under the hood the agent is a LangGraph graph: a "model" node and a "tools" node connected by edges, with the messages list as shared state. When you outgrow create_agent you can build your own graph with StateGraph, adding custom nodes, conditional edges, checkpointers for memory and interrupts for human approval. create_agent also supports middleware for things like summarizing long histories or adding human-in-the-loop checks.

Agent Best Practices

  • Start with few tools; too many confuse small models.
  • Write a system prompt that says when to use each tool.
  • Add a checkpointer for memory across turns (see the memory lesson).
  • Limit loops with a recursion limit in the config to avoid runaway costs.
  • Trace runs in LangSmith to see why an agent made a decision.

Frequently asked questions

What replaced create_react_agent in LangChain 1.0?

create_agent from langchain.agents. It replaces langgraph.prebuilt.create_react_agent and the older AgentExecutor, which moved to langchain-classic.

Can LangChain agents run with local models?

Yes. Pass "ollama:model-name" or a ChatOllama instance. Choose a model with good tool calling support; quality varies a lot between small models.

What is the difference between a chain and an agent?

A chain follows fixed steps you define. An agent lets the model choose which tools to call and how many times, in a loop.