Fransys
Tous les cours
M12
1 h 30
Pédagogie complète

Multi-modal avancé : vision, PDF, documents complexes

PDF support direct, document understanding, analyse de charts/diagrammes.

Devs, équipes documents, legal, finance, médical

Pourquoi ce module

Claude Opus 4.8 traite les PDFs et images nativement : multi-pages, OCR serveur Anthropic intégré, mise en page préservée, extraction jusqu'à 32 MB par PDF. Le marché des outils d'extraction documentaire (Docsumo, Rossum) vaut 2,5 Md€ en 2026, mais la majorité des cas BtoB (factures, contrats, rapports) ne nécessite pas ML custom — la vision Claude, combinée à JSON schema strict et tool use, résout 95 % des besoins production.

Ce module vous transforme en expert extraction documentaire serverless : vous lisez un PDF de 30 pages, en extrayez 500 lignes de facture avec TVA et totaux, validez le JSON et l'exportez en CSV, le tout en < 5 secondes.

Claude Code lit une image (@fichier) et la décrit : vision multimodale dans le terminal
La vision en une ligne : @image.png charge le fichier (Read), Claude voit et décrit le contenu. Même principe pour un PDF — base de l'extraction documentaire de ce module.
Écran d'ordinateur affichant l'analyse d'un document
Extraction documentaire serverless avec Claude Vision (PDF → JSON strict)

Prérequis : avoir une clé API Anthropic, maîtriser JSON schema et les bases du tool use (modules J1–J3), avoir lu la documentation vision d'Anthropic.

Objectifs pédagogiques

À l'issue de ce module, vous serez capable de :

  1. Charger et traiter des PDFs multi-pages (jusqu'à 100 pages) avec OCR serveur transparent, sans dépendre d'une API OCR externe
  2. Extraire du JSON structuré d'un PDF avec un schéma Zod/Pydantic strict, validation côté client, taux de précision 97+%
  3. Coder une skill /facture-extract qui lit une facture PDF (même scannée), extrait lignes + TVA + totaux, valide et pousse en CSV
  4. Coder une skill /contrat-analyze qui parcourt un contrat multi-pages, marque les clauses critiques (prix, date, parties, durée), cite les pages source
  5. Concevoir une stratégie de résolution : Opus 4.7/4.8 accepte jusqu'à 2576 px sur le grand côté (haute résolution, coords pixel-exactes) ; ~1568 px reste le sweet spot coût/perf à viser par downscaling quand la fidélité n'est pas critique (limite 5 MB/image après base64)
  6. Orchestrer vision + tool use : utiliser Claude pour le parsing visuel, valider avec un schéma JSON, en cas d'erreur, redemander un refinement au modèle

Plan détaillé

  1. Capacités vision Anthropic : PDF natif, OCR, formats, limites
  2. Limites critiques : taille, pages, résolution, coûts
  3. Downscaling et compression — best practices
  4. Pattern extraction structurée : vision + JSON schema
  5. Validation côté client : Zod/Pydantic
  6. Skill /facture-extract : démo complète
  7. Skill /contrat-analyze : citation de pages source
  8. Tool use vision : refinement itératif
  9. Tableaux et diagrammes : document understanding avancé
  10. Atelier : pipeline PDF → JSON → CSV

Capacités vision Anthropic

PDF support natif (depuis mai 2024)

Format : application/pdf, jusqu'à 100 pages par requête, jusqu'à 32 MB par PDF.

⚠️ Limites à revérifier : les plafonds de pages et de résolution évoluent avec les modèles. Les modèles récents (Opus 4.7+) acceptent des PDF plus volumineux et des images de résolution plus élevée que les valeurs historiques citées ici. Confirmez les limites en vigueur sur docs.claude.com avant de dimensionner un pipeline.

Avantages vs upload image séquentiellement :

ApprocheLatenceCoûts tokensLimites
PDF natif (1 requête)2-3s pour 50 pages~2000 tokens pour 50pMax 100 pages
Images séquentielles (50 requêtes)8-10s~3500 tokens (overhead requête)Pas de contexte cross-page
Tesseract OCR local + texte15-20sRéduit mais latence hauteTextes multi-colonne cassés

Qui utiliser quand :

  • PDF natif : extraction rapide, 1-100 pages, budget tokens OK
  • Images séquentielles : > 100 pages, besoin de paralléléiser, contexte par page silo
  • Tesseract local : données sensibles (RGPD), offline, mais OCR qualité médiane

Formats et limites

Formats supportés : PDF (natif), PNG, JPG, WebP, GIF (transparence + animation OK).

Tailles max par asset :

  • Image : 5 MB après base64 (~6,67 MB brut)
  • PDF : 32 MB brut
  • Total requête : 200 MB (tous assets + texte)

Résolution (Opus 4.7 / 4.8) :

  • Max haute résolution : 2576 px sur le grand côté (depuis Opus 4.7). Les coordonnées renvoyées par le modèle sont 1:1 avec les pixels (plus de recalage d'échelle). Activation automatique, aucun beta header requis.
  • Sweet spot coût/perf : ~1568 px sur le grand côté (recommandé quand la pleine résolution n'apporte rien)
  • Min lisibilité : ~512 px (OCR dégradé)

⚠️ Ne downscalez pas par réflexe. Une image pleine résolution sur Opus 4.7/4.8 peut coûter jusqu'à ~4784 image tokens (≈ 3× l'ancien plafond ~1600), mais pour de l'extraction fine (petits caractères, tampons, tableaux denses, manuscrit) la haute résolution augmente nettement la précision. Ramenez à ~1568 px uniquement quand la fidélité n'est pas critique.

Astuce : une facture de 800×1000 en JPG compressé = 120 KB, après base64 = 160 KB. Pas de souci. Une capture d'écran 3000×2000 non compressée = 8 MB ; compressée en WebP = 1,5 MB. À faire.

OCR natif vs approches legacy

L'OCR d'Anthropic est côté serveur, transparent, inclus dans le coût vision :

Ancienne approche (2023):
PDF → upload → Tesseract local (15s) → texte → Claude → JSON

Nouvelle approche (2024+):
PDF → Claude vision directement → JSON
(OCR serveur Anthropic inclus, 2-3s end-to-end)

Gain : -80 % latence, zéro dépendance OCR, OCR qualité supérieure (gère multilingue, sans serif, dégradé).

Limites critiques et stratégies

Limite 1 : 100 pages max par requête

Une facture = 1 page. Un contrat = 30 pages. Un rapport annuel = 150 pages.

Stratégie si > 100 pages :

async function extractLargeDoc(pdfPath: string) {
  const numPages = await getPageCount(pdfPath);
  const chunks = Math.ceil(numPages / 100);
  
  for (let i = 0; i < chunks; i++) {
    const startPage = i * 100 + 1;
    const endPage = Math.min((i + 1) * 100, numPages);
    
    const chunk = await extractPages(pdfPath, startPage, endPage);
    results.push(...chunk);
  }
  return mergeResults(results); // Déduplique chevauchements
}

Limite 2 : 5 MB par image après base64

Une facture JPG scannée = ~2-3 MB décompressée, `450 KB après JPEG compression normal, OK. Une capture d'écran 4K sans compression = 15 MB, trop lourd.

Downscaling TypeScript :

import sharp from "sharp";

async function downscaleImage(filePath: string): Promise<Buffer> {
  const metadata = await sharp(filePath).metadata();
  
  // Optimisation COÛT : ramène à 1568px sur le grand côté.
  // Le plafond réel d'Opus 4.7/4.8 est 2576px — vise TARGET=2576 si la fidélité prime
  // (petits caractères, tableaux denses). Ici on optimise le coût.
  const TARGET = 1568;
  const scale = Math.min(
    TARGET / (metadata.width ?? 1),
    TARGET / (metadata.height ?? 1)
  );
  
  if (scale < 1) {
    return sharp(filePath)
      .resize(
        Math.round((metadata.width ?? 1) * scale),
        Math.round((metadata.height ?? 1) * scale),
        { fit: "inside", withoutEnlargement: true }
      )
      .jpeg({ quality: 85, progressive: true })
      .toBuffer();
  }
  return fs.readFileSync(filePath);
}

// Avant vision call :
const imageBase64 = (await downscaleImage("facture.jpg")).toString("base64");

Limite 3 : Coûts tokens

Vision a un coût en image tokens :

  • Formule : ⌈largeur / 28⌉ × ⌈hauteur / 28⌉ tokens visuels (chaque patch 28×28 pixels = 1 token)
  • Sans overhead fixe (exemple : 200×200 px = 64 tokens, 1000×1000 px = 1296 tokens)

Facturation :

  • Facture 1 page optimisée (1568×2000) = ~300 tokens
  • Contrat 30 pages PDF = ~9000 tokens
  • 1 million factures/mois = ~300M tokens/mois ≈ 700-2100 € selon le modèle (Haiku 4.5 à Sonnet 4.6 ; ou 350-1050 € avec batch processing 50 % discount, prix API juin 2026)

ROI : Automatiser 1000 factures/mois en-maison ≈ 40 heures FTE, coût ~2000 € vs 150 € en API = 13× ROI.

Pattern extraction structurée

Claude Code lit une capture d'écran via @ et en extrait les valeurs en JSON structuré
Vision → JSON, en pratique : @…png charge l'image (Read), Claude voit le tableau et ses barres, puis renvoie un JSON conforme au schéma demandé (valeurs lues à l'écran). Même chaîne pour une facture, un contrat ou un graphique scanné.

Vision + JSON schema strict

Le pattern gold standard pour l'extraction est :

Voici l'architecture complète du pipeline extraction visuelle → JSON validé → application métier :

Chargement du schéma…

Pipeline extraction : téléchargement → vision → validation → export avec boucle refinement
Vision lit le document → Claude raisonne sur la mise en page
→ Claude génère JSON conforme au schéma → Client valide

Schéma exemple (Zod TypeScript) :

import { z } from "zod";

const InvoiceSchema = z.object({
  invoiceNumber: z.string().min(1),
  date: z.string().date(),
  dueDate: z.string().date(),
  vendor: z.object({
    name: z.string(),
    address: z.string(),
    taxId: z.string().regex(/^FR[0-9]{11}$/)
  }),
  customer: z.object({
    name: z.string(),
    address: z.string(),
    taxId: z.string().optional()
  }),
  lineItems: z.array(
    z.object({
      description: z.string(),
      quantity: z.number().positive(),
      unitPrice: z.number().nonnegative(),
      taxRate: z.number().min(0).max(1),
      amount: z.number().nonnegative()
    })
  ),
  subtotal: z.number().nonnegative(),
  taxAmount: z.number().nonnegative(),
  totalDue: z.number().positive(),
  pageNumber: z.number().min(1),
  sourceHash: z.string().describe("SHA256 of original PDF for audit")
});

type Invoice = z.infer<typeof InvoiceSchema>;

Appel vision + refinement

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

// Note : pour des PDF réutilisés ou volumineux en production, préférez la Files API
// (uploader une fois, réutiliser `file_id` au lieu de renvoyer le base64 à chaque appel) :
//   const f = await client.beta.files.upload({ file: ... });
//   source: { type: "file", file_id: f.id }
// Le base64 ci-dessous reste pratique pour les fichiers ponctuels.
async function extractInvoice(pdfPath: string): Promise<Invoice> {
  const pdfBase64 = fs.readFileSync(pdfPath).toString("base64");
  
  const response = await client.messages.create({
    model: "claude-opus-4-8",
    max_tokens: 2048,
    messages: [
      {
        role: "user",
        content: [
          {
            type: "document",
            source: {
              type: "base64",
              media_type: "application/pdf",
              data: pdfBase64
            }
          },
          {
            type: "text",
            text: `Extrait le JSON de cette facture en respectant strictement ce schéma:\n${JSON.stringify(InvoiceSchema)}\n\nRéponds UNIQUEMENT avec du JSON valide, pas d'explication.`
          }
        ]
      }
    ]
  });
  
  const jsonText = response.content[0].type === "text" ? response.content[0].text : "";
  const parsed = JSON.parse(jsonText);
  
  // Valide et lève si invalide
  return InvoiceSchema.parse(parsed);
}

💡 Mieux : structured outputs natifs. Plutôt que « Réponds UNIQUEMENT en JSON » + JSON.parse (qui peut échouer), contraignez la génération au schéma — le JSON est garanti conforme, sans boucle de refinement pour cause de JSON malformé. (Le mécanisme des structured outputsoutput_config.format, contraintes supportées, prefills retirés — est traité à fond dans M3 ; ici on l'applique à l'extraction vision.)

import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";

const res = await client.messages.parse({
  model: "claude-opus-4-8",
  max_tokens: 2048,
  messages: [{ role: "user", content: [
    { type: "document", source: { type: "base64", media_type: "application/pdf", data: pdfBase64 } },
    { type: "text", text: "Extrais cette facture." },
  ]}],
  output_config: { format: zodOutputFormat(InvoiceSchema) },
});
const invoice = res.parsed_output; // déjà typé Invoice, garanti conforme au schéma

Le SDK retire automatiquement les contraintes Zod non supportées par les structured outputs (.regex(), .min()/.max() numériques, .date()) du schéma envoyé et les revalide côté client. La boucle de refinement ci-dessous reste utile pour les erreurs métier (montants incohérents, total ≠ somme des lignes), pas pour le JSON malformé.

En cas d'erreur de parsing (ou de validation métier) :

async function extractInvoiceWithRefinement(
  pdfPath: string,
  maxRetries: number = 2
): Promise<Invoice> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await extractInvoice(pdfPath);
    } catch (error) {
      if (attempt === maxRetries) throw error;
      
      // Refinement : redemande au modèle de corriger
      const retry = await client.messages.create({
        model: "claude-opus-4-8",
        max_tokens: 2048,
        messages: [
          {
            role: "user",
            content: [
              {
                type: "document",
                source: { type: "base64", media_type: "application/pdf", data: pdfBase64 }
              },
              {
                type: "text",
                text: `ERREUR: ${error.message}\n\nRée-examine la facture. Ton dernier JSON était invalide car: [détail]. Corrige-le et valide: ${JSON.stringify(InvoiceSchema)}`
              }
            ]
          }
        ]
      });
    }
  }
}

Skill /facture-extract

Structure complète d'une skill d'extraction facture.

Architecture (~/.claude/skills/facture-extract/) :

facture-extract/
├── SKILL.md          # orchestration
├── VALIDATION.md     # schéma Zod complet
├── EXAMPLES.md       # 3 factures réelles (anonymisées)
└── tests/
    ├── golden_facture_1.pdf
    ├── golden_facture_1.json
    └── integration.test.ts

SKILL.md (extrait) :

---
name: facture-extract
description: PDF facture → JSON validé + CSV
allowed-tools:
  - Bash(cat, jq, csv)
argument-hint: <PDF_PATH>
model: claude-opus-4-8
---

## Phases

### Phase 1 — Downscale et base64
Si image > 1568px ou > 5 MB, compresse via Sharp.

### Phase 2 — Vision extraction
Appelle Claude vision sur le PDF. Schéma strict (Zod).

### Phase 3 — Validation
Valide le JSON via Zod. Si erreur, refinement.

### Phase 4 — CSV export
Génère CSV (headers: invoiceNumber, vendor, amount, tax, date).

## Input
PDF facture, n'importe quel format ou scan.

## Output
- JSON structuré (validé)
- CSV ligne pour import en base
- Audit: source hash + timestamp

Démo exécution :

/facture-extract ~/Downloads/Acme_Invoice_2026-05-03.pdf

# Sortie :
# ✓ Downscale: 2400×3200 → 1568×2090
# ✓ Vision: 342 tokens consommés
# ✓ JSON validé: 1 facture, 18 lignes
# ✓ CSV créé: facture_acme_20260503.csv
# {
#   "invoiceNumber": "INV-2026-0547",
#   "vendor": { "name": "ACME Corp", ... },
#   "totalDue": 4850.50,
#   "taxAmount": 845.67,
#   ...
# }

Skill /contrat-analyze

Pour les contrats multi-pages, le besoin est différent : pas une simple extraction, mais annotation + citation de pages source.

Voici comment structurer le workflow d'analyse de contrats multi-pages :

Chargement du schéma…

Pipeline contrat : identification multilingue des clauses + citation pages + scoring risque

Architecture :

contrat-analyze/
├── SKILL.md
├── CLAUSES.md        # 30 types de clauses identifiées
└── EXAMPLES.md       # contrat 15p annoté

Phases :

1. Vision lit tout le contrat (jusqu'à 100p)
2. Identifie : parties, dates, montants, durée, résiliation, IP
3. Pour chaque clause critique → cite la page source exacte
4. Génère JSON + Markdown annotée

Schéma de sortie :

const ContractClauseSchema = z.object({
  type: z.enum([
    "parties",
    "effective_date",
    "term_months",
    "price",
    "payment_terms",
    "termination",
    "ip_ownership",
    "confidentiality",
    "liability_cap",
    "governing_law"
  ]),
  text: z.string(),
  pageNumbers: z.array(z.number()),
  severity: z.enum(["critical", "important", "reference"]),
  redFlag: z.string().optional().describe("Risque légal détecté")
});

const ContractAnalysisSchema = z.object({
  documentName: z.string(),
  totalPages: z.number(),
  parties: z.array(z.string()),
  startDate: z.string().date(),
  endDate: z.string().date().optional(),
  estimatedValue: z.number().optional(),
  clauses: z.array(ContractClauseSchema),
  summary: z.string().max(500)
});

Démo :

/contrat-analyze ~/contrats/SLA_Provider_2026.pdf

# ✓ 12 pages traitées
# Parties: "Acme Inc", "Tech Consulting SARL"
# ✓ Dates extraites: 2026-05-01 → 2027-04-30
# ✓ Montant: 150 000 € (p. 3)
# ✓ Clauses critiques:
#   - Résiliation anticipée (p. 8) [RED FLAG: délai 15j vs norme 30j]
#   - Limitation responsabilité: 50k€ max (p. 11)
#   - Loi applicable: droit français (p. 12)

Tableaux et diagrammes

Tableau extraction

Les tableaux PDF donnent du fil à retordre à l'OCR classique. Vision Anthropic les détecte et les structure bien.

Pattern :

const TableCellSchema = z.object({
  row: z.number(),
  col: z.number(),
  text: z.string(),
  isHeader: z.boolean()
});

const TableExtractionSchema = z.object({
  pageNumber: z.number(),
  tableIndex: z.number(),
  rows: z.number(),
  cols: z.number(),
  cells: z.array(TableCellSchema),
  markdown: z.string().describe("Rendu markdown du tableau")
});

async function extractTable(pdfPath: string, tableNumber: number = 0) {
  // Vision lit le PDF
  // Identifie les tableaux par structure visuelle (cellules, bordures)
  // Extrait en JSON structuré
  // Convertit en Markdown pour réédition
}

Diagrammes (flowchart, architecture)

Vision détecte les formes, flèches, texte dans les diagrams. Utile pour :

  • Architectures système (data lineage)
  • Flowcharts process (compliance docs)
  • Organigrammes (org charts)

Pattern :

const DiagramElementSchema = z.object({
  id: z.string(),
  type: z.enum(["box", "circle", "diamond", "arrow", "text"]),
  label: z.string(),
  connections: z.array(z.string()).describe("IDs des éléments connectés")
});

const DiagramSchema = z.object({
  pageNumber: z.number(),
  elements: z.array(DiagramElementSchema),
  interpretation: z.string().describe("Explication du diagramme en prose")
});

Vision + JSON schema = reconstruction visuelle → texte → back to structure.

Atelier : pipeline PDF → JSON → CSV (60 min)

Livrable :

  1. Skill /facture-extract exécutable
  2. Zod schema validant sur 5 factures test
  3. CSV exporté, importable en Excel
  4. Audit trail (hash PDF + timestamp)

Tâches :

  1. Downscaling (15 min)

    • Prendre 3 factures : PDF natif, JPG scan, PNG screenshot
    • Tester downscale via Sharp
    • Vérifier taille finale < 5 MB
  2. Schema + validation (20 min)

    • Écrire Zod schema complet pour 1 facture
    • Parser 3 factures, relever différences de structure
    • Adapter schema (champs optionnels, alternatives)
  3. Vision call + refinement (15 min)

    • Appeler Claude vision sur les 3 factures
    • Traiter erreurs parsing (retry logic)
    • Afficher taux de précision (champs extraits / champs attendus)
  4. CSV export + validation (10 min)

    • Générer CSV avec headers corrects
    • Importer dans un tableur (Excel, Sheets)
    • Vérifier montants, TVA, dates

Document understanding avancé

Au-delà des factures simples, vous rencontrez :

Type de docDéfi visuelPattern
Factures multi-colonnesColonnes pas alignéesVision détecte colonnes → extrait par colonne
Contrats scannés dégradésOCR peu lisibleRefinement + prompt pour "lis même si flou"
Tableaux imbriquésLimites de cellules invisiblesVision détecte via espaces, aligne
Diagrammes + texte mixÉléments superposésDeux passes : d'abord shapes, puis texte OCR
Formules mathématiquesLaTeX/MathMLVision interprète, générer comme "x + 2y = 5"

Guideline : si un humain ne peut pas lire, vision non plus. Mais si lisible pour humain, vision le fait 97 % du temps.

Pour aller plus loin

Récapitulatif

À retenir absolument :

  1. PDF natif = 100 pages max, 32 MB max, OCR transparent (côté Anthropic)
  2. Downscale à 1568×1568 pour l'efficacité, compresse agressivement
  3. JSON schema strict + refinement itératif = 97%+ précision
  4. Vision + tool use = citez les pages source (audit trail critique)
  5. Coûts : 1000 factures = 150 € API vs 400 € FTE, ROI immédiat