TellWorldAI World Archive
Ask中文

Home›Practice›Practice

Practice

LangGraph quickstart: build a tool-calling agent

LangGraph builds agents as explicit graphs of state, nodes and edges. This quickstart wires a small model-and-tool loop with Claude in one Python file, then shows how to add memory and pause for human input.

This guide is for readers who want their first agent built from explicit pieces rather than a black box. It follows the LangGraph quickstart, which builds a small calculator agent in one Python file. By the end you will understand state, nodes, edges and the tool loop, and you will know how to add memory and pauses.

What LangGraph is

LangGraph is a low-level orchestration framework and runtime for long-running, stateful agents. It was built by LangChain Inc, but the README says it can be used without LangChain.[14] Its core model is a graph. A workflow is a shared state, nodes that read the state and return updates, and edges that decide what runs next. Edges are either fixed or conditional.[3] You do not hide the loop inside a prompt. You draw it.

Before you start

Install the packages with pip install -U langgraph langchain langchain-anthropic, or with uv add langgraph langchain langchain-anthropic.[1]

pip install -U langgraph langchain langchain-anthropic

The quickstart needs a model-provider API key. Set it in your shell with export ANTHROPIC_API_KEY="your-api-key", or put ANTHROPIC_API_KEY=your-api-key in a .env file.[1]

Build the agent

The quickstart puts the whole agent in one file, agent.py, in eight steps: define tools and the model; define state; define a model node; define a tool node; define the end logic; build and compile the agent; optionally add LangSmith tracing; and run the agent.[1]

  1. Define the tools and the model. The model is initialized with init_chat_model("claude-sonnet-4-6", temperature=0). Tools are functions marked with the @tool decorator from langchain.tools, and model.bind_tools(tools) binds them to the model.[1]
  2. Define the state. The state is MessagesState(TypedDict), with messages: Annotated[list[AnyMessage], operator.add] and llm_calls: int. The Annotated wrapper with operator.add appends new messages instead of replacing the list.[1][3] LangGraph also ships a built-in reducer, add_messages, imported from langgraph.graph.message. It updates existing messages by ID and accepts shorthand message formats, where plain operator.add only appends.[3]
  3. Define the model node. A node is a function that reads the state and returns an update to it. The model node calls the model and returns its reply as new messages.[3]
  4. Define the tool node. A tool node runs the tool calls the model asked for. The workflow examples write it as a plain function that loops over tool_calls, invokes each tool, and returns a ToolMessage with the matching tool_call_id for each result.[6] The prebuilt ToolNode does the same job and also handles parallel execution and errors. It is added like this: builder.add_node("tools", ToolNode([search, calculator])).[6]
  5. Define the end logic. The routing function should_continue(state: MessagesState) -> Literal["tool_node", END] returns "tool_node" when the last message has tool_calls, and END otherwise.[1]
  6. Build and compile. The quickstart creates StateGraph(MessagesState), adds the nodes with add_node, and connects them. add_edge(START, "llm_call") starts the run. add_conditional_edges("llm_call", should_continue, ["tool_node", END]) routes after each model call. add_edge("tool_node", "llm_call") sends the tool results back to the model. Then compile() turns the graph into something runnable.[1] Compilation checks the structure for orphaned nodes, so a node nothing connects to is caught here.[3]
  7. Run it. Start the file with python agent.py. The agent is invoked with agent.invoke({"messages": messages}), and the quickstart reports the tool result as 7.[1]
python agent.py

What the graph looks like

The overview's smallest graph has one node and two edges, and it shows the skeleton every LangGraph program shares:[2]

from langgraph.graph import StateGraph, MessagesState, START, END

def mock_llm(state: MessagesState):
    return {"messages": [{"role": "ai", "content": "hello world"}]}

graph = StateGraph(MessagesState)
graph.add_node(mock_llm)
graph.add_edge(START, "mock_llm")
graph.add_edge("mock_llm", END)
graph = graph.compile()

graph.invoke({"messages": [{"role": "user", "content": "hi!"}]})

START is the virtual entry point and END marks a terminal edge. The entry point is an edge from START.[3] Send and Command are the two patterns the build checklist recommends for more involved cases. Send fans out the same node over items whose count is only known at runtime, and Command lets one step both update state and choose the next node.[13]

Loops need a stop

The calculator agent is a loop: the model calls a tool, the tool result goes back to the model, and the model decides whether to call another tool. A loop needs a stopping condition, and here the conditional edge to END provides it. LangGraph also caps the number of super-steps with a recursion limit. Exceeding it raises GraphRecursionError, which is imported from langgraph.errors, and you set the limit with recursion_limit in the config.[5]

From version 1.1.4 the default recursion limit is 10,007 super-steps, and between 1.0.6 and 1.1.3 it was 10,000. The LANGGRAPH_DEFAULT_RECURSION_LIMIT environment variable or a top-level recursion_limit config key overrides it.[3]

Add memory

The agent in the quickstart forgets everything after a run. LangGraph has two persistence systems for fixing that. Checkpointers save a thread's graph state, which gives you short-term memory within one conversation. Stores hold application-defined data that can be shared across threads, which gives you long-term memory.[8]

To keep state between calls, compile the graph with a checkpointer. The persistence quickstart does it like this:[8]

from langgraph.checkpoint.memory import InMemorySaver
from langgraph.store.memory import InMemoryStore

checkpointer = InMemorySaver()
store = InMemoryStore()

graph = builder.compile(checkpointer=checkpointer, store=store)

result = graph.invoke(
    {"messages": [{"role": "user", "content": "Hi, my name is Bob."}]},
    {"configurable": {"thread_id": "thread-1"}},
)

When you invoke a graph with a checkpointer, you must pass a thread_id in the configurable part of the config, for example {"configurable": {"thread_id": "1"}}. The checkpointer uses it as the primary key for storing and loading checkpoints.[9] Multi-turn conversations come from compiling with checkpointer=checkpointer, using InMemorySaver from langgraph.checkpoint.memory.[11]

Persistence also has a durability setting, passed as durability=. "exit" persists only when the graph exits, "async" persists in the background during the next step, and "sync" persists before the next step runs.[9]

Pause for human input

interrupt(), imported from langgraph.types, pauses execution inside a node. It saves state with the checkpointer and waits, with no time limit. Using it requires a checkpointer, a thread_id in the config, and a JSON-serializable payload.[10] You resume by calling with Command(resume=...). The value you pass becomes the return value of the paused interrupt() call, and you must reuse the same thread_id.[10]

When the graph resumes, the node runs again from its beginning. Any work done before interrupt() in that node must therefore be idempotent, meaning it can run twice without harm.[7]

Limits and common problems

In-memory checkpointers are the first trap. MemorySaver and InMemorySaver keep checkpoints in RAM, so all of them are lost when the process restarts. Production setups should use a persistent checkpointer such as PostgresSaver or SqliteSaver.[8]

Interrupts need the checkpointer as well as the thread ID. Without a checkpointer the graph cannot pause and resume.[7]

Loops that never reach END end in GraphRecursionError once they hit the limit. A fix is a clearer stop condition in the routing function, not only a larger limit.[5]

Next steps

The quickstart is the best next read, because it covers the whole calculator agent step by step.[1] For the state and routing rules, read the Graph API overview and the state page.[3][4] For memory and pauses, read the persistence, checkpointers and interrupts pages.[8][9][10] Before you design a larger graph, read the build checklist.[13]

Sources

  1. 1
    QuickstartLangChain Docs
  2. 2
    LangGraph overviewLangChain Docs
  3. 3
    Graph API overviewLangChain Docs
  4. 4
  5. 5
  6. 6
    Workflows and agentsLangChain Docs
  7. 7
  8. 8
    PersistenceLangChain Docs
  9. 9
    CheckpointersLangChain Docs
  10. 10
    InterruptsLangChain Docs
  11. 11
    MemoryLangChain Docs
  12. 12
    StreamingLangChain Docs
  13. 13
  14. 14
    LangGraph READMELangChain (GitHub)

Cite this page: LangGraph quickstart: build a tool-calling agent. TellWorld, https://www.tellworld.net/practice/practice-langgraph-quickstart. Updated 2026-11-14

Related news

View all