<overview> La Génération Augmentée par Récupération (RAG) améliore les réponses des LLM en récupérant un contexte pertinent à partir de sources de connaissances externes.
Pipeline :
- Index : Charger → Diviser → Incorporer → Stocker
- Récupérer : Requête → Incorporer → Chercher → Retourner docs
- Générer : Docs + Requête → LLM → Réponse
Composants clés :
- Chargeurs de documents : Ingérer les données à partir de fichiers, web, bases de données
- Séparateurs de texte : Diviser les documents en chunks
- Embeddings : Convertir le texte en vecteurs
- Magasins vectoriels : Stocker et rechercher les embeddings </overview>
<vectorstore-selection>
| Magasin vectoriel | Cas d'usage | Persistance |
|---|---|---|
| InMemory | Test | Mémoire uniquement |
| FAISS | Local, haute performance | Disque |
| Chroma | Développement | Disque |
| Pinecone | Production, géré | Cloud |
</vectorstore-selection>
Pipeline RAG complet
<ex-basic-rag-setup> <python> Pipeline RAG de bout en bout : charger des documents, les diviser en chunks, incorporer, stocker, récupérer et générer une réponse.
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import InMemoryVectorStore
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.documents import Document
# 1. Load documents
docs = [
Document(page_content="LangChain is a framework for LLM apps.", metadata={}),
Document(page_content="RAG = Retrieval Augmented Generation.", metadata={}),
]
# 2. Split documents
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
splits = splitter.split_documents(docs)
# 3. Create embeddings and store
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = InMemoryVectorStore.from_documents(splits, embeddings)
# 4. Create retriever
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
# 5. Use in RAG
model = ChatOpenAI(model="gpt-4.1")
query = "What is RAG?"
relevant_docs = retriever.invoke(query)
context = "\n\n".join([doc.page_content for doc in relevant_docs])
response = model.invoke([
{"role": "system", "content": f"Use this context:\n\n{context}"},
{"role": "user", "content": query},
])
</python> <typescript> Pipeline RAG de bout en bout : charger des documents, les diviser en chunks, incorporer, stocker, récupérer et générer une réponse.
import { ChatOpenAI, OpenAIEmbeddings } from "@langchain/openai";
import { MemoryVectorStore } from "@langchain/classic/vectorstores/memory";
import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters";
import { Document } from "@langchain/core/documents";
// 1. Load documents
const docs = [
new Document({ pageContent: "LangChain is a framework for LLM apps.", metadata: {} }),
new Document({ pageContent: "RAG = Retrieval Augmented Generation.", metadata: {} }),
];
// 2. Split documents
const splitter = new RecursiveCharacterTextSplitter({ chunkSize: 500, chunkOverlap: 50 });
const splits = await splitter.splitDocuments(docs);
// 3. Create embeddings and store
const embeddings = new OpenAIEmbeddings({ model: "text-embedding-3-small" });
const vectorstore = await MemoryVectorStore.fromDocuments(splits, embeddings);
// 4. Create retriever
const retriever = vectorstore.asRetriever({ k: 4 });
// 5. Use in RAG
const model = new ChatOpenAI({ model: "gpt-4.1" });
const query = "What is RAG?";
const relevantDocs = await retriever.invoke(query);
const context = relevantDocs.map(doc => doc.pageContent).join("\n\n");
const response = await model.invoke([
{ role: "system", content: `Use this context:\n\n${context}` },
{ role: "user", content: query },
]);
</typescript> </ex-basic-rag-setup>
Chargeurs de documents
<ex-loading-pdf> <python> Charger un fichier PDF et extraire chaque page en tant que document séparé.
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("./document.pdf")
docs = loader.load()
print(f"Loaded {len(docs)} pages")
</python> <typescript> Charger un fichier PDF et extraire chaque page en tant que document séparé.
import { PDFLoader } from "@langchain/community/document_loaders/fs/pdf";
const loader = new PDFLoader("./document.pdf");
const docs = await loader.load();
console.log(`Loaded ${docs.length} pages`);
</typescript> </ex-loading-pdf>
<ex-loading-web-pages> <python> Récupérer et analyser le contenu d'une URL web dans un document.
from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader("https://docs.langchain.com")
docs = loader.load()
</python> <typescript> Récupérer et analyser le contenu d'une URL web dans un document en utilisant Cheerio.
import { CheerioWebBaseLoader } from "@langchain/community/document_loaders/web/cheerio";
const loader = new CheerioWebBaseLoader("https://docs.langchain.com");
const docs = await loader.load();
</typescript> </ex-loading-web-pages>
<ex-loading-directory> <python> Charger tous les fichiers texte d'un répertoire en utilisant un motif glob.
from langchain_community.document_loaders import DirectoryLoader, TextLoader
# Load all text files from directory
loader = DirectoryLoader(
"path/to/documents",
glob="**/*.txt", # Pattern for files to load
loader_cls=TextLoader
)
docs = loader.load()
</python> </ex-loading-directory>
Division de texte
<ex-text-splitting> <python> Diviser les documents en chunks en utilisant RecursiveCharacterTextSplitter avec taille et chevauchement configurables.
from langchain_text_splitters import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, # Characters per chunk
chunk_overlap=200, # Overlap for context continuity
separators=["\n\n", "\n", " ", ""], # Split hierarchy
)
splits = splitter.split_documents(docs)
</python> </ex-text-splitting>
Magasins vectoriels
<ex-chroma-vectorstore> <python> Créer un magasin vectoriel Chroma persistant et le recharger depuis le disque.
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
vectorstore = Chroma.from_documents(
documents=splits,
embedding=OpenAIEmbeddings(),
persist_directory="./chroma_db",
collection_name="my-collection",
)
# Load existing
vectorstore = Chroma(
persist_directory="./chroma_db",
embedding_function=OpenAIEmbeddings(),
collection_name="my-collection",
)
</python> <typescript> Créer un magasin vectoriel Chroma connecté à un serveur Chroma en cours d'exécution.
import { Chroma } from "@langchain/community/vectorstores/chroma";
import { OpenAIEmbeddings } from "@langchain/openai";
const vectorstore = await Chroma.fromDocuments(
splits,
new OpenAIEmbeddings(),
{ collectionName: "my-collection", url: "http://localhost:8000" }
);
</typescript> </ex-chroma-vectorstore>
<ex-faiss-vectorstore> <python> Créer un magasin vectoriel FAISS, l'enregistrer sur le disque et le recharger.
from langchain_community.vectorstores import FAISS
vectorstore = FAISS.from_documents(splits, embeddings)
vectorstore.save_local("./faiss_index")
# Load (requires allow_dangerous_deserialization)
loaded = FAISS.load_local(
"./faiss_index",
embeddings,
allow_dangerous_deserialization=True
)
</python> <typescript> Créer un magasin vectoriel FAISS, l'enregistrer sur le disque et le recharger.
import { FaissStore } from "@langchain/community/vectorstores/faiss";
const vectorstore = await FaissStore.fromDocuments(splits, embeddings);
await vectorstore.save("./faiss_index");
const loaded = await FaissStore.load("./faiss_index", embeddings);
</typescript> </ex-faiss-vectorstore>
Récupération
<ex-similarity-search> <python> Effectuer une recherche par similarité et récupérer les résultats avec les scores de pertinence.
# Basic search
results = vectorstore.similarity_search(query, k=5)
# With scores
results_with_score = vectorstore.similarity_search_with_score(query, k=5)
for doc, score in results_with_score:
print(f"Score: {score}, Content: {doc.page_content}")
</python> <typescript> Effectuer une recherche par similarité et récupérer les résultats avec les scores de pertinence.
// Basic search
const results = await vectorstore.similaritySearch(query, 5);
// With scores
const resultsWithScore = await vectorstore.similaritySearchWithScore(query, 5);
for (const [doc, score] of resultsWithScore) {
console.log(`Score: ${score}, Content: ${doc.pageContent}`);
}
</typescript> </ex-similarity-search>
<ex-mmr-search> <python> Utiliser MMR (Maximal Marginal Relevance) pour équilibrer la pertinence et la diversité dans les résultats de recherche.
# MMR balances relevance and diversity
retriever = vectorstore.as_retriever(
search_type="mmr",
search_kwargs={"fetch_k": 20, "lambda_mult": 0.5, "k": 5},
)
</python> </ex-mmr-search>
<ex-metadata-filtering> <python> Ajouter des métadonnées aux documents et filtrer les résultats de recherche par propriétés de métadonnées.
# Add metadata when creating documents
docs = [
Document(
page_content="Python programming guide",
metadata={"language": "python", "topic": "programming"}
),
]
# Search with filter
results = vectorstore.similarity_search(
"programming",
k=5,
filter={"language": "python"} # Only Python docs
)
</python> </ex-metadata-filtering>
<ex-rag-with-agent> <python> Créer un agent qui utilise RAG comme outil pour répondre à des questions.
from langchain.agents import create_agent
from langchain.tools import tool
@tool
def search_docs(query: str) -> str:
"""Search documentation for relevant information."""
docs = retriever.invoke(query)
return "\n\n".join([d.page_content for d in docs])
agent = create_agent(
model="gpt-4.1",
tools=[search_docs],
)
result = agent.invoke({
"messages": [{"role": "user", "content": "How do I create an agent?"}]
})
</python> <typescript> Créer un agent qui utilise RAG comme outil pour répondre à des questions.
import { createAgent } from "langchain";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
const searchDocs = tool(
async (input) => {
const docs = await retriever.invoke(input.query);
return docs.map(d => d.pageContent).join("\n\n");
},
{
name: "search_docs",
description: "Search documentation for relevant information.",
schema: z.object({ query: z.string() }),
}
);
const agent = createAgent({
model: "gpt-4.1",
tools: [searchDocs],
});
const result = await agent.invoke({
messages: [{ role: "user", content: "How do I create an agent?" }],
});
</typescript> </ex-rag-with-agent>
<boundaries>
Ce que vous POUVEZ configurer
- Taille et chevauchement des chunks
- Modèle d'embedding
- Nombre de résultats (k)
- Filtres de métadonnées
- Algorithmes de recherche : Similarité, MMR
Ce que vous NE POUVEZ PAS configurer
- Dimensions d'embedding (par modèle)
- Mélanger les embeddings de différents modèles dans le même magasin </boundaries>
<fix-chunk-size> <python> Une taille de chunk de 500-1500 est généralement appropriée.
# WRONG: Too small (loses context) or too large (hits limits)
splitter = RecursiveCharacterTextSplitter(chunk_size=50)
splitter = RecursiveCharacterTextSplitter(chunk_size=10000)
# CORRECT
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
</python> <typescript> Une taille de chunk de 500-1500 est généralement appropriée.
// WRONG: Too small or too large
const splitter = new RecursiveCharacterTextSplitter({ chunkSize: 50 });
// CORRECT
const splitter = new RecursiveCharacterTextSplitter({ chunkSize: 1000, chunkOverlap: 200 });
</typescript> </fix-chunk-size>
<fix-chunk-overlap> <python> Utiliser un chevauchement (10-20 % de la taille du chunk) pour maintenir le contexte aux limites.
# WRONG: No overlap - context breaks at boundaries
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
# CORRECT: 10-20% overlap
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
</python> </fix-chunk-overlap>
<fix-persist-vectorstore> <python> Utiliser un magasin vectoriel persistant au lieu d'en mémoire pour éviter la perte de données.
# WRONG: InMemory - lost on restart
vectorstore = InMemoryVectorStore.from_documents(docs, embeddings)
# CORRECT
vectorstore = Chroma.from_documents(docs, embeddings, persist_directory="./chroma_db")
</python> <typescript> Utiliser un magasin vectoriel persistant au lieu d'en mémoire pour éviter la perte de données.
// WRONG: Memory - lost on restart
const vectorstore = await MemoryVectorStore.fromDocuments(docs, embeddings);
// CORRECT
const vectorstore = await Chroma.fromDocuments(docs, embeddings, { collectionName: "my-collection" });
</typescript> </fix-persist-vectorstore>
<fix-consistent-embeddings> <python> Utiliser le même modèle d'embedding pour l'indexation et la requête.
# WRONG: Different embeddings for index and query - incompatible!
vectorstore = Chroma.from_documents(docs, OpenAIEmbeddings(model="text-embedding-3-small"))
retriever = vectorstore.as_retriever(embeddings=OpenAIEmbeddings(model="text-embedding-3-large"))
# CORRECT: Same model
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_documents(docs, embeddings)
retriever = vectorstore.as_retriever() # Uses same embeddings
</python> <typescript> Utiliser le même modèle d'embedding pour l'indexation et la requête.
const embeddings = new OpenAIEmbeddings({ model: "text-embedding-3-small" });
const vectorstore = await Chroma.fromDocuments(docs, embeddings);
const retriever = vectorstore.asRetriever(); // Uses same embeddings
</typescript> </fix-consistent-embeddings>
<fix-faiss-deserialization> <python> Autoriser explicitement la désérialisation lors du chargement d'index FAISS.
# WRONG: Will raise error
loaded_store = FAISS.load_local("./faiss_index", embeddings)
# CORRECT
loaded_store = FAISS.load_local("./faiss_index", embeddings, allow_dangerous_deserialization=True)
</python> </fix-faiss-deserialization>
<fix-dimension-mismatch> <python> S'assurer que les dimensions d'embedding correspondent aux dimensions de l'index du magasin vectoriel.
# WRONG: Index has 1536 dimensions but using 512-dim embeddings
pc.create_index(name="idx", dimension=1536, metric="cosine")
vectorstore = PineconeVectorStore.from_documents(
docs, OpenAIEmbeddings(model="text-embedding-3-small", dimensions=512), index=pc.Index("idx")
) # Error: dimension mismatch!
# CORRECT: Match dimensions
embeddings = OpenAIEmbeddings() # Default 1536
</python> </fix-dimension-mismatch>