online evalsの重要性
本番運用中に行うべきこと
評価が一通り終わり、本番運用を開始したとしても、AI Agentは多くのケースで自然言語などの非構造データを受け付けるため、入力の自由度が高く、想定外の問いや使い方が発生しやすい特性があります。さらに、利用が広がるにつれてユーザーの使い方や期待値も変化し、運用の中で挙動のドリフトが起きやすくなります。
LLMアプリケーションの本番運用では、典型的に次のような問題が起きます。
- 入力分布の変化(ドリフト): 新しい業務・季節性・ユーザー層の変化で、想定外の入力が増える
- ロングテールの失敗: オフライン評価に含まれていない稀なケースで破綻する
- 品質とコストのトレードオフ: 品質指標を上げるほど、レイテンシやコストが増えやすい
- 安全性の継続的担保: 有害性、PII(個人情報)、ポリシー違反などは常にリスクになる
こうした現実に対して、オンライン評価は「本番の実データを観測し、必要ならその場で介入する」ための仕組みです。トレースがあることで 何が起きたか は追えますが、オンライン評価はそこに 良し悪し の軸を付与し、運用上の判断を可能にします。
方法としては、アプリケーション上でヒューマンフィードバックを集める方法や、品質を担保するためにガードレールを用いる方法、後で改善に向けたヒントや不具合の兆候を確認するためのモニタリングがあります。また、コストが高くなりすぎていないか、レイテンシーが長すぎていないかなどの観点も含めて、複数の仕組みを組み合わせることが重要です。
ガードレールとモニタリング
online evalsでは、主にガードレールとモニタリングを考えます。
ガードレールは、問題のある入力や出力がユーザーに届く前に、ブロックしたり修正したりするための仕組みです。一方、モニターは、本番トラフィックを継続的に評価し、品質や安全性の傾向、劣化、不具合の兆候を観測するための仕組みです。
両者の基盤になるのがScorerです。Scorerはガードレールにもモニターにも使えますが、目的と運用要件は異なります。重要なのは、同じ採点ロジックでも、介入するか観測するかで設計が変わる点です。
| 側面 | ガードレール | モニター |
|---|---|---|
| 目的 | 問題を防ぐための能動的介入 | 分析のための受動的観察 |
| タイミング | リアルタイム(出力前) | 非同期またはバッチ処理可能 |
| パフォーマンス | 高速である必要あり | バックグラウンドで実行可能 |
| サンプリング | 通常は全リクエスト | サンプリング可能(例: 10%) |
| 制御フロー | 出力をブロック・修正可能 | アプリケーションフローに影響なし |
| リソース使用 | 効率的である必要あり | より多くのリソースを使用可能 |
例えば、有害性チェックのScorerは、ガードレールとして使えば「即座にブロック」できます。一方で、モニターとして使えば「有害性レベルの推移を追跡」できます。
重要な点として、Scorerの結果はTraceに保存されます。つまり、ガードレールとしてScorerを使うだけでも、結果は履歴として蓄積され、後からモニタリングや分析に転用できます。
GuardrailをSDKで実装する
Guardrailは、AI Agentの出力がユーザーに届く前に実行するチェックです。Weaveでは、@weave.op()で計装した関数を.call()で呼び出すと、結果と一緒にCallオブジェクトを取得できます。そのCallに対してapply_scorer()を使うことで、Scorerの結果をTraceに紐づけられます。
import weave
from weave import Scorer
weave.init("my-team/my-project")
class ToxicityScorer(Scorer):
@weave.op()
def score(self, output: str) -> dict:
# 実際には有害性検出ロジックに置き換えます
return {"flagged": False, "reason": None}
@weave.op()
def generate_text(prompt: str) -> str:
# 実際にはLLM呼び出しに置き換えます
return "Generated response..."
async def generate_safe_response(prompt: str) -> str:
result, call = generate_text.call(prompt)
safety = await call.apply_scorer(ToxicityScorer())
if safety.result["flagged"]:
return f"I cannot generate that content: {safety.result['reason']}"
return resultこの形にしておくと、「どの入力に対して、どの出力が生成され、どのScorerがどう判定したのか」がWeaveに残ります。単なるif文で止めるだけでなく、後からTraceを検索し、失敗ケースを分析し、offline eval用のDatasetに戻すことができます。
Guardrailは必ずしもブロックだけではありません。軽微な問題なら再生成する、PIIらしき部分をマスクする、より安全なテンプレートに差し替える、といった介入も考えられます。どこまで介入するかは、リスクの大きさ、レイテンシ要件、ユーザー体験によって決めます。
Monitorで本番の挙動を継続的に見る
Monitorは、本番の挙動を継続的に測るための仕組みです。WeaveのMonitorsでは、@weave.op()でトレースされている関数を対象に、LLM-as-a-judge Scorerを使って本番トラフィックを受動的にスコアリングできます。
Guardrailと違い、Monitorはアプリケーションコードに直接スコアリング処理を埋め込まなくても、Weave UIから設定できます。スコアに応じてアプリケーションの振る舞いを変える必要がある場合はGuardrailsを使い、まず傾向を見たい場合はMonitorsを使います。
Monitorが向いているのは、例えば次のようなケースです。
- 出力の正確性や有用性を継続的に確認したい
- モデルやプロンプトの変更後に品質が落ちていないか見たい
- 実ユーザー環境で、どの種類の失敗が増えているかを見たい
- レイテンシやコストと品質指標を合わせて見たい
Monitorを作るときは、まず監視対象の@weave.op()が少なくとも一度実行され、TraceとしてWeaveに記録されている必要があります。そのうえで、Weave UIのMonitorsから監視対象のOperation、Sampling rate、Judge model、Scoring promptなどを設定します。
Scoring promptの例:
入力情報に基づいて、AI Agentの出力が正確かを評価してください。
入力:
{inputs}
出力:
{output}
JSONで is_correct と reasoning を返してください。Scoring promptでは、{output}、{inputs}、個別の入力引数(例: {question}や{ground_truth})を参照できます。これにより、AI Agentの出力を本番の実データに対して継続的に評価できます。
なお、Monitorsの利用可否や対象環境は利用しているW&Bのデプロイ形態に依存します。実際に設定する際は、利用中の環境でWeave UIのMonitorsが使えるかを確認してください。
運用で気をつけること
online evalsは強力ですが、設計を誤ると、レイテンシやコストが増えたり、不要なブロックが増えたりします。最初は小さく始め、重要なリスクからGuardrail化し、観測したい品質指標をMonitorに回すのが現実的です。
| 観点 | 考え方 |
|---|---|
| レイテンシ | ユーザーに返す前に必要なチェックだけGuardrailにします |
| コスト | MonitorはSampling rateを低めにして始めます |
| 指標 | 何を良い・悪いとするかをScoring promptに明確に書きます |
| 再利用 | Scorer結果をTraceに残し、失敗ケースをDatasetへ戻します |
| 役割分担 | 危険なものはGuardrail、傾向を見るものはMonitorにします |
offline evalは、変更前後で本当に改善したかを確認するために使います。online evalsは、本番で想定外の入力や劣化が起きていないかを継続的に見るために使います。この2つをつなげることで、本番で起きた問題を評価Datasetへ戻し、次の改善へ進めるようになります。
次の章では、本番運用の中で集まるFeedbackやAnnotationを継続的に集め、AI Agentの改善サイクルに戻していく方法を見ていきます。