langgraph-fundamentals

rozwer's avatarfrom rozwer

Core concepts for building LangGraph applications. Use when creating StateGraph workflows, defining nodes and edges, managing state with TypedDict/Pydantic, or understanding basic graph structure. Covers state schemas, reducers, node functions, edge types (normal, conditional), and graph compilation.

⭐0stars🔀0forks📁View on GitHub🕐Updated Dec 29, 2025⬇️1downloads

When & Why to Use This Skill

This Claude skill provides a comprehensive guide to LangGraph fundamentals, a powerful orchestration framework for building stateful, multi-actor LLM applications. It covers essential concepts such as StateGraph initialization, node and edge definition, and advanced state management using TypedDict and Pydantic. By mastering these core components, developers can create complex, cyclic agentic workflows with robust control over execution flow and state persistence.

Use Cases

  • Building ReAct-style agents that utilize external tools and iterative reasoning to solve complex queries.
  • Designing multi-agent systems where specialized LLM nodes collaborate and share a common state to complete multi-step tasks.
  • Implementing sophisticated state management with custom reducers to handle message history and data accumulation in long-running conversations.
  • Creating dynamic execution flows using conditional edges that route tasks based on real-time LLM outputs or state changes.
namelanggraph-fundamentals
descriptionCore concepts for building LangGraph applications. Use when creating StateGraph workflows, defining nodes and edges, managing state with TypedDict/Pydantic, or understanding basic graph structure. Covers state schemas, reducers, node functions, edge types (normal, conditional), and graph compilation.

LangGraph Fundamentals

LangGraph is a low-level orchestration framework for building stateful, multi-actor LLM applications with cyclic graphs.

Core Concepts

StateGraph

The central abstraction. Initialize with a state schema, add nodes and edges, then compile.

from langgraph.graph import StateGraph, START, END
from typing import TypedDict, Annotated
import operator

class State(TypedDict):
    messages: Annotated[list, operator.add]  # Reducer: append
    count: int  # Override: replace

graph = StateGraph(State)

State Schema

Define with TypedDict or Pydantic BaseModel. Two update modes:

Mode Syntax Behavior
Override field: Type Replace value
Reduce field: Annotated[Type, reducer] Apply reducer function

Common reducers:

  • operator.add - Append to list
  • add_messages - Append messages with deduplication
from langgraph.graph.message import add_messages

class ChatState(TypedDict):
    messages: Annotated[list, add_messages]

Nodes

Functions that receive state and return partial state updates.

def my_node(state: State) -> dict:
    return {"count": state["count"] + 1}

graph.add_node("my_node", my_node)
# Or auto-name from function:
graph.add_node(my_node)  # name = "my_node"

Async nodes:

async def async_node(state: State) -> dict:
    result = await some_async_call()
    return {"data": result}

Edges

Connect nodes to define execution flow.

Normal edges - Fixed transitions:

graph.add_edge(START, "node_a")
graph.add_edge("node_a", "node_b")
graph.add_edge("node_b", END)

Conditional edges - Dynamic routing:

def route(state: State) -> str:
    if state["count"] > 5:
        return "finish"
    return "continue"

graph.add_conditional_edges(
    "node_a",
    route,
    {"finish": END, "continue": "node_b"}
)

Fan-out/Fan-in - Parallel execution:

# Fan-out: single node to multiple
graph.add_edge("start", "task_a")
graph.add_edge("start", "task_b")

# Fan-in: multiple nodes to single (waits for all)
graph.add_edge(["task_a", "task_b"], "merge")

Compilation and Execution

# Compile
app = graph.compile()

# Invoke (sync)
result = app.invoke({"messages": [], "count": 0})

# Stream (sync)
for event in app.stream({"messages": []}, stream_mode="updates"):
    print(event)

# Async
result = await app.ainvoke({"messages": []})
async for event in app.astream({"messages": []}):
    print(event)

Complete Example: ReAct Agent

from typing import Annotated, Literal
from typing_extensions import TypedDict
from langchain.chat_models import init_chat_model
from langchain.tools import tool
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode

class State(TypedDict):
    messages: Annotated[list, add_messages]

@tool
def search(query: str) -> str:
    """Search the web."""
    return f"Results for: {query}"

tools = [search]
model = init_chat_model("gpt-4o").bind_tools(tools)

def agent(state: State) -> dict:
    response = model.invoke(state["messages"])
    return {"messages": [response]}

def should_continue(state: State) -> Literal["tools", "__end__"]:
    last = state["messages"][-1]
    if last.tool_calls:
        return "tools"
    return "__end__"

graph = StateGraph(State)
graph.add_node("agent", agent)
graph.add_node("tools", ToolNode(tools))
graph.add_edge(START, "agent")
graph.add_conditional_edges("agent", should_continue)
graph.add_edge("tools", "agent")

app = graph.compile()

Key Points

  • Nodes return partial state (only keys to update)
  • Use Annotated with reducers for accumulating values
  • START and END are special constants for entry/exit
  • Always compile before invoke/stream
  • Graph must have path from START to END