Ce que vous saurez faire
- Assistant juridique OHADA avec RAG
- Parser les Actes uniformes
- Obliger citation d’articles
- Déployer Streamlit
Étape 1 — Stack
Ingestion: PyMuPDF + Tesseract OCR (textes scannés)
Chunking: par article OHADA
Embeddings: voyage-3
Vector DB: ChromaDB
Reranker: cohere rerank-multilingual-v3.0
LLM: Claude Sonnet 4.6 (citations fiables)
Étape 2 — Parser OHADA
import pymupdf, re
from pathlib import Path
def parser_ohada(pdf_path):
doc = pymupdf.open(pdf_path)
texte = "\n".join(p.get_text() for p in doc)
articles = re.split(r'(Article\s+\d+\s*(?:bis|ter)?\s*\.?-?)', texte)
chunks = []
for i in range(1, len(articles)-1, 2):
num = articles[i].strip()
contenu = articles[i+1].strip()
if len(contenu) < 10: continue
chunks.append({
"texte": f"{num} {contenu}",
"metadata": {"source": Path(pdf_path).stem, "article": num,
"acte": "OHADA"}})
return chunks
Étape 3 — Indexation Chroma
import chromadb, voyageai
vo = voyageai.Client()
chroma = chromadb.PersistentClient(path="./chroma_ohada")
coll = chroma.get_or_create_collection("ohada")
for pdf in Path("./textes_ohada").glob("*.pdf"):
chunks = parser_ohada(str(pdf))
texts = [c["texte"] for c in chunks]
embs = vo.embed(texts, model="voyage-3", input_type="document").embeddings
coll.add(
documents=texts, embeddings=embs,
metadatas=[c["metadata"] for c in chunks],
ids=[f"{c['metadata']['source']}-{c['metadata']['article']}-{i}"
for i,c in enumerate(chunks)])
Étape 4 — Retrieval + reranking
import cohere
co = cohere.Client()
def recherche(question, k_retrieve=20, k_final=6):
q_emb = vo.embed([question], model="voyage-3", input_type="query").embeddings[0]
res = coll.query(query_embeddings=[q_emb], n_results=k_retrieve)
docs = res["documents"][0]
metas = res["metadatas"][0]
rerank = co.rerank(model="rerank-multilingual-v3.0",
query=question, documents=docs, top_n=k_final)
return [{"texte":docs[r.index], "meta":metas[r.index], "score":r.relevance_score}
for r in rerank.results]
Étape 5 — LLM avec citations obligatoires
from anthropic import Anthropic
claude = Anthropic()
SYSTEM = """Tu es un assistant juridique OHADA.
Règles strictes:
1. Cite chaque affirmation avec [acte, article]
2. Si info absente: "Information non disponible dans les textes fournis"
3. Aucune interprétation: reste factuel
4. Ton formel juridique français
5. Si question hors OHADA: refuser"""
def repondre(question):
chunks = recherche(question)
contexte = "\n\n".join(f"[{c['meta']['acte']}, {c['meta']['article']}]\n{c['texte']}"
for c in chunks)
r = claude.messages.create(
model="claude-sonnet-4-6", max_tokens=1500,
system=[{"type":"text","text":SYSTEM,"cache_control":{"type":"ephemeral"}}],
messages=[{"role":"user","content":
f"Extraits:\n{contexte}\n\nQuestion: {question}"}])
return r.content[0].text, [c["meta"] for c in chunks]
Étape 6 — Interface Streamlit
import streamlit as st
st.title("Assistant OHADA")
if "hist" not in st.session_state: st.session_state.hist = []
q = st.chat_input("Question juridique...")
if q:
with st.spinner("Recherche..."):
rep, sources = repondre(q)
st.session_state.hist.append({"role":"user","content":q})
st.session_state.hist.append({"role":"assistant","content":rep,"sources":sources})
for m in st.session_state.hist:
with st.chat_message(m["role"]):
st.write(m["content"])
if m.get("sources"):
with st.expander("Sources"):
for s in m["sources"]:
st.caption(f"- {s['acte']} {s['article']}")
Étape 7 — Garde-fous
AVERTISSEMENT = """⚠ Assistant pédagogique basé sur textes OHADA publiés.
Ne remplace pas un avocat/notaire pour décisions contractuelles."""
INTERDITS = ["rédaction contrat", "conseil personnalisé", "défense judiciaire"]
def garde_fou(q, r):
if any(x in q.lower() for x in INTERDITS):
return r + "\n\n⚠ Pour ces cas, consultez un juriste."
return r
Étape 8 — Évaluation
from ragas import evaluate
from ragas.metrics import faithfulness, context_precision
result = evaluate(dataset, metrics=[faithfulness, context_precision])
# Seuil: faithfulness >= 0.90 (citations correctes)
Étape 9 — Déploiement
fly launch
fly secrets set ANTHROPIC_API_KEY=... VOYAGE_API_KEY=... COHERE_API_KEY=...
fly deploy
Coûts 100 questions/jour
Embeddings indexation: 0,5 USD one-off
Reranking: 0,50 USD/mois
Claude Sonnet avec cache: 5-7 USD/mois
Chroma + Streamlit: gratuit
Total: ~15 USD/mois (9k FCFA)
Besoin d'un site web ?
Confiez-nous la Création de Votre Site Web
Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.
À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité