Intelligence Artificielle

Assistant juridique OHADA avec Claude et RAG

12 دقائق للقراءة

Ce que vous saurez faire

  1. Assistant juridique OHADA avec RAG
  2. Parser les Actes uniformes
  3. Obliger citation d’articles
  4. Déployer Streamlit

Vue d’ensemble 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)

Vue d’ensemble 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

Vue d’ensemble 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)])

Vue d’ensemble 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]

Vue d’ensemble 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]

Vue d’ensemble 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']}")

Vue d’ensemble 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

Vue d’ensemble 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)

Vue d’ensemble 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)

Étape 1 — Cadrer le périmètre légal et éthique

Avant la première ligne de code, posez les limites. Un assistant juridique OHADA n’est pas un avocat. Il oriente, cite les actes uniformes pertinents, propose des modèles de clauses — il ne rend pas d’avis engageant. Toute interface utilisateur doit afficher cette mention en clair, et chaque réponse du modèle doit être citable et vérifiable.

Périmètre couvert : les 9 actes uniformes en vigueur de l’OHADA — Droit commercial général, Sociétés commerciales et GIE, Sûretés, Procédures collectives, Voies d’exécution, Arbitrage, Droit comptable, Transport de marchandises par route, Sociétés coopératives. Tous les textes sont publics sur ohada.org.

Périmètre exclu : conseil patrimonial impliquant des prêts à intérêts (riba) — l’assistant doit rediriger vers un montage mourabaha via une banque islamique (BIS au Sénégal, BIIC au Bénin) lorsque l’utilisateur mentionne un crédit. C’est une règle de produit, pas un filtre cosmétique.

Étape 2 — Récupérer et nettoyer les actes uniformes

Téléchargez les 9 PDF officiels depuis ohada.org/index.php/fr/actes-uniformes. Les versions consolidées sont nommées « Acte uniforme révisé portant sur … ». Vérifiez la date de dernière révision en première page — ne travaillez jamais sur une version pré-2010 pour le DCG ou pré-2014 pour les sociétés commerciales.

Convertissez en texte avec pdftotext (paquet poppler-utils) :

mkdir -p ohada/raw ohada/clean
cd ohada/raw
for f in *.pdf; do
  pdftotext -layout "$f" "../clean/${f%.pdf}.txt"
done

Ce que vous devez voir : 9 fichiers .txt totalisant 600-900 ko. Inspectez visuellement les premiers et derniers articles de chaque acte pour vérifier qu’aucun texte n’a été tronqué.

Étape 3 — Découper en chunks par article

Le découpage naïf en blocs de 500 tokens casse la cohérence juridique. Le bon découpage colle à la structure : un chunk = un article (Article 1, Article 2, etc.) avec son préambule de section. La regex Python utilisée est r"\nArticle\s+(\d+)" avec drapeau IGNORECASE, qui détecte les en-têtes d’article quel que soit le formatage.

Pour chaque match, on extrait le texte jusqu’au prochain match, on stocke source+article+content dans une liste de dictionnaires, et on sérialise en JSON. Test concluant : entre 1 800 et 2 500 chunks pour l’ensemble des 9 actes. Si vous obtenez moins de 1 000 chunks, la regex n’a pas matché — vérifiez l’encodage du texte source.

Étape 4 — Indexer dans Pinecone avec Voyage AI embeddings

Pinecone Starter (gratuit jusqu’à 1 index) suffit largement pour 2 500 vecteurs. Voyage AI fournit des embeddings voyage-3-large (1024 dimensions) performants en français juridique et est partenaire officiel d’Anthropic.

pip install pinecone-client voyageai anthropic

Créez l’index avec dimension 1024 et metric cosine, en région aws us-east-1 (gratuite sur Starter). Puis itérez sur les chunks par batches de 32, calculez l’embedding via vo.embed(texts, model='voyage-3-large', input_type='document'), et upsertez dans Pinecone avec un ID composite source-article et les métadonnées.

Sortie de référence : la console Pinecone (app.pinecone.io) affiche ~2 000 vecteurs dans l’index ohada-rag. Coût d’indexation Voyage : ~0,12 USD pour l’ensemble.

Étape 5 — Construire la chaîne RAG avec Claude Opus

La logique : recevoir la question, la convertir en embedding via Voyage AI, retrouver les 5 articles OHADA les plus proches via Pinecone query, injecter dans un prompt système strict, appeler Claude Opus 4.7.

Le prompt système doit imposer : (1) répondre uniquement à partir des extraits fournis, (2) citer chaque affirmation avec [Source : nom_acte, art. N], (3) refuser et rediriger si la question dépasse les 9 actes, (4) ajouter un disclaimer mourabaha pour toute mention de crédit, (5) clore systématiquement par « Information générale, non substituable à un conseil juridique ».

msg = client.messages.create(
    model='claude-opus-4-7',
    max_tokens=1500,
    system=SYSTEM,
    messages=[{'role': 'user', 'content': prompt}]
)

Test concluant : la réponse mentionne explicitement l’AU-Sociétés et un numéro d’article, et se termine par le disclaimer.

Étape 6 — Interface Streamlit pour l’équipe juridique

Une équipe juridique à Cotonou ou à Conakry n’utilisera pas un script Python en ligne de commande. Streamlit (streamlit.io, gratuit) permet une interface web en 30 lignes hébergeable sur Streamlit Community Cloud avec authentification SSO.

import streamlit as st
from rag import ask

st.set_page_config(page_title='Assistant OHADA', page_icon='⚖️')
st.title('Assistant juridique OHADA')
st.warning('Information générale, non substituable à un conseil d\'avocat.')

q = st.text_area('Votre question juridique :', height=100)
if st.button('Interroger') and q:
    with st.spinner('Recherche...'):
        rep = ask(q)
    st.markdown(rep)

Résultat type : interface accessible à l’équipe en moins de 5 minutes via streamlit run app.py. Pour la production, hébergez sur Streamlit Cloud avec authentification Google ou Microsoft, jamais en accès anonyme — la facturation Anthropic exploserait au premier scraper venu.

Étape 7 — Évaluer et boucler la qualité

Constituez une grille de 30-50 questions de référence avec les bonnes réponses validées par un juriste OHADA (durée mandat administrateur SA, formes de sûretés réelles, délai opposition à un commandement de payer). Pour chaque question, mesurez : (a) Claude cite-t-il l’acte et l’article corrects ? (b) la réponse est-elle juridiquement exacte ? (c) le disclaimer est-il présent ?

Visez ≥ 90 % sur les trois critères avant déploiement réel. Si le score plafonne à 70-80 %, le problème vient en général du chunking (étape 3) — testez un découpage par section + article au lieu d’article seul. Pour creuser ce sujet, voyez notre tutoriel OSINT défensif et suivi de contrats Excel.

Evaluer le taux d’hallucination du RAG juridique sur un set de questions reference

Un assistant RAG sur les actes uniformes OHADA n’a de valeur que s’il restitue des informations exactes, sourcees et complètes. La methode professionnelle d’evaluation tient en quatre etapes : constituer un set de 50 a 100 questions juridiques realistes (recouvrement, baux, surete, societes), faire repondre l’assistant, faire valider chaque reponse par un avocat OHADA experimente, puis calculer trois indicateurs cles : taux de reponses correctes, taux de citations sources verifiables, taux d’hallucinations (informations inventees ou attribuees a tort).

Visez un taux de reponses correctes superieur a 85 pour cent et un taux d’hallucinations inferieur a 5 pour cent avant toute mise en production. Documentez chaque cas d’echec dans un journal des erreurs avec la cause racine probable : chunk mal segmente, embeddings de mauvaise qualite, prompt insuffisamment cadre, modele trop creatif. Ce journal devient la roadmap d’amelioration continue du systeme.

Repetez cette evaluation a chaque modification majeure (changement de modele, modification du chunking, ajustement du prompt) pour eviter les regressions silencieuses. Une regression de 2 a 3 points sur le taux de reponses correctes peut passer inapercu en utilisation quotidienne mais miner serieusement la confiance des utilisateurs sur la duree.

Monitorer la consommation et le cout API Anthropic en production

Un assistant RAG en production consomme des tokens a chaque requete utilisateur, et le cout peut deriver rapidement si le monitoring est neglige. La console Anthropic expose un tableau de bord avec la consommation horaire, journaliere et mensuelle ventilee par cle API. Configurez des alertes a 50 pour cent, 80 pour cent et 100 pour cent du budget mensuel prevu, avec notification sur le canal Slack ou la boite mail de l’equipe technique. Cette discipline previent la mauvaise surprise en fin de mois.

Au-dela du cout brut, suivez le cout par requete utilisateur en divisant le total mensuel par le nombre de requetes traitees. Un cout par requete superieur a 0,15 USD signale generalement un prompt systeme trop long, un nombre de chunks de contexte excessif, ou un modele plus puissant que necessaire pour la tache. L’optimisation de ces trois leviers permet typiquement de reduire le cout par requete de 30 a 50 pour cent sans degradation de la qualite.

Activez le cache de prompt pour les sections systeme stables (consignes, exemples) qui se repetent a chaque requete. Le cache reduit le cout des tokens d’entree d’un facteur 10 sur les portions cachees, ce qui change radicalement l’economie d’un assistant a fort volume.

Gerer les versions du systeme RAG sans casser la production

Un assistant RAG evolue continuellement : nouveaux documents ajoutes, prompts ajustes, modele bascule vers une version plus recente. Sans gestion de versions disciplinee, ces modifications produisent rapidement un systeme dont personne ne sait plus exactement comment il se comporte. La parade tient en trois pratiques : tagger chaque mise en production avec un numero semver (par exemple v1.4.2), conserver dans un depot Git le triplet prompt-systeme + parametres modele + corpus de documents, et maintenir un changelog clair par version.

Avant de basculer une nouvelle version en production, executez l’evaluation sur le set de questions reference et comparez aux versions precedentes. Si le taux de reponses correctes baisse, ne deployez pas et identifiez la cause racine. Pour les modifications du corpus (ajout d’un nouvel acte uniforme, par exemple), documentez precisement la date d’ajout et le perimetre couvert pour pouvoir reproduire les conditions d’une reponse passee si un litige surgit. Voir notre tutoriel Git et GitHub pour structurer ce versionnage.

Encadrer juridiquement la responsabilite de l’assistant face aux utilisateurs

Un assistant juridique OHADA, meme excellent, ne remplace pas la consultation d’un avocat. Cette nuance doit etre rendue explicite dans l’interface utilisateur : avertissement clair en pied de chaque reponse precisant que l’assistant est un outil d’orientation et que toute decision engageante necessite la validation d’un professionnel du droit. Ce cadrage protege le cabinet ou la fintech qui exploite l’assistant et evite les contentieux lies a des conseils mal interpretes.

Conservez les conditions generales d’utilisation a jour, validees par un avocat, et faites accepter ces CGU a chaque nouvel utilisateur. Pour les usages professionnels, prevoyez aussi des conditions specifiques (B2B) signees par les structures clientes qui delimitent precisement le perimetre d’usage et la repartition de responsabilite.

Documentez la procedure de signalement : un utilisateur qui detecte une reponse manifestement erronee doit pouvoir le signaler en deux clics. Tracez chaque signalement, traitez-le sous 48 heures et utilisez ces retours pour enrichir le journal des erreurs et orienter les ameliorations du systeme.

Articles connexes Claude

مشاركة