EvaluationLogger offre un moyen flexible et incrémentiel de journaliser des données d’évaluation directement depuis votre code Python ou TypeScript. Vous n’avez pas besoin d’une connaissance approfondie des types de données internes de Weave : il vous suffit d’instancier un logger et d’utiliser ses méthodes (log_prediction, log_score, log_summary) pour enregistrer les étapes de l’évaluation.
Cette approche est particulièrement utile dans les flux de travail complexes où l’ensemble du jeu de données ou tous les évaluateurs ne sont pas forcément définis à l’avance.
Contrairement à l’objet Evaluation standard, qui nécessite un Dataset prédéfini et une liste d’objets Scorer, EvaluationLogger vous permet de journaliser des prédictions individuelles et les scores associés de façon incrémentielle, à mesure qu’ils deviennent disponibles.
Vous préférez une évaluation plus structurée ?Si vous préférez un framework d’évaluation plus prescriptif avec des jeux de données et des évaluateurs prédéfinis, Voir le framework Evaluation standard de Weave.EvaluationLogger offre de la flexibilité, tandis que le framework standard apporte structure et orientation.
- Initialisez le logger : Créez une instance de
EvaluationLogger, en fournissant éventuellement des métadonnées sur le modèle et le jeu de données. Les valeurs par défaut seront utilisées si vous les omettez.
Pour capturer l’utilisation des tokens et le coût des LLM calls (par ex. OpenAI), initialisez EvaluationLogger avant toute invocation de LLM**.
Si vous appelez d’abord votre LLM, puis consignez les prédictions ensuite, les données de token et de coût ne seront pas capturées.
- Consignez les prédictions : Appelez
log_prediction pour chaque paire entrée/sortie de votre système.
- Consignez les scores : Utilisez le
ScoreLogger renvoyé pour appeler log_score pour la prédiction. Plusieurs scores par prédiction sont pris en charge.
- Terminez la prédiction : Appelez toujours
finish() après avoir consigné les scores d’une prédiction afin de la finaliser.
- Consignez le résumé : Une fois toutes les prédictions traitées, appelez
log_summary pour agréger les scores et ajouter des métriques personnalisées facultatives.
Après avoir appelé finish() sur une prédiction, il n’est plus possible d’y consigner d’autres scores.
Pour voir un exemple de code Python illustrant le flux de travail décrit, consultez le Basic example.
L’exemple suivant montre comment utiliser EvaluationLogger pour journaliser les prédictions et les scores directement dans votre code existant.
La fonction de modèle user_model est définie puis appliquée à une liste d’entrées. Pour chaque exemple :
- L’entrée et la sortie sont enregistrées à l’aide de
log_prediction.
- Un score simple de correction (
correctness_score) est enregistré via log_score.
finish() finalise l’enregistrement pour cette prédiction.
Enfin, log_summary enregistre les métriques agrégées et déclenche la synthèse automatique des scores dans Weave.
import weave
from openai import OpenAI
from weave import EvaluationLogger
weave.init('your-team/your-project')
# Initialiser EvaluationLogger AVANT d'appeler le modèle pour garantir le suivi des tokens
eval_logger = EvaluationLogger(
model="my_model",
dataset="my_dataset"
)
# Exemple de données d'entrée (peut être n'importe quelle structure de données)
eval_samples = [
{'inputs': {'a': 1, 'b': 2}, 'expected': 3},
{'inputs': {'a': 2, 'b': 3}, 'expected': 5},
{'inputs': {'a': 3, 'b': 4}, 'expected': 7},
]
# Exemple de logique de modèle utilisant OpenAI
@weave.op
def user_model(a: int, b: int) -> int:
oai = OpenAI()
response = oai.chat.completions.create(
messages=[{"role": "user", "content": f"What is {a}+{b}?"}],
model="gpt-4o-mini"
)
# Utiliser la réponse d'une façon ou d'une autre (ici on retourne simplement a + b pour simplifier)
return a + b
# Parcourir les exemples, effectuer des prédictions et enregistrer
for sample in eval_samples:
inputs = sample["inputs"]
model_output = user_model(**inputs) # Passer les entrées en tant que kwargs
# Enregistrer l'entrée et la sortie de la prédiction
pred_logger = eval_logger.log_prediction(
inputs=inputs,
output=model_output
)
# Calculer et enregistrer un score pour cette prédiction
expected = sample["expected"]
correctness_score = model_output == expected
pred_logger.log_score(
scorer="correctness", # Nom de chaîne simple pour le scorer
score=correctness_score
)
# Finaliser l'enregistrement pour cette prédiction spécifique
pred_logger.finish()
# Enregistrer un résumé final pour l'ensemble de l'évaluation.
# Weave agrège automatiquement les scores 'correctness' enregistrés ci-dessus.
summary_stats = {"subjective_overall_score": 0.8}
eval_logger.log_summary(summary_stats)
print("Enregistrement de l'évaluation terminé. Consultez les résultats dans l'interface Weave.")
Le SDK TypeScript propose deux modèles d’API :
- API fire-and-forget (recommandée dans la plupart des cas) : utilisez
logPrediction() sans await pour une journalisation synchrone et non bloquante
- API avec attente : utilisez
logPredictionAsync() avec await lorsque vous devez vous assurer que les opérations sont terminées avant de continuer
Nous recommandons fire-and-forget dans les cas suivants :
- Débit élevé : traitez plusieurs prédictions en parallèle sans attendre chaque opération de journalisation
- Modification minimale du code : ajoutez la journalisation de l’évaluation sans restructurer votre flux async/await existant
- Simplicité : moins de code passe-partout et une syntaxe plus claire pour la plupart des scénarios d’évaluation
Le modèle fire-and-forget est sûr, car logSummary() attend automatiquement la fin de toutes les opérations en attente avant d’agréger les résultats.L’exemple suivant évalue les prédictions d’un modèle avec le modèle fire-and-forget. Il configure un logger d’évaluation, exécute un modèle simple sur trois échantillons de test, puis journalise la prédiction sans utiliser await :import weave, {EvaluationLogger} from 'weave';
import OpenAI from 'openai';
await weave.init('your-team/your-project');
// Initialiser EvaluationLogger AVANT d'appeler le modèle pour garantir le suivi des tokens
const evalLogger = new EvaluationLogger({
name: 'my-eval',
model: 'my_model',
dataset: 'my_dataset'
});
// Exemple de données d'entrée
const evalSamples = [
{inputs: {a: 1, b: 2}, expected: 3},
{inputs: {a: 2, b: 3}, expected: 5},
{inputs: {a: 3, b: 4}, expected: 7},
];
// Exemple de logique de modèle avec OpenAI
const userModel = weave.op(async function userModel(a: number, b: number): Promise<number> {
const oai = new OpenAI();
const response = await oai.chat.completions.create({
messages: [{role: 'user', content: `What is ${a}+${b}?`}],
model: 'gpt-4o-mini'
});
return a + b;
});
// Itérer sur les exemples, effectuer des prédictions et journaliser avec le pattern fire-and-forget
for (const sample of evalSamples) {
const {inputs} = sample;
const modelOutput = await userModel(inputs.a, inputs.b);
// Fire-and-forget : aucun await nécessaire pour logPrediction
const scoreLogger = evalLogger.logPrediction(inputs, modelOutput);
// Calculer et journaliser un score pour cette prédiction
const correctnessScore = modelOutput === sample.expected;
// Fire-and-forget : aucun await nécessaire pour logScore
scoreLogger.logScore('correctness', correctnessScore);
// Fire-and-forget : aucun await nécessaire pour finish
scoreLogger.finish();
}
// logSummary attend en interne la fin de toutes les opérations en cours
const summaryStats = {subjective_overall_score: 0.8};
await evalLogger.logSummary(summaryStats);
console.log('Journalisation de l\'évaluation terminée. Consultez les résultats dans l\'interface Weave.');
Utilisez l’API awaitable lorsque vous devez vous assurer que chaque opération est terminée avant de continuer, par exemple pour la gestion des erreurs ou des dépendances séquentielles.Dans l’exemple suivant, au lieu d’appeler logPrediction() sans await, on utilise logPredictionAsync() avec await pour s’assurer que chaque opération est terminée avant de passer à la suivante :// Utiliser logPredictionAsync plutôt que logPrediction
const scoreLogger = await evalLogger.logPredictionAsync(inputs, modelOutput);
// Attendre la fin de chaque opération
await scoreLogger.logScore('correctness', correctnessScore);
await scoreLogger.finish();
EvaluationLogger offre des modes d’utilisation flexibles au-delà du flux de travail de base pour répondre à des scénarios d’évaluation plus complexes. Cette section présente des techniques avancées, notamment l’utilisation de gestionnaires de contexte pour la gestion automatique des ressources, la séparation de l’exécution du modèle et de la journalisation, l’utilisation de données de médias enrichis et la comparaison côte à côte de plusieurs évaluations de modèles.
Utiliser des gestionnaires de contexte
EvaluationLogger prend en charge les gestionnaires de contexte (instructions with) pour les prédictions comme pour les scores. Cela permet d’avoir un code plus clair, un nettoyage automatique des ressources et un meilleur suivi des opérations imbriquées, comme les appels à un LLM judge.
L’utilisation des instructions with dans ce contexte offre les avantages suivants :
- Appels automatiques à
finish() à la sortie du contexte
- Meilleur suivi des tokens/coûts pour les appels LLM imbriqués
- Définition de la sortie après l’exécution du modèle dans le contexte de prédiction
import openai
import weave
weave.init("nested-evaluation-example")
oai = openai.OpenAI()
# Initialiser le logger
ev = weave.EvaluationLogger(
model="gpt-4o-mini",
dataset="joke_dataset"
)
user_prompt = "Tell me a joke"
# Utiliser un gestionnaire de contexte pour la prédiction - pas besoin d'appeler finish()
with ev.log_prediction(inputs={"user_prompt": user_prompt}) as pred:
# Effectuez votre appel au modèle dans le contexte
result = oai.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": user_prompt}],
)
# Définir la sortie après l'appel au modèle
pred.output = result.choices[0].message.content
# Journaliser des scores simples
pred.log_score("correctness", 1.0)
pred.log_score("ambiguity", 0.3)
# Utiliser un gestionnaire de contexte imbriqué pour les scores qui nécessitent des appels LLM
with pred.log_score("llm_judge") as score:
judge_result = oai.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Rate how funny the joke is from 1-5"},
{"role": "user", "content": pred.output},
],
)
# Définir la valeur du score après le calcul
score.value = judge_result.choices[0].message.content
# finish() est automatiquement appelé à la sortie du bloc 'with'
ev.log_summary({"avg_score": 1.0})
Ce schéma garantit que toutes les opérations imbriquées sont suivies et attribuées à la prédiction parente, ce qui vous donne des données précises d’utilisation des tokens et de coût dans la Weave UI.TypeScript ne prend pas en charge le modèle d’instruction with de Python pour les gestionnaires de contexte. Utilisez plutôt le modèle fire-and-forget avec des appels explicites à finish().L’exemple suivant journalise une prédiction, ajoute des scores simples et un score de LLM judge, puis finalise la prédiction avec finish() :import weave from 'weave';
import OpenAI from 'openai';
import {EvaluationLogger} from 'weave/evaluationLogger';
await weave.init('your-team/your-project');
const oai = new OpenAI();
// Initialiser le logger
const ev = new EvaluationLogger({
name: 'joke-eval',
model: 'gpt-4o-mini',
dataset: 'joke_dataset',
});
const userPrompt = 'Tell me a joke';
// Obtenir la sortie du modèle
const result = await oai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{role: 'user', content: userPrompt}],
});
const modelOutput = result.choices[0].message.content;
// Journaliser la prédiction avec la sortie
const pred = ev.logPrediction({user_prompt: userPrompt}, modelOutput);
// Journaliser des scores simples
pred.logScore('correctness', 1.0);
pred.logScore('ambiguity', 0.3);
// Pour les scores de LLM judge, effectuez l'appel et journalisez le résultat
const judgeResult = await oai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{role: 'system', content: 'Rate how funny the joke is from 1-5'},
{role: 'user', content: modelOutput || ''},
],
});
pred.logScore('llm_judge', judgeResult.choices[0].message.content);
// Appeler explicitement finish une fois le scoring terminé
pred.finish();
await ev.logSummary({avg_score: 1.0});
Bien que TypeScript ne dispose pas de nettoyage automatique avec les gestionnaires de contexte, logSummary() finalise automatiquement toute prédiction non terminée avant d’agréger les résultats. Vous pouvez vous appuyer sur ce comportement si vous préférez ne pas appeler finish() explicitement.
Lier à un jeu de données existant
Lorsque vous passez des jeux de données bruts comme inputs à log_prediction, Weave réimporte les données à chaque exécution d’évaluation. Cela stocke des données en double, ce qui peut gaspiller de l’espace si le jeu de données est volumineux ou si un grand nombre d’évaluations le réutilisent.
Pour éviter cette duplication, publiez votre jeu de données dans Weave avant d’exécuter des évaluations, puis passez les lignes du jeu de données publié comme inputs. Weave résout les références aux lignes publiées à l’aide de références internes au lieu de réimporter les données. Cette technique vous offre la même expérience de liaison que le framework d’évaluation standard, où chaque prédiction renvoie à une ligne précise du jeu de données dans la Weave UI.
L’exemple suivant publie un jeu de données et y crée un lien dans EvaluationLogger, avant de le récupérer et de l’itérer comme n’importe quel autre jeu de données.
import weave
from weave import EvaluationLogger
weave.init("your-team-name/your-project-name")
# Publier le jeu de données (ne doit être fait qu'une seule fois)
dataset = weave.Dataset(
name="my_eval_dataset",
rows=[
{"question": "What is the capitol of France?", "expected": "Paris"},
{"question": "What U.S. state is Seattle in?", "expected": "Washington"},
{"question": "In what country is Mount Fuji located in?", "expected": "Japan"},
],
)
weave.publish(dataset)
# Récupérer le jeu de données publié
dataset = weave.ref("my_eval_dataset").get()
import weave, {EvaluationLogger, Dataset} from 'weave';
await weave.init('your-team-name/your-project-name');
// Publier le jeu de données (ne doit être fait qu'une seule fois)
const dataset = new Dataset({
name: 'my_eval_dataset',
rows: [
{"question": "What is the capitol of France?", "expected": "Paris"},
{"question": "What U.S. state is Seattle in?", "expected": "Washington"},
{"question": "In what country is Mount Fuji located in?", "expected": "Japan"},
],
});
const datasetRef = await dataset.save();
// Récupérer le jeu de données publié
const published = await datasetRef.get();
Obtenir les sorties avant le logging
Vous pouvez d’abord calculer les sorties de votre modèle, puis consigner séparément les prédictions et les scores. Cela permet de mieux dissocier la logique d’évaluation de celle du logging.
# Initialisez EvaluationLogger AVANT d'appeler le modèle pour garantir le suivi des tokens
ev = EvaluationLogger(
model="example_model",
dataset="example_dataset"
)
# Les sorties du modèle (par ex. les appels OpenAI) doivent être générées après l'initialisation du logger pour le suivi des tokens
outputs = [your_output_generator(**inputs) for inputs in your_dataset]
preds = [ev.log_prediction(inputs, output) for inputs, output in zip(your_dataset, outputs)]
for pred, output in zip(preds, outputs):
pred.log_score(scorer="greater_than_5_scorer", score=output > 5)
pred.log_score(scorer="greater_than_7_scorer", score=output > 7)
pred.finish()
ev.log_summary()
Le modèle « fire-and-forget » est particulièrement efficace pour traiter plusieurs prédictions en parallèle.L’exemple suivant traite des évaluations par lots en parallèle en créant plusieurs instances concurrentes de EvaluationLogger :// Initialisez EvaluationLogger AVANT d'appeler le modèle pour garantir le suivi des tokens
const ev = new EvaluationLogger({
name: 'parallel-eval',
model: 'example_model',
dataset: 'example_dataset'
});
// Les sorties du modèle, comme les appels OpenAI, doivent être générées après l'initialisation du logger pour le suivi des tokens
const outputs = await Promise.all(
yourDataset.map(inputs => yourOutputGenerator(inputs))
);
// Fire-and-forget : traite toutes les prédictions sans attendre
const preds = yourDataset.map((inputs, i) =>
ev.logPrediction(inputs, outputs[i])
);
preds.forEach((pred, i) => {
const output = outputs[i];
// Fire-and-forget : aucun await nécessaire
pred.logScore('greater_than_5_scorer', output > 5);
pred.logScore('greater_than_7_scorer', output > 7);
pred.finish();
});
// logSummary attend toutes les opérations en attente
await ev.logSummary();
Vous pouvez utiliser le modèle « fire-and-forget » pour traiter autant d’évaluations en parallèle que vos ressources de calcul le permettent.
Les entrées, les sorties et les scores peuvent inclure des médias enrichis, comme des images, des vidéos, de l’audio ou des tableaux structurés. Il suffit de passer un dict ou un objet média aux méthodes log_prediction ou log_score.
import io
import wave
import struct
from PIL import Image
import random
from typing import Any
import weave
def generate_random_audio_wave_read(duration=2, sample_rate=44100):
n_samples = duration * sample_rate
amplitude = 32767 # amplitude maximale sur 16 bits
buffer = io.BytesIO()
# Écrire les données wave dans le tampon
with wave.open(buffer, 'wb') as wf:
wf.setnchannels(1)
wf.setsampwidth(2) # 16 bits
wf.setframerate(sample_rate)
for _ in range(n_samples):
sample = random.randint(-amplitude, amplitude)
wf.writeframes(struct.pack('<h', sample))
# Rembobiner le tampon au début pour pouvoir le lire
buffer.seek(0)
# Renvoyer un objet Wave_read
return wave.open(buffer, 'rb')
rich_media_dataset = [
{
'image': Image.new(
"RGB",
(100, 100),
color=(
random.randint(0, 255),
random.randint(0, 255),
random.randint(0, 255),
),
),
"audio": generate_random_audio_wave_read(),
}
for _ in range(5)
]
@weave.op
def your_output_generator(image: Image.Image, audio) -> dict[str, Any]:
return {
"result": random.randint(0, 10),
"image": image,
"audio": audio,
}
ev = EvaluationLogger(model="example_model", dataset="example_dataset")
for inputs in rich_media_dataset:
output = your_output_generator(**inputs)
pred = ev.log_prediction(inputs, output)
pred.log_score(scorer="greater_than_5_scorer", score=output["result"] > 5)
pred.log_score(scorer="greater_than_7_scorer", score=output["result"] > 7)
ev.log_summary()
Le SDK TypeScript prend en charge la journalisation d’images et de fichiers audio à l’aide des fonctions weaveImage et weaveAudio. L’exemple suivant charge des fichiers image et audio, les traite avec un modèle et journalise les résultats avec des scores.import weave, {EvaluationLogger} from 'weave';
import * as fs from 'fs';
await weave.init('your-team/your-project');
// Charger les images et l’audio à partir de fichiers
const richMediaDataset = [
{
image: weave.weaveImage({data: fs.readFileSync('sample1.png')}),
audio: weave.weaveAudio({data: fs.readFileSync('sample1.wav')}),
},
{
image: weave.weaveImage({data: fs.readFileSync('sample2.png')}),
audio: weave.weaveAudio({data: fs.readFileSync('sample2.wav')}),
},
];
// Modèle qui traite les médias et renvoie les résultats
const yourOutputGenerator = weave.op(
async (inputs: {image: any; audio: any}) => {
const result = Math.floor(Math.random() * 10);
return {
result,
image: inputs.image,
audio: inputs.audio,
};
},
{name: 'yourOutputGenerator'}
);
const ev = new EvaluationLogger({
name: 'rich-media-eval',
model: 'example_model',
dataset: 'example_dataset',
});
for (const inputs of richMediaDataset) {
const output = await yourOutputGenerator(inputs);
// Journaliser la prédiction avec des médias enrichis dans les entrées comme dans les sorties
const pred = ev.logPrediction(inputs, output);
pred.logScore('greater_than_5_scorer', output.result > 5);
pred.logScore('greater_than_7_scorer', output.result > 7);
pred.finish();
}
await ev.logSummary();
Journaliser et comparer plusieurs évaluations
Avec EvaluationLogger, vous pouvez journaliser et comparer plusieurs évaluations.
-
Exécutez l’exemple de code ci-dessous.
-
Dans la Weave UI, accédez à l’onglet
Evals.
-
Sélectionnez les evals que vous souhaitez comparer.
-
Cliquez sur le bouton Compare. Dans la vue de comparaison, vous pouvez :
- Choisir quelles evals ajouter ou supprimer
- Choisir quelles métriques afficher ou masquer
- Parcourir des exemples précis pour voir comment différents modèles se sont comportés pour la même entrée dans un jeu de données donné
Pour plus d’informations sur les comparaisons, voir Comparisons
import weave
models = [
"model1",
"model2",
{"name": "model3", "metadata": {"coolness": 9001}}
]
for model in models:
# EvalLogger doit être initialisé avant les appels au modèle pour capturer les tokens
ev = EvaluationLogger(
name="comparison-eval",
model=model,
dataset="example_dataset",
scorers=["greater_than_3_scorer", "greater_than_5_scorer", "greater_than_7_scorer"],
eval_attributes={"experiment_id": "exp_123"}
)
for inputs in your_dataset:
output = your_output_generator(**inputs)
pred = ev.log_prediction(inputs=inputs, output=output)
pred.log_score(scorer="greater_than_3_scorer", score=output > 3)
pred.log_score(scorer="greater_than_5_scorer", score=output > 5)
pred.log_score(scorer="greater_than_7_scorer", score=output > 7)
pred.finish()
ev.log_summary()
import weave from 'weave';
import {EvaluationLogger} from 'weave/evaluationLogger';
import {WeaveObject} from 'weave/weaveObject';
await weave.init('your-team/your-project');
const models = [
'model1',
'model2',
new WeaveObject({name: 'model3', metadata: {coolness: 9001}})
];
for (const model of models) {
// EvalLogger doit être initialisé avant les appels au modèle pour capturer les tokens
const ev = new EvaluationLogger({
name: 'comparison-eval',
model: model,
dataset: 'example_dataset',
description: 'Model comparison evaluation',
scorers: ['greater_than_3_scorer', 'greater_than_5_scorer', 'greater_than_7_scorer'],
attributes: {experiment_id: 'exp_123'}
});
for (const inputs of yourDataset) {
const output = await yourOutputGenerator(inputs);
// Pattern « fire-and-forget » pour une journalisation simple et efficace
const pred = ev.logPrediction(inputs, output);
pred.logScore('greater_than_3_scorer', output > 3);
pred.logScore('greater_than_5_scorer', output > 5);
pred.logScore('greater_than_7_scorer', output > 7);
pred.finish();
}
await ev.logSummary();
}
- Appelez
finish() rapidement après chaque prédiction.
- Utilisez
log_summary pour enregistrer des métriques qui ne sont pas liées à une prédiction individuelle (par ex., la latence globale).
- La journalisation des médias enrichis est idéale pour l’analyse qualitative.
- Comportement de fin automatique : Bien que nous recommandions d’appeler explicitement
finish() pour chaque prédiction par souci de clarté, logSummary() termine automatiquement toutes les prédictions non terminées. En revanche, une fois que le script a appelé finish(), il ne peut plus enregistrer de scores.
- Options de configuration : Utilisez les options de configuration, notamment
name, description, dataset, model, scorers et attributes, pour organiser et filtrer vos évaluations dans la Weave UI.