0Pricing
AI Engineering Academy · Leçon

Évolution des schémas et compatibilité descendante

Gérez les changements incompatibles de schéma dans les pipelines d’extraction de longue durée en versionnant les schémas, en migrant les extractions historiques et en exécutant une validation parallèle pendant les transitions.

Évolution des schémas et compatibilité descendante est une leçon AI Engineering Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Engineering Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Engineering Academy comprend 4 leçons au total.

Pourquoi les schémas évoluent au fil du temps

Les schémas d’extraction ne sont pas statiques. Les exigences métier évoluent, de nouveaux types de documents apparaissent et vous découvrez des champs que vous auriez dû capturer dès le départ. Modifier un schéma dans une chaîne de traitement en production crée un problème de compatibilité ascendante : les enregistrements déjà extraits utilisent l’ancien schéma, tandis que les nouveaux utilisent le nouveau. La gestion sécurisée de cette transition constitue l’évolution des schémas.

Versionner vos schémas

Attribuez un numéro de version à chaque schéma et stockez-le avec chaque enregistrement extrait. Lorsque vous modifiez le schéma, incrémentez la version. Vous pouvez ainsi interroger les enregistrements par version de schéma, exécuter des migrations sur les anciens enregistrements et conserver une logique de validation distincte pour chaque version. Un simple champ texte schema_version dans chaque modèle de sortie suffit.

from pydantic import BaseModel
from typing import Literal

class InvoiceV1(BaseModel):
    schema_version: Literal['1.0'] = '1.0'
    vendor: str
    total_amount: float

class InvoiceV2(BaseModel):
    schema_version: Literal['2.0'] = '2.0'
    vendor: str
    vendor_tax_id: str | None = None  # new field
    total_amount: float
    currency: str = 'USD'  # new field with default

Modifications additives ou incompatibles

Les modifications additives sont sûres : ajouter un champ facultatif ou un champ possédant une valeur par défaut ne casse ni l’ancien code d’extraction ni les anciens enregistrements. Les modifications incompatibles sont risquées : renommer un champ, changer son type de chaîne en entier ou supprimer un champ cassera les utilisateurs en aval. Privilégiez toujours les modifications additives. Lorsqu’une modification incompatible est inévitable, créez une nouvelle version majeure du schéma et effectuez la migration de manière contrôlée.

# Safe: additive change - add optional field
class ProductV2(BaseModel):
    name: str
    price: float
    sku: str | None = None   # NEW optional field - backward safe
    category: str = 'general'  # NEW with default - backward safe

# Risky: breaking change - rename or retype
# class ProductV2(BaseModel):
#     product_name: str  # RENAMED from name - breaks consumers
#     price_cents: int   # RETYPED from float - breaks data

Stocker la version du schéma dans la base de données

Incluez la version du schéma dans votre table de résultats d’extraction afin de toujours savoir quelle version a produit chaque enregistrement. Une colonne jsonb contenant toutes les données extraites, accompagnée d’une colonne texte schema_version, constitue un modèle courant. Vous pouvez ainsi écrire des requêtes tenant compte de la version et migrer sélectivement les anciens enregistrements pendant les périodes de faible trafic.

-- PostgreSQL table design
CREATE TABLE extractions (
    doc_id TEXT PRIMARY KEY,
    schema_version TEXT NOT NULL,
    extracted_data JSONB NOT NULL,
    extracted_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_schema_version ON extractions(schema_version);

-- Query old records needing migration
SELECT doc_id, extracted_data
FROM extractions
WHERE schema_version = '1.0'
LIMIT 1000;

Écrire des scripts de migration

Écrivez un script de migration pour chaque transition de version du schéma. Il doit lire les anciens enregistrements, les transformer au nouveau format, puis les réécrire avec la nouvelle version. Exécutez les migrations par petits lots avec des transactions afin qu’un échec ne laisse pas la base de données dans un état partiellement migré. Conservez toujours l’ancien schéma jusqu’à la vérification complète de la migration.

import asyncpg
import json

async def migrate_v1_to_v2(pool, batch_size=100):
    async with pool.acquire() as conn:
        rows = await conn.fetch(
            'SELECT doc_id, extracted_data FROM extractions WHERE schema_version=$1 LIMIT $2',
            '1.0', batch_size
        )
        for row in rows:
            old = row['extracted_data']
            new_data = {
                'schema_version': '2.0',
                'vendor': old['vendor'],
                'vendor_tax_id': None,  # unknown for old records
                'total_amount': old['total_amount'],
                'currency': 'USD'  # assume USD for old records
            }
            await conn.execute(
                'UPDATE extractions SET extracted_data=$1, schema_version=$2 WHERE doc_id=$3',
                json.dumps(new_data), '2.0', row['doc_id']
            )

Validation parallèle pendant les transitions

Pendant une migration de schéma, effectuez une validation parallèle : réalisez l’extraction simultanément avec l’ancien et le nouveau schéma sur un échantillon de documents entrants. Comparez les résultats pour vérifier que le nouveau schéma capture tout ce que capturait l’ancien, ainsi que les nouveaux champs. Ne retirez l’ancien schéma qu’après avoir obtenu une parité stable sur un échantillon statistiquement significatif.

async def parallel_validate(text: str) -> dict:
    v1_result, v2_result = await asyncio.gather(
        extract_with_schema(text, InvoiceV1),
        extract_with_schema(text, InvoiceV2)
    )
    discrepancy = (
        v1_result.vendor != v2_result.vendor or
        abs(v1_result.total_amount - v2_result.total_amount) > 0.01
    )
    if discrepancy:
        log_discrepancy(text, v1_result, v2_result)
    return {'v1': v1_result, 'v2': v2_result, 'discrepancy': discrepancy}

Indicateurs de fonctionnalité pour le déploiement d’un schéma

Utilisez des indicateurs de fonctionnalité pour contrôler le moment où votre chaîne de traitement passe de l’ancien schéma au nouveau. Vous pouvez ainsi déployer progressivement le nouveau schéma sur un pourcentage du trafic, surveiller les taux d’erreur et revenir instantanément en arrière en cas de problème, sans redéployer le code. Des services d’indicateurs de fonctionnalité comme LaunchDarkly ou une simple ligne dans une base de données conviennent tous deux.

import os

def get_active_schema():
    version = os.environ.get('EXTRACTION_SCHEMA_VERSION', '1.0')
    schemas = {
        '1.0': InvoiceV1,
        '2.0': InvoiceV2,
    }
    return schemas.get(version, InvoiceV1)

async def extract_document(text: str):
    SchemaClass = get_active_schema()
    return await extract_with_schema(text, SchemaClass)

Compatibilité des utilisateurs en aval avec les types union

Les utilisateurs en aval qui lisent les données extraites doivent gérer correctement plusieurs versions du schéma. Utilisez une union discriminée dans le code consommateur afin de sélectionner la logique d’analyse appropriée en fonction du champ schema_version. Cette approche est plus robuste que des chaînes de conditions if-else et plus facile à étendre lorsque la version 3 arrivera.

from pydantic import BaseModel
from typing import Union, Annotated
from typing import Literal

def parse_extraction(raw: dict) -> Union[InvoiceV1, InvoiceV2]:
    version = raw.get('schema_version', '1.0')
    if version == '1.0':
        return InvoiceV1(**raw)
    elif version == '2.0':
        return InvoiceV2(**raw)
    else:
        raise ValueError(f'Unknown schema version: {version}')

Tester les modifications du schéma avant le déploiement

Avant de déployer un nouveau schéma, exécutez-le sur l’ensemble de votre jeu de tests de régression : une collection préparée de documents représentatifs dont les sorties attendues sont connues. Comparez les scores F1 de chaque champ entre l’ancien et le nouveau schéma. Une régression du score F1 pour un champ quelconque signifie que la description du nouveau schéma a semé la confusion dans le modèle : corrigez la description du champ avant la mise en production.

def eval_schema_on_test_set(test_cases: list, SchemaClass) -> dict:
    field_f1 = {}
    for case in test_cases:
        result = extract_with_schema(case['text'], SchemaClass)
        for field in case['expected']:
            expected = case['expected'][field]
            actual = getattr(result, field, None)
            # Update precision/recall counters
            update_metrics(field_f1, field, expected, actual)
    return {k: compute_f1(v) for k, v in field_f1.items()}

Gérer l’obsolescence d’un schéma

Lorsqu’une version de schéma n’est plus utilisée pour les nouvelles extractions, vous pouvez la déclarer obsolète. Cela signifie qu’il faut cesser d’accepter de nouveaux enregistrements dans cette version, conserver la possibilité de lire les anciens enregistrements et programmer une date de retrait à laquelle ils seront migrés ou archivés. Documentez l’obsolescence dans un journal des modifications afin que tous les utilisateurs sachent qu’ils doivent mettre à jour leur code d’analyse.

DEPRECATED_VERSIONS = {'1.0'}
SUNSET_DATE = '2026-09-01'

def warn_if_deprecated(version: str):
    if version in DEPRECATED_VERSIONS:
        import warnings
        warnings.warn(
            f'Schema version {version} is deprecated. '
            f'It will be removed after {SUNSET_DATE}. '
            'Migrate consumers to version 2.0.',
            DeprecationWarning,
            stacklevel=2
        )

Journal des modifications et communication

Chaque modification de schéma doit s’accompagner d’une entrée dans le journal des modifications décrivant ce qui a changé, pourquoi, les instructions de migration et l’impact attendu. Partagez ces entrées avec toutes les équipes qui utilisent les données extraites avant de déployer la modification. De nombreux désastres liés aux migrations de schémas ne proviennent pas de défaillances techniques, mais d’utilisateurs qui n’ont pas été informés de la modification à venir.

# CHANGELOG.md entry format:
# ## Schema v2.0 (2026-07-01)
# ### Changes
# - ADDED: vendor_tax_id (Optional[str]) - VAT/EIN extracted from header
# - ADDED: currency (str, default='USD') - detected from symbol/code
# ### Migration
# Run: python scripts/migrate_v1_to_v2.py --batch-size=500
# ### Consumers
# - billing-service: update parse_extraction() to handle v2
# - audit-service: query now supports currency filter

Vérification rapide

Vérifiez votre compréhension de l’évolution des schémas et de la compatibilité ascendante dans les chaînes d’extraction.

Récapitulatif de la leçon

Dans cette leçon, vous avez appris que le versionnage des schémas stocke un identifiant de version avec chaque enregistrement extrait afin de permettre une migration sélective, que les modifications additives sont sûres, tandis que le renommage ou le changement de type des champs exige une migration soigneuse, et que la validation parallèle permet de vérifier le nouveau schéma avant de retirer l’ancien. Nous allons maintenant mesurer la latence des LLM avec les métriques TTFT et TPOT.

Questions Fréquemment Posées

La leçon « Évolution des schémas et compatibilité descendante » est-elle gratuite ?

Oui — le texte complet de « Évolution des schémas et compatibilité descendante » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Engineering Academy, passe à CoddyKit PRO. Le cours AI Engineering Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Évolution des schémas et compatibilité descendante » ?

Gérez les changements incompatibles de schéma dans les pipelines d’extraction de longue durée en versionnant les schémas, en migrant les extractions historiques et en exécutant une validation parallè… Tu pratiques AI Engineering Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer AI Engineering Academy ?

Aucune expérience préalable n'est requise. AI Engineering Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.

Combien de temps prend la leçon « Évolution des schémas et compatibilité descendante » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon AI Engineering Academy ?

Oui. Chaque leçon AI Engineering Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Instructor : extraction typée avec Pydantic
  2. Gérer les données partielles et manquantes
  3. Traitement par lots avec l’asynchronisme et des files d’attente
  4. Évolution des schémas et compatibilité descendante
← Retour à AI Engineering Academy