LangChain RAG
RAG (Retrieval-Augmented Generation) permet à l'IA de répondre à des questions en se basant sur vos documents privés sans fine-tuning du modèle. Il vous suffit de vectoriser et de stocker les documents, et l'Agent peut récupérer le contenu pertinent pour répondre.
Qu'est-ce que le RAG
Les grands modèles ordinaires ne peuvent répondre qu'au contenu existant dans leurs données d'entraînement. Si vos documents sont privés (documents internes d'entreprise, notes personnelles), le modèle ne les connaît pas. Le RAG résout ce problème :
- Étape hors ligne: Diviser les documents en petits morceaux → Utiliser un modèle d'Embedding pour les convertir en vecteurs → Les stocker dans une base de données vectorielle
- Étape en ligne: L'utilisateur pose une question → Convertir la question en vecteur → Rechercher le contenu le plus similaire dans la base de données vectorielle → Envoyer le contenu récupéré au modèle comme contexte → Le modèle répond en se basant sur le contenu récupéré
Flux de travail RAG
┌──────────────────────────────────────────────────────┐ │ 离线阶段(索引) │ │ │ │ 文档 → DocumentLoader → TextSplitter → Embedding │ │ ↓ │ │ VectorStore │ └──────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────┐ │ 在线阶段(检索) │ │ │ │ 用户提问 → Embedding → 相似度搜索 → 检索结果 │ │ ↓ │ │ 检索结果 + 用户问题 → 模型 → 回答 │ └──────────────────────────────────────────────────────┘

Préparation de l’environnement
Installez les dépendances liées à RAG :
$ pip install langchain-deepseek langchain-chroma chromadb
| Paquet | Objectif |
|---|---|
| langchain-deepseek | Fournit le modèle d'embedding OpenAI |
| langchain-chroma | Intégration LangChain pour la base de données vectorielle Chroma |
| chromadb | Base de données vectorielle Chroma (légère, adaptée aux débutants) |
Initialisation du modèle d'embedding
Exemple
load_dotenv()
from langchain_openai import OpenAIEmbeddings
# Modèle d'embedding de texte d'OpenAI
# Convertir du texte en vecteur (un ensemble de nombres à virgule flottante)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# Test : convertir un extrait de texte en vecteur
text = "EXAMPLE est une plateforme d'apprentissage de la programmation"
vector = embeddings.embed_query(text)
print(f"Texte : {text}")
print(f"Dimension du vecteur : {len(vector)}") # text-embedding-3-small est de dimension 1536
print(f"Les 5 premières valeurs du vecteur : {vector[:5]}")
Résultat de l'exécution :
Text: Example 是一个编程学习平台 Vector dimension: 1536 First 5 vector values: [0.0123, -0.0045, 0.0234, -0.0012, 0.0089]
Alternativement, si vous n'avez pas de clé OpenAI, vous pouvez utiliser le service Embedding d'Alibaba Bailian..envVous devez ajouter la clé Alibaba Bailian au fichier de configuration :
DASHSCOPE_API_KEY="sk-xxx"
Code après configuration :
Exemple
from dotenv import load_dotenv
load_dotenv()
from langchain_openai import OpenAIEmbeddings
# Modèle d'embedding de texte d'OpenAI
# Convertir du texte en vecteur (un ensemble de nombres à virgule flottante)
# Utiliser le service Qwen Embedding d'Alibaba Cloud Bailian (DashScope)
# L'API Embedding de Bailian est compatible avec la spécification de l'API OpenAI, donc utilisez directement langchain-openai
# OpenAIEmbeddings, pointez simplement base_url vers le point de terminaison compatible de Bailian,
# pas besoin d'installer langchain-community / dashscope (ce package n'est plus maintenu).
# text-embedding-v4 est actuellement le modèle vectoriel polyvalent recommandé, produisant par défaut des vecteurs de 1024 dimensions.
#
# Deux paramètres clés sont essentiels :
# - check_embedding_ctx_length=False : OpenAIEmbeddings utilise tiktoken par défaut
# pour pré-encoder le texte en tableaux d'ID de jetons avant l'envoi (c'est le format reconnu par l'API officielle OpenAI),
# mais l'interface compatible de Bailian n'accepte que des chaînes brutes. Si vous ne désactivez pas cette option, elle signalera
# une erreur "contents is neither str nor list of str".
# - chunk_size=10: l'interface d'Embedding de Bailian accepte au maximum 10 morceaux de texte par requête.
# OpenAIEmbeddings regroupe 1000 éléments à la fois par défaut. Si la base de connaissances est légèrement plus grande, elle dépassera la limite et signalera une erreur.
embeddings = OpenAIEmbeddings(
model="text-embedding-v4",
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
check_embedding_ctx_length=False,
chunk_size=10,
)
# Test : convertir un extrait de texte en vecteur
text = "EXAMPLE est une plateforme d'apprentissage de la programmation"
vector = embeddings.embed_query(text)
print(f"Texte : {text}")
print(f"Dimension du vecteur : {len(vector)}") # text-embedding-3-small est de dimension 1536
print(f"Les 5 premières valeurs du vecteur : {vector[:5]}")
Créer un magasin de vecteurs
Exemple
from langchain_chroma import Chroma
# Initialiser le modèle d'Embedding
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# Créer un magasin de vecteurs Chroma (les données sont enregistrées dans un répertoire local)
vector_store = Chroma(
collection_name="example_docs",
embedding_function=embeddings,
persist_directory="./chroma_db", # Répertoire de persistance
)
# Ajouter des documents (la forme la plus simple : une liste de textes)
textes = [
"EXAMPLE est un site web gratuit d'apprentissage de la programmation qui propose des tutoriels sur HTML, CSS, JavaScript, Python, etc.",
"Le tutoriel de base Python3 comprend 30 chapitres, adapté aux débutants sans connaissances préalables, couvrant la configuration de l'environnement, la syntaxe de base, la programmation orientée objet, et plus encore.",
"Le tutoriel de base HTML comporte 25 chapitres, couvrant des connaissances de base telles que les balises HTML, les formulaires et le multimédia.",
]
# add_texts convertit automatiquement le texte en vecteurs et les stocke
vector_store.add_texts(texts)
print(f"Ajout de {len(texts)} documents au magasin de vecteurs")
Recherche sémantique
Exemple
results = vector_store.similarity_search(
"Je veux apprendre Python. Quels tutoriels recommandez-vous ?",
k=2, # Retourne les 2 résultats les plus similaires
)
print("Résultats de la recherche :")
for i, doc in enumerate(results):
print(f"\n"Résultat {i+1} :")
print(f" Contenu : {doc.page_content}")
print(f" Métadonnées : {doc.metadata}")
Résultat de l'exécution :
搜索结果:
Result 1:
Content: Python3 基础教程共 30 章,适合零基础入门...
Metadata: {}
Result 2:
Content: Example是一个免费的编程学习网站...
Metadata: {}
Notez que le premier résultat de recherche est plus pertinent que le second — bien que le premier contienne le mot-clé "Python", il est classé parsimilarité sémantiqueplutôt que par correspondance de mots-clés. C'est l'avantage de la recherche vectorielle.
Créer un Retriever
Retriever est une interface standardisée pour Vector Store :
Exemple
retriever = vector_store.as_retriever(
search_type="similarity", # Recherche par similarité
search_kwargs={"k": 3}, # Renvoyer les 3 meilleurs résultats
)
# Utiliser le retriever
docs = retriever.invoke("Parcours d'apprentissage Python")
for doc in docs:
print(f"- {doc.page_content[:60]}...")