Ce que vous saurez faire
A la fin de ce tutoriel, vous saurez utiliser LlamaIndex pour transformer la base documentaire de votre PME (PDF, Word, Excel, emails Outlook, pages web internes) en un index intelligent interrogeable en langage naturel. Cas d’usage concrets pour le Senegal : assistant juridique qui retrouve la bonne clause dans 200 contrats, support technique qui repond depuis 1500 fiches produits, RH qui consulte la convention collective. Vous deploierez un script Python operationnel en moins de 2 heures, pour un cout API mensuel d’environ 8000 FCFA pour 500 requetes par jour.
Etape 1 : Comprendre LlamaIndex en 1 minute
LlamaIndex (anciennement GPT Index) est une bibliotheque Python qui orchestre 3 etapes : ingestion (lecture des fichiers), indexation (decoupage et vectorisation), et requete (recherche + reponse par un LLM). Difference avec LangChain : LlamaIndex est specialise documents, plus simple, plus rapide a mettre en place quand le but est purement RAG documentaire.
Etape 2 : Installer LlamaIndex
python -m venv venv
source venv/bin/activate
pip install llama-index==0.11.7
pip install llama-index-llms-anthropic==0.3.1
pip install llama-index-embeddings-huggingface==0.3.1
pip install llama-index-readers-file==0.2.1
pip install python-dotenv==1.0.1
Etape 3 : Organiser votre base documentaire
Creez une structure claire :
mon-projet/
documents/
contrats/
contrat-orange-2023.pdf
contrat-sonatel-2024.pdf
procedures/
manuel-rh.docx
reglement-interieur.pdf
catalogues/
produits-2025.xlsx
index_storage/
main.py
.env
Etape 4 : Configurer la cle Anthropic et le modele
Dans .env :
ANTHROPIC_API_KEY=sk-ant-api03-VOTRECLE
Dans main.py, on configure Claude comme LLM par defaut et un embedding local pour reduire les couts :
from llama_index.core import Settings
from llama_index.llms.anthropic import Anthropic
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from dotenv import load_dotenv
load_dotenv()
Settings.llm = Anthropic(model="claude-3-5-sonnet-20241022", max_tokens=1024)
Settings.embed_model = HuggingFaceEmbedding(
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
)
Settings.chunk_size = 800
Settings.chunk_overlap = 100
Etape 5 : Charger tous les documents en une commande
SimpleDirectoryReader lit recursivement tous les PDF, DOCX, XLSX, TXT et MD :
from llama_index.core import SimpleDirectoryReader
documents = SimpleDirectoryReader(
input_dir="./documents",
recursive=True,
required_exts=[".pdf", ".docx", ".xlsx", ".txt", ".md"]
).load_data()
print(f"{len(documents)} documents charges")
Pour une PME avec 500 fichiers, comptez 30 secondes de chargement.
Etape 6 : Construire l’index vectoriel
from llama_index.core import VectorStoreIndex
index = VectorStoreIndex.from_documents(
documents,
show_progress=True
)
print("Index construit")
Sur 500 documents (environ 10 000 chunks), comptez 5 minutes sur CPU. Avec un GPU, moins d’une minute.
Etape 7 : Persister l’index sur disque
Indispensable : sans cette etape, vous reconstruisez tout a chaque demarrage et payez des appels API inutiles :
index.storage_context.persist(persist_dir="./index_storage")
print("Index sauvegarde")
L’index occupe environ 50 Mo pour 500 documents.
Etape 8 : Recharger un index existant
from llama_index.core import StorageContext, load_index_from_storage
storage_context = StorageContext.from_defaults(persist_dir="./index_storage")
index = load_index_from_storage(storage_context)
print("Index recharge depuis disque")
Le rechargement prend moins de 3 secondes, meme pour 100 000 documents.
Etape 9 : Lancer une premiere requete
query_engine = index.as_query_engine(
similarity_top_k=4,
response_mode="compact"
)
reponse = query_engine.query(
"Quelle est la duree de preavis pour un employe en CDI selon notre reglement interieur ?"
)
print(reponse)
Reponse type : « Selon le reglement interieur, le preavis pour un CDI est d’un mois pour les employes et de trois mois pour les cadres. »
Etape 10 : Afficher les sources citees
Indispensable pour un usage professionnel et juridique :
print("\nSources :")
for node in reponse.source_nodes:
fichier = node.metadata.get("file_name", "inconnu")
page = node.metadata.get("page_label", "")
score = node.score
print(f"- {fichier} (page {page}) score {score:.2f}")
Etape 11 : Affiner avec un prompt metier
Le prompt par defaut est generique. Pour un cabinet juridique senegalais :
from llama_index.core import PromptTemplate
template = """Tu es un assistant juridique pour un cabinet a Dakar.
Reponds uniquement en t'appuyant sur les documents fournis.
Cite la source (nom du fichier et page) entre crochets.
Si l'information n'est pas dans les documents, reponds "Information non trouvee".
Contexte :
---
{context_str}
---
Question : {query_str}
Reponse argumentee :"""
prompt = PromptTemplate(template)
query_engine = index.as_query_engine(similarity_top_k=4)
query_engine.update_prompts({"response_synthesizer:text_qa_template": prompt})
Etape 12 : Mettre a jour l’index quand un document change
Au lieu de tout reconstruire, on insere ou on supprime selectivement :
# Ajouter un nouveau contrat
nouveau = SimpleDirectoryReader(input_files=["./documents/contrats/contrat-tigo-2025.pdf"]).load_data()
for doc in nouveau:
index.insert(doc)
# Supprimer un document obsolete
index.delete_ref_doc("ancien_doc_id", delete_from_docstore=True)
# Persister les changements
index.storage_context.persist(persist_dir="./index_storage")
Etape 13 : Mode chat avec memoire de conversation
Pour des echanges suivis, utilisez chat_engine au lieu de query_engine :
chat_engine = index.as_chat_engine(
chat_mode="condense_plus_context",
verbose=False
)
while True:
question = input("Vous : ")
if question.lower() in ["quit", "exit"]:
break
reponse = chat_engine.chat(question)
print(f"Assistant : {reponse}\n")
Le chat se souvient du contexte : « Et la garantie ? » comprend qu’on parle du produit precedemment evoque.
Etape 14 : Optimiser les couts en production
Trois leviers pour reduire la facture Anthropic :
# 1. Cache des reponses pour questions frequentes
from llama_index.core import set_global_handler
set_global_handler("simple")
# 2. Modele moins cher pour les requetes simples
from llama_index.llms.anthropic import Anthropic
llm_eco = Anthropic(model="claude-3-haiku-20240307", max_tokens=512)
# 3. Limiter le contexte recupere
query_engine = index.as_query_engine(
similarity_top_k=3, # 3 chunks au lieu de 10
response_mode="compact" # Compactage avant envoi a Claude
)
Resultat : passage de 8000 FCFA a 2500 FCFA par mois pour 500 requetes par jour.
Erreurs
Erreur 1 : Reconstruire l’index a chaque execution. Verifiez avec os.path.exists(« ./index_storage ») avant de reconstruire. Sinon vous brulez votre quota API.
Erreur 2 : Charger des fichiers Excel mal formates. LlamaIndex lit feuille par feuille. Si vos cellules fusionnees sont nombreuses, exportez d’abord en CSV propre.
Erreur 3 : Oublier les metadonnees. Ajoutez doc.metadata[« categorie »] = « RH » pour pouvoir filtrer ensuite. Sans cela, impossible de cibler une recherche.
Erreur 4 : similarity_top_k trop eleve. Au-dessus de 8, vous envoyez trop de contexte a Claude (cout x5) sans gain de qualite.
Erreur 5 : Documents avec OCR rate. Si votre PDF est un scan, LlamaIndex extrait du charabia. Pretraitez avec Tesseract OCR avant indexation.
Checklist
- Python 3.11+ et environnement virtuel actif
- Cle API Anthropic configuree dans .env et exclue de git
- Structure documents/ organisee par categories metier
- Modele d’embedding multilingue installe en local
- Chunk size entre 600 et 1000 selon densite documentaire
- Index persiste dans index_storage/ et exclu de git si volumineux
- Test de rechargement de l’index sans reconstruction valide
- Prompt template adapte au metier (juridique, RH, technique)
- Sources citees affichees a chaque reponse
- Procedure d’ajout et suppression incrementale documentee
- Mode chat teste avec 10 echanges enchaines
- Cout API mesure et plafond mensuel configure dans console Anthropic
- Sauvegarde quotidienne d’index_storage/ sur disque externe
- Documentation utilisateur final remise aux equipes (RH, juridique, technique)