Retrieval-Augmented Generation with LangChain
This course's earlier ancestor, plain RAG, is common enough that LangChain provides ready-built pieces for every step: loading documents, splitting them, embedding, storing, and retrieving. This lesson wires those pieces into a chain instead of hand-writing each step.
Loading and splitting documents
RecursiveCharacterTextSplitter tries to split on paragraph breaks first, falling back to sentences, then words, so chunks stay as semantically coherent as possible instead of cutting mid-sentence at a fixed character count. chunk_overlap repeats a few characters between adjacent chunks so a fact split across a chunk boundary still appears whole in at least one chunk.
Embedding and storing in a vector store
This needs a real API key to compute embeddings, so it's read-only here. FAISS.from_texts embeds every chunk and stores the resulting vectors for similarity search, .as_retriever() wraps the vector store as a Runnable, so it fits directly into an LCEL chain, search_kwargs={'k': 3} returns the 3 most similar chunks for a given query.
Wiring retrieval into a chain
Read-only, needs a real model and vector store. The dictionary {'context': ..., 'question': ...} runs both branches in parallel on the same input: retriever | format_docs turns the raw question into retrieved, formatted context, while RunnablePassthrough() just forwards the original question unchanged, both results land in prompt's two placeholders.
WARNING
The prompt explicitly says "using only this context", this is what keeps the model grounded, without it, a model will happily answer from its own training data instead of your retrieved documents, defeating the entire purpose of RAG.