# Langgraph

> Expert guidance for building stateful, multi-actor AI agents with LangGraph - graphs, nodes, edges, state management, and agent architectures.

- Skill: `htooayelwinict/langgraph` (Agent Skill)
- Install (CLI): `npx skillmds@latest add htooayelwinict/langgraph`
- Raw SKILL.md: https://api.skillmd.com/api/skills/htooayelwinict/langgraph/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: htooayelwinict (https://skillmd.com/u/htooayelwinict)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/htooayelwinict/langgraph

---


# LangGraph Skill

Use this skill when building stateful, cyclic AI agent workflows with LangGraph.

## 📚 Documentation Lookup (Context7)

Always verify patterns with latest docs:
```
mcp_context7_resolve-library-id(libraryName="langgraph", query="StateGraph conditional edges")
mcp_context7_query-docs(libraryId="/langchain-ai/langgraph", query="checkpointer persistence")
```

## Core Concepts

### 1. State Definition
```python
from typing import Annotated, TypedDict
from langgraph.graph.message import add_messages

class AgentState(TypedDict):
    messages: Annotated[list, add_messages]
    context: str
    iteration: int

# With Pydantic
from pydantic import BaseModel

class State(BaseModel):
    messages: list = []
    current_step: str = "start"
```

### 2. Basic Graph Structure
```python
from langgraph.graph import StateGraph, START, END

# Define the graph
workflow = StateGraph(AgentState)

# Add nodes (functions that transform state)
def agent_node(state: AgentState) -> dict:
    response = llm.invoke(state["messages"])
    return {"messages": [response]}

def tool_node(state: AgentState) -> dict:
    # Execute tools based on last message
    return {"messages": [tool_result]}

workflow.add_node("agent", agent_node)
workflow.add_node("tools", tool_node)

# Add edges
workflow.add_edge(START, "agent")
workflow.add_edge("tools", "agent")

# Conditional edge
def should_continue(state: AgentState) -> str:
    last_message = state["messages"][-1]
    if last_message.tool_calls:
        return "tools"
    return END

workflow.add_conditional_edges("agent", should_continue)

# Compile
app = workflow.compile()
```

### 3. Prebuilt Components
```python
from langgraph.prebuilt import create_react_agent, ToolNode

# Quick ReAct agent
tools = [search_tool, calculator_tool]
agent = create_react_agent(llm, tools)

# Tool execution node
tool_node = ToolNode(tools)
```

### 4. Checkpointing (Memory/Persistence)
```python
from langgraph.checkpoint.memory import MemorySaver
from langgraph.checkpoint.sqlite import SqliteSaver

# In-memory (for development)
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)

# SQLite (for persistence)
with SqliteSaver.from_conn_string(":memory:") as saver:
    app = workflow.compile(checkpointer=saver)

# Invoke with thread_id for conversation continuity
config = {"configurable": {"thread_id": "user-123"}}
result = app.invoke({"messages": [HumanMessage("Hi")]}, config)

# Continue conversation
result = app.invoke({"messages": [HumanMessage("Follow up")]}, config)
```

### 5. Human-in-the-Loop
```python
from langgraph.graph import StateGraph

# Add interrupt before sensitive operations
app = workflow.compile(
    checkpointer=memory,
    interrupt_before=["sensitive_action"]  # Pause here
)

# Resume after human approval
result = app.invoke(None, config)  # Continues from checkpoint
```

### 6. Subgraphs
```python
# Define inner graph
inner_workflow = StateGraph(InnerState)
inner_workflow.add_node("process", process_node)
inner_workflow.add_edge(START, "process")
inner_workflow.add_edge("process", END)
inner_graph = inner_workflow.compile()

# Use as node in outer graph
outer_workflow = StateGraph(OuterState)
outer_workflow.add_node("subgraph", inner_graph)
```

### 7. Streaming
```python
# Stream node outputs
for event in app.stream({"messages": [HumanMessage("Hello")]}):
    for node_name, output in event.items():
        print(f"{node_name}: {output}")

# Stream tokens from LLM
async for event in app.astream_events(input, version="v2"):
    if event["event"] == "on_chat_model_stream":
        print(event["data"]["chunk"].content, end="")
```

## Agent Architectures

### ReAct Agent
```python
from langgraph.prebuilt import create_react_agent

agent = create_react_agent(
    model=llm,
    tools=tools,
    state_modifier="You are a helpful assistant."  # System prompt
)
```

### Plan-and-Execute
```python
class PlanExecuteState(TypedDict):
    input: str
    plan: list[str]
    past_steps: list[tuple[str, str]]
    response: str

def planner(state):
    # Generate plan
    plan = plan_chain.invoke({"input": state["input"]})
    return {"plan": plan.steps}

def executor(state):
    # Execute current step
    task = state["plan"][0]
    result = execute_chain.invoke({"task": task})
    return {
        "past_steps": [(task, result)],
        "plan": state["plan"][1:]
    }

def should_end(state):
    return END if not state["plan"] else "executor"

workflow = StateGraph(PlanExecuteState)
workflow.add_node("planner", planner)
workflow.add_node("executor", executor)
workflow.add_edge(START, "planner")
workflow.add_conditional_edges("planner", should_end)
workflow.add_conditional_edges("executor", should_end)
```

### Multi-Agent Supervisor
```python
from langgraph.prebuilt import create_react_agent

# Create specialized agents
researcher = create_react_agent(llm, [search_tool])
coder = create_react_agent(llm, [code_tool])

class SupervisorState(TypedDict):
    messages: Annotated[list, add_messages]
    next: str

def supervisor(state):
    # Decide which agent to call
    decision = router_chain.invoke(state["messages"])
    return {"next": decision.next_agent}

def call_researcher(state):
    result = researcher.invoke({"messages": state["messages"]})
    return {"messages": result["messages"]}

def call_coder(state):
    result = coder.invoke({"messages": state["messages"]})
    return {"messages": result["messages"]}

workflow = StateGraph(SupervisorState)
workflow.add_node("supervisor", supervisor)
workflow.add_node("researcher", call_researcher)
workflow.add_node("coder", call_coder)

workflow.add_edge(START, "supervisor")
workflow.add_conditional_edges("supervisor", lambda s: s["next"])
workflow.add_edge("researcher", "supervisor")
workflow.add_edge("coder", "supervisor")
```

## Best Practices

1. **State Design** - Keep state minimal; use `add_messages` reducer for message accumulation
2. **Node Functions** - Return partial state updates, not full state
3. **Conditional Edges** - Use for dynamic routing based on state
4. **Checkpointing** - Always use for production to enable persistence
5. **Streaming** - Use `astream_events` for real-time UX
6. **Error Handling** - Add retry logic in nodes or use fallback edges
7. **Testing** - Test nodes individually before composing

## Common Patterns

### State Reducer
```python
from operator import add
from typing import Annotated

class State(TypedDict):
    items: Annotated[list, add]  # Appends to list
    messages: Annotated[list, add_messages]  # Smart message merging
```

### Parallel Branches
```python
workflow.add_node("branch_a", node_a)
workflow.add_node("branch_b", node_b)
workflow.add_edge(START, "branch_a")
workflow.add_edge(START, "branch_b")  # Both run in parallel
workflow.add_edge("branch_a", "join")
workflow.add_edge("branch_b", "join")
```

### Dynamic Tool Selection
```python
def route_to_tool(state):
    tool_call = state["messages"][-1].tool_calls[0]
    return tool_call["name"]

workflow.add_conditional_edges("agent", route_to_tool, {
    "search": "search_node",
    "calculate": "calc_node"
})
```

## Installation
```bash
pip install langgraph
pip install langgraph-checkpoint-sqlite  # For SQLite persistence
```

