Intermediate14 min
LCEL: Advanced Runnables
RunnableParallel, RunnableBranch, RunnableLambda, and RunnableConfig form the production toolkit for LCEL pipelines. Know when each earns its place, how they fail, and how to compose them without regrets at 3am.
Quick Reference
- →RunnablePassthrough.assign() enriches a dict without losing existing keys
- →RunnableParallel runs branches concurrently via asyncio — I/O-bound only, no CPU speedup
- →RunnableBranch: use for 2–4 static branches; use LangGraph for state or 5+ branches
- →RunnableLambda wraps any Python callable into the Runnable interface
- →.configurable_fields() lets callers swap model params at runtime with no redeploy
- →.configurable_alternatives() lets callers swap entire model objects at runtime
- →.with_retry(stop_after_attempt=2) before .with_fallbacks([...]) — retry first, then fall back
- →When one RunnableParallel branch fails, the entire step fails — guard each branch individually
When to Use Advanced Runnables
Advanced runnables are for custom pipelines, not agent loops
In LangChain v1, agent logic belongs in langchain.agents.create_agent. Advanced runnables — RunnableParallel, RunnableBranch, configurable_fields — are best for RAG chains, data pipelines, and model composition where you control the structure. For tool-calling loops or multi-step reasoning, reach for create_agent or LangGraph first.
| Use case | Tool | Why not the others |
|---|---|---|
| Fetch from multiple sources before prompting | RunnableParallel | Cuts total latency when sources are I/O-bound (vector index, DB, API) |
| Route between 2–4 static content types | RunnableBranch | LangGraph is overkill; plain if/else loses streaming and Runnable interface |
| Transform data between chain steps | RunnableLambda | More explicit than a dict comprehension; gets .batch() and .astream() for free |
| Swap model or temperature at runtime | configurable_fields | Avoids code branching and redeploys for configuration changes |
| Swap entire provider at runtime | configurable_alternatives | One chain, multiple backends, zero if/else in caller code |
| Survive model downtime or rate limits | .with_fallbacks() | Native to the Runnable interface — no custom try/except needed |
| Handle transient 429 / 500 errors | .with_retry() | Adds exponential backoff in one call; always pair with with_fallbacks() |
| Complex routing with state or memory | LangGraph | RunnableBranch has no state — each call is independent |
| Tool calling / agent loop | create_agent | LCEL doesn't manage tool execution or message history |