langchain-ai/langchain
Runnables and LCEL
Runnable is the universal invocation protocol — almost everything in LangChain implements it. LCEL (LangChain Expression Language) is the syntax for composing runnables with |, RunnableParallel, RunnableBranch, and friends.
Source root: libs/core/langchain_core/runnables/.
Purpose
Before LCEL, LangChain had Chain.run, Chain.__call__, LLM.predict, LLM.generate, Tool.run, and dozens of other call methods. Different objects did the same thing under different names. Runnable collapses everything into one contract:
class Runnable(Generic[Input, Output]):
def invoke(self, input: Input, config: RunnableConfig | None = None) -> Output: ...
async def ainvoke(self, input: Input, config: RunnableConfig | None = None) -> Output: ...
def batch(self, inputs: list[Input], config: ... = None) -> list[Output]: ...
async def abatch(self, inputs: list[Input], config: ... = None) -> list[Output]: ...
def stream(self, input: Input, config: ... = None) -> Iterator[Output]: ...
async def astream(self, input: Input, config: ... = None) -> AsyncIterator[Output]: ...
def astream_events(self, input: Input, ...) -> AsyncIterator[StreamEvent]: ...Every implementer gets the full set "for free" — base implementations of batch/abatch use invoke/ainvoke with a thread pool, astream falls back to a single-chunk stream of invoke's result, and so on. Implementers override the methods they can do better.
Directory layout
libs/core/langchain_core/runnables/
├── __init__.py # Public re-exports
├── base.py # The Runnable class hierarchy (~5,800 lines)
├── branch.py # RunnableBranch (if-then-else routing)
├── config.py # RunnableConfig, ensure_config, patch_config
├── configurable.py # ConfigurableField, ConfigurableFieldSpec
├── fallbacks.py # RunnableWithFallbacks
├── graph.py # The graph rendering API (.get_graph())
├── graph_ascii.py # ASCII graph rendering
├── graph_mermaid.py # Mermaid graph rendering
├── graph_png.py # PNG graph rendering via mermaid.ink
├── history.py # RunnableWithMessageHistory
├── passthrough.py # RunnableAssign, RunnablePassthrough, RunnablePick
├── retry.py # RunnableRetry (legacy; prefer with_retry)
├── router.py # RouterRunnable
├── schema.py # StreamEvent
└── utils.py # AddableDict, gather helpersKey abstractions
| Symbol | File | Description |
|---|---|---|
Runnable |
libs/core/langchain_core/runnables/base.py |
The base class — every other concept on this page derives from it |
RunnableSerializable |
libs/core/langchain_core/runnables/base.py |
A Runnable that can be saved/loaded via langchain_core.load.serializable |
RunnableSequence |
libs/core/langchain_core/runnables/base.py |
What the | operator builds: a chain of runnables |
RunnableParallel (RunnableMap) |
libs/core/langchain_core/runnables/base.py |
Run multiple runnables on the same input, return a dict of outputs |
RunnableLambda |
libs/core/langchain_core/runnables/base.py |
Wrap a plain function as a Runnable |
RunnableGenerator |
libs/core/langchain_core/runnables/base.py |
Wrap a generator function for streaming |
RunnableBinding |
libs/core/langchain_core/runnables/base.py |
Apply a config / kwargs override to a runnable |
RunnableBranch |
libs/core/langchain_core/runnables/branch.py |
If-elif-else routing |
RunnableWithFallbacks |
libs/core/langchain_core/runnables/fallbacks.py |
Try a runnable, fall back to another on failure |
RunnableWithMessageHistory |
libs/core/langchain_core/runnables/history.py |
Wrap a runnable to carry chat history per session |
RunnableAssign, RunnablePassthrough, RunnablePick |
libs/core/langchain_core/runnables/passthrough.py |
Add/keep/select keys in a dict input |
RouterRunnable |
libs/core/langchain_core/runnables/router.py |
Route to one of N runnables based on a key |
RunnableConfig |
libs/core/langchain_core/runnables/config.py |
The config TypedDict — callbacks, tags, metadata, run_name, configurable |
ConfigurableField |
libs/core/langchain_core/runnables/configurable.py |
Mark an attribute as runtime-configurable via .configurable_fields |
chain |
libs/core/langchain_core/runnables/base.py |
Decorator that turns a function into a RunnableLambda |
How LCEL works
The | operator is implemented via Runnable.__or__. prompt | model returns a RunnableSequence([prompt, model]). Adding | parser extends it to RunnableSequence([prompt, model, parser]). The sequence's invoke walks the steps in order; astream chains the per-step streams.
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
prompt = ChatPromptTemplate.from_messages([("user", "Translate to French: {text}")])
chain = prompt | model | StrOutputParser()
chain.invoke({"text": "Hello"}) # -> "Bonjour"
chain.batch([{"text": "Hi"}, {"text": "Bye"}]) # parallel
async for chunk in chain.astream({"text": "Hi"}):
print(chunk, end="")RunnableParallel is constructed implicitly when a dict is on either side of the pipe:
from langchain_core.runnables import RunnablePassthrough
retrieve_and_answer = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| model
| StrOutputParser()
)The dict literal coerces to RunnableParallel({"context": ..., "question": ...}), which runs both branches concurrently and feeds the merged output to prompt.
Configuration propagation
RunnableConfig flows through every nested call. It carries:
callbacks— a list ofBaseCallbackHandlerinstancestags,metadata— for filtering in LangSmithrun_name,run_id— display names and identifiersmax_concurrency— parallelism cap forbatch,abatch,RunnableParallelrecursion_limit— for nestedRunnableLambdacallsconfigurable— runtime overrides forConfigurableFieldattributes
ensure_config and patch_config (in libs/core/langchain_core/runnables/config.py) are the helpers used at every level to merge user-provided config with the defaults set on a runnable.
Streaming
There are two streaming APIs:
stream/astream— yield outputs as they arrive. The unit depends on the runnable: a chat model yieldsAIMessageChunkper token; a sequence yields whatever the last runnable yields.astream_events— yield typed events for every runnable in the tree (on_chain_start,on_llm_stream,on_tool_end, …). This is what powers UIs that need fine-grained progress (e.g. "the model is calling the search tool").
StreamEvent is defined in libs/core/langchain_core/runnables/schema.py. Versions: v1 and v2 (default in newer code).
Error handling and retries
Every Runnable has helper methods that wrap it:
.with_retry(retry_if_exception_type=..., stop_after_attempt=..., wait_exponential_jitter=True)returns a new runnable that retries on the given exceptions usingtenacity..with_fallbacks([alt1, alt2], exceptions_to_handle=...)returns aRunnableWithFallbacksthat falls through to alternates on failure..with_config(callbacks=..., tags=..., ...)returns aRunnableBindingwith the override applied..with_listeners(on_start=..., on_end=...)adds simple lifecycle listeners.
Graph rendering
Calling runnable.get_graph() returns a Graph object representing the runnable's structure. It can be rendered to ASCII (graph.draw_ascii()), Mermaid (graph.draw_mermaid(), optionally draw_mermaid_png()), or PNG via the mermaid.ink API. This is what generates the diagrams in LangChain docs.
Integration points
- Every primitive (chat models, LLMs, tools, prompts, output parsers, retrievers, vector stores) implements
Runnable. langchain(v1) wrapslanggraphgraphs with the Runnable interface so they can be composed.langchain-classicchains and agents implementRunnableso legacy code can pipe them.- LangSmith tracing plugs in via the
callbacksfield ofRunnableConfig.
Entry points for modification
- For a new operator, prefer composition. If you must add a new class, place it in
libs/core/langchain_core/runnables/and re-export from__init__.py. - For a new event in
astream_events, editlibs/core/langchain_core/runnables/schema.pyandlibs/core/langchain_core/tracers/event_stream.py(the tracer that emits them). - For a new graph renderer, look at the
graph_*.pyfiles for the existing pattern.
Related
- primitives/messages — what runnables emit and consume
- primitives/language-models — the most common Runnable
- primitives/callbacks-and-tracers — the observability flowing through every Runnable
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.