HOW-TO · RAG
How to Set Up Basic LangGraph Agent from Scratch
Target environment
Ubuntu 24.04 · Ollama 0.4.x
PREREQUISITES
LangGraph installed, Ollama running, Python 3.10+
What this does
LangGraph enables building stateful, cyclic agent workflows where nodes represent steps (LLM calls, tool execution) and edges define transitions. This guide builds a simple ReAct-style agent from scratch.
Steps
- Define the agent state. Use
TypedDictto specify the state schema.
from typing import TypedDict, Annotated, Sequence
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages
from langchain_core.messages import BaseMessage
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], add_messages]
- Create the LLM node. Define a function that calls the LLM and returns the response.
from langchain_ollama import ChatOllama
llm = ChatOllama(model="llama3.2", temperature=0)
def call_model(state: AgentState) -> dict:
response = llm.invoke(state["messages"])
return {"messages": [response]}
- Build the graph. Add nodes and edges.
workflow = StateGraph(AgentState)
workflow.add_node("agent", call_model)
workflow.set_entry_point("agent")
workflow.add_edge("agent", END)
app = workflow.compile()
- Define a tool node (optional but common). For agents that call tools.
def tool_node(state: AgentState) -> dict:
# Parse tool calls from last message, execute, return results
return {"messages": [tool_result_message]}
workflow.add_node("tools", tool_node)
workflow.add_conditional_edges("agent", should_continue, {"continue": "tools", "end": END})
- Invoke the agent.
from langchain_core.messages import HumanMessage
result = app.invoke({
"messages": [HumanMessage(content="What is the capital of France?")]
})
print(result["messages"][-1].content)
Verification
python -c "
from langgraph.graph import StateGraph, END
from typing import TypedDict
class S(TypedDict):
x: int
def inc(s):
return {'x': s['x'] + 1}
g = StateGraph(S)
g.add_node('inc', inc)
g.set_entry_point('inc')
g.add_edge('inc', END)
app = g.compile()
r = app.invoke({'x': 0})
print(r['x'])
# Expected: 1
"
Common failures
- Missing state key. The state dict must contain all keys defined in the TypedDict. Initialize with defaults in the first invocation.
- No
add_messagesreducer. Without the reducer annotation, messages overwrite instead of appending. - Graph compilation fails without END. Every path must eventually reach
ENDor a terminal node. - Version mismatch - The installed package or runtime differs from the command shown; check the version first and rerun the smallest verification command.
- Local environment drift - Another service, virtual environment, model, or path is being used; print the active binary path and configuration before changing the guide steps.
Related guides
- How to Define State Schema in LangGraph
- How to Implement Tool Calling in LangGraph Agents