Your First Graph
State, nodes, and edges.
Let's write the smallest useful graph, with no model at all, so that you can see the structure clearly. Two nodes. One classifies a message, and one replies.

- The smallest useful graph
- No model yet
- Two nodes
Two nodes in a line
First, state. It's a typed dictionary, with three fields. Each node is an ordinary function. It takes the state, and returns only the fields that it wants to change. Then we build the graph. Add the nodes, connect them with edges from start to end, and compile it. Run it. Our message went in, each node added its bit, and the full state came out. Notice that the nodes don't call each other. The graph runs them.
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
class State(TypedDict):
message: str
kind: str
reply: str
def classify(state):
kind = "tracking" if "where" in state["message"].lower() else "other"
return {"kind": kind}
def respond(state):
return {"reply": f"Handled as {state['kind']}."}
graph = StateGraph(State)
graph.add_node("classify", classify)
graph.add_node("respond", respond)
graph.add_edge(START, "classify")
graph.add_edge("classify", "respond")
graph.add_edge("respond", END)
app = graph.compile()
print(app.invoke({"message": "Where is my chain?"})){'message': 'Where is my chain?', 'kind': 'tracking', 'reply': 'Handled as tracking.'}Seeing the graph
Because a graph is data, LangGraph can draw it. This one has an agent, and a tools node, with an arrow pointing back. That's our loop. We print it in a text format called mermaid. Run it. That text renders as a real diagram. You can paste it into any mermaid viewer, and share it with your team. Try doing that with a hand written loop.
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
class State(TypedDict):
x: int
g = StateGraph(State)
g.add_node("agent", lambda s: {"x": s["x"] + 1})
g.add_node("tools", lambda s: {"x": s["x"]})
g.add_edge(START, "agent")
g.add_conditional_edges("agent", lambda s: "tools" if s["x"] < 2 else END, ["tools", END])
g.add_edge("tools", "agent")
app = g.compile()
print(app.get_graph().draw_mermaid())---
config:
flowchart:
curve: linear
---
graph TD;
__start__([<p>__start__</p>]):::first
agent(agent)
tools(tools)
__end__([<p>__end__</p>]):::last
__start__ --> agent;
agent -.-> __end__;
agent -.-> tools;
tools --> agent;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
classDef last fill:#bfb6fcSummary
Nodes update the state, and edges decide what's next. So far, our path has been fixed. Next, we'll make it branch.
Key takeaways- State is a typed dictionary
- Nodes return only changes
- Graphs can draw themselves