LangGraphLangGraph 1.2 · Python 3.10+
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
37 small wins to finish your pathNext lesson

Answers with a fixed shape

A TypedDict describes your state but never checks it. If you would rather be told when something is wrong, use a Pydantic model instead.

Everything you have written so far used TypedDict, which is a description and nothing more. Put a number where a string belongs and it will sail through and break somewhere later. A Pydantic model is the same description with the checking turned on.

Example
from pydantic import BaseModel
from langgraph.graph import StateGraph, START

class State(BaseModel):
    ticket: str
    urgent: bool = False

def triage(state: State):
    return {"urgent": "charge" in state.ticket}

builder = StateGraph(State)
builder.add_node("triage", triage)
builder.add_edge(START, "triage")

print(builder.compile().invoke({"ticket": "charged twice"}))

Two differences from a TypedDict. The node reads state.ticket with a dot instead of square brackets, and urgent has a default, so you did not have to pass it in.

What you get for it

Example
from pydantic import BaseModel, ValidationError
from langgraph.graph import StateGraph, START

class State(BaseModel):
    ticket: str

def triage(state: State):
    return {"ticket": state.ticket.upper()}

builder = StateGraph(State)
builder.add_node("triage", triage)
builder.add_edge(START, "triage")

try:
    builder.compile().invoke({"ticket": 12345})
except ValidationError as e:
    print("rejected at the door:", e.errors()[0]["msg"])

The run stopped before any node ran. With a TypedDict that same call would have reached triage and failed on .upper(), several steps away from the thing that was actually wrong.

Which to use

UseWhen
TypedDictMost of the time. It is lighter, and the state is coming from your own code.
BaseModelWhen the state comes from outside, from a web request or a form, and you want it checked at the edge.
There is a cost
A Pydantic state is checked when a run starts and when a node returns. It is not free, and on a state carrying a long conversation the checking is real work. Most graphs stay on TypedDict for that reason.

The other kind of fixed shape

There is a related idea worth knowing the name of. You can also ask the model to answer in a fixed shape rather than in prose, by handing with_structured_output a schema.

python
from pydantic import BaseModel

class Triage(BaseModel):
    category: str
    urgent: bool

sorted_ticket = model.with_structured_output(Triage).invoke(messages)
print(sorted_ticket.category, sorted_ticket.urgent)

That one has no output on this page, because our stand-in model cannot do it. It works by binding the schema as a tool, so it needs a model that really understands tools. Come back to it in lesson 30, once you have a real model.

Try it yourself
  • Add a third field with a default and invoke without passing it.
  • Return the wrong type from triage and see where the error appears.
  • Change the state to a TypedDict and confirm the bad ticket is no longer rejected.

This is what real progress feels like.