Subgraph Patterns
Overview
Subgraphs enable modular, reusable graph components that can be embedded within larger parent graphs. This pattern supports encapsulation, testing, and composition of complex agent systems.
Architecture
Key Concepts
State Transformation
Subgraphs can have different state schemas than parent graphs. Transformation functions bridge the gap:
- state_in: Convert parent state to subgraph input
- state_out: Convert subgraph output to parent state updates
def state_in(parent_state: ParentState) -> SubgraphState:
"""Transform parent state to subgraph input."""
return {
"query": parent_state["user_question"],
"documents": [],
"answer": "",
}
def state_out(subgraph_state: SubgraphState, parent_state: ParentState) -> dict:
"""Transform subgraph output to parent updates."""
return {
"rag_answer": subgraph_state["answer"],
"sources": subgraph_state["documents"],
}Usage
Basic Subgraph Wrapping
from langgraph_ollama_local.patterns.subgraphs import create_subgraph_node
# Create wrapped node
rag_node = create_subgraph_node(
rag_graph,
state_in,
state_out,
)
# Add to parent graph
parent.add_node("rag", rag_node)Field Mappers
For simple field renaming:
from langgraph_ollama_local.patterns.subgraphs import (
field_mapper_in,
field_mapper_out,
)
state_in = field_mapper_in(
("user_question", "query"), # parent_field -> subgraph_field
("context", "documents"),
)
state_out = field_mapper_out(
("answer", "rag_response"), # subgraph_field -> parent_field
)Chaining Subgraphs
from langgraph_ollama_local.patterns.subgraphs import chain_subgraphs
chained = chain_subgraphs([
(retrieval_graph, retrieve_in, retrieve_out),
(grading_graph, grade_in, grade_out),
(generation_graph, generate_in, generate_out),
])
parent.add_node("rag_pipeline", chained)Conditional Subgraphs
from langgraph_ollama_local.patterns.subgraphs import conditional_subgraph
def needs_web_search(state):
return len(state.get("documents", [])) < 2
node = conditional_subgraph(
needs_web_search,
(web_search_graph, ws_in, ws_out),
(direct_answer_graph, da_in, da_out),
)Retry Pattern
from langgraph_ollama_local.patterns.subgraphs import retry_subgraph
def should_retry(output, state):
return output.get("quality_score", 0) < 0.7
node = retry_subgraph(
generation_graph,
gen_in, gen_out,
should_retry,
max_retries=3,
)Available Functions
| Function | Purpose |
|---|---|
create_subgraph_node | Wrap subgraph as parent node |
create_subgraph_node_async | Async version |
field_mapper_in | Create state_in from field mappings |
field_mapper_out | Create state_out from field mappings |
passthrough_state_in | Identity transform (same schema) |
passthrough_state_out | Identity transform (same schema) |
chain_subgraphs | Run subgraphs sequentially |
conditional_subgraph | Choose subgraph based on condition |
parallel_subgraphs | Run subgraphs and merge outputs |
retry_subgraph | Add retry logic to subgraph |
Best Practices
- Keep subgraphs focused: One responsibility per subgraph
- Test independently: Verify subgraphs work before composing
- Clear interfaces: Document state_in and state_out contracts
- Handle errors: Consider what happens if subgraph fails
Common Patterns
RAG as Subgraph
class RAGState(TypedDict):
query: str
documents: list
answer: str
# Build RAG subgraph
rag_graph = build_rag_graph(retriever, llm)
# Embed in agent
agent.add_node("rag", create_subgraph_node(
rag_graph,
lambda s: {"query": s["question"], "documents": [], "answer": ""},
lambda out, s: {"rag_answer": out["answer"]},
))Tool as Subgraph
Complex tools can be subgraphs with their own logic:
# Calculator subgraph with validation and computation
calc_graph = build_calculator_graph()
# Wrap as tool-like node
agent.add_node("calculator", create_subgraph_node(
calc_graph,
lambda s: {"expression": s["tool_input"]},
lambda out, s: {"tool_result": out["result"]},
))When to Use Subgraphs
| Use Subgraphs | Use Regular Nodes |
|---|---|
| Reusable across multiple graphs | Single-use logic |
| Different state schema needed | Same state schema |
| Complex multi-step logic | Simple operations |
| Need independent testing | Tightly coupled to parent |
| Swappable implementations | Fixed implementation |
Related Patterns
Quiz
Test your understanding of subgraph patterns:
Knowledge Check
What is the primary benefit of using subgraphs in LangGraph?
Knowledge Check
What are state_in and state_out functions used for in subgraphs?
Knowledge Check
When should you use regular nodes instead of subgraphs?
Knowledge Check
Which function would you use to create state transformation for simple field renaming between schemas?
Knowledge Check
What pattern would you use to run a subgraph multiple times until a quality threshold is met?