Module 7: Advanced Flows

Introduction: Real-World Complex Workflows

Overview

Your Research Agent v1 works. It takes a topic, breaks it into sub-queries, searches in parallel, synthesizes a report. On the happy path, it's flawless. But the happy path doesn't exist in production.

Run your agent against a real search API for a full day. Here's what you're going to find:

  • At 2:47 PM, the API returns 429 Too Many Requests. Your agent crashes.
  • At 3:12 PM, one source takes 15 seconds to respond. Your agent sits there waiting.
  • At 4:05 PM, an external service is down. Your agent returns an error with no partial results — even though the other two sources responded perfectly.

None of this is a bug in your code. It's the reality of systems that depend on external APIs, unstable networks, and third-party services. The agent you built in Module 6 does everything you asked of it. What it doesn't do is survive the real world.

This module closes that gap. You're going to add the patterns that turn a working prototype into a system a team can put in production without fear.


Where are we in the guide?

This is Module 7 of the guide LangChain & LangGraph: From Chains to Agents. It's the last module of Block 2 (LangGraph Fundamentals).

Block 1: LangChain Core (Modules 1-4)            ✅ Completed
Block 2: LangGraph Fundamentals (Modules 5-7)    ← YOU ARE HERE (Module 7)
Block 3: Advanced LangGraph (Modules 8-10)
Block 4: Production (Modules 11-12)
Your progress:

Block 1 — LangChain Core                    ✅ Completed
    │
    │  Module 1: Models and Providers        ✅
    │  Module 2: Tools and Tool Calling      ✅
    │  Module 3: Agents (create_agent)       ✅
    │  Module 4: Middleware and Customization ✅
    │
    ▼
Block 2 — LangGraph Fundamentals
    │
    │  Module 5: Introduction to LangGraph   ✅ Completed
    │  Module 6: Functional API              ✅ Completed
    │  Module 7: Advanced Flows              ← YOU ARE HERE
    │
    ▼
Blocks 3-4 — Advanced + Production          🔒

In Module 5 you mastered the Graph API: StateGraph, nodes, edges, conditional edges, typed state. In Module 6 you learned the Functional API: @entrypoint, @task, native control flow, and you built the Research Agent v1. Now you add the patterns that make that agent fault-tolerant, fast, and modular.


The bridge: from "it works" to "it works in the real world"

What you already know how to do

After Modules 5 and 6, you can:

  • ✅ Build graphs with StateGraph, typed nodes, conditional edges
  • ✅ Create workflows with @entrypoint and @task
  • ✅ Use Python control flow (if/else, for, try/except) inside entrypoints
  • ✅ Run tasks in parallel with Futures
  • ✅ Combine the Graph API and the Functional API in the same project
  • ✅ Build an end-to-end agent (Research Agent v1)

What's missing

You know how to build graphs and functional workflows. But production isn't clean — APIs fail, searches take too long, logic gets complicated, and errors propagate in ways you didn't anticipate. What's missing isn't LangGraph knowledge. It's systems engineering knowledge applied to LangGraph.


The real problems that motivate this module

Every pattern you'll learn here is born from a concrete problem. These aren't "nice-to-have features" — they're solutions to problems you'll hit the first week your agent is in production.

Problem 1: Your search API returns 429 Too Many Requests

You're making 50 searches per minute. The API has a rate limit of 30 per minute. Starting at search 31, you get 429 Too Many Requests. Without retry, your agent crashes and the user sees an error. With immediate retry, you fire 20 more requests in a second — you make the problem worse. What you need is retry with exponential backoff: wait 1 second, then 2, then 4, with random jitter so you don't sync up with other clients.

Solution: Cycles and retry patterns (Capsule 02)

Problem 2: Searching 3 sources sequentially takes 9 seconds

Your agent searches the web, academic papers, and news. Each source takes ~3 seconds. Sequentially: 3 + 3 + 3 = 9 seconds. Your user waits 9 seconds staring at an empty screen. But the three searches are independent — there's no reason to wait for one to finish before launching the next.

Solution: Branching and merge (Capsule 03) — you run all 3 in parallel: ~3 seconds total

Problem 3: The "search + summarize" pattern repeats for every source

For every source you do the same thing: call the API, parse the response, extract the key points, generate a partial summary. You repeat that 4-step sequence 3 times (once per source). If you copy and paste it, you end up with 12 nodes of duplicated logic. If the papers source needs a different parser, you have to find and modify the right nodes among those 12.

Solution: Subgraphs (Capsule 04) — you encapsulate "search + summarize" into a reusable subgraph

Problem 4: One source is completely down

The academic papers API has been returning 503 Service Unavailable for 3 hours. Your retries run out. Without a fallback, your agent returns a full error — even though the web and news sources responded perfectly with useful results. The user gets nothing when they could have gotten a partial report with 2 of 3 sources.

Solution: Error handling and graceful degradation (Capsules 05-06) — your agent returns partial results with a note explaining which source wasn't available


The patterns this module covers

PatternProblem it solvesImpact
Cycles and retryAPIs that fail intermittentlyThe agent recovers automatically from transient errors
Branching and mergeSlow sequential searches3x faster execution with parallelism
SubgraphsDuplicated logic across sourcesModular composition, one change affects every use
Map-reduceProcessing collections in parallelScales to N sources without changing the topology
Error handlingFailures that crash the whole systemGraceful degradation with partial results
Production patternsTimeouts, rate limits, loggingAn observable, controllable system

Module map

CapsuleTopicWhat you'll learn
01IntroductionContext, motivation, roadmap, connection to the project (this capsule)
02Cycles and loops: retry patternsCycles in graphs, retry with exponential backoff + jitter, recursion_limit, StateGraph vs Functional API
03Branching and merge: parallel executionFan-out/fan-in, Send API, parallel branches, merging results, deduplication
04Subgraphs: modular compositionGraphs as nodes, shared state, encapsulating logic, reuse
05Map-reduce: processing collectionsSend API for dynamic collections, parallel map, reduce with aggregation
06Error handling and fallback patternsTry/except in graphs, fallback nodes, graceful degradation, circuit breaker
07Production patternsPer-node timeouts, internal rate limiting, structured logging, health checks
08Project: Research Agent v2Integrating retry, parallel branching, and error handling into the Research Agent

Learning flow: You start with the most immediate pattern — retry when an API fails (02). Then you speed things up with parallel execution (03). With parallelism under your belt, you encapsulate repeated logic in subgraphs (04) and scale to collections with map-reduce (05). Error handling (06) weaves into every previous pattern, it's not an isolated topic. Production patterns (07) add the final observability layer. In capsule 08, everything converges in the Research Agent v2.


The project evolves: Research Agent v1 → v2

This module doesn't rewrite the Research Agent. It improves it. Every change is a layer on top of the code you already wrote in Module 6.

Before (Module 6 — v1)

@entrypoint()
def research_agent(inputs: dict) -> dict:
    query = inputs["query"]

    # Break it down into sub-queries
    sub_queries = decompose_query(query).result()

    # Search sequentially — one source at a time
    all_results = []
    for sq in sub_queries:
        result = search_source(sq).result()  # Blocks until it completes
        all_results.append(result)

    # Synthesize the report
    report = synthesize_report(all_results).result()
    return report

Problems:

  • ❌ Sequential search — if each source takes 3s, 3 sources = 9s
  • ❌ No retry — if an API returns 429, the agent crashes
  • ❌ No fallback — if one source is down, everything fails
  • ❌ No timeouts — one slow source blocks the whole pipeline
  • ❌ No logging — you don't know where it failed or how long each step took

After (Module 7 — v2)

@entrypoint()
def research_agent(inputs: dict) -> dict:
    query = inputs["query"]

    # Break it down into sub-queries
    sub_queries = decompose_query(query).result()

    # Search in parallel — every source simultaneously
    search_futures = [search_with_retry(sq) for sq in sub_queries]
    results = []
    for future in search_futures:
        try:
            results.append(future.result())
        except SourceUnavailableError:
            results.append(partial_result(future.source, reason="unavailable"))

    # Synthesize with partial results if needed
    report = synthesize_report(results).result()
    return report

Improvements:

  • ✅ Parallel search — 3 sources in ~3s (3x faster)
  • ✅ Retry with backoff — automatic retries on transient errors
  • ✅ Graceful degradation — if one source fails, it returns partial results
  • ✅ Per-source timeouts — no slow source blocks the entire pipeline
  • ✅ Structured logging — every step records duration, errors, and results

The Module 6 code is still there. What changes is how you run the search (parallel instead of sequential), how you handle errors (retry + fallback instead of crash), and how you observe the system (logging instead of silence).


Connection to Block 3: what comes next

Module 7 closes Block 2 (LangGraph Fundamentals). After this module, your Research Agent is robust and fast. What it still doesn't have:

Block 3ModuleWhat it adds to the Research Agent
Advanced LangGraphM8: Memory and PersistenceIf the agent crashes mid-investigation, it resumes where it left off. It remembers previous investigations across sessions.
Advanced LangGraphM9: Human-in-the-LoopBefore running expensive searches, it asks for human approval. The user can modify sub-queries before they run.
Advanced LangGraphM10: Multi-Agent SystemsInstead of a single agent doing everything, a team: Researcher searches, Analyst analyzes, Writer drafts, Supervisor coordinates.
Module 7 (you are here):
    Research Agent v2 — robust, parallel, with error handling
        │
        ▼
Module 8: + Persistence
    The agent saves state. It can resume if it crashes.
        │
        ▼
Module 9: + Human approval
    The agent asks permission before expensive actions.
        │
        ▼
Module 10: + Multi-agent
    A team of specialized agents with a supervisor.

For M8's persistence to work, your agent needs to handle errors correctly (if it crashes with corrupt state, resuming is useless). For M9's human-in-the-loop to work, your agent needs to be designed with pauses and continuations (which subgraphs make easier). For M10's multi-agent to work, your agent needs to be modular (which subgraphs enable).

This module isn't just "adding robustness." It's building the technical foundation that makes the next three modules possible.


Technical setup

Prerequisites

Before continuing, check that you have:

  • Modules 5 and 6 completed — you know how to build graphs with StateGraph and workflows with the Functional API
  • A working Research Agent v1 — the Module 6 project runs end-to-end
  • Python 3.11+ installed
  • ✅ At least one API key from a provider (OpenAI recommended)

Installation

If you completed Modules 5-6, you already have everything installed. Verify:

pip install langgraph langchain-openai python-dotenv

There are no new packages in this module. The advanced patterns (retry, branching, subgraphs, map-reduce) are part of langgraph core.

New packages from the standard library

This module uses two packages from Python's standard library that you didn't use in previous modules:

PackageWhat you use it for in this module
timetime.sleep() to implement backoff between retries
randomrandom.uniform() to add jitter to the backoff

You don't need to install anything — they're part of Python. But you'll be using them constantly in the retry and branching capsules.

Verify everything works

import time
import random
from typing import TypedDict, Annotated
import operator
from langgraph.graph import StateGraph, START, END
from langgraph.func import entrypoint, task

print(f"time: {time.__name__}")
print(f"random: {random.__name__}")
print(f"StateGraph: {StateGraph.__name__}")
print(f"entrypoint: {entrypoint.__name__}")
print(f"task: {task.__name__}")
print("Setup complete for Module 7")
# Expected output:
# time: time
# random: random
# StateGraph: StateGraph
# entrypoint: entrypoint
# task: task
# Setup complete for Module 7

Both APIs in play

In this module you'll use both the Graph API and the Functional API. Some patterns (cycles, branching with the Send API) express themselves naturally in StateGraph. Others (retry with a while loop) are better expressed with the Functional API. Part of the learning is developing judgment about when to use each one.

PatternRecommended APIWhy
Cycles/retryBothStateGraph if the retry is visible; Functional if it's internal
Branching (Send API)StateGraphThe Send API is a Graph API feature
SubgraphsStateGraphGraph composition is a Graph API concept
Map-reduceStateGraphSend API for dynamic fan-out
Error handlingBothNative try/except in Functional; fallback nodes in StateGraph
Timeouts, loggingBothThey're code patterns, not topology patterns

What this module does NOT cover

  • Advanced persistence and checkpointing — Covered in Module 8. Here you'll mention checkpoints as context, but you won't implement them in depth.
  • Human-in-the-loop (interrupts, approvals) — Covered in Module 9. Here you design the agent to be "pausable," but you don't implement the interrupts.
  • Multi-agent systems — Covered in Module 10. Here you build modular subgraphs that later become independent agents.
  • LangSmith and full observability — Covered in Module 12. Here you add basic structured logging, but the full instrumentation comes later.
  • Deployment — This module's production patterns are at the code level (timeouts, rate limiting, logging). Deployment to infrastructure is Module 12's topic.

Evidence of success

By the end of this module, you'll know you succeeded if:

  • ✅ You can implement a retry cycle with exponential backoff and jitter — and explain why retry without backoff is an anti-pattern
  • ✅ Your agent searches 3 sources in parallel and takes ~3s instead of ~9s
  • ✅ If one source is down, your agent returns partial results with the sources that did respond
  • ✅ You can encapsulate repeated logic in subgraphs and reuse it
  • ✅ Your Research Agent v2 doesn't crash on transient errors — it retries, degrades gracefully, and logs what happened
  • ✅ You know when to use StateGraph vs the Functional API for each pattern

This module's mindset: systems engineering

Modules 5 and 6 taught tools: StateGraph, Functional API, nodes, edges, tasks, entrypoints. This module teaches systems thinking.

The difference:

  • Tools: "How do I do a retry in LangGraph?"
  • Systems thinking: "My agent depends on 3 external APIs. What's my failure budget? What happens if two of three fail? How long can the user wait? What do I show them while they wait?"

Every pattern in this module answers an engineering question, not an API question. Retry isn't "a LangGraph feature" — it's a distributed-systems principle you implement using LangGraph. Parallel branching isn't "an elegant optimization" — it's the difference between 3 seconds and 9 seconds of latency that your users will notice.

Think like a systems engineer. The tools are the means, not the end.

The questions you're going to learn to answer

Before this module, your design process was: "What nodes do I need? How do I connect them?" After this module, your process will also include:

Engineering questionPattern that answers it
"What happens if API X doesn't respond?"Retry with backoff → fallback
"What's the maximum the user can wait?"Timeout budget per operation
"Can I do these operations simultaneously?"Parallel branching (fan-out/fan-in)
"Does this logic repeat in several places?"Reusable subgraph
"What do I show the user if I fail partially?"Graceful degradation
"How do I know my agent is healthy in production?"Structured logging + health checks

These questions aren't specific to LangGraph. They're questions every systems engineer asks when designing a service. What changes is how you answer them — using graphs, nodes, and conditional edges instead of HTTP middleware or infrastructure-level circuit breakers.

The most common mistake: optimizing the happy path

Your Research Agent v1 has a perfect happy path: it decomposes, searches, synthesizes. The report comes out flawless. And the natural instinct is to polish that happy path — better prompts, better formatting, more sources.

Resist that instinct. A system that works perfectly 95% of the time but blows up in the remaining 5% isn't ready for production. That 5% is where users lose trust. It's where your system earns a reputation for being "unstable."

This module focuses on the 5%. On making your agent predictable, not just in the best case, but in the worst one too. The happy path already works. Now make the unhappy path acceptable.


Summary

  • You're in Module 7 of 12, closing Block 2 (LangGraph Fundamentals). After Modules 5-6, you know how to build graphs and functional workflows. This module adds the production patterns
  • Four real problems motivate this module: APIs returning 429 (→ retry), slow sequential searches (→ parallel branching), duplicated logic across sources (→ subgraphs), downed sources that crash everything (→ graceful degradation)
  • The Research Agent evolves from v1 (sequential, no error handling, crashes on failures) to v2 (parallel, automatic retry, graceful degradation). The M6 code is still there — this module adds layers on top
  • Six patterns: cycles/retry, branching/merge, subgraphs, map-reduce, error handling, production patterns. Each one is born from a concrete problem
  • Connection to Block 3: this module's patterns are technical prerequisites for memory (M8), human-in-the-loop (M9), and multi-agent (M10)
  • Both APIs in play: some patterns are better expressed in StateGraph (branching, subgraphs) and others in the Functional API (retry). Part of the learning is developing judgment about when to use each one
  • The mindset: think like a systems engineer, not like an API user. The patterns are engineering principles implemented with LangGraph

Additional resources

  1. LangGraph — Concepts: Cycles — Official documentation on cycles and recursion_limit in LangGraph
  2. LangGraph — How to create branches for parallel node execution — Official guide to fan-out/fan-in with the Send API
  3. LangGraph — How to add and use subgraphs — Official guide to composing graphs inside graphs
  4. LangGraph — How to create map-reduce branches — Official guide to map-reduce with the Send API
  5. Exponential Backoff and Jitter (AWS Architecture Blog) — The reference article on backoff with jitter. Required reading
  6. Release It! — Michael Nygard — The book that popularized circuit breakers and stability patterns. Advanced context

Module 7 — LangChain & LangGraph: From Chains to Agents

Next capsule: Cycles and Loops: Retry Patterns — your search API fails 10% of the time. You'll implement retry with exponential backoff + jitter in StateGraph and the Functional API, and you'll understand why retry without backoff is an anti-pattern that amplifies problems instead of solving them.

Previous capsule: Evolving Project: Research Agent Base (v1) — the working end-to-end agent that you're now going to make robust and fast.