LlamaIndex
Le framework Python focalisé sur le RAG : indexer des documents et interroger un LLM avec un contexte pertinent. Là où LangChain est généraliste, LlamaIndex se concentre sur une seule chose et la fait extrêmement bien — un RAG fonctionnel en 5 lignes.
À quoi ça sert
Un RAG (Retrieval-Augmented Generation) résout un problème simple : un LLM ne connaît pas tes documents (PDFs internes, base de connaissance, code source…). Plutôt que de fine-tuner un modèle, on va chercher les passages pertinents avant de poser la question, et on les colle dans le prompt comme contexte.
LlamaIndex automatise cette chaîne :
- Ingestion — charger des documents depuis 200+ sources (fichiers locaux, Notion, Slack, Confluence, base SQL, APIs…).
- Indexation — découper en chunks (« Nodes »), calculer les embeddings, stocker dans un vector store.
- Retrieval — pour une question, retrouver les N chunks les plus pertinents.
- Réponse — passer la question + le contexte au LLM via un query engine, récupérer la réponse avec ses sources.
- Chat — version multi-turn qui garde la mémoire de la conversation.
- Évaluation — outils pour mesurer la qualité d'un RAG (faithfulness, relevance) sans le faire à l'œil.
LlamaIndex est spécialisé RAG : son API est optimisée pour ingester → indexer → requêter des documents. Plus rapide à mettre en place sur ce cas précis. LangChain est un framework généraliste : RAG, agents, chains, outils — plus large, plus flexible, plus complexe. Règle pratique : si tu fais un chatbot sur tes documents, prends LlamaIndex. Si tu as besoin d'agents qui appellent des outils ou de pipelines multi-LLM, prends LangChain. Les deux peuvent cohabiter — LlamaIndex s'utilise même en interne dans certaines chaînes LangChain.
Un exemple d'usage
RAG complet en 5 lignes utiles, sur un dossier de fichiers texte, avec Ollama en local — pas de clé API à gérer :
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.llms.ollama import Ollama
from llama_index.embeddings.ollama import OllamaEmbedding
# Config globale : quel LLM, quels embeddings on utilise partout
Settings.llm = Ollama(model="llama3.2")
Settings.embed_model = OllamaEmbedding(model_name="nomic-embed-text")
# Charger + indexer tout un dossier en 2 lignes
docs = SimpleDirectoryReader("./notes").load_data()
index = VectorStoreIndex.from_documents(docs)
# Poser une question
qe = index.as_query_engine()
print(qe.query("Quelle est la procédure pour déployer en staging ?"))
SimpleDirectoryReader détecte automatiquement le format
(PDF, .txt, .md, .docx…) et appelle le bon loader.
VectorStoreIndex.from_documents découpe, embed et indexe
en une opération. as_query_engine() renvoie un objet
callable qui fait le retrieve + le RAG. C'est cette compacité qui
fait la force de LlamaIndex pour le pur cas RAG.
How-to : installer et utiliser LlamaIndex
-
Installer les paquets
Comme LangChain, LlamaIndex est modulaire : un core + une lib par intégration. Avec UV :
bashuv add llama-index # Au moins un fournisseur de LLM : uv add llama-index-llms-ollama uv add llama-index-embeddings-ollama # (ou OpenAI / Anthropic / HuggingFace selon) uv add llama-index-llms-openai uv add llama-index-embeddings-openaillama-indextout court inclut le core + OpenAI par défaut (héritage historique). Si tu n'utilises pas OpenAI, tu peux installerllama-index-coretout seul. -
Configurer le LLM par défaut
Settingsest l'objet global qui dit à LlamaIndex quels LLM et embeddings utiliser. On le configure une fois en début de programme :pythonfrom llama_index.core import Settings from llama_index.llms.ollama import Ollama from llama_index.embeddings.ollama import OllamaEmbedding Settings.llm = Ollama(model="llama3.2", request_timeout=120) Settings.embed_model = OllamaEmbedding(model_name="nomic-embed-text") Settings.chunk_size = 512 Settings.chunk_overlap = 50Settings vs paramètre expliciteOn peut aussi passer
llm=etembed_model=à chaque objet — utile pour tester deux LLMs en parallèle. Mais pour 99% des cas,Settingsen début de fichier est plus propre. -
Charger des documents
SimpleDirectoryReadercouvre les besoins courants. Pour des sources plus spécifiques, LlamaIndex propose une centaine de readers via le « Llama Hub ».pythonfrom llama_index.core import SimpleDirectoryReader # Tout un dossier (auto-détection des formats) docs = SimpleDirectoryReader("./data").load_data() # Filtrer par extension docs = SimpleDirectoryReader( "./data", required_exts=[".pdf", ".md"], recursive=True, ).load_data() # Fichiers précis docs = SimpleDirectoryReader(input_files=["manuel.pdf"]).load_data() -
Construire un index
VectorStoreIndexest l'index par défaut (vectoriel, recherche par similarité cosine). Il existe d'autres index (SummaryIndex,KeywordTableIndex,KnowledgeGraphIndex) pour des stratégies différentes.pythonfrom llama_index.core import VectorStoreIndex index = VectorStoreIndex.from_documents(docs) # Persister sur disque pour ne pas tout réindexer à chaque run index.storage_context.persist(persist_dir="./index_store") # Recharger plus tard from llama_index.core import StorageContext, load_index_from_storage storage = StorageContext.from_defaults(persist_dir="./index_store") index = load_index_from_storage(storage) -
Query engine (one-shot)
pythonqe = index.as_query_engine(similarity_top_k=4) response = qe.query("Quelle est la garantie produit ?") print(response) print(response.source_nodes) # les chunks utilisés print(response.source_nodes[0].metadata) # source de chacunsimilarity_top_kcontrôle combien de chunks on envoie au LLM. Trop peu = info manquante. Trop = on dépasse la fenêtre. 3-5 est un bon défaut. -
Chat engine (multi-turn)
Le query engine oublie tout entre deux questions. Le chat engine garde l'historique pour les conversations :
pythonchat = index.as_chat_engine(chat_mode="context") print(chat.chat("Quels sont les délais de garantie ?")) print(chat.chat("Et pour les pièces détachées ?")) # se souvient du contexte chat.reset() # vide l'historique -
Customiser le retrieval
Pour aller au-delà du retrieval naïf : reranking, filtres sur les métadonnées, recherche hybride (vectoriel + mots-clés).
pythonfrom llama_index.core.vector_stores import MetadataFilters, ExactMatchFilter # Filtrer sur une métadonnée (ex: ne chercher que dans la doc v2) filters = MetadataFilters(filters=[ ExactMatchFilter(key="version", value="v2"), ]) qe = index.as_query_engine(filters=filters, similarity_top_k=5) -
Vector store externe (production)
Par défaut LlamaIndex stocke tout en mémoire. Pour la production, on branche un vrai vector store (PostgreSQL + pgvector, Qdrant, Chroma…) :
pythonfrom llama_index.vector_stores.postgres import PGVectorStore from llama_index.core import StorageContext, VectorStoreIndex vs = PGVectorStore.from_params( database="rag", host="localhost", password="…", port=5432, user="app", table_name="chunks", embed_dim=768, ) storage = StorageContext.from_defaults(vector_store=vs) index = VectorStoreIndex.from_documents(docs, storage_context=storage)
Aide-mémoire
from llama_index.core import Settings
Settings.llm = Ollama(model="llama3.2")
Settings.embed_model = OllamaEmbedding(model_name="nomic-embed-text")
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
docs = SimpleDirectoryReader("./data").load_data()
index = VectorStoreIndex.from_documents(docs)
print(index.as_query_engine().query("…"))
index.storage_context.persist("./store")
storage = StorageContext.from_defaults(persist_dir="./store")
index = load_index_from_storage(storage)
chat = index.as_chat_engine(chat_mode="context")
chat.chat("…"); chat.chat("…"); chat.reset()
LlamaIndex et le reste de l'écosystème
- LangChain — l'alternative généraliste. LlamaIndex est plus simple pour le RAG pur ; LangChain s'impose dès qu'on a besoin d'agents, de tools ou de chaînes multi-étapes complexes. Voir l'encadré comparatif plus haut.
-
Ollama /
Hugging Face —
fournisseurs de LLMs et d'embeddings locaux. Packages dédiés
llama-index-llms-ollamaetllama-index-embeddings-huggingface. -
PostgreSQL — avec
l'extension pgvector, devient un vector store production prêt
pour LlamaIndex via
llama-index-vector-stores-postgres. -
FastAPI — exposer un
endpoint
/askqui appelle le query engine. Charger l'index au démarrage via le lifespan, le requêter à chaque requête HTTP. -
Streamlit — démos
RAG en quelques dizaines de lignes : un input texte, un appel
query_engine.query(), l'affichage de la réponse et des sources. -
Pydantic — pour
forcer une structure de sortie au LLM
(
StructuredLLM, sortie typée). Indispensable dès qu'on veut consommer la réponse par programme plutôt que l'afficher brut. - MLflow — tracker des expériences RAG (variations de chunk_size, embed_model, top_k) et comparer les métriques d'évaluation produites par les evaluators LlamaIndex.
Si tu changes de modèle d'embeddings ou de
chunk_size après avoir indexé, il faut tout
réindexer. Les vecteurs existants ne sont plus dans le
même espace. À garder à l'esprit en prod : versionne le couple
(embed_model, chunk_size) avec l'index lui-même, par exemple via
DVC.
Pour aller plus loin
- Site officiel : llamaindex.ai
- Documentation Python : docs.llamaindex.ai
- Tutoriels « Starter » : docs.llamaindex.ai/en/stable/getting_started/starter_example
- LlamaHub (loaders & tools) : llamahub.ai