Lancer une étape individuellement

Le pipeline complet se lance d’un seul argo submit (voir l’accueil). Mais pour déboguer, relancer une étape échouée ou itérer sur une seule brique, on peut exécuter chaque étape isolément — soit via Argo, soit en local. Cette page rassemble les commandes vérifiées pour les deux modes.

ImportantToujours fournir run_id et run_date

Par défaut, run_id vaut le nom du workflow Argo et run_date sa date de création. Une étape relancée isolément crée donc un nouveau dossier S3 vide si on ne lui passe pas explicitement le run_id/run_date du run d’origine — et elle ne trouvera pas ses entrées. Récupérez-les depuis le nom du workflow d’origine (argo list) ou depuis le chemin S3 …/workflow_runs/{run_date}/{run_id}/.

Prérequis : secrets et variables d’environnement

Via Argo, les secrets sont injectés depuis secret-codif-coicop-bdf (cf. README.md). En local, il faut exporter soi-même les variables requises par l’étape :

Étape Variables d’environnement requises
preprocessing, codif-regex, codif-lcs, final-output AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_S3_ENDPOINT, AWS_ENDPOINT_URL
prune AWS_* + DDC_ENCRYPTION_KEY
create-vector-db, create-vector-db-annotations AWS_* + DDC_ENCRYPTION_KEY + LLMLAB_URL, LLMLAB_API_KEY + QDRANT_URL, QDRANT_API_KEY, QDRANT_API_PORT
run-rag, run-rag-annotations AWS_* + DDC_ENCRYPTION_KEY + LLMLAB_* + QDRANT_* + MLFLOW_TRACKING_URI, MLFLOW_TRACKING_USERNAME, MLFLOW_TRACKING_PASSWORD + LANGFUSE_BASE_URL, LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY
run-ttc AWS_* + MLFLOW_TRACKING_* (chargement du modèle depuis MLflow)
decide-coicop AWS_* + LLMLAB_API_KEY (+ LLMLAB_URL pour un endpoint non-OpenAI)
report AWS_* + MLFLOW_TRACKING_* (facultatif : sans MLFLOW_TRACKING_URI, le log MLflow est sauté)
sirus-predict AWS_* + MLFLOW_TRACKING_* (résolution de sirus-model-uri)
entraînement SIRUS (sirus/train.sh, hors pipeline) AWS_* + MLFLOW_TRACKING_*obligatoires ici, contrairement au report : le modèle et ses métriques n’ont pas d’autre destination, et le script refuse de démarrer sans MLFLOW_TRACKING_URI

Mode 1 — via Argo (--entrypoint)

Chaque étape est un template nommé dans argo/codif-pipeline.yaml. L’option --entrypoint lance ce template seul ; ses paramètres d’entrée sont résolus par nom depuis les -p passés en ligne de commande.

# Étapes simples : seuls run_id / run_date sont requis
argo submit argo/codif-pipeline.yaml --entrypoint codif-regex \
  -p run_id=codif-abc12 -p run_date=2026-03-20
argo submit argo/codif-pipeline.yaml --entrypoint codif-lcs \
  -p run_id=codif-abc12 -p run_date=2026-03-20
argo submit argo/codif-pipeline.yaml --entrypoint prune \
  -p run_id=codif-abc12 -p run_date=2026-03-20

# preprocessing : il faut aussi le fichier d'entrée et le mappage de colonnes
argo submit argo/codif-pipeline.yaml --entrypoint preprocessing \
  -p run_id=codif-abc12 -p run_date=2026-03-20 \
  -p input_file=s3://projet-budget-famille/data/workflow_inputs/mon_fichier.csv \
  -p text_column=NAT_DEP -p shop_column=MAG_DEP -p budget_column=MONT_DEP \
  -p annee_column= -p source_column=

# run-rag / run-rag-annotations : model-name est un argument du workflow
# (pas de sampling ici : il est centralisé à codif-regex)
argo submit argo/codif-pipeline.yaml --entrypoint run-rag \
  -p run_id=codif-abc12 -p run_date=2026-03-20 -p model-name=gemma4-26b-moe
argo submit argo/codif-pipeline.yaml --entrypoint run-rag-annotations \
  -p run_id=codif-abc12 -p run_date=2026-03-20 \
  -p model-name=gemma4-26b-moe -p sample-annotations=

# run-ttc : ttc-model-uri a une valeur par défaut, surchargeable
argo submit argo/codif-pipeline.yaml --entrypoint run-ttc \
  -p run_id=codif-abc12 -p run_date=2026-03-20

# final-output : reprend le mappage de colonnes pour restaurer les noms d'origine
argo submit argo/codif-pipeline.yaml --entrypoint final-output \
  -p run_id=codif-abc12 -p run_date=2026-03-20 \
  -p text_column=NAT_DEP -p shop_column=MAG_DEP -p budget_column=MONT_DEP -p annee_column=
AvertissementNoms d’inputs ≠ noms d’arguments du workflow

Deux templates déclarent des inputs dont le nom diffère des paramètres globaux du workflow. En --entrypoint, c’est le nom de l’input du template qu’il faut passer :

# decide-coicop : inputs "model" et "concurrency"
# (et non decide-model / decide-concurrency)
argo submit argo/codif-pipeline.yaml --entrypoint decide-coicop \
  -p run_id=codif-abc12 -p run_date=2026-03-20 \
  -p model=gemma4-26b-moe -p concurrency=5

# report : inputs "experiment-name" (et non report-experiment) et "step-timings"
argo submit argo/codif-pipeline.yaml --entrypoint report \
  -p run_id=codif-abc12 -p run_date=2026-03-20 \
  -p input_file= -p experiment-name=codif-coicop-eval \
  -p model-name= -p decide-model=gemma4-26b-moe \
  -p decide-concurrency=5 -p ttc-model-uri= -p skip-vector-db=true \
  -p skip-report=false -p step-timings='{}'

En cas de doute, valider avec argo submit --dry-run … avant de soumettre.

AstuceRelancer uniquement les étapes échouées

Plutôt que de relancer étape par étape, argo retry <nom-du-workflow> reprend le DAG d’origine là où il a échoué, avec les mêmes paramètres (donc le même run_id).

Mode 2 — en local

Chaque sous-dossier est autonome (pyproject.toml + uv.lock). Les commandes ci-dessous sont celles exécutées par les conteneurs Argo, à lancer depuis la racine du dépôt après avoir exporté les variables d’environnement du tableau ci-dessus.

RUN_ID=codif-abc12
RUN_DATE=2026-03-20
RUN_ROOT="s3://projet-budget-famille/data/workflow_runs/$RUN_DATE/$RUN_ID"

1. preprocessing

cd preprocessing && uv sync
uv run main.py --run-id $RUN_ID --run-date $RUN_DATE \
  --input-file s3://projet-budget-famille/data/workflow_inputs/mon_fichier.csv \
  --text-column NAT_DEP --shop-column MAG_DEP --budget-column MONT_DEP

2. codif-regex

cd regex-codif && uv sync
uv run src/main.py --run-id $RUN_ID --run-date $RUN_DATE

3. codif-lcs (R)

cd stats-annotations
Rscript R/main.R --run-id=$RUN_ID --run-date=$RUN_DATE
Note

Le parsing des options de R/main.R impose la syntaxe --option=valeur (signe =, pas d’espace).

4. prune (depuis prune/)

cd prune && uv sync
uv run scripts/main.py --config config/config.yaml \
  --run-id $RUN_ID --run-date $RUN_DATE

Produit les 5 artefacts prunés sous $RUN_ROOT/prune/ (voir 3. Prune). À lancer avant les étapes RAG.

5. Branche RAG notices (depuis coicop-rag/)

cd coicop-rag && uv sync

# Partagé entre runs — à ne refaire que si la nomenclature prunée a changé :
uv run scripts/0_create_vector_db.py --config config/config.yaml \
  --run-id $RUN_ID --run-date $RUN_DATE

# Propre au run :
uv run scripts/2_run_rag.py --config config/config.yaml \
  --run-id $RUN_ID --run-date $RUN_DATE \
  --model_name gemma4-26b-moe   # facultatif
Note

Attention au mélange de styles : les scripts attendent --run-id/--run-date (tirets) mais --model_name/--sample_size (tirets bas).

6. Branche RAG annotations (depuis coicop-rag-annotations/)

cd coicop-rag-annotations && uv sync

# Partagé entre runs — indexe la KB prunée + le suggester dans Qdrant :
uv run scripts/0_build_annotation_vector_db.py --config config/config.yaml \
  --run-id $RUN_ID --run-date $RUN_DATE

# Propre au run — --skip-eval false = mode évaluation (métriques),
# --skip-eval true = mode production (prédictions seules) :
uv run scripts/1_run_rag.py --config config/config.yaml \
  --run-id $RUN_ID --run-date $RUN_DATE --skip-eval false

Sortie : $RUN_ROOT/rag-annotation/predictions.parquet (le dossier s’appelle rag-annotation, pas run-rag-annotations).

7. run-ttc (depuis codif-ttc/)

cd codif-ttc && uv sync
uv run main.py predict-basic \
  --model "mlflow-artifacts:/10/cacf2603514b4887bbfb77e2654c9bc1/artifacts/model" \
  --file   "$RUN_ROOT/codif-regex/raw_test_without_regex.parquet" \
  --output "$RUN_ROOT/run-ttc/predictions.parquet" \
  --text-column l_pr_product --top-k 10

L’URI du modèle est le paramètre de workflow ttc-model-uri (cf. argo/codif-pipeline.yaml).

8. decide-coicop

cd decide-coicop && uv sync
uv run main.py decide-coicop \
  --lcs-file "$RUN_ROOT/codif-lcs/raw_test_LCS.parquet" \
  --rag-file "$RUN_ROOT/run-rag/predictions.parquet" \
  --rag-annotations-file "$RUN_ROOT/rag-annotation/predictions.parquet" \
  --ttc-file "$RUN_ROOT/run-ttc/predictions.parquet" \
  --mapping-file "$RUN_ROOT/prune/mapping_lvl4.parquet" \
  --output-file "$RUN_ROOT/decide-coicop/predictions.parquet" \
  --extra-columns-file "$RUN_ROOT/preprocessing/raw_test.parquet" \
  --model gemma4-26b-moe --concurrency 5

En mode production, remplacer --extra-columns-file par "$RUN_ROOT/preprocessing/observations.parquet". Sans --mapping-file, les codes ne sont pas normalisés (troncature + élagage) — le pipeline Argo le passe toujours.

Si --output-file existe déjà, l’étape reprend automatiquement les observations non traitées (checkpoint toutes les 50 observations) — relancer la même commande suffit après une interruption.

Pour déboguer une seule observation (affiche le prompt et la décision, n’écrit rien) :

uv run main.py decide-coicop --id <uuid-de-la-ligne> --output json \
  --model gemma4-26b-moe \
  --lcs-file "$RUN_ROOT/codif-lcs/raw_test_LCS.parquet" \
  --rag-file "$RUN_ROOT/run-rag/predictions.parquet" \
  --rag-annotations-file "$RUN_ROOT/rag-annotation/predictions.parquet" \
  --ttc-file "$RUN_ROOT/run-ttc/predictions.parquet" \
  --mapping-file "$RUN_ROOT/prune/mapping_lvl4.parquet"

8bis. sirus-predict (depuis sirus/)

Alternative au juge LLM (cf. 8bis. SIRUS) : ne tourne dans le pipeline que si conciliation: sirus. Python pur, aucun besoin de R.

cd sirus && uv sync
uv run main.py predict \
  --lcs-file "$RUN_ROOT/codif-lcs/raw_test_LCS.parquet" \
  --rag-file "$RUN_ROOT/run-rag/predictions.parquet" \
  --rag-annotations-file "$RUN_ROOT/rag-annotation/predictions.parquet" \
  --ttc-file "$RUN_ROOT/run-ttc/predictions.parquet" \
  --mapping-file "$RUN_ROOT/prune/mapping_lvl4.parquet" \
  --tocodify-file "$RUN_ROOT/codif-regex/raw_test_without_regex.parquet" \
  --extra-columns-file "$RUN_ROOT/preprocessing/raw_test.parquet" \
  --model-uri "mlflow-artifacts:/12/9f3c.../artifacts/model" \
  --output-file "$RUN_ROOT/sirus-predict/predictions.parquet"

En mode production, remplacer --extra-columns-file par "$RUN_ROOT/preprocessing/observations.parquet". L’URI du modèle est le paramètre de workflow sirus-model-uri ; un chemin local vers un dossier contenant rules.json est aussi accepté, ce qui permet de tester sans MLflow.

9. final-output

cd final-output && uv sync
uv run main.py --run-id $RUN_ID --run-date $RUN_DATE \
  --input-file s3://projet-budget-famille/data/workflow_inputs/mon_fichier.csv \
  --text-column NAT_DEP --shop-column MAG_DEP --budget-column MONT_DEP

(--input-file en mode production seulement : il sélectionne observations.parquet comme base et restaure le nom du fichier livré.)

10. report

cd report && uv sync
uv run main.py --run-id $RUN_ID --run-date $RUN_DATE \
  --experiment-name codif-coicop-eval

Le mode (évaluation ou prédiction) est détecté automatiquement (voir 8. Report). Sans MLFLOW_TRACKING_URI, le log MLflow est simplement sauté.

Entraîner le modèle SIRUS (hors pipeline)

L’entraînement n’est pas une étape du pipeline : il produit un modèle destiné à un run futur, et sirus-model-uri doit être connue au argo submit. Il se lance donc à la main, comme celui de TTC, sur un run d’évaluation passé — un run de production ne porte pas la vérité terrain dont l’ajustement a besoin.

cd sirus/
./train.sh 2026-06-29/codif-vvkv9

Réglages optionnels, par variables d’environnement (les défauts conviennent dans la quasi-totalité des cas) : NUM_RULE, MAX_DEPTH, SEED, EXPERIMENT.

Le script enchaîne trois étapes : construction de la table candidat-level en Python, ajustement en R, mesures et log MLflow en Python. Il vérifie au préalable que MLFLOW_TRACKING_URI est définie — seul échec qui n’arriverait qu’au dernier pas, après plusieurs minutes d’ajustement. La première exécution compile le paquet sirus depuis la source d’archive CRAN (~1 min 30) : il a été archivé et n’existe plus en binaire.

Il termine en affichant l’URI à recopier dans argo/params.yaml :

Modèle SIRUS loggué. Pour l'utiliser, mettre dans argo/params.yaml :
    sirus-model-uri: mlflow-artifacts:/12/9f3c.../artifacts/model
Astuce

Les artefacts restent dans --artifacts-dir. Si le log MLflow échoue (réseau, URI mal réglée), relancer la 3ᵉ étape seule suffit — inutile de réajuster le modèle :

uv run main.py finalize --artifacts-dir artifacts/codif-vvkv9 \
  --experiment codif-coicop-sirus --run-id codif-vvkv9 --run-date 2026-06-29

Déboguer un run

Logs des étapes. Chaque étape tourne dans son pod :

argo list                          # retrouver le workflow
argo get  <nom-du-workflow>        # statut du DAG, étape par étape
argo logs <nom-du-workflow>        # logs agrégés (ou --container main, -f pour suivre)

Inspecter les fichiers intermédiaires sur S3. Toutes les sorties d’étapes sont des parquet sous $RUN_ROOT/<étape>/. DuckDB permet de les interroger directement :

import duckdb, os
con = duckdb.connect()
con.execute(f"""
    CREATE SECRET (TYPE S3,
        KEY_ID '{os.environ["AWS_ACCESS_KEY_ID"]}',
        SECRET '{os.environ["AWS_SECRET_ACCESS_KEY"]}',
        SESSION_TOKEN '{os.environ["AWS_SESSION_TOKEN"]}',
        ENDPOINT '{os.environ["AWS_S3_ENDPOINT"]}',
        URL_STYLE 'path');
""")
con.sql(f"SELECT * FROM read_parquet('{RUN_ROOT}/decide-coicop/predictions.parquet') LIMIT 10")

Comprendre un code manquant. Dans le fichier livré, predicted_code vide signifie « ni regex, ni LLM ». La raison de l’échec LLM est dans la colonne llm_error de $RUN_ROOT/decide-coicop/predictions.parquet (cf. 8. Decide).

Tracer les appels LLM. Les appels de run-rag et run-rag-annotations sont tracés dans Langfuse (prompt, réponse, latence par produit). Les métriques de chaque branche RAG vont dans MLflow (expériences test et rag-annotation), et les paramètres/métriques du run complet dans l’expérience codif-coicop-eval via l’étape report, avec le report.html en artefact.


Retour à l’accueil