Prebuilts remove boilerplate and handle edge cases; knowing the current names avoids deprecated APIs.
LangGraph's langgraph.prebuilt module packages the agent-loop pieces:
ToolNode(tools)is a ready tools node. It runs all tool calls from the last message (in parallel), returns matchingToolMessages, and by default turns tool exceptions into error messages the model can read.tools_conditionis the routing function: it returns"tools"when the last message has tool calls, otherwiseEND.
So the hand-built loop shrinks to adding ToolNode as the "tools" node and calling add_conditional_edges("model", tools_condition). Your graph stays fully customizable around them.
For a standard agent with no custom flow, use LangChain's `create_agent` (from langchain.agents import create_agent). It builds and compiles a LangGraph graph for you, accepts a model name or object, tools and a system prompt, and supports middleware (hooks that run before or after model and tool calls, for example summarizing history or requiring human approval). Because the result is a compiled LangGraph graph, everything in this course (checkpointers, streaming, interrupts, deployment) applies to it.
Older tutorials use langgraph.prebuilt.create_react_agent. It was deprecated in LangGraph 1.0 in favour of create_agent; avoid it in new code.
When to choose what: create_agent first; your own graph with ToolNode when you need extra steps, branches or several agents; a fully hand-built tools node when tool execution itself needs custom logic.
Example
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.tools import tool
from langgraph.graph import StateGraph, START, MessagesState
from langgraph.prebuilt import ToolNode, tools_condition
@tool
def get_weather(city: str) -> str:
"""Current weather for a city."""
return f"Sunny in {city}"
# Option 1: your own graph with prebuilt pieces
model = init_chat_model("claude-sonnet-4-6").bind_tools([get_weather])
b = StateGraph(MessagesState)
b.add_node("model", lambda s: {"messages": [model.invoke(s["messages"])]})
b.add_node("tools", ToolNode([get_weather]))
b.add_edge(START, "model")
b.add_conditional_edges("model", tools_condition) # -> "tools" or END
b.add_edge("tools", "model")
graph = b.compile()
# Option 2: a complete agent (also a compiled LangGraph graph)
agent = create_agent("claude-sonnet-4-6", tools=[get_weather],
system_prompt="You are a helpful travel assistant.")
agent.invoke({"messages": [{"role": "user", "content": "Weather in Oslo?"}]})Remember
- ToolNode runs tool calls; tools_condition routes to 'tools' or END
- create_agent (LangChain) builds a full agent graph with middleware
- create_react_agent is deprecated since LangGraph 1.0
- Prebuilt agents are compiled graphs: all LangGraph features apply
Watch out for
- Copying create_react_agent from an old tutorial; migrate to langchain.agents.create_agent.