Aller au contenu
Chandler Nguyen
IA11 min de lecture

J'ai évalué 40 podcasts IA dans 7 langues. Six corrections de pipeline plus tard — voici ce qui s'est amélioré.

J'ai construit un framework d'évaluation pour noter mon pipeline de podcasts IA sur 40 épisodes réels dans 7 langues. L'étape de révision aggravait les scripts (3.34 → 2.91). Toutes les URLs de citation semblaient fausses (score : 1.28). Le chinois était la langue la plus faible (2.88). Six corrections, une journée et un nouveau modèle plus tard — voici les chiffres avant/après et chaque changement que j'ai apporté.

Le mois dernier, j'ai livré un changement de pipeline dont j'étais vraiment fier. Une réécriture de prompt. Une étape de révision en contexte complet. Une grille détaillée pour détecter les répétitions et imposer une variété structurelle entre les segments.

Je l'ai déployé. Observé pendant six semaines. Je me suis dit que ça marchait.

Puis j'ai construit un framework d'évaluation. Je l'ai fait tourner sur 40 vrais épisodes de production dans 7 langues. Et j'ai découvert que l'étape de révision — celle que j'avais conçue avec tant de soin — rendait les scripts mesurablement moins bons.

Pas neutre. Pire.

Le dialogue par segment a obtenu 3,34 sur 5. Le plan a obtenu 3,01. Et le script final, après la révision ? 2,91.

L'étape conçue pour améliorer les scripts réduisait la qualité de plus de 12 %.

Ce basculement — de « je pense que ça marche » à « je sais que non » — a commencé il y a quelques semaines. Je regardais le cours d'Andrew Ng sur l'IA agentique sur DeepLearning.AI, où il insiste sur quelque chose qui paraît évident mais ne l'est pas : les évaluations et les traces sont le fondement de tout système agentique. Sans elles, vous débuggez dans le noir. Avec elles, vous savez exactement quel maillon de la chaîne a cédé.

Je faisais des vérifications de qualité ad-hoc depuis des mois — des métriques structurelles comme les ratios de tours de parole et l'équilibre des intervenants, plus un juge LLM comparant des variantes A/B de prompts. Elles détectaient les régressions évidentes. Mais elles n'étaient pas exhaustives. Elles couvraient une seule étape (le dialogue), une langue à la fois, et étaient conçues pour des tests A/B de prompts, pas pour des audits de qualité à l'échelle du pipeline.

La remarque d'Andrew sur les traces m'a percuté. Mon pipeline compte cinq appels LLM majeurs par épisode — recherche, plan, dialogue par segment, intro/outro et révision — plus une passe TTS ElevenLabs. J'avais des métriques de qualité pour un seul. Les quatre autres, je leur faisais confiance à l'instinct.

Alors j'ai construit un vrai système d'évaluation. Complet. Multidimensionnel. Ré-exécutable. Voici ce qu'il a trouvé, les six corrections que j'ai livrées en une journée, et ce qui s'est vraiment amélioré.


La baseline : trois chiffres qui ont tout changé

J'ai évalué 40 épisodes terminés de ma base de production — couvrant les 7 langues (en, vi, ja, ko, es, zh, fr) et 10 styles de podcast — avec trois grilles de notation à cinq dimensions chacune. Un juge LLM (GPT-5.6-terra) a noté chaque étape.

StageScoreWorst Dimension
Dialogue (per-segment)3.34Factual Grounding: 2.17
Outline (research + structure)3.01Citation Credibility: 1.28
Final Script (post-review)2.91Publishability: 1.95

Trois choses m'ont immédiatement sauté aux yeux :

1. La passe de révision dégradait les scripts de 0,43. Le dialogue obtenait 3,34. Après révision ? 2,91. L'étape conçue pour améliorer la qualité la réduisait.

2. Toutes les URLs de citation étaient des redirections opaques. Chaque « URL source » dans chaque plan pointait vers vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQ.... Elles fonctionnent pour un humain qui clique, mais paraissent complètement fabriquées aux yeux d'un évaluateur automatisé. 344 faits avaient des URLs source. Zéro avaient un resolved_url — un champ qui n'existait même pas encore.

3. La publiabilité était la dimension la plus basse de tout le pipeline (1,95). De vrais podcasteurs, a déterminé le juge d'évaluation, ne publieraient pas ces scripts sous leur propre nom. Des patterns d'IA détectables : ouvertures de segment identiques, transitions génériques, absence de personnalité de l'hôte.

L'évaluation m'a donné une liste classée de ce qu'il fallait corriger exactement. J'ai passé le reste de la journée à corriger.


Les six corrections (et leur impact mesuré)

Correction 1 : URLs de citation — 0 % à 100 % de résolution

Avant : 0 fait de recherche sur 344 avait un resolved_url. Chaque URL semblait fabriquée.

Correction : Un résolveur d'URL de 60 lignes qui s'exécute pendant la génération du plan, suit la redirection Vertex AI jusqu'à la source réelle, et stocke les deux URLs (l'originale pour la conformité aux CGU de Google, la résolue pour tout le reste).

def resolve_grounding_url(url: str) -> str:
    if "grounding-api-redirect" not in url:
        return url
    response = requests.head(url, allow_redirects=True, timeout=5)
    return response.url if response.url != url else url

Après : 23 faits de recherche sur 23 dans les nouveaux épisodes d'aujourd'hui ont un resolved_url renseigné — de vraies URLs comme simonwillison.net, axios.com, thinkingmachines.ai. 100 % de résolution.


Correction 2 : Changement du modèle de révision (Gemini → DeepSeek)

Avant : Gemini 3.5 Flash faisait la passe de révision. Il faisait des modifications légères et conservatrices : changeait « Exactement ! » en « Aucun doute là-dessus ! » mais conservait surtout le texte original. Il ajoutait du remplissage qui aplatissait le dialogue. La densité des balises audio baissait. Le ratio type-token baissait. Le nombre de tours gonflait.

Correction : J'ai basculé la passe de révision sur DeepSeek v4-pro (384K de sortie max, plafonnée à 96K). J'ai rendu le fournisseur configurable :

provider = get_provider("review")  # reads REVIEW_PROVIDER env var
response = provider.generate(
    prompt=prompt, temperature=0.0,
    max_output_tokens=96000,
)

Vérification : Déployé en production. Un épisode d'actualité tech en vietnamien est passé par le pipeline complet avec la révision DeepSeek — 10,3K → 11,6K tokens, terminé en 121 secondes, 0 passe de resserrage nécessaire. Un deuxième épisode (en anglais) a traité 7,9K → 17K tokens en 203 secondes. La clé API DeepSeek réside dans Google Cloud Secret Manager, injectée automatiquement au déploiement via service.yaml.


Correction 3 : Auto-critique du plan (amélioration de +0,50)

Avant : Les plans allaient directement de Gemini à l'utilisateur sans aucun contrôle qualité interne. Score moyen : 3,01.

Correction : Ajout d'une étape de critique automatisée. DeepSeek v4-pro évalue le plan selon une grille à 6 dimensions (les 5 dimensions du plan plus le nombre de segments), retourne des scores + un feedback spécifique, et stocke la critique dans les métadonnées du podcast.

J'ai ensuite mené une expérience contrôlée : prendre 6 épisodes dont les plans avaient obtenu moins de 3,0, exécuter la critique DeepSeek, renvoyer le feedback à Gemini comme instructions de régénération, et re-noter.

Après : +0,50 d'amélioration globale sur les 6 épisodes.

DimensionBeforeAfterDelta
Content Boundaries3.334.17+0.83
Research Depth2.673.17+0.50
Citation Credibility1.001.50+0.50
Structural Logic3.674.17+0.50
Audience Fit2.172.33+0.17

Le pire épisode est passé de 1,80 à 3,20 (+1,40). Seul 1 sur 6 a empiré. La critique est maintenant activée par défaut en production — chaque nouveau plan reçoit ce contrôle qualité avant que l'utilisateur ne le voie.


Correction 4 : Les plans à un seul segment échouent maintenant franchement

Avant : L'évaluation a montré des épisodes avec un seul segment et zéro fait de recherche avec des scores aussi bas que 2,07. C'étaient des cas d'échec que le pipeline ne traitait pas comme des échecs.

Correction : Si le générateur de plan produit moins de 3 segments valides après une tentative de récupération, le podcast est marqué FAILED. Plus de plans à un seul segment qui arrivent aux utilisateurs. À la prochaine tentative de création, le crédit de l'utilisateur est libéré pour réessayer.


Correction 5 : Règles de localisation en chinois

Avant : Les épisodes en chinois obtenaient 2,88 — le score le plus bas des 7 langues. Des artefacts de traduction (expressions anglaises traduites littéralement), des ouvertures de segment identiques, des noms d'hôtes par défaut en anglais (Alex/Maya) au lieu de noms chinois (明辉/晓雯).

Correction : J'ai écrit des règles de dialogue spécifiques au chinois : patterns conversationnels natifs (constructions 不是...而是...), particules finales appropriées (吧/啊/呢), consignes anti-traduction (ne jamais traduire « medical miracle » littéralement), métaphores du football chinois pour les épisodes de Coupe du Monde, et profils d'hôtes spécifiques à la langue avec des personnalités distinctes.

Le template de dialogue chinois est passé de la réutilisation des valeurs par défaut anglaises à son propre guide de 80 lignes couvrant les patterns conversationnels, les formulations de désaccord et le cadrage spécifique à l'audience pour chaque style de podcast.


Correction 6 : Noms d'hôtes par défaut pour les langues non anglaises

Avant : Plusieurs épisodes non anglophones avaient des hôtes nommés Alex et Maya. Les profils d'hôtes spécifiques à chaque langue existaient, mais le chemin de fallback dans le générateur de plan était codé en dur sur les valeurs par défaut anglaises.

Correction : J'ai tracé la correction à travers le pipeline de résolution de profils sensible à la langue. Les épisodes de production récents utilisent maintenant 翔太/健一 (ja), Mạnh/Nga (vi), Hugo/Camille (fr), 明辉/晓雯 (zh). Les commits de juillet avaient déjà corrigé la edge function et le flux de création — le fallback restant était dans le générateur de plan lui-même.


Le framework d'évaluation (réutilisable)

Le framework qui a trouvé tout cela fait environ 500 lignes de Python, trois fichiers de grille (5 dimensions chacun), un juge GPT-5.6-terra partagé et un orchestrateur :

docs/pipeline/evals/
├── run.py # Orchestrator: extract → judge → report
├── judge.py # Shared LLM judge (rate with rubric)
├── rubric_outline.py # Stage 1: 5 dimensions, 1-5 scale
├── rubric_dialogue.py # Stage 2: 5 dimensions, 1-5 scale
├── rubric_final_script.py # Stage 3: 5 dimensions, 1-5 scale
├── dataset_40.json # Extracted production data
├── scores.json # Machine-readable scores
└── report.md # Auto-generated report

J'ai aussi construit une couche d'expérimentation pour les comparaisons A/B :

docs/pipeline/evals/experiments/
├── review_ab.py # Compare two review models
├── outline_critique_ab.py # Critique → regenerate → compare
├── shared.py # Score comparator, report generator
└── results/ # Archived by date

Lance python docs/pipeline/evals/run.py --full après tout changement de pipeline et obtiens un rapport en ~8 minutes. Lance experiments/review_ab.py --episodes 10 pour comparer des modèles. Les résultats sont archivés par date pour le suivi des tendances — tu veux savoir si la qualité s'est améliorée ce mois-ci par rapport au mois dernier ? Fais un diff des scores.

L'évaluation complète des 40 épisodes coûte environ 1-2 $ en appels API. Les expériences coûtent encore moins. Pour le signal que tu obtiens en retour — une liste classée des étapes et dimensions exactes du pipeline qui nécessitent attention — c'est l'outil de debugging le moins cher que j'aie construit.


Ce qui ne marche toujours pas

L'expérience A/B de révision DeepSeek a besoin du prompt de production complet. Le script d'expérience utilisait un prompt simplifié de 15 lignes. La révision en production utilise un prompt de 80 lignes avec des règles anti-répétition, des quotas de phrases signatures, des garde-fous éditoriaux et une politique de durée. Avec le prompt simplifié, DeepSeek a montré des résultats essentiellement neutres (-0,04). Avec le prompt complet en production, le pipeline s'exécute avec succès en anglais et en vietnamien. Je dois mettre à jour l'expérience pour refléter la production et relancer.

La localisation en chinois a besoin de validation. Les règles ont l'air correctes sur le papier, les profils d'hôtes sont écrits, les guides de dialogue sont en place. Mais je n'ai pas encore fait tourner l'évaluation sur de nouveaux épisodes en chinois pour confirmer que le score est monté depuis 2,88. C'est une priorité cette semaine.

Je dois relancer l'évaluation complète des 40 épisodes sur de nouveaux épisodes. Les six corrections sont déployées. La prochaine étape est d'extraire 40 épisodes générés après ces changements, de les passer dans les mêmes évaluations et de comparer avec la baseline historique. Si le score du script final passe de 2,91 à plus de 3,0, et que la crédibilité des citations passe de 1,28 à quelque chose de raisonnable, je saurai que les changements ont fonctionné de bout en bout.


L'audit de pipeline en trois questions

Après cette expérience, j'audite maintenant chaque changement de pipeline avec trois questions :

1. Y a-t-il un contrôle qualité entre chaque étape ? Mon plan allait de Gemini directement à l'utilisateur. L'ajout de l'étape de critique a attrapé les pires plans avant que quiconque ne les voie. Chaque étape du pipeline a besoin d'un contrôle qualité — une évaluation LLM automatisée contre des critères explicites.

2. Chaque étape améliore-t-elle vraiment la qualité quand on la mesure ? L'exécuter et supposer que ça aide ne suffit pas. Il faut des scores avant/après littéraux sur le même contenu. Mon étape de révision a dégradé les scripts pendant six semaines avant que je ne la mesure. Mesure d'abord, ne suppose rien.

3. Puis-je identifier quelle dimension a cassé ? « La qualité est mauvaise » n'est pas actionnable. « La crédibilité des citations est à 1,28 parce que 100 % des URLs sont des redirections opaques » l'est. Une grille multidimensionnelle par étape te dit exactement où regarder. J'ai passé des heures à enquêter sur mon étape de révision avant l'évaluation. Avec l'évaluation, j'ai passé des secondes — les chiffres pointaient directement vers la publiabilité et le modèle de révision.


Questions fréquentes

Faire tourner des évaluations LLM, ça ne revient pas cher ?

L'évaluation complète des 40 épisodes coûte environ 1-2 $ en appels API (GPT-5.6-terra, ~420K tokens au total). Les expériences A/B coûtent encore moins. Pour le signal que tu obtiens en retour — une liste classée des étapes exactes du pipeline qui nécessitent attention — c'est l'outil de debugging le moins cher que j'aie construit, et moins cher que les crédits que les utilisateurs gaspilleraient sur des épisodes cassés.

Pourquoi 5 dimensions par étape ? Pourquoi pas juste « qualité globale » ?

« Qualité globale » te dit que quelque chose ne va pas. Ça ne te dit pas quoi. Quand j'ai vu Crédibilité des citations à 1,28, j'ai tout de suite su que les URLs étaient cassées. Quand j'ai vu Publiabilité à 1,95, j'ai su que les signaux d'IA étaient détectables. Cinq dimensions te donnent un diagnostic différentiel. Une dimension te donne un thermomètre.

Comment maintiens-tu la cohérence du juge LLM ?

Même modèle (GPT-5.6-terra), même température (0,0), même effort de raisonnement (medium), mêmes prompts de grille à chaque fois. Les scores sont archivés avec des horodatages pour pouvoir comparer entre les dates. Changer le juge change la baseline — choisis-en un et garde-le.

Que se passe-t-il quand le juge lui-même se trompe ?

La grille inclut des justifications obligatoires pour chaque score — le juge doit citer des preuves spécifiques du contenu. J'ai aussi fait une revue qualitative manuelle de 10 épisodes dans les 7 langues pour calibrer le juge. Les scores du LLM correspondaient étroitement à mon jugement humain. Pour les dimensions critiques où le LLM pourrait ne pas être fiable (comme la « publiabilité », qui requiert un jugement culturel), des vérifications humaines ponctuelles sont essentielles.


Je construis DIALOGUE, une plateforme de podcasts IA, en solo, le soir et le week-end. J'écris sur ce que j'apprends en chemin.

Si tu as construit un système d'évaluation pour ton propre pipeline LLM, je suis curieux : comment mesures-tu la qualité, et qu'as-tu découvert qui t'a surpris ?

Voilà, c'est tout pour moi.

À bientôt, Chandler