A Full RAG Chain
A production-shaped LangChain RAG pipeline: ingestion, vector store, retrieval with reranking, prompt assembly, citation, and evaluation.
LangChain — RAG chain
EXAMPLE
# ===== Pipeline overview =====
# docs -> chunks -> embeddings -> vector store
# question -> retrieve -> rerank -> prompt -> LLM -> answer + citations
# offline: evaluate retrieval + answer faithfulness
# ===== Ingestion =====
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
loader = DirectoryLoader('./corpus', glob='**/*.md', loader_cls=TextLoader)
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(
chunk_size=800, chunk_overlap=120,
separators=['\n\n', '\n', '. ', ' ', ''],
)
chunks = splitter.split_documents(docs)
emb = OpenAIEmbeddings(model='text-embedding-3-small')
store = Chroma.from_documents(chunks, emb, persist_directory='./chroma')
store.persist()
# ===== Retrieve + rerank =====
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CohereRerank
base = store.as_retriever(search_kwargs={'k': 20})
rerank = CohereRerank(model='rerank-english-v3.0', top_n=5)
retriever = ContextualCompressionRetriever(
base_compressor=rerank, base_retriever=base
)
# ===== Prompt + LLM =====
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
PROMPT = ChatPromptTemplate.from_template('''
You are a careful assistant. Answer ONLY from the provided context.
If the context does not contain the answer, say so explicitly.
Cite sources as [#] using the source labels.
# Question
{question}
# Context
{context}
'''.strip())
def format_context(docs):
return '\n\n'.join(f'[{i+1}] {d.metadata.get("source","?")}\n{d.page_content}' for i, d in enumerate(docs))
llm = ChatOpenAI(model='gpt-4o-mini', temperature=0)
chain = (
{'context': retriever | format_context, 'question': RunnablePassthrough()}
| PROMPT
| llm
| StrOutputParser()
)
print(chain.invoke('What is our SLA for incident response?'))
# ===== Evaluation =====
# Build a small golden set (50-200 Q+A pairs).
# Score on two axes:
# 1. Retrieval recall - is the right chunk in top-k?
# 2. Answer faithfulness - does the answer match the cited chunk?
from langchain.evaluation import load_evaluator
faithfulness = load_evaluator('labeled_pairwise_string', criteria='faithfulness')
# loop golden set, call chain, score, log to a CSV.
# ===== Patterns to internalise =====
# - Chunk on paragraph boundaries, not fixed tokens
# - Always rerank when you have > 5 candidates
# - Prompt the model to refuse rather than hallucinate
# - Cite by chunk index, render label in UI
# - Evaluate retrieval and answer separately; they fail differently
# ===== Pitfalls =====
# - chunk_size too small -> chopped sentences ruin embeddings
# - chunk_size too large -> low precision on retrieval
# - Cosine vs dot product mismatch between embedder and store
# - No metadata filter on multi-tenant corpora -> data leaks
# - Trusting answers without faithfulness eval -> silently confident wrong answers
Why it matters
Retrieval is the part of RAG that most often fails. Chunk on natural boundaries, rerank aggressively, refuse loudly, evaluate both axes. The shape above survives across embedder, model, and store changes — you swap parts without rewriting the chain.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
rag_prompt = ChatPromptTemplate.from_template('''Answer using only the context.\n\nContext: {context}\n\nQuestion: {q}''')
rag = ({'context': retriever, 'q': RunnablePassthrough()} | rag_prompt | llm | StrOutputParser())
print(rag.invoke('How do I get a refund?'))
Try it Yourself »
Discussion
Loading…