Ce que vous saurez faire
A la fin de ce tutoriel, vous saurez construire une application RAG (Retrieval Augmented Génération) avec LangChain Python et Claude (Anthropic). Vous indexerez les documents PDF de votre PME sénégalaise (catalogues produits, fiches techniques, conditions générales de vente), puis vous interrogerez Claude qui repondra en s’appuyant sur ces documents. Résultat concret : un assistant interne qui répond aux commerciaux en moins de 3 secondes, base uniquement sur vos données vérifiées, sans inventer de prix en FCFA. Coute estime : 15 000 FCFA par mois pour 1000 requetes.
Étape 1 : Préparer l’environnement Python
Sur votre poste Windows ou Ubuntu, installez Python 3.11 minimum. Créez un dossier projet et un environnement virtuel pour isoler les dépendances :
mkdir rag-pme-dakar
cd rag-pme-dakar
python -m venv venv
venv\Scripts\activate # Windows
source venv/bin/activate # Linux/Mac
pip install --upgrade pip
Étape 2 : Installer LangChain et le SDK Anthropic
Installez les paquets necessaires. Nous prenons les versions stables compatibles entre elles :
pip install langchain==0.2.16
pip install langchain-anthropic==0.1.23
pip install langchain-community==0.2.16
pip install pypdf==4.3.1
pip install chromadb==0.5.5
pip install sentence-transformers==3.0.1
pip install python-dotenv==1.0.1
Étape 3 : Recuperer la cle API Anthropic
Allez sur console.anthropic.com, créez un compte, ajoutez 5 USD (environ 3000 FCFA) en credit via carte Visa internationale ou Wave en passant par Wise. Generez une cle API qui commence par sk-ant-. Créez un fichier .env a la racine du projet :
ANTHROPIC_API_KEY=sk-ant-api03-VOTRECLEICI
Ajoutez .env a votre .gitignore pour ne jamais publier la cle sur GitHub.
Étape 4 : Charger vos PDF métier
Placez vos documents (catalogue.pdf, cgv.pdf, tarifs.pdf) dans un dossier docs/. Le code suivant charge automatiquement tous les PDF :
from langchain_community.document_loaders import PyPDFDirectoryLoader
loader = PyPDFDirectoryLoader("./docs")
documents = loader.load()
print(f"Documents charges : {len(documents)} pages")
Pour 50 pages typiques d’une PME, le chargement prend moins de 5 secondes.
Étape 5 : Decouper en chunks intelligents
Claude ne peut pas digerer un PDF entier. Il faut decouper en morceaux de 800 caractères avec 100 caractères de chevauchement pour preserver le contexte :
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=800,
chunk_overlap=100,
separators=["\n\n", "\n", ". ", " "]
)
chunks = splitter.split_documents(documents)
print(f"Chunks crees : {len(chunks)}")
Étape 6 : Générer les embeddings localement
Pour éviter les frais OpenAI, on utilise un modèle open-source qui tourne sur votre PC. Le modèle paraphrase-multilingual-MiniLM gere bien le français :
from langchain_community.embeddings import HuggingFaceEmbeddings
embeddings = HuggingFaceEmbeddings(
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
model_kwargs={"device": "cpu"}
)
Premier téléchargement : 450 Mo, ensuite tout est en cache local.
Étape 7 : Stocker dans ChromaDB
ChromaDB est une base vectorielle gratuite qui s’execute en local. Aucun serveur a louer :
from langchain_community.vectorstores import Chroma
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db"
)
vectorstore.persist()
print("Index sauvegarde dans ./chroma_db")
Étape 8 : Configurer Claude comme moteur de réponse
On utilise Claude 3.5 Sonnet pour la qualité, ou Claude 3 Haiku pour réduire les coûts (4x moins cher) :
from langchain_anthropic import ChatAnthropic
from dotenv import load_dotenv
load_dotenv()
llm = ChatAnthropic(
model="claude-3-5-sonnet-20241022",
temperature=0.2,
max_tokens=1024
)
Étape 9 : Construire la chaine RAG
On assemble retrieval + génération. Le retriever cherche les 4 chunks les plus pertinents :
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
template = """Tu es l'assistant interne d'une PME senegalaise.
Reponds UNIQUEMENT avec les informations du contexte ci-dessous.
Si l'information n'y est pas, reponds "Information non disponible".
Les prix sont toujours en FCFA.
Contexte :
{context}
Question : {question}
Reponse :"""
prompt = PromptTemplate(template=template, input_variables=["context", "question"])
qa = RetrievalQA.from_chain_type(
llm=llm,
retriever=vectorstore.as_retriever(search_kwargs={"k": 4}),
chain_type_kwargs={"prompt": prompt}
)
Étape 10 : Poser une première question
Testez avec une question réelle de vos commerciaux :
question = "Quel est le prix du modele Solaris 200W et la garantie ?"
reponse = qa.invoke({"query": question})
print(reponse["result"])
Réponse type : « Le modèle Solaris 200W coute 145 000 FCFA TTC avec une garantie de 24 mois pièce et main d’oeuvre. »
Étape 11 : Ajouter les sources citées
Pour la confiance, affichez le PDF source. Modifiez la chaine :
qa = RetrievalQA.from_chain_type(
llm=llm,
retriever=vectorstore.as_retriever(search_kwargs={"k": 4}),
chain_type_kwargs={"prompt": prompt},
return_source_documents=True
)
result = qa.invoke({"query": question})
for doc in result["source_documents"]:
print(f"Source : {doc.metadata['source']} page {doc.metadata['page']}")
Étape 12 : Mesurer le coût par requete
Claude facture en tokens. Une requete RAG typique = 1500 tokens d’entree + 200 tokens de sortie. Avec Claude 3.5 Sonnet : 0,005 USD soit environ 3 FCFA par question. Pour 1000 questions par mois : 3000 FCFA. Pour réduire encore, basculez sur claude-3-haiku-20240307 : 0,0008 USD par requete soit moins de 1 FCFA.
Étape 13 : Exposer en API web avec FastAPI
Pour que vos commerciaux interrogent depuis un navigateur :
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Question(BaseModel):
texte: str
@app.post("/ask")
def ask(q: Question):
reponse = qa.invoke({"query": q.texte})
return {"reponse": reponse["result"]}
# Lancer : uvicorn main:app --host 0.0.0.0 --port 8000
Étape 14 : Déployer chez un hébergeur africain
Hebergez l’application chez Orange Business Sénégal (VPS 4 Go RAM a 25 000 FCFA par mois) ou sur un Raspberry Pi 5 dans vos locaux pour les données sensibles. Configurez un nom de domaine .sn via NIC Sénégal (15 000 FCFA par an), activez HTTPS gratuit avec Let’s Encrypt via Certbot.
Erreurs
Erreur 1 : Cle API exposée sur GitHub. Anthropic la revoque automatiquement et vous facture les usages frauduleux. Solution : .gitignore stricte et secrets dans variables d’environnement système en production.
Erreur 2 : Chunks trop gros (3000 caractères). Le retrieval devient flou et Claude noie sa réponse. Restez entre 500 et 1000.
Erreur 3 : Oublier le prompt strict. Sans la consigne « uniquement avec le contexte », Claude invente parfois des prix. Toujours ajouter la phrase « Si l’information n’y est pas, reponds Information non disponible ».
Erreur 4 : Indexer a chaque requete. Genere les embeddings une fois, persistez avec Chroma, rechargez avec Chroma(persist_directory=…).
Erreur 5 : Utiliser Claude pour les embeddings. C’est 50 fois plus cher. Utilisez sentence-transformers en local, gratuit.
Checklist
Avant mise en production, vérifiez :
- Python 3.11+ installe et environnement virtuel actif
- Cle API Anthropic dans .env, jamais commitee
- Au moins 10 PDF métier dans /docs pour un index utile
- Chunks entre 500 et 1000 caractères avec overlap de 100
- Modèle d’embedding multilingue installe en local
- Base ChromaDB persistee sur disque
- Prompt template avec consigne anti-hallucination
- Test avec 20 questions réelles de vos commerciaux
- Sources citées affichees a chaque réponse
- Coût par requete mesure et budget mensuel valide
- API FastAPI exposée derriere HTTPS
- Sauvegardes hebdomadaires de chroma_db/ sur disque externe
- Logs des questions sauvegardes pour améliorer l’index
- Procédure de re-indexation documentée pour mises a jour catalogue
Etape 1 : comprendre le defi des factures africaines
Une facture fournisseur scannee a Dakar ou Abidjan presente trois caracteristiques qui mettent en echec les OCR traditionnels comme Tesseract. Premiere caracteristique, les mises en page heterogenes : un meme fournisseur peut basculer d’un modele Word imprime sur Canon vers un recu manuscrit emis depuis un commercant du marche Sandaga. Deuxieme caracteristique, le melange francais-wolof-anglais selon les zones et les operateurs. Troisieme caracteristique, les montants en FCFA avec espaces ou points comme separateurs de milliers (12.500.000 ou 12 500 000 FCFA pour un meme montant).
Claude Vision (modele claude-opus-4 ou sonnet) gere ces trois defis sans entrainement specifique. Vous obtenez en sortie un JSON structure avec emetteur, lignes, montants et taxes. Le cout typique d’extraction tourne autour de 0,015 USD par facture standard, soit environ 9,8 FCFA au taux 1 EUR = 655,957 FCFA via la conversion croisee — bien moins cher qu’une saisie manuelle a 200 FCFA la ligne.
Etape 2 : preparer les images pour l API
Claude accepte les images en JPEG, PNG, GIF et WEBP, jusqu a 5 Mo et 7 990 pixels par cote. Les scans bruts depuis un copieur Ricoh ou un photo smartphone Android d entree de gamme depassent souvent la limite. Compressez avant envoi.
magick input.jpg -resize 2000x2000\> -quality 82 facture-prep.jpg
# Verifie la taille finale
ls -la facture-prep.jpg
# Doit etre < 2 Mo
Le redimensionnement a 2000 pixels suffit pour conserver la lisibilite des chiffres et reduit le temps de reponse Claude de 40 pourcent. Si la facture contient un tableau dense, montez a 2500 pixels pour ne pas perdre les chiffres fins. Si la sortie magick reste superieure a 2 Mo, baissez la qualite a 75.
Etape 3 : encoder l image en base64
L API Claude attend un payload JSON avec l image encodee en base64. En Python, deux lignes suffisent.
import base64
with open('facture-prep.jpg', 'rb') as f:
img_b64 = base64.standard_b64encode(f.read()).decode('utf-8')
print(f'Taille base64 : {len(img_b64)} caracteres')
La taille base64 doit rester sous 7 Mo pour passer dans le payload (la limite de 5 Mo s applique a l image originale, mais base64 ajoute 33 pourcent). Si l output depasse 7 millions de caracteres, repassez par l etape 2 avec une qualite plus basse.
Etape 4 : ecrire le prompt structure
La cle d un OCR fiable est un prompt qui force la structure JSON. Demandez explicitement le format, listez les champs obligatoires et imposez le format des montants en chiffres bruts sans separateur.
PROMPT = """Extrais cette facture en JSON strict. Schema obligatoire :
{
"fournisseur": { "nom": str, "ninea": str|null, "telephone": str|null },
"facture": { "numero": str, "date": "YYYY-MM-DD", "echeance": "YYYY-MM-DD"|null },
"lignes": [ { "designation": str, "quantite": float, "prix_unitaire": int, "total": int } ],
"totaux": { "ht": int, "tva": int, "ttc": int, "devise": "XOF"|"EUR"|"USD" }
}
Regles : montants en entiers sans separateur, dates au format ISO, null si absent.
Reponds uniquement avec le JSON, sans commentaire."""
Le prompt impose la devise XOF pour le franc CFA UEMOA (Senegal, Cote d Ivoire, Mali, Burkina Faso, Benin, Togo, Niger, Guinee-Bissau). Pour la CEMAC (Cameroun, Gabon, Tchad, RCA, Congo, Guinee equatoriale) utilisez XAF. Les deux francs CFA partagent la parite avec l euro mais sont juridiquement distincts.
Etape 5 : appeler Claude et parser la reponse
Avec le SDK Anthropic officiel, l appel tient en quelques lignes. Recuperez la cle API depuis console.anthropic.com et stockez-la dans une variable d environnement.
from anthropic import Anthropic
import json, os
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
resp = client.messages.create(
model="claude-opus-4",
max_tokens=2048,
messages=[{
"role": "user",
"content": [
{ "type": "image", "source": { "type": "base64", "media_type": "image/jpeg", "data": img_b64 } },
{ "type": "text", "text": PROMPT }
]
}]
)
facture = json.loads(resp.content[0].text)
print(f"Fournisseur : {facture['fournisseur']['nom']} | Total : {facture['totaux']['ttc']} {facture['totaux']['devise']}")
Sortie typique : Fournisseur ETS DIOUF SARL puis Total 1485000 XOF. Si le parsing JSON echoue, nettoyez la reponse en retirant les fences markdown que Claude ajoute parfois malgre la consigne.
Etape 6 : valider les montants extraits
L OCR n est jamais fiable a 100 pourcent. Implementez trois controles automatiques avant d integrer la facture dans la comptabilite.
def valider(f):
erreurs = []
somme_lignes = sum(l["total"] for l in f["lignes"])
if abs(somme_lignes - f["totaux"]["ht"]) > 1:
erreurs.append("HT incoherent")
tva_calc = round(f["totaux"]["ht"] * 0.18)
if abs(tva_calc - f["totaux"]["tva"]) > 5 and f["totaux"]["tva"] > 0:
erreurs.append("TVA suspecte")
if f["totaux"]["ttc"] != f["totaux"]["ht"] + f["totaux"]["tva"]:
erreurs.append("TTC ne somme pas")
return erreurs
Le taux de TVA Senegal est 18 pourcent, Cote d Ivoire 18 pourcent, Cameroun 19,25 pourcent. Toute facture qui sort des controles part en file d attente revue humaine. En production sur 1 000 factures par mois, environ 5 a 8 pourcent demandent une intervention manuelle, ce qui reste tres rentable.
Etape 7 : enrichir avec les donnees fournisseurs
Le NINEA (Numero d Identification National des Entreprises et des Associations) au Senegal et le RCCM en Cote d Ivoire sont rarement bien lus depuis un scan flou. Croisez avec votre referentiel interne pour deduire le fournisseur a partir du nom et completer le champ NINEA depuis votre base.
Une fonction simple match_fournisseur(nom) qui fait un fuzzy match avec rapidfuzz suffit pour 80 pourcent des cas. Les 20 pourcent restants sont des nouveaux fournisseurs qui demandent une creation manuelle, mais l OCR vous a deja fourni le nom et le telephone — gain de temps net.
Etape 8 : integrer dans le workflow comptable
Une fois la facture validee, exportez vers le format de votre logiciel comptable. Sage 100 attend un import au format CSV avec un en-tete defini, Odoo accepte du JSON via son API REST. Programmez une exportation quotidienne via cron ou un workflow n8n auto-heberge.
Tenez un journal d extraction (timestamp, fichier source, hash, JSON sortie, statut validation) pour la tracabilite fiscale. En cas de controle, vous prouvez que le montant comptabilise correspond bien au PDF d origine. Pour explorer plus loin, consultez Claude Vision pour extraire des donnees d images et le guide automatiser la comptabilite d une PME africaine.
Etape 9 : surveiller couts et derives en production
Une fois le pipeline en exploitation, suivez deux indicateurs hebdomadaires : cout moyen par facture (en USD et en FCFA au taux 1 EUR = 655,957 FCFA) et taux de validation automatique. Si le cout grimpe, c’est souvent une derive de taille d image — verifiez la sortie de l etape 2. Si le taux de validation chute sous 90 pourcent, un nouveau modele de facture est apparu chez un fournisseur recurrent et merite un prompt few-shot dedie.
Conservez un echantillon de 50 factures de reference avec leur JSON attendu pour pouvoir lancer une regression a chaque mise a jour de modele Claude. La regression doit tourner en moins de cinq minutes et alerter sur Slack ou Discord en cas d ecart superieur a 2 pourcent par rapport a la baseline.