Passer au contenu principal
Il s’agit d’un notebook interactif. Vous pouvez l’exécuter en local ou utiliser les liens ci-dessous :

Prérequis

Avant de commencer, installez et importez les bibliothèques requises, obtenez votre clé API W&B et initialisez votre projet Weave.
# Installer les dépendances requises
!pip install openai weave -q
python
import json
import os

from google.colab import userdata
from openai import OpenAI

import weave
python
# Obtenir les clés API
os.environ["OPENAI_API_KEY"] = userdata.get(
    "OPENAI_API_KEY"
)  # veuillez définir les clés comme secrets d'environnement Colab depuis le menu à gauche
os.environ["WANDB_API_KEY"] = userdata.get("WANDB_API_KEY")

# Définir le nom du projet
# Remplacez la valeur PROJECT par le nom de votre projet
PROJECT = "vlm-handwritten-ner"

# Initialiser le projet Weave
weave.init(PROJECT)

1. Créez et itérez des prompts avec Weave

Une bonne conception de prompts est essentielle pour guider le modèle afin qu’il extraie correctement les entités. Commencez par créer un prompt de base qui indique au modèle quoi extraire de nos données d’image et sous quel format. Ensuite, vous stockerez le prompt dans Weave pour en assurer le suivi et l’itération.
# Créez votre objet prompt avec Weave
prompt = """
Extract all readable text from this image. Format the extracted entities as a valid JSON.
Do not return any extra text, just the JSON. Do not include ```json```
Use the following format:
{"Patient Name": "James James","Date": "4/22/2025","Patient ID": "ZZZZZZZ123","Group Number": "3452542525"}
"""
system_prompt = weave.StringPrompt(prompt)
# Publiez votre prompt dans Weave
weave.publish(system_prompt, name="NER-prompt")
Ensuite, améliorez le prompt en ajoutant davantage d’instructions et de règles de validation afin de réduire les erreurs dans la sortie générée.
better_prompt = """
You are a precision OCR assistant. Given an image of patient information, extract exactly these fields into a single JSON object—and nothing else:

- Patient Name
- Date (MM/DD/YYYY)
- Patient ID
- Group Number

Validation rules:
1. Date must match MM/DD/YY; if not, set Date to "".
2. Patient ID must be alphanumeric; if unreadable, set to "".
3. Always zero-pad months and days (e.g. "04/07/25").
4. Omit any markup, commentary, or code fences.
5. Return strictly valid JSON with only those four keys.

Do not return any extra text, just the JSON. Do not include ```json```
Example output:
{"Patient Name":"James James","Date":"04/22/25","Patient ID":"ZZZZZZZ123","Group Number":"3452542525"}
"""
# Modifier le prompt
system_prompt = weave.StringPrompt(better_prompt)
# Publier le prompt modifié dans Weave
weave.publish(system_prompt, name="NER-prompt")

2. Obtenir le jeu de données

Ensuite, récupérez le jeu de données de notes manuscrites à utiliser comme entrée du pipeline OCR. Les images du jeu de données sont déjà encodées en base64, ce qui signifie que les données peuvent être utilisées par le LLM sans prétraitement.
# Récupérer le jeu de données depuis le projet Weave suivant
dataset = weave.ref(
    "weave://wandb-smle/vlm-handwritten-ner/object/NER-eval-dataset:G8MEkqWBtvIxPYAY23sXLvqp8JKZ37Cj0PgcG19dGjw"
).get()

# Accéder à un exemple spécifique dans le jeu de données
example_image = dataset.rows[3]["image_base64"]

# Afficher l'example_image
from IPython.display import HTML, display

html = f'<img src="{example_image}" style="max-width: 100%; height: auto;">'
display(HTML(html))

3. Construire le pipeline NER

Ensuite, construisez le pipeline NER. Le pipeline se composera de deux fonctions :
  1. Une fonction encode_image qui prend une image PIL du jeu de données et renvoie une chaîne représentant l’image encodée en base64, pouvant être transmise au VLM
  2. Une fonction extract_named_entities_from_image qui prend une image et un prompt système, et renvoie les entités extraites de cette image conformément au prompt système
# Fonction traçable utilisant GPT-4-Vision
def extract_named_entities_from_image(image_base64) -> dict:
    # Initialisation du client LLM
    client = OpenAI()

    # Configuration du prompt d'instruction
    # Vous pouvez également utiliser un prompt stocké dans Weave avec weave.ref("weave://wandb-smle/vlm-handwritten-ner/object/NER-prompt:FmCv4xS3RFU21wmNHsIYUFal3cxjtAkegz2ylM25iB8").get().content.strip()
    prompt = better_prompt

    response = client.responses.create(
        model="gpt-4.1",
        input=[
            {
                "role": "user",
                "content": [
                    {"type": "input_text", "text": prompt},
                    {
                        "type": "input_image",
                        "image_url": image_base64,
                    },
                ],
            }
        ],
    )

    return response.output_text
Maintenant, créez une fonction appelée named_entity_recognation qui :
  • Envoie les données de l’image au pipeline NER
  • Renvoie un JSON correctement formaté avec les résultats
Utilisez le décorateur @weave.op() pour suivre et tracer automatiquement l’exécution de la fonction dans l’interface W&B. À chaque exécution de named_entity_recognation, les résultats complets de la trace sont visibles dans la Weave UI. Pour voir les traces, accédez à l’onglet Traces de votre projet Weave.
# Fonction NER pour les évaluations
@weave.op()
def named_entity_recognation(image_base64, id):
    result = {}
    try:
        # 1) appeler l'op de vision, récupérer une chaîne JSON
        output_text = extract_named_entities_from_image(image_base64)

        # 2) analyser le JSON une seule fois
        result = json.loads(output_text)

        print(f"Processed: {str(id)}")
    except Exception as e:
        print(f"Failed to process {str(id)}: {e}")
    return result
Enfin, exécutez le pipeline sur le jeu de données et consultez les résultats. Le code suivant parcourt le jeu de données et enregistre les résultats dans un fichier local processing_results.json. Les résultats sont également consultables dans Weave UI.
# Résultats de sortie
results = []

# parcourir toutes les images du jeu de données
for row in dataset.rows:
    result = named_entity_recognation(row["image_base64"], str(row["id"]))
    result["image_id"] = str(row["id"])
    results.append(result)

# Enregistrer tous les résultats dans un fichier JSON
output_file = "processing_results.json"
with open(output_file, "w") as f:
    json.dump(results, f, indent=2)

print(f"Results saved to: {output_file}")
Vous verrez un résultat semblable à celui-ci dans le tableau Traces de Weave UI.
Screenshot 2025-05-02 at 12.03.00 PM.png

4. Évaluer le pipeline avec Weave

Maintenant que vous avez créé un pipeline pour effectuer de la NER à l’aide d’un VLM, vous pouvez utiliser Weave pour l’évaluer de façon systématique et voir dans quelle mesure il est performant. Pour en savoir plus sur les évaluations dans Weave, consultez Aperçu des évaluations. Les évaluateurs constituent un élément fondamental d’une évaluation dans Weave. Les évaluateurs servent à évaluer les sorties de l’IA et à renvoyer des métriques d’évaluation. Ils prennent la sortie de l’IA, l’analysent et renvoient un dictionnaire de résultats. Les évaluateurs peuvent utiliser vos données d’entrée comme référence si nécessaire et peuvent également renvoyer des informations supplémentaires, comme des explications ou le raisonnement issu de l’évaluation. Dans cette section, vous allez créer deux évaluateurs pour évaluer le pipeline :
  1. Évaluateur programmatique
  2. Évaluateur LLM-as-a-judge

Scorer programmatique

Le scorer programmatique, check_for_missing_fields_programatically, prend la sortie du modèle (la sortie de la fonction named_entity_recognition) et identifie quelles keys sont manquantes ou vides dans les résultats. Cette vérification est particulièrement utile pour repérer les échantillons où le modèle n’a extrait aucun champ.
# Ajouter weave.op() pour suivre l'exécution du scorer
@weave.op()
def check_for_missing_fields_programatically(model_output):
    # Clés requises pour chaque entrée
    required_fields = {"Patient Name", "Date", "Patient ID", "Group Number"}

    for key in required_fields:
        if (
            key not in model_output
            or model_output[key] is None
            or str(model_output[key]).strip() == ""
        ):
            return False  # Cette entrée a un champ manquant ou vide

    return True  # Tous les champs requis sont présents et non vides

LLM-as-a-judge scorer

À l’étape suivante de l’évaluation, les données de l’image et la sortie du modèle sont toutes deux fournies afin de garantir que l’évaluation reflète les performances réelles en NER. Le contenu de l’image est explicitement pris en compte, et pas seulement la sortie du modèle. Le scorer utilisé pour cette étape, check_for_missing_fields_with_llm, utilise un LLM pour effectuer le scoring (plus précisément le gpt-4o d’OpenAI). Comme indiqué dans le contenu de eval_prompt, check_for_missing_fields_with_llm renvoie une valeur Boolean. Si tous les champs correspondent aux informations de l’image et que le formatage est correct, le scorer renvoie true. Si un champ est manquant, vide, incorrect ou ne correspond pas aux informations attendues, le résultat est false, et le scorer renvoie également un message expliquant le problème.
# Le prompt système pour le LLM-as-a-judge

eval_prompt = """
Vous êtes un système de validation OCR. Votre rôle est d'évaluer si le texte structuré extrait d'une image reflète fidèlement les informations contenues dans cette image.
Validez uniquement le texte structuré et utilisez l'image comme source de vérité.

Expected input text format:
{"Patient Name": "First Last", "Date": "04/23/25", "Patient ID": "131313JJH", "Group Number": "35453453"}

Critères d'évaluation :
- Les quatre champs doivent être présents.
- Aucun champ ne doit être vide ou contenir des valeurs fictives/malformées.
- Le champ "Date" doit être au format MM/JJ/AA (ex. : "04/07/25") (le remplissage avec des zéros est autorisé)

Score :
- Retourner : {"Correct": true, "Reason": ""} si **tous les champs** correspondent aux informations de l'image et que le formatage est correct.
- Retourner : {"Correct": false, "Reason": "EXPLANATION"} si **un** champ est manquant, vide, incorrect ou ne correspond pas.

Exigences de sortie :
- Répondre uniquement avec un objet JSON valide.
- "Correct" doit être un booléen JSON : true ou false (pas une chaîne ou un nombre).
- "Reason" doit être une chaîne courte et précise indiquant le problème — ex. : "Patient Name mismatch", "Date not zero-padded", ou "Missing Group Number".
- Ne pas retourner d'explication ou de formatage supplémentaire.

Votre réponse doit être exactement l'une des suivantes :
{"Correct": true, "Reason": null}
OR
{"Correct": false, "Reason": "EXPLANATION_HERE"}
"""

# Ajouter weave.op() pour suivre l'exécution du scorer
@weave.op()
def check_for_missing_fields_with_llm(model_output, image_base64):
    client = OpenAI()
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "developer", "content": [{"text": eval_prompt, "type": "text"}]},
            {
                "role": "user",
                "content": [
                    {
                        "type": "image_url",
                        "image_url": {
                            "url": image_base64,
                        },
                    },
                    {"type": "text", "text": str(model_output)},
                ],
            },
        ],
        response_format={"type": "json_object"},
    )
    response = json.loads(response.choices[0].message.content)
    return response

5. Lancer l’Évaluation

Enfin, définissez un appel d’évaluation qui parcourra automatiquement le dataset transmis et enregistrera les résultats dans la Weave UI. Le code suivant lance l’évaluation et applique les deux évaluateurs à chaque sortie du pipeline NER. Les résultats sont visibles dans l’onglet Evals de la Weave UI.
evaluation = weave.Evaluation(
    dataset=dataset,
    scorers=[
        check_for_missing_fields_with_llm,
        check_for_missing_fields_programatically,
    ],
    name="Evaluate_4.1_NER",
)

print(await evaluation.evaluate(named_entity_recognation))
Lorsque vous exécutez le code ci-dessus, un lien vers le tableau d’Évaluation dans la Weave UI est généré. Suivez ce lien pour afficher les résultats et comparer différentes itérations du pipeline sur les modèles, prompts et jeux de données de votre choix. La Weave UI crée automatiquement une visualisation comme celle ci-dessous pour votre équipe.
Screenshot 2025-05-02 at 12.26.15 PM.png