Principle:Langchain ai Langgraph Runnable Wrapping
| Knowledge Sources | |
|---|---|
| Domains | Internal, Runtime, Tracing |
| Last Updated | 2026-02-11 15:00 GMT |
Overview
Runnable Wrapping is the principle of transforming plain Python functions and callable sequences into LangChain-compatible `Runnable` objects with automatic tracing, context propagation, and runtime dependency injection.
Description
LangGraph graph nodes, tools, and tasks are defined as ordinary Python functions, but the execution runtime requires them to conform to LangChain's `Runnable` protocol for invocation, tracing, streaming, and configuration management. Runnable Wrapping bridges this gap through two core classes: `RunnableCallable` and `RunnableSeq`.
`RunnableCallable` wraps a sync or async function as a `Runnable` that automatically handles: invocation with tracing callbacks (creating chain start/end/error events for LangSmith observability), context propagation via `set_config_context`, and runtime dependency injection. The injection system inspects the function's signature at construction time, matching parameter names and type annotations against a registry of injectable keywords (`config`, `writer`, `store`, `previous`, `runtime`). At call time, the appropriate values are extracted from the runtime configuration and passed as keyword arguments. If the wrapped function returns another `Runnable`, it is automatically invoked (recursion).
`RunnableSeq` chains multiple `Runnable` steps into a sequence where the output of each step becomes the input of the next. It handles tracing for the entire sequence as a single chain run, with each step tracked as a child run. The first step receives full context propagation while subsequent steps run without context overhead.
The utility function `coerce_to_runnable()` normalizes diverse callable-like inputs (functions, async functions, generators, dicts) into proper `Runnable` instances, serving as the entry point for the graph compiler when processing user-defined node functions.
Usage
Use Runnable Wrapping when:
- Defining graph nodes -- user functions are automatically wrapped during graph compilation.
- Implementing dependency injection -- declare `config`, `store`, `writer`, or `previous` as keyword parameters and they are injected at runtime.
- Composing node pipelines -- use `RunnableSeq` to chain a node function with its associated stream writers.
- Normalizing inputs -- use `coerce_to_runnable()` to convert heterogeneous callable inputs into the `Runnable` interface.
Theoretical Basis
Runnable Wrapping is grounded in several software engineering principles:
1. Decorator pattern: `RunnableCallable` decorates a plain function with cross-cutting concerns (tracing, context propagation, dependency injection) without modifying the function's code. This separation of concerns allows node authors to write simple functions while the framework handles observability and runtime plumbing.
2. Signature-based dependency injection: Rather than requiring explicit registration or annotations, the injection system inspects the function's parameter names and type hints at construction time. This is a form of convention over configuration -- if a parameter is named `store` and typed as `BaseStore`, it receives the store instance automatically.
3. Context propagation: Each invocation sets up a scoped context (via `set_config_context`) that makes the current config and tracing state available to nested calls. This ensures that tracing spans form a correct parent-child hierarchy and that configurable values flow through the entire call tree.
4. Protocol compliance: By wrapping functions as `Runnable` objects, the system ensures they participate uniformly in LangChain's composition, serialization, streaming, and callback systems. This is an application of the Liskov Substitution Principle -- any `Runnable` can be used wherever another `Runnable` is expected.