home
diamond Go Premium
Data Engineering Path  ·  Data & AI

Chains and LCEL (LangChain Expression Language)

In legacy software, composing functions looks like nested calls: result = parse(model(format(input)))

This becomes unreadable and makes adding asynchronous execution, streaming, and error handling a nightmare.

LangChain Expression Language (LCEL) is a declarative domain-specific language designed to compose LLM primitives into production chains using the Unix pipe operator (|).


1. The Pipe Operator (|) and the Runnable Protocol

Under LCEL, every component (prompts, models, retrievers, output parsers) implements the Runnable Protocol:

flowchart LR
    Input["Input Dictionary:<br/>{'question': 'Spark DPP'}"] --> Prompt["ChatPromptTemplate"]
    Prompt -->|Formatted Messages| Model["ChatModel (LLM)"]
    Model -->|AIMessage Object| Parser["StrOutputParser"]
    Parser --> Output["Final String Answer"]

    style Input fill:#475569,color:#fff
    style Prompt fill:#2563eb,color:#fff
    style Model fill:#7c3aed,color:#fff
    style Parser fill:#059669,color:#fff
    style Output fill:#d97706,color:#fff

In Python code, this is expressed as:

chain = prompt | model | StrOutputParser()
result = chain.invoke({"question": "Explain dynamic partition pruning in Spark"})

The 4 Universal Runnable Methods

Every Runnable component automatically gains four execution methods out of the box:

Method Execution Mode Use Case
invoke(input) Synchronous Single user requests, CLI tools
ainvoke(input) Asynchronous (async/await) High-concurrency FastAPI web servers
batch(inputs) Parallel Batching Processing 10,000 warehouse records in parallel
stream(input) Generator / Streaming Emitting tokens live to chat interfaces via WebSockets/SSE

2. Advanced LCEL Primitives

Data pipelines require parallel branches, branching logic, and custom data transformations. LCEL provides specialized Runnable utilities:

flowchart TD
    Input["User Query:<br/>'Compare Snowflake vs Databricks'"]

    Input --> Fork["RunnableParallel"]
    Fork --> Branch1["Branch 1: Fetch Snowflake Docs (Retriever)"]
    Fork --> Branch2["Branch 2: Fetch Databricks Docs (Retriever)"]

    Branch1 --> Merge["Join Results into Context Dict"]
    Branch2 --> Merge

    Merge --> Prompt["Synthesis Prompt"]
    Prompt --> Model["LLM"]
    Model --> Output["Comparative Analysis"]

    style Input fill:#334155,color:#fff
    style Fork fill:#2563eb,color:#fff
    style Branch1 fill:#059669,color:#fff
    style Branch2 fill:#7c3aed,color:#fff
    style Merge fill:#d97706,color:#fff
    style Output fill:#10b981,color:#fff

Key LCEL Primitives:

  1. RunnablePassthrough: Passes the input data through unchanged or dynamically assigns new keys to an input dictionary.
  2. RunnableParallel: Executes multiple branches concurrently on separate threads, then bundles their outputs into a single dictionary.
  3. RunnableLambda: Converts any regular Python function into an LCEL-compatible Runnable.

3. Hands-on: Building an LCEL Chain with Parallelism

from typing import Any, Callable

class SimpleRunnable:
    """Demonstrates how the LCEL pipe operator works under the hood."""
    def __init__(self, func: Callable[[Any], Any]):
        self.func = func

    def __or__(self, other):
        """Overload the Unix pipe operator |"""
        if isinstance(other, SimpleRunnable):
            return SimpleRunnable(lambda x: other.invoke(self.invoke(x)))
        return NotImplemented

    def invoke(self, input_data: Any) -> Any:
        return self.func(input_data)

# Building a 3-stage SQL Optimization pipeline
extract_tables = SimpleRunnable(
    lambda query: {"query": query, "tables": ["orders", "customers"]}
)

annotate_partitions = SimpleRunnable(
    lambda data: {
        **data,
        "partition_advice": "Ensure 'orders' is filtered by 'order_date' cluster key."
    }
)

format_summary = SimpleRunnable(
    lambda data: (
        f"Query Analysis for Tables {data['tables']}:
"
        f"Recommendation: {data['partition_advice']}"
    )
)

if __name__ == "__main__":
    # LCEL Composition using |
    sql_review_chain = extract_tables | annotate_partitions | format_summary

    test_query = "SELECT * FROM orders JOIN customers ON orders.c_id = customers.id"
    report = sql_review_chain.invoke(test_query)

    print("=== LCEL Chain Output ===")
    print(report)

Key Takeaways

  • LCEL replaces messy nested code with clean declarative pipelines using the pipe operator (|).
  • All Runnables support streaming, async, and batch automatically without writing custom boilerplate.
  • RunnableParallel enables concurrent retrieval across disparate data sources.
Find this content helpful? ☕ Buy me a coffee

Entity Details

Create New Item

help

Submit Technical Query

Have a question or run into an issue? Describe it below, upload an optional screenshot, and our engineering team will answer it!

image Attach image (optional)

Submit Feedback

build Free Developer Utility Free Tool
gavel

Privacy & Legal Disclaimer

1. Client-Side Browser Processing

All utility tools on DeepEngineerHub (including Image to PDF, Text Formatters, JSON Converters, and Encryptors) execute 100% locally within your client browser using WebAssembly and JavaScript. No uploaded images, text, or documents are transmitted, collected, or stored on remote servers.

2. Limitation of Liability ("As-Is" Provision)

Tools and services are provided free of charge for convenience and educational purposes "as-is" without warranties of any kind. DeepEngineerHub shall not be held liable for any data loss, formatting inconsistencies, or indirect damages resulting from tool usage.

3. Open Source & Third-Party Software

Certain utilities utilize open-source client libraries (such as jsPDF, Mermaid.js, Pyodide) licensed under MIT, Apache, or BSD open licenses. All intellectual property remains with their respective copyright holders.