Skip to Content

LangChain Basics (Chains, Runnables, LCEL)

When to use

Wire an LLM into a multi-step pipeline: prompt, model call, parse, branch, retry. The first framework most teams try.

Analogy

A factory assembly line. Each station takes inputs, transforms them, hands off to the next. LangChain Expression Language (LCEL) is the pipe syntax that glues the stations together.

Data-flow diagram

   prompt template  ->  llm  ->  output parser
        |                |        |
        v                v        v
   chain.invoke({'topic':'cats'}) -> 'Cats are great'

   LCEL: prompt | llm | parser  (pipe composes runnables)

Deep explanation

LangChain is the most common Python framework for LLM apps. The modern style is LCEL (LangChain Expression Language): you compose Runnables via the pipe operator into a chain. Every Runnable has the same interface (invoke, batch, stream); you can swap models, swap parsers, swap prompts without touching downstream code. Use LangChain when you want a stable composition API; use raw OpenAI/Anthropic SDKs for simple single-call apps.

Examples

Example 1

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
 
prompt = ChatPromptTemplate.from_template('Tell me a joke about {topic}')
llm    = ChatOpenAI(model='gpt-4o-mini')
chain  = prompt | llm | StrOutputParser()
print(chain.invoke({'topic':'cats'}))

Prompt | llm | parser composes three Runnables into a single chain — standard pattern across LangChain.

Example 2

# batch + stream work too on any Runnable
results = chain.batch([{'topic':'dogs'}, {'topic':'octopuses'}])
for token in chain.stream({'topic':'astronauts'}):
    print(token, end='', flush=True)

.batch parallelises inputs; .stream yields tokens as they arrive — same chain, no rewrites.

Example 3

# add fallback model on OpenAI outage
from langchain_anthropic import ChatAnthropic
robust = (prompt
          | llm.with_fallbacks([ChatAnthropic(model='claude-haiku-4-5'),])
          | StrOutputParser())
print(robust.invoke({'topic':'cats'}))

.with_fallbacks adds resilience without changing downstream logic — crucial for production.

Common mistake

Manually concatenating strings instead of using prompt templates. Result is a tangled mess of single quotes and missing variables. Always use a template.

Key takeaway

LCEL is the modern path: prompt | llm | parser, composition with pipe, .invoke / .batch / .stream as one interface. Use with_fallbacks for resilience.

Production Failure Playbook

Failure scenario 1: f-string-into-prompt-template

Failure scenario 2: no-fallbacks-on-outage