Pipeline d'orchestration pour la codification automatique des produits de l'enquête Budget de Famille (BDF) selon la nomenclature COICOP.
Le pipeline est orchestré via Argo Workflows (argo/pipeline.yaml) selon le DAG suivant :
┌──→ prune-coicop ──→ create-vector-db ─────────────┐ (skippable)
preprocessing ──┤ ├──→ run-rag ─┐
└──→ codif-regex ──→ prune-annotations ─────────────┘ │
├──→ codif-lcs ─────────────────────────────────────┼──→ decide-coicop ──→ report (opt-in)
└──→ run-ttc ──────────────────────────────────────┘
Construit le dataset d'annotations à partir des sources brutes (COPAIN, historique, suggester).
- Code dans
preprocessing/(ex-repoconstruction-dataset) - Exporte le dataset consolidé sur S3
Élague les hiérarchies linéaires de la nomenclature COICOP brute.
- Code dans
coicop-rag/(scripts/0_prunning_coicop.py) - Supprime le niveau 5 (Poste) de la nomenclature
- Produit les notices prunées et la table de mapping niveau 4 sur S3
Encode les notices COICOP dans une base vectorielle Qdrant.
- Code dans
coicop-rag/(scripts/0_create_vector_db.py) - Génère les embeddings via le modèle VLLM (
VLLM_EMBEDDING_URL) - Indexe les vecteurs dans Qdrant (
QDRANT_URL)
Tronque les codes d'annotation au niveau 4 et normalise les codes de vérité terrain via la table de mapping COICOP.
- Code dans
coicop-rag/(scripts/1_prune_annotations.py)
Codification des libellés produits par approche regex.
- Code dans
regex-codif/(ex-reporegex_codif)
Codification des libellés produits par approche LCS (Longest Common Subsequence) en R.
- Code dans
stats-annotations/
Classifie les annotations via un pipeline RAG (Retrieval-Augmented Generation).
- Code dans
coicop-rag/(scripts/2_run_rag.py) - Récupère les contextes pertinents depuis Qdrant
- Génère les codes COICOP via le modèle VLLM (
VLLM_GENERATION_URL) - Enregistre les métriques dans MLflow (
MLFLOW_TRACKING_URI) - Trace les expériences dans Langfuse (
LANGFUSE_BASE_URL)
Prédictions TTC via un classifieur pré-entraîné.
- Code dans
coicop-bdf-classifier/(ex-repocoicop_bdf_classifier, bientôt archivé en amont) - L'étape argo utilise actuellement l'image pré-construite
ghcr.io/micedre/coicop_bdf_classifier:latest - Étape destinée à être supprimée à terme
Arbitrage final des prédictions par un LLM-as-judge : fusionne les sorties de codif-lcs, run-rag et run-ttc et sélectionne le meilleur code COICOP par observation.
- Code dans
coicop-bdf-classifier/(sous-commandeuv run main.py decide-coicop) - Entrées :
s3://.../codif-lcs/raw_test_LCS.parquets3://.../run-rag/predictions.parquets3://.../run-ttc/predictions.parquet
- Sortie :
s3://.../decide-coicop/predictions.parquet - Utilise un endpoint OpenAI-compatible (
LLMLAB_API_KEY, optionnellementLLMLAB_URLpour un backend non-OpenAI) - Court-circuit consensus : si les trois sources convergent (et que la confiance TTC ≥ 0.90), aucune requête LLM n'est émise
- Filtrage de nomenclature : seules les sections COICOP pertinentes sont envoyées au prompt (réduction ×4–10 du nombre de tokens)
- Reprise automatique : relancer l'étape avec le même
run_id/run_datereprend les observations non traitées depuis le fichier de sortie existant
Rapport d'exactitude Quarto (HTML auto-contenu) sur la sortie de decide-coicop.
- Code dans
report/— Quarto + Python (pandas, duckdb, matplotlib, seaborn) - Déclenché par
skip-report=false; désactivé par défaut - Entrée :
s3://.../decide-coicop/predictions.parquet - Sortie :
s3://.../report/report.html - Contenu :
- Accuracy globale par niveau COICOP (1 à 5) pour LCS, RAG, TTC, LLM
- Accuracy par
shop,shop_type_nameet quartile debudget - Matrice de confusion (top 20 paires
codevsllm_codeau niveau 4) - Calibration : accuracy par bucket de
llm_confiance - Consensus vs désaccord des sources amont : apport de l'arbitrage LLM
- Méthodologie accuracy par niveau : tronquer
codeet la prédiction auxkpremiers segments ; les observations dont la vérité a moins dekniveaux sont exclues du dénominateur à ce niveau
Ce dépôt rassemble le code de toutes les étapes du pipeline, auparavant dispersé dans plusieurs repos.
| Dossier | Origine | Rôle |
|---|---|---|
argo/ |
— | Workflows Argo (pipeline.yaml, ttc-pipeline.yaml, rbac.yaml) |
preprocessing/ |
construction-dataset |
Étape preprocessing |
regex-codif/ |
regex_codif |
Étape codif-regex |
coicop-rag/ |
coicop-rag |
Étapes prune-coicop, prune-annotations, create-vector-db, run-rag |
stats-annotations/ |
stats-annotations |
Étape codif-lcs (R) |
coicop-bdf-classifier/ |
coicop_bdf_classifier |
Classifieur TTC (source vendorisée, image pré-construite encore utilisée par run-ttc) |
report/ |
— | Rapport Quarto d'exactitude (étape report, opt-in) |
Chaque sous-dossier Python conserve son propre pyproject.toml / uv.lock et peut être développé et exécuté indépendamment.
Le secret Kubernetes secret-codif-coicop-bdf doit exister dans le namespace et contenir les clés suivantes :
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN,
AWS_S3_ENDPOINT, AWS_ENDPOINT_URL,
VLLM_EMBEDDING_URL, VLLM_EMBEDDING_API_KEY,
VLLM_GENERATION_URL, VLLM_GENERATION_API_KEY,
QDRANT_URL, QDRANT_API_KEY, QDRANT_API_PORT,
LANGFUSE_BASE_URL, LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY,
MLFLOW_TRACKING_URI, MLFLOW_TRACKING_USERNAME, MLFLOW_TRACKING_PASSWORD,
OLLAMA_URL, OLLAMA_API_KEY,
DDC_ENCRYPTION_KEY,
LLMLAB_API_KEY, LLMLAB_URL # requis pour decide-coicop (LLMLAB_URL optionnel)
# Pipeline complet
argo submit argo/pipeline.yaml
# Limiter à N annotations (utile pour tester)
argo submit argo/pipeline.yaml -p sample_size=100
# Utiliser un modèle spécifique pour run-rag
argo submit argo/pipeline.yaml -p model-name=openai/gpt-oss-120b
# Sauter la construction de la vector DB (si déjà construite)
argo submit argo/pipeline.yaml -p skip-vector-db=true
# Combinaison de paramètres
argo submit argo/pipeline.yaml -p skip-vector-db=true -p sample_size=100
# Activer le rapport d'exactitude (désactivé par défaut)
argo submit argo/pipeline.yaml -p skip-report=falsepython3 -c "
import sys, yaml
with open('argo/pipeline.yaml') as f:
w = yaml.safe_load(f)
# Modifier les paramètres souhaités, ex:
for p in w['spec']['arguments']['parameters']:
if p['name'] == 'skip-vector-db':
p['value'] = 'true'
if p['name'] == 'sample_size':
p['value'] = '100'
print(yaml.dump(w, default_flow_style=False))
" | kubectl create -f -| Paramètre | Défaut | Description |
|---|---|---|
sample_size |
(vide) | Nombre d'annotations à traiter (toutes si vide) |
model-name |
(vide) | Modèle LLM à utiliser pour run-rag (défaut du config si vide) |
skip-vector-db |
false |
Si true, saute prune-coicop et create-vector-db |
decide-model |
gemma4-26b-moe |
Modèle LLM utilisé par decide-coicop (vide → défaut gpt-4o de la commande) |
decide-concurrency |
5 |
Nombre d'appels LLM parallèles de decide-coicop |
skip-report |
true |
Si false, génère le rapport Quarto d'exactitude après decide-coicop |