Skip to content
Back to skills

Langgraph Implementation

ASecurity

Implements LangGraph stateful agent workflows including state graphs, conditional routing, checkpointing, human-in-the-loop approval, and persistence patterns for building reliable multi-step AI agent applications.

  • 4 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added June 12, 2026
ai-agentspythongosqlnodetestingdebugginggitapidatabasedocumentation

Works with

  • api

Security analysis

A100/100

Scanned June 12, 2026

npx -y skills add paulpas/agent-skill-router --skill langgraph-implementation --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Langgraph Implementation?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Langgraph Implementation
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/paulpas-langgraph-implementation/badge)](https://www.skillsdirectory.com/skills/paulpas-langgraph-implementation)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---




name: langgraph-implementation
description: Implements LangGraph stateful agent workflows including state graphs, conditional routing, checkpointing, human-in-the-loop approval, and persistence patterns for building reliable multi-step AI agent applications.
license: MIT
compatibility: opencode
metadata:
  version: "1.0.0"
  domain: coding
  triggers: langgraph, state graph, agent workflow, conditional routing, human in the loop, checkpointing, langchain graph, persistent agent
  archetypes:
    - tactical
    - generation
  anti_triggers:
    - brainstorming
    - vague ideation
    - high level architecture
  response_profile:
    verbosity: low
    directive_strength: high
    abstraction_level: operational
  role: implementation
  scope: implementation
  output-format: code
  content-types: [code, guidance, do-dont, examples]
  related-skills: crewai-agent-workflows, autogen-conversational-patterns, framework-utilization




---





# LangGraph Implementation Patterns

Implements stateful AI agent workflows using LangGraph's declarative graph API. Builds reliable multi-step agents with explicit state machines, conditional routing, human-in-the-loop approval gates, and automatic checkpointing for replay and debugging.

## TL;DR Checklist

- [ ] Define `BaseModel`-typed state class with all fields needed across the workflow
- [ ] Register each node function with a clear signature accepting `(state: State) -> PartialState`
- [ ] Add edges between nodes using `add_edge(START, first_node)` and `add_edge(node, END)`
- [ ] Use `add_conditional_edges()` for branching logic with explicit routing functions returning string labels
- [ ] Enable checkpointing via `MemorySaver` or persistent checkpoint store for state recovery
- [ ] Add human-in-the-loop interruption point with `Command(resume=<value>)` pattern
- [ ] Run graph with `graph.invoke(initial_state, config={"configurable": {"thread_id": "..."}})`

---

## When to Use

Use this skill when:

- Building a multi-step AI agent that needs to maintain state across steps (retrieval reasoning generation)
- Implementing conditional branching based on LLM output or external tool results
- Requiring checkpoint replay capability for debugging or pausing resuming workflows
- Needing human-in-the-loop approval at specific decision points in the workflow
- Building agents that must survive process restarts with state persistence

## When NOT to Use

Avoid this skill for:

- Simple single-turn LLM calls — use `langchain` chains instead, no graph needed
- Pure parallel tool execution without state dependency — a simple `asyncio.gather` suffices
- Event-driven architectures requiring long-running async workers — use Temporal or Celery instead

---

## Core Workflow

1. **Define the State Schema** — Create a `TypedDict` or Pydantic model that captures every piece of state flowing through the graph. Use `Annotated` operators for merge strategies on fields that accumulate across nodes.

```python
from typing import TypedDict, Annotated, Sequence
from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages

class AgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], add_messages]  # Appends new messages
    context: str  # Last node write wins (default operator)
    decision: str | None  # Routing label set by reasoning node
    research_summary: str | None
```

2. **Implement Node Functions** — Each node is an async or sync function that receives the full state and returns a partial state dict. Nodes must be pure with respect to side effects (I/O goes in tools, not nodes).

```python
from langchain_core.tools import tool
from langgraph.graph import StateGraph, START, END
from langgraph.types import Command
from typing_extensions import TypedDict
import operator
from typing import Annotated, Sequence
from langchain_core.messages import AIMessage, HumanMessage
from langgraph.graph.message import add_messages

# Tool implementations
@tool
def search_web(query: str) -> str:
    """Search the web for current information."""
    return f"Results for: {query}"

@tool
def generate_report(context: str) -> str:
    """Generate a report from research context."""
    return f"Report based on: {context[:200]}..."

# Node functions
async def retriever_node(state: AgentState) -> dict:
    """Retrieve context by searching web based on user query."""
    last_message = state["messages"][-1]
    if isinstance(last_message, HumanMessage):
        query = last_message.content
        results = search_web.invoke({"query": query})
        return {"context": results.content, "messages": [AIMessage(content=f"Research: {results.content}")]}
    return {"messages": [AIMessage(content="No new input to retrieve")]}

# Conditional routing function
def route_after_retrieval(state: AgentState) -> str:
    """Decide next step based on research quality."""
    context = state.get("context", "")
    if len(context) > 50:
        return "generate"
    return "ask_followup"

# Build the graph
graph_builder = StateGraph(AgentState)
graph_builder.add_node("retriever", retriever_node)
graph_builder.add_node("generator", generate_report)
graph_builder.add_node("followup", lambda s: {"messages": [HumanMessage(content="Ask user for more info")]})

# Add edges
graph_builder.add_edge(START, "retriever")
graph_builder.add_conditional_edges(
    "retriever",
    route_after_retrieval,
    {"generate": "generator", "ask_followup": "followup"},
)
graph_builder.add_edge("generator", END)
graph_builder.add_edge("followup", END)

# Compile with checkpointing and human-in-the-loop
from langgraph.checkpoint.memory import MemorySaver

checkpointer = MemorySaver()
graph = graph_builder.compile(checkpointer=checkpointer)

# Execution
config = {"configurable": {"thread_id": "thread-1"}}
result = graph.invoke(
    {"messages": [HumanMessage(content="Latest AI trends")]},
    config=config,
)
```

3. **Implement Human-in-the-Loop Pattern** — Use `langgraph.types.Command` to pause execution and await human input at specific points in the workflow.

```python
from langgraph.types import Command
from typing import Literal

async def reasoning_node(state: AgentState) -> Command[Literal["approve", "revise"]]:
    """Reason about results and request human approval."""
    context = state.get("context", "")
    
    # LLM reasoning step
    reasoning = await llm.ainvoke([
        SystemMessage(content="Analyze the research and recommend a course of action."),
        HumanMessage(content=context),
    ])
    
    needs_approval = "important decision" in reasoning.content.lower() or \
                     state.get("research_summary") is None
    
    if needs_approval:
        return Command(
            goto="human_review",
            update={"decision": reasoning.content},
        )
    
    return Command(goto="generate_report", update={"decision": reasoning.content})

async def human_review_node(state: AgentState) -> dict:
    """Wait for human input and resume the graph."""
    # This node is an interruption point — execution pauses here
    # Human provides feedback via graph.invoke(resume=...)
    return {"human_feedback": "approved"}

# Add the human review edge
graph_builder.add_edge("reasoning", "human_review")
graph_builder.add_conditional_edges(
    "human_review",
    lambda state: "approve" if state.get("decision") == "important" else "revise",
    {"approve": END, "revise": "retriever"},  # Loop back to retrieve
)
```

4. **Implement Persistent Checkpointing** — For production workflows, replace `MemorySaver` with a database-backed checkpointer to survive process restarts and enable state replay.

```python
from langgraph.checkpoint.postgres import PostgresSaver
import psycopg2

conn_str = "postgresql://user:pass@localhost:5432/agents"
db_conn = psycopg2.connect(conn_str)
checkpointer = PostgresSaver(db_conn)

# Initialize tables (run once)
checkpointer.setup()

graph = graph_builder.compile(checkpointer=checkpointer)

# Save state at specific points for later replay
snapshot = checkpointer.get_tuple({"configurable": {"thread_id": "thread-1"}})
if snapshot:
    print(f"Last saved step: {snapshot.metadata}")

# Resume from a specific checkpoint
graph.invoke(None, config={"configurable": {"thread_id": "thread-1", "checkpoint_id": snapshot.checkpoint.id}})
```

## Implementation Patterns

### Pattern 1: Fan-out / Fan-in Parallel Execution

Use parallel nodes to execute independent tasks simultaneously, then merge results. LangGraph supports fan-out via multiple edges from one node and fan-in by having multiple nodes write to shared state fields with merge operators.

```python
from langgraph.graph import StateGraph, START, END
import operator

class ResearchState(TypedDict):
    queries: list[str]
    results: Annotated[dict, operator.or_]  # Merges dicts from parallel nodes
    final_report: str | None

async def research_node(state: ResearchState) -> dict:
    """Perform one piece of research."""
    idx = state.get("next_query_idx", 0)
    if idx >= len(state["queries"]):
        return {}
    query = state["queries"][idx]
    result = await search_tool.ainvoke({"query": query})
    return {f"results_{idx}": result.content, "next_query_idx": idx + 1}

async def consolidate(state: ResearchState) -> dict:
    """Merge parallel research results into a final report."""
    all_results = {k: v for k, v in state["results"].items() if v}
    prompt = "\n".join(all_results.values())
    report = await llm.ainvoke([HumanMessage(content=f"Synthesize: {prompt}")])
    return {"final_report": report.content}

graph = StateGraph(ResearchState)
graph.add_node("research", research_node)
graph.add_node("consolidate", consolidate)
graph.add_edge(START, "research")
graph.add_edge("research", "consolidate")
graph.add_edge("consolidate", END)
compiled = graph.compile()

# Run with multiple parallel queries
result = compiled.invoke({"queries": ["AI trends 2025", "LLM benchmarks", "Agent frameworks"]})
```

### Pattern 2: State Machine with Loop Detection

Implement explicit state transitions with loop detection to prevent infinite recursion when conditional edges create cycles.

```python
from langgraph.graph import StateGraph, START, END
from typing import TypedDict

class ApprovalState(TypedDict):
    proposal: str
    reviewer_feedback: list[str]
    revision_count: int
    approved: bool

MAX_REVISIONS = 3

async def review_node(state: ApprovalState) -> dict:
    """Simulate reviewer providing feedback."""
    if state["revision_count"] < MAX_REVISIONS:
        return {"reviewer_feedback": [f"Feedback on revision {state['revision_count']}"]}
    return {"approved": True}

async def revise_node(state: ApprovalState) -> dict:
    """Revise proposal based on feedback or accept rejection."""
    if state["revision_count"] >= MAX_REVISIONS:
        return {"approved": False}
    
    revised = f"{state['proposal']}\n\nAddressed: {state['reviewer_feedback'][-1]}"
    return {"proposal": revised, "revision_count": state["revision_count"] + 1}

graph = StateGraph(ApprovalState)
graph.add_node("review", review_node)
graph.add_node("revise", revise_node)
graph.add_edge(START, "review")
graph.add_conditional_edges(
    "review",
    lambda s: "revise" if not s["approved"] else "__end__",
    {"revise": "revise", "__end__": END},
)
# revise -> review creates a loop bounded by MAX_REVISIONS check in revise_node

compiled = graph.compile()
```

### Pattern 3: Subgraph Decomposition for Complex Workflows

Break large graphs into reusable subgraphs to keep individual graph definitions manageable and enable composition.

```python
from langgraph.graph import StateGraph, START, END

# Subgraph: Document Processing Pipeline
class DocProcessState(TypedDict):
    raw_text: str
    cleaned: str | None
    extracted_entities: list[str] | None

async def clean_text(state: DocProcessState) -> dict:
    """Remove noise and normalize text."""
    return {"cleaned": state["raw_text"].strip().replace("\r\n", "\n")}

async def extract_entities(state: DocProcessState) -> dict:
    """Extract named entities from cleaned text."""
    entities = await nlp_tool.ainvoke({"text": state["cleaned"]})
    return {"extracted_entities": entities}

doc_subgraph = StateGraph(DocProcessState)
doc_subgraph.add_node("clean", clean_text)
doc_subgraph.add_node("extract", extract_entities)
doc_subgraph.add_edge(START, "clean")
doc_subgraph.add_edge("clean", "extract")
doc_subgraph.add_edge("extract", END)
compiled_doc_subgraph = doc_subgraph.compile()

# Main Graph using the subgraph as a node
class MainState(TypedDict):
    documents: list[str]
    processed_results: list[dict] | None
    summary: str | None

async def process_documents(state: MainState) -> dict:
    """Run document processing subgraph for each document."""
    results = []
    for doc in state["documents"]:
        result = await compiled_doc_subgraph.ainvoke({"raw_text": doc})
        results.append(result)
    return {"processed_results": results}

main_graph = StateGraph(MainState)
main_graph.add_node("process", process_documents)
main_graph.add_edge(START, "process")
main_graph.add_edge("process", END)
main_app = main_graph.compile()
```

## Constraints

### MUST DO
- Always define state schema with explicit merge operators (`Annotated` with `add_messages`, `operator.add`, etc.) for fields written by multiple nodes
- Use `START` and `END` sentinel nodes — every graph must have an entry edge from `START` and exit edges to `END`
- Implement checkpointing in production workflows using database-backed checkpointer (PostgreSQL, SQLite)
- Add explicit loop termination conditions when conditional edges create cycles in the graph
- Log graph execution with `thread_id` for replay — always pass config with `"configurable": {"thread_id": "..."}`
- Name edge labels consistently and document the routing logic in docstrings for conditional edges

### MUST NOT DO
- Do NOT put LLM calls or tool invocations directly as node functions without wrapping them in proper error handling and timeout guards
- Do NOT mutate the state dict directly inside nodes — always return a new partial state dict from `invoke()` or `ainvoke()`
- Do NOT skip checkpointing in workflows that run for more than 30 seconds or involve human-in-the-loop steps
- Do NOT create cycles without explicit termination conditions — unbounded loops cause infinite execution and resource exhaustion
- Do NOT share mutable objects across threads — each graph invocation gets its own state instance, but shared checkpointer storage must be thread-safe

## Related Skills

| Skill | Purpose |
|---|---|
| `crewai-agent-workflows` | Role-based multi-agent collaboration with task delegation and autonomous tool use |
| `autogen-conversational-patterns` | Conversational multi-agent chat groups for iterative problem solving |
| `framework-utilization` | General framework adoption strategy and learning patterns applicable to any framework |

## Live References

> Authoritative documentation links for this domain. The model follows markdown links at load time to resolve external references and inline content.

- [LangGraph Official Documentation](https://langchain-ai.github.io/langgraph/) — Comprehensive LangGraph docs covering state graphs, checkpointing, streaming, and human-in-the-loop patterns
- [LangGraph Studio (Development IDE)](https://langchain-ai.github.io/langgraph/studio/) — LangGraph's development environment for building, testing, and debugging agent workflows
- [State Graph Pattern (LangGraph Concept)](https://langchain-ai.github.io/langgraph/concepts/high_level/) — Official explanation of the StateGraph abstraction for building stateful multi-agent applications
- [Checkpointing and Persistence in LangGraph](https://langchain-ai.github.io/langgraph/concepts/persistence/) — LangGraph docs on saving, restoring, and managing agent conversation state
- [LangChain Ecosystem Integration](https://python.langchain.com/docs/integrations/) — LangChain's integration catalog showing how LangGraph connects with tools, memory, and LLM providers

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…