EvaluationLogger は、Python または TypeScript のコードから評価データを直接ログに記録するための、柔軟でインクリメンタルな方法を提供します。Weave の内部データ型に関する深い知識は必要ありません。ロガーをインスタンス化し、そのメソッド(log_prediction、log_score、log_summary)を使用して評価ステップを記録するだけです。
このアプローチは、データセット全体や基礎となるすべてのスコアラーが事前に定義されていないような、複雑なワークフローにおいて特に役立ちます。
定義済みの Dataset と Scorer オブジェクトのリストを必要とする標準的な Evaluation オブジェクトとは対照的に、EvaluationLogger では、個々の予測とそれに関連するスコアを、利用可能になった時点でインクリメンタルに記録できます。
より構造化された評価をお好みですか?定義済みのデータセットとスコアラーを備えた、より規範的な評価フレームワークを好む場合は、Weave の標準評価フレームワーク を参照してください。EvaluationLogger が柔軟性を提供するのに対し、標準フレームワークは構造とガイドラインを提供します。
基本的なワークフロー
- ロガーの初期化:
EvaluationLogger のインスタンスを作成します。オプションで model や dataset に関するメタデータを提供できます。省略した場合はデフォルト値が使用されます。
LLM 呼び出し(OpenAI など)のトークン使用量とコストを把握するには、LLM を呼び出す前に EvaluationLogger を初期化してください。
LLM を先に呼び出してから予測をログに記録した場合、トークンとコストのデータは取得されません。
- 予測のログ記録: システムからの各入力/出力ペアに対して
log_prediction を呼び出します。
- スコアのログ記録: 返された
ScoreLogger を使用して、予測に対する log_score を行います。1 つの予測に対して複数のスコアをサポートしています。
- 予測の終了: 予測のスコアをログに記録した後は、必ず
finish() を呼び出して確定させてください。
- サマリーのログ記録: すべての予測が処理された後、
log_summary を呼び出してスコアを集計し、オプションでカスタムメトリクスを追加します。
予測に対して finish() を呼び出した後は、その予測にスコアを記録することはできません。
説明したワークフローを示す Python コードについては、基本的な例 を参照してください。
基本的な例
次の例では、EvaluationLogger を使用して、既存のコード内で予測とスコアをインラインでログに記録する方法を示します。
user_model 関数が定義され、入力リストに適用されます。各例について:
- 入力と出力が
log_prediction を使用してログに記録されます。
- 単純な正解スコア(
correctness_score)が log_score 経由でログに記録されます。
finish() によってその予測のログ記録が完了します。
最後に、log_summary が集計メトリクスを記録し、Weave での自動スコアサマリーをトリガーします。
import weave
from openai import OpenAI
from weave import EvaluationLogger
weave.init('your-team/your-project')
# トークン追跡を確実にするため、モデルを呼び出す前に EvaluationLogger を初期化します
eval_logger = EvaluationLogger(
model="my_model",
dataset="my_dataset"
)
# 入力データの例(任意のデータ構造を使用できます)
eval_samples = [
{'inputs': {'a': 1, 'b': 2}, 'expected': 3},
{'inputs': {'a': 2, 'b': 3}, 'expected': 5},
{'inputs': {'a': 3, 'b': 4}, 'expected': 7},
]
# 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"
)
# レスポンスを何らかの方法で使用します(ここでは簡単のため a + b を返します)
return a + b
# サンプルを反復処理し、予測してログに記録します
for sample in eval_samples:
inputs = sample["inputs"]
model_output = user_model(**inputs) # 入力を kwargs として渡します
# 予測の入力と出力をログに記録します
pred_logger = eval_logger.log_prediction(
inputs=inputs,
output=model_output
)
# この予測のスコアを計算してログに記録します
expected = sample["expected"]
correctness_score = model_output == expected
pred_logger.log_score(
scorer="correctness", # スコアラーのシンプルな文字列名
score=correctness_score
)
# この特定の予測のログ記録を終了します
pred_logger.finish()
# 評価全体の最終サマリーをログに記録します。
# Weave は上記でログに記録された 'correctness' スコアを自動的に集計します。
summary_stats = {"subjective_overall_score": 0.8}
eval_logger.log_summary(summary_stats)
print("Evaluation logging complete. View results in the Weave UI.")
TypeScript SDK は 2 つの API パターンを提供します。
- Fire-and-forget API(ほとんどの場合に推奨):同期的な非ブロッキング ログ記録のために、
await なしで logPrediction() を使用します。
- Awaitable API:処理を進める前に操作が完了したことを確認する必要がある場合に、
await 付きで logPredictionAsync() を使用します。
以下の理由から fire-and-forget を推奨します:
- 高スループット:各ログ操作を待たずに、複数の予測を並列で処理できます。
- 最小限のコード変更:既存の async/await フローを再構築することなく、評価ログを追加できます。
- シンプルさ:ほとんどの評価シナリオにおいて、ボイラープレートコードが少なく、構文がクリーンになります。
logSummary() は、結果を集計する前に保留中のすべての操作が完了するのを自動的に待機するため、fire-and-forget パターンは安全です。次の例では、fire-and-forget パターンを使用してモデルの予測を評価します。評価ロガーを設定し、3 つのテストサンプルでシンプルなモデルを実行し、await を使用せずに予測をログに記録します。import weave, {EvaluationLogger} from 'weave';
import OpenAI from 'openai';
await weave.init('your-team/your-project');
// トークン追跡を確実にするため、モデルを呼び出す前に EvaluationLogger を初期化します
const evalLogger = new EvaluationLogger({
name: 'my-eval',
model: 'my_model',
dataset: 'my_dataset'
});
// 入力データの例
const evalSamples = [
{inputs: {a: 1, b: 2}, expected: 3},
{inputs: {a: 2, b: 3}, expected: 5},
{inputs: {a: 3, b: 4}, expected: 7},
];
// 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;
});
// サンプルを反復処理し、予測し、fire-and-forget パターンでログに記録します
for (const sample of evalSamples) {
const {inputs} = sample;
const modelOutput = await userModel(inputs.a, inputs.b);
// Fire-and-forget: logPrediction に await は不要です
const scoreLogger = evalLogger.logPrediction(inputs, modelOutput);
// この予測のスコアを計算してログに記録します
const correctnessScore = modelOutput === sample.expected;
// Fire-and-forget: logScore に await は不要です
scoreLogger.logScore('correctness', correctnessScore);
// Fire-and-forget: finish に await は不要です
scoreLogger.finish();
}
// logSummary は内部で保留中のすべての操作が完了するのを待ちます
const summaryStats = {subjective_overall_score: 0.8};
await evalLogger.logSummary(summaryStats);
console.log('Evaluation logging complete. View results in the Weave UI.');
エラーハンドリングや逐次的な依存関係を管理する場合など、各操作が完了してから次に進む必要がある場合は、awaitable API を使用してください。次の例では、await なしの logPrediction() を呼び出す代わりに、await 付きの logPredictionAsync() を使用して、各操作が完了してから次へ進むようにしています。// logPrediction の代わりに logPredictionAsync を使用します
const scoreLogger = await evalLogger.logPredictionAsync(inputs, modelOutput);
// 各操作を await します
await scoreLogger.logScore('correctness', correctnessScore);
await scoreLogger.finish();
高度な使用法
EvaluationLogger は、より複雑な評価シナリオに対応するために、基本的なワークフローを超えた柔軟なパターンを提供します。このセクションでは、自動リソース管理のためのコンテキストマネージャーの使用、モデル実行とログ記録の分離、リッチメディアデータの処理、複数のモデル評価の並列比較などの高度なテクニックについて説明します。
コンテキストマネージャーの使用
EvaluationLogger は、予測とスコアの両方でコンテキストマネージャー(with ステートメント)をサポートしています。これにより、コードがよりクリーンになり、リソースの自動クリーンアップが可能になり、LLM 判定の呼び出しなどのネストされた操作の追跡が改善されます。
この文脈で with ステートメントを使用すると、以下の利点があります:
- コンテキストを抜けるときに
finish() が自動的に呼び出される
- ネストされた LLM 呼び出しのトークン/コスト追跡が改善される
- 予測コンテキスト内でのモデル実行後に出力を設定できる
import openai
import weave
weave.init("nested-evaluation-example")
oai = openai.OpenAI()
# ロガーの初期化
ev = weave.EvaluationLogger(
model="gpt-4o-mini",
dataset="joke_dataset"
)
user_prompt = "Tell me a joke"
# 予測にコンテキストマネージャーを使用 - finish() を呼び出す必要はありません
with ev.log_prediction(inputs={"user_prompt": user_prompt}) as pred:
# コンテキスト内でモデル呼び出しを行います
result = oai.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": user_prompt}],
)
# モデル呼び出し後に出力を設定します
pred.output = result.choices[0].message.content
# シンプルなスコアをログに記録します
pred.log_score("correctness", 1.0)
pred.log_score("ambiguity", 0.3)
# 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},
],
)
# 計算後にスコア値を設定します
score.value = judge_result.choices[0].message.content
# 'with' ブロックを抜けるときに finish() が自動的に呼び出されます
ev.log_summary({"avg_score": 1.0})
このパターンにより、すべてのネストされた操作が追跡され、親の予測に帰属することが保証され、Weave UI で正確なトークン使用量とコストデータが得られます。TypeScript には Python のコンテキストマネージャーのような with ステートメントのパターンはありません。代わりに、明示的な finish() 呼び出しを伴う fire-and-forget パターンを使用してください。次の例では、予測をログに記録し、シンプルなスコアと LLM 判定スコアを追加してから、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();
// ロガーの初期化
const ev = new EvaluationLogger({
name: 'joke-eval',
model: 'gpt-4o-mini',
dataset: 'joke_dataset',
});
const userPrompt = 'Tell me a joke';
// モデル出力を取得
const result = await oai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{role: 'user', content: userPrompt}],
});
const modelOutput = result.choices[0].message.content;
// 出力とともに予測をログに記録
const pred = ev.logPrediction({user_prompt: userPrompt}, modelOutput);
// シンプルなスコアをログに記録
pred.logScore('correctness', 1.0);
pred.logScore('ambiguity', 0.3);
// LLM 判定スコアの場合、呼び出しを行って結果をログに記録
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);
// スコアリングが完了したら明示的に finish を呼び出します
pred.finish();
await ev.logSummary({avg_score: 1.0});
TypeScript にはコンテキストマネージャーによる自動クリーンアップはありませんが、logSummary() は結果を集計する前に、未完了の予測を自動的に終了させます。明示的に finish() を呼び出したくない場合は、この動作を利用できます。
ログ記録の前に出力を取得する
最初にモデルの出力を計算し、後で予測とスコアを個別にログに記録することができます。これにより、評価ロジックとログ記録ロジックをより適切に分離できます。
# トークン追跡を確実にするため、モデルを呼び出す前に EvaluationLogger を初期化します
ev = EvaluationLogger(
model="example_model",
dataset="example_dataset"
)
# モデル出力(例:OpenAI 呼び出し)は、トークン追跡のためにロガー初期化後に行う必要があります
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()
複数の予測を並列で処理する場合、fire-and-forget パターンが非常に有効です。次の例では、EvaluationLogger の複数の同時インスタンスを作成することで、評価を並列でバッチ処理しています。// トークン追跡を確実にするため、モデルを呼び出す前に EvaluationLogger を初期化します
const ev = new EvaluationLogger({
name: 'parallel-eval',
model: 'example_model',
dataset: 'example_dataset'
});
// トークン追跡のため、OpenAI 呼び出しなどのモデル出力はロガー初期化後に行う必要があります
const outputs = await Promise.all(
yourDataset.map(inputs => yourOutputGenerator(inputs))
);
// Fire-and-forget: await せずにすべての予測を処理します
const preds = yourDataset.map((inputs, i) =>
ev.logPrediction(inputs, outputs[i])
);
preds.forEach((pred, i) => {
const output = outputs[i];
// Fire-and-forget: await は不要です
pred.logScore('greater_than_5_scorer', output > 5);
pred.logScore('greater_than_7_scorer', output > 7);
pred.finish();
});
// logSummary は保留中のすべての操作を待ちます
await ev.logSummary();
fire-and-forget パターンを使用すると、計算リソースが許す限り、いくらでも評価を並列で処理できます。
リッチメディアのログ記録
入力、出力、スコアには、画像、動画、音声、構造化テーブルなどのリッチメディアを含めることができます。log_prediction または 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 # 16ビット最大振幅
buffer = io.BytesIO()
# wave データをバッファに書き込む
with wave.open(buffer, 'wb') as wf:
wf.setnchannels(1)
wf.setsampwidth(2) # 16ビット
wf.setframerate(sample_rate)
for _ in range(n_samples):
sample = random.randint(-amplitude, amplitude)
wf.writeframes(struct.pack('<h', sample))
# バッファを最初から読み取れるように巻き戻す
buffer.seek(0)
# 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()
TypeScript SDK は weaveImage 関数と weaveAudio 関数を使用した画像と音声のログ記録をサポートしています。次の例では、画像ファイルと音声ファイルを読み込み、モデルで処理し、スコアとともに結果をログに記録します。import weave, {EvaluationLogger} from 'weave';
import * as fs from 'fs';
await weave.init('your-team/your-project');
// ファイルから画像と音声を読み込む
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')}),
},
];
// メディアを処理して結果を返すモデル
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);
// 入力と出力の両方にリッチメディアを含む予測をログに記録
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();
複数の評価をログに記録して比較する
EvaluationLogger を使用すると、複数の評価をログに記録して比較できます。
-
下記のサンプルコードを実行します。
-
Weave UI で、
Evals タブに移動します。
-
比較したい評価(evals)を選択します。
-
Compare ボタンをクリックします。比較ビューでは、以下のことができます。
- 追加または削除する評価の選択
- 表示または非表示にするメトリクスの選択
- 特定の例をページ送りして、同じデータセットの同じ入力に対して異なるモデルがどのように機能したかを確認
比較の詳細については、Comparisons を参照してください。
import weave
models = [
"model1",
"model2",
{"name": "model3", "metadata": {"coolness": 9001}}
]
for model in models:
# トークンをキャプチャするため、モデルを呼び出す前に EvalLogger を初期化する必要があります
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 を初期化する必要があります
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);
// クリーンで効率的なログ記録のための fire-and-forget パターン
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();
}
使用上のヒント
- 各予測の直後に速やかに
finish() を呼び出してください。
log_summary を使用して、単一の予測に関連付けられていないメトリクス(例:全体のレイテンシ)をキャプチャします。
- リッチメディアのログ記録は定性分析に最適です。
- 自動終了動作: 明確にするために各予測で明示的に
finish() を呼び出すことを推奨しますが、logSummary() は未完了の予測を自動的に終了させます。ただし、スクリプトが finish() を呼び出すと、それ以上スコアを記録することはできません。
- 設定オプション:
name、description、dataset、model、scorers、attributes などの設定オプションを使用して、Weave UI で評価を整理およびフィルタリングします。