Advanced 6 min read Updated Sep 8, 2026

Tools & Tool-Calling Agents

If you've searched for how to build a LangChain agent, you've probably landed on at least one tutorial using AgentExecutor - and that tutorial is now teaching you a deprecated pattern. This guide covers both: giving a model a tool in the first place, and the current, actively-maintained way to let it use that tool in a loop.

Step 1: define a tool

The @tool decorator turns a normal Python function into something a model can be offered and choose to call. The function's docstring matters - it's what the model reads to decide when the tool is relevant:

from langchain_core.tools import tool

@tool
def get_weather(city: str) -> str:
    """Get the current weather for a given city."""
    return weather_api.lookup(city)

Step 2: give the model access to it

bind_tools attaches one or more tools to a model, returning a new model that knows those tools exist and can request to call them:

model_with_tools = model.bind_tools([get_weather])
response = model_with_tools.invoke("What's the weather in Mumbai?")
# response.tool_calls now contains the requested call, if the model decided to use it

That single call doesn't run the tool for you - it just tells you the model wants to. Actually calling the function, feeding the result back, and letting the model produce a final answer is the "agent loop," and that's where the deprecated pattern comes in.

deprecated AgentExecutor maintenance mode create_agent() current, recommended Tool loop runs on LangGraph

Both paths reach the same loop - but only one of them is where new work should start.

Step 3: build the agent with create_agent, not AgentExecutor

AgentExecutor is LangChain's original agent runner, and as of LangChain 1.0 it's officially in maintenance mode - the team's own guidance is to migrate off it, with support planned to end in December 2026. The replacement is create_agent, and the detail worth knowing is that it isn't a from-scratch rewrite of the old pattern - it calls LangGraph's execution engine underneath. You get a one-function call on the surface, with the same looping, state-tracking machinery from the LangGraph guides doing the actual work:

from langchain.agents import create_agent

agent = create_agent(model, tools=[get_weather])
result = agent.invoke({"messages": [("user", "What's the weather in Mumbai?")]})

For a simple, single-tool assistant, that's genuinely the whole thing - create_agent handles the call-tool-then-respond loop for you, the same loop covered step by step in the LangGraph guide on building your first agent.

When to reach past create_agent to raw LangGraph: the moment you need something create_agent's defaults don't cover - a custom routing rule between more than one kind of step, a pause for human approval, or coordinating several agents - drop down to building the graph yourself with StateGraph. create_agent is a well-built default for the common case, not a ceiling.
Share this guide

Was this guide helpful?

Thanks for the feedback!

Want more hands-on AI builds like this?

APA Mastery runs live, practical sessions on working with modern AI tools - not just theory.

See What's On →
← PreviousRetrieval & RAG