HOW-TO · RAG
How to Define State Schema in LangGraph
Target environment
Ubuntu 24.04 · Ollama 0.4.x
PREREQUISITES
LangGraph installed, Python 3.10+
What this does
The state schema defines what data flows through a LangGraph workflow. Each node reads from and writes to this shared state, with reducers controlling how updates are applied.
Steps
- Define a basic state schema with TypedDict. Every key is a state field.
from typing import TypedDict
class SearchState(TypedDict):
query: str
results: list[str]
error: str | None
- Add reducer annotations for append semantics. Use
Annotatedto specify how updates merge.
from typing import Annotated, TypedDict
from operator import add
class ChatState(TypedDict):
messages: Annotated[list, add] # appends new messages
context: str
step: int
- Use
add_messagesreducer for LangChain message objects. This handles message deduplication by ID.
from typing import TypedDict, Annotated, Sequence
from langgraph.graph.message import add_messages
from langchain_core.messages import BaseMessage
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], add_messages]
next_agent: str
- Define a default factory for complex types. Prevents key errors on first access.
from typing import TypedDict
from dataclasses import dataclass, field
@dataclass
class WorkflowContext:
documents: list[str] = field(default_factory=list)
score: float = 0.0
class AdvancedState(TypedDict):
query: str
context: WorkflowContext
- Inspect state at runtime. Use
NodeInterruptor logging to see state shape.
def inspect_node(state: AgentState) -> dict:
print(f"State keys: {list(state.keys())}")
print(f"Messages count: {len(state['messages'])}")
return {}
Verification
python -c "
from typing import TypedDict, Annotated
from operator import add
class S(TypedDict):
items: Annotated[list, add]
s: S = {'items': ['a']}
s['items'] = s['items'] + ['b']
print(s['items'])
# Expected: ['a', 'b']
"
Common failures
- Missing
Annotatedreducer. Without a reducer, updating a field replaces it instead of merging. This causes data loss in cyclic graphs. - Mutability side effects. If a node modifies a list in place, the reducer may not trigger. Always return new values.
- KeyError on first access. Nodes try to read a key that hasn't been initialized. Provide defaults or use
state.get("key", default). - 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 Set Up Basic LangGraph Agent from Scratch
- How to Implement Memory in LangGraph State