home / skills / htooayelwinict / claude-config / langgraph

langgraph skill

/skills/langgraph

This skill helps you design and manage stateful, multi-agent workflows with LangGraph, enabling dynamic routing, memory, and subgraph architectures.

npx playbooks add skill htooayelwinict/claude-config --skill langgraph

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
7.3 KB
---
name: langgraph
description: Expert guidance for building stateful, multi-actor AI agents with LangGraph - graphs, nodes, edges, state management, and agent architectures.
allowed-tools: Read, Edit, Bash, Grep, mcp_context7
---

# 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
```

Overview

This skill provides expert guidance for designing stateful, multi-actor AI agent workflows using LangGraph. It focuses on graphs, nodes, edges, state management, checkpointing, streaming, and common agent architectures like ReAct, Plan-and-Execute, and multi-agent supervisors. The guidance emphasizes practical patterns, persistence, and human-in-the-loop control for reliable, production-ready agents.

How this skill works

The skill explains how to define a typed state, add nodes that return partial state updates, and connect nodes with edges or conditional edges to create cyclic, stateful workflows. It covers compiling graphs into runnable apps with optional checkpointers for persistence, streaming node outputs and model tokens, and composing subgraphs or prebuilt agent components such as ReAct or ToolNode. It also shows patterns for parallel branches, dynamic tool routing, and interrupt points for human approval.

When to use it

  • Building multi-step agents that must maintain conversation or workflow state across steps.
  • Coordinating multiple specialized agents (researcher, coder, planner/executor) within one workflow.
  • Implementing persistent conversations or long-running workflows with checkpointing.
  • Needing real-time UX with token and node-level streaming.
  • Adding human-in-the-loop interrupts before sensitive or irreversible actions.

Best practices

  • Design minimal, explicit state shapes and use reducers (e.g., add_messages) for accumulators.
  • Have node functions return partial updates instead of replacing full state.
  • Always enable a checkpointer for production to preserve continuity across invocations.
  • Use conditional edges for dynamic routing and build fallback edges for error handling.
  • Test nodes independently and validate subgraphs before composing larger workflows.

Example use cases

  • A ReAct agent that invokes search and calculator tools and loops until a final answer is produced.
  • Plan-and-Execute pipeline where a planner emits a step list and an executor runs each step sequentially.
  • Multi-agent supervisor that routes tasks between a researcher and a coder based on a routing chain.
  • Long-running conversational assistant that persists dialogue using a SQLite checkpointer.
  • Human-in-the-loop approval flow that interrupts before a sensitive action and resumes after approval.

FAQ

How do I persist conversation state between runs?

Compile your StateGraph with a checkpointer (MemorySaver for dev, SqliteSaver for persistence) and invoke with a thread_id in config to continue the same conversation.

Can I stream both node outputs and LLM tokens?

Yes. Use app.stream for node-level events and astream_events for model token streaming to support real-time UX.