LangChain Crash Course
Theme
Palette
Download
Caption (tap to copy)
📖 Deep dive (full written explanation)
This is the mechanics post, and the cover signals depth: we're looking at Runnables and LCEL, the actual architecture beneath the friendly pipe syntax. Posts 1 and 2 stayed at 'wire the components together.' Now we make that precise enough to read and write any chain.
The goal is that by the end the reader understands the Runnable contract, how the pipe operator composes runnables into a sequence, how the data's type changes at each step, and how RunnableParallel and RunnablePassthrough route data through more complex flows. This is the architecture most tutorials gloss over while teaching the syntax.
This slide states the one idea that makes all of LCEL click: every component is a Runnable, and a Runnable is anything with an invoke method that takes an input and returns an output. Prompts, models, parsers, and even plain Python functions all implement this same contract.
The reason this matters so much is uniformity. Because everything shares one method signature, anything can be composed with anything else. There's no special glue per component type. Once the reader sees that 'it's all just objects with invoke,' the framework stops feeling like a grab-bag of classes and starts feeling like a single, consistent system.
This slide explains the pipe operator precisely. The | takes two runnables and returns a new one — a RunnableSequence. Calling invoke on that sequence feeds your input through each step in order. So prompt | model | parser is itself a single Runnable whose invoke runs all three in turn.
The framing to hold onto is 'it's plain function composition with a clean syntax.' If you've ever chained functions where the output of one is the input of the next, you already understand LCEL. The pipe is just a readable way to express that composition, and the result is an object you can invoke, stream, or batch like any other runnable.
The pipeline diagram makes the type flow visible: an input dict like {topic: ...} enters, the prompt turns it into messages, the model turns those into an AIMessage, and the parser turns that into a string or dict. Each stage is labeled with what it produces.
Seeing the types on the arrows is the whole point. A chain isn't a vague flow of 'stuff' — it's a precise relay where each step expects a specific input type and produces a specific output type. This diagram primes the reader for the next slide, which argues that knowing these types is exactly how you debug a chain when a step receives something it didn't expect.
This slide drives home that each step reshapes the data, framing the chain as a relay of types. A prompt template takes a dict of variables and outputs a list of messages. The chat model takes those messages and outputs an AIMessage object. A parser takes that message and outputs a plain string or a typed structure.
The practical payoff is debugging. When a chain breaks, it's almost always because one step received a type it didn't expect — a parser handed raw text instead of a message, or a prompt handed the wrong variable. Knowing the type at every hop turns 'the chain is broken' into 'step two output the wrong type,' which is a fixable problem.
This code slide shows a complete prompt-to-model-to-parser chain so the type flow becomes concrete. It builds a summarization prompt, a chat model, and a StrOutputParser, then composes all three with the pipe. Invoking it with a dict containing the text returns a clean string.
The StrOutputParser is the load-bearing detail here: without it, invoke returns an AIMessage object and you'd have to reach into .content yourself. The parser pulls the plain text out, so the chain's final output is a ready-to-use string. This is the canonical minimal chain, and it's the foundation the parallel and passthrough slides build more complex flows on top of.
This slide introduces RunnableParallel, the tool for fanning one input out to several branches. It runs multiple runnables on the same input and collects their outputs into a dict keyed by the names you give. So you can feed one piece of text into both a summary chain and a keyword-extraction chain at once.
The value is both expressiveness and performance. Expressiveness, because many real tasks naturally branch — you want several things computed from the same input. Performance, because the branches can run concurrently rather than one after another. This is the first step beyond a strictly linear chain, and it's essential for the RAG pattern shown shortly.
This code slide shows RunnableParallel in action. It wraps two existing chains — a summary chain and a keyword chain — under named keys, then invokes the whole thing with one input dict. The result is a dict with both outputs: {"summary": ..., "keywords": ...}, with both branches having run on the same article.
The shape of the output is the key takeaway: a RunnableParallel turns several runnables into one runnable that produces a dictionary. That dictionary is often exactly what the next step — frequently a prompt template with multiple variables — needs as its input, which is what makes parallel a natural building block in larger chains rather than a standalone trick.
This slide introduces RunnablePassthrough, the piece that lets a later step see the original input alongside computed values. It forwards its input unchanged, so you can carry the raw input forward while other branches transform it.
The canonical use is RAG, and the slide names it directly: you pass the user's question straight through while, in parallel, a retriever uses that same question to fetch context. The prompt then receives both the untouched question and the retrieved context. Without passthrough, you'd lose access to the original question after the retrieval step consumed it. It's a small utility that turns out to be indispensable for any chain where a value needs to skip past a transformation.
The flow diagram ties parallel and passthrough together into the RAG shape that post 4 will build. The input question enters, a parallel step both retrieves context and passes the question through, the prompt combines context and question, and the model produces a grounded answer.
This is the architectural punchline of the whole post: the linear chain plus RunnableParallel plus RunnablePassthrough compose into the single most important pattern in LangChain. Seeing the abstract pieces assemble into a recognizable, useful shape prepares the reader to read the real RAG code in the next post as a concrete instance of this diagram rather than as new magic.
The tips slide compresses the architecture into five rules. Every component is a Runnable with an invoke method. The pipe builds a RunnableSequence. Each step reshapes the data's type. RunnableParallel fans one input out to many branches. RunnablePassthrough carries data forward unchanged.
These five rules are enough to read essentially any LangChain chain you'll encounter. A reader who holds them can look at an unfamiliar chain — even a long, branching one — and decompose it into runnables, sequences, parallels, and passthroughs. That's the goal of a mechanics post: not to memorize one chain, but to gain the ability to parse all of them.
The CTA points from architecture to a real build. We've covered the Runnable contract, the pipe composition, the type flow between steps, and the parallel and passthrough runnables that enable branching.
Day 80's teaser promises a complete, runnable RAG chain. Post 4 assembles everything here — splitting documents, embedding them, building a retriever, and wiring it into an LCEL chain with passthrough — into about thirty lines of code you can paste, point at your own documents, and run today.