本番環境でのプロンプト性能監視
プロンプトのバージョンごとに、レイテンシ、コスト、品質スコア、失敗率を追跡します。
「本番環境でのプロンプト性能監視」はCoddyKit上の無料AI Prompt Engineeringレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Prompt Engineering学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Prompt Engineeringコースには全4レッスンが含まれています。
プロンプトのパフォーマンスを監視する理由
本番環境にデプロイしたプロンプトは「完成」ではありません。モデルの動作は更新によって変化し、ユーザー入力も時間とともに変わるため、コストが予期せず急増することもあります。継続的な監視によって、ユーザーに影響が及ぶ前にリグレッションを検出し、支出を予測可能な状態に保てます。
プロンプトバージョンごとの主要メトリクス
本番環境では、プロンプトバージョンごとに次の5つのメトリクスを追跡します。
- 平均レイテンシー:リクエストから完全なレスポンスが返るまでの時間(P50、P95、P99)
- 1回あたりのコスト:入力トークン数 × 価格 + 出力トークン数 × 価格
- 品質スコア:自動評価(LLM-as-judgeまたはタスクメトリクス)
- エラー率:APIエラー + 形式不正な出力のパース失敗
- ユーザー満足度:サムズアップ評価、再試行率、セッション放棄率
計装:メトリクスの記録
すべてのLLM呼び出しを計装でラップし、後からの分析やアラートに備えて、主要なメトリクスをすべて時系列ストアまたはデータベースに記録します。
import time
import openai
client = openai.OpenAI(api_key='YOUR_API_KEY')
def instrumented_call(prompt_id, version, messages, model):
start = time.time()
error = False
response = None
try:
response = client.chat.completions.create(
model=model,
messages=messages
)
except Exception as e:
error = True
raise
finally:
latency_ms = (time.time() - start) * 1000
usage = response.usage if response else None
record_metric({
'prompt_id': prompt_id,
'version': version,
'latency_ms': latency_ms,
'input_tokens': usage.prompt_tokens if usage else 0,
'output_tokens': usage.completion_tokens if usage else 0,
'error': error,
'timestamp': time.time()
})
return response1回あたりのコストの計算
1回あたりのコスト = 入力トークン数 × 入力価格 + 出力トークン数 × 出力価格です。トークン数の生データを保存しておけば、価格が変更されたときにいつでもコストを再計算できます。
# pricing.py — model pricing table (per 1M tokens)
PRICING = {
'gpt-4o': {'input': 2.50, 'output': 10.00},
'gpt-4o-mini': {'input': 0.15, 'output': 0.60},
'claude-3-5-sonnet-20241022': {'input': 3.00, 'output': 15.00},
}
def cost_usd(model, input_tokens, output_tokens):
p = PRICING.get(model)
if not p:
return None
cost = (input_tokens / 1_000_000) * p['input'] \
+ (output_tokens / 1_000_000) * p['output']
return round(cost, 6)
# Example
c = cost_usd('gpt-4o-mini', input_tokens=800, output_tokens=200)
print(f'Cost per call: ${c}') # Cost per call: $0.000240
# Daily cost estimate
calls_per_day = 50_000
print(f'Daily cost: ${round(c * calls_per_day, 2)}') # $12.00自動品質スコアリング
本番環境の規模で出力品質を自動的にスコアリングするには、LLMジャッジを使用します。コストを管理可能な範囲に抑えるため、品質スコアリングの対象には呼び出しの5~10%をサンプリングします。
import random
JUDGE_SAMPLE_RATE = 0.05 # score 5% of calls
JUDGE_PROMPT = '''Rate the quality of this AI response on a scale of 1-5.
1=Very poor, 3=Acceptable, 5=Excellent.
Return only the integer score.
User input: {input}
AI response: {output}'''
def maybe_score_quality(user_input, ai_output, model='gpt-4o-mini'):
if random.random() > JUDGE_SAMPLE_RATE:
return None # not sampled
judge_messages = [{'role': 'user', 'content':
JUDGE_PROMPT.format(input=user_input, output=ai_output)}]
response = client.chat.completions.create(
model=model, messages=judge_messages, max_tokens=5
)
try:
score = int(response.choices[0].message.content.strip())
return max(1, min(5, score)) # clamp to 1-5
except ValueError:
return None時系列DBへのメトリクス保存
時系列データベース(InfluxDB、TimescaleDB、またはタイムスタンプインデックスを持つ単純なPostgreSQLテーブルでも)は、呼び出しごとのメトリクスを効率的に保存し、ダッシュボード用の集計クエリにも対応します。
-- TimescaleDB / PostgreSQL schema for prompt metrics
CREATE TABLE prompt_metrics (
ts TIMESTAMPTZ NOT NULL DEFAULT NOW(),
prompt_id VARCHAR(100),
version VARCHAR(20),
model VARCHAR(50),
latency_ms FLOAT,
input_tokens INT,
output_tokens INT,
cost_usd FLOAT,
quality_score FLOAT, -- NULL if not sampled
error BOOLEAN DEFAULT FALSE
);
-- Convert to hypertable (TimescaleDB)
SELECT create_hypertable('prompt_metrics', 'ts');
-- Query: hourly P95 latency by version
SELECT
date_trunc('hour', ts) AS hour,
version,
PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY latency_ms) AS p95_latency
FROM prompt_metrics
WHERE prompt_id = 'summarize-article'
AND ts > NOW() - INTERVAL '24 hours'
GROUP BY 1, 2
ORDER BY 1;メトリクスダッシュボードの構築
ダッシュボードでは、5つの主要メトリクスをリアルタイムで確認できます。TimescaleDBをデータソースとしてGrafanaを使用するか、カスタムのWebダッシュボードを構築します。主なパネルは次のとおりです。
- バージョン別の時間経過に伴うレイテンシーP50/P95/P99
- 1回あたりのコストの推移(日次・週次)
- エラー率(パーセンテージ)
- 品質スコアの移動平均
- ユーザー満足度スコア
# Simple dashboard query aggregation in Python
def get_dashboard_stats(conn, prompt_id, hours=24):
with conn.cursor() as cur:
cur.execute('''
SELECT
version,
COUNT(*) AS calls,
AVG(latency_ms) AS avg_latency,
PERCENTILE_CONT(0.95)
WITHIN GROUP (ORDER BY latency_ms) AS p95_latency,
AVG(cost_usd) AS avg_cost,
AVG(quality_score) FILTER (WHERE quality_score IS NOT NULL) AS avg_quality,
SUM(error::int)::float / COUNT(*) AS error_rate
FROM prompt_metrics
WHERE prompt_id = %s
AND ts > NOW() - INTERVAL %s
GROUP BY version
ORDER BY MAX(ts) DESC
''', (prompt_id, f'{hours} hours'))
return cur.fetchall()プロンプトのリグレッションに対する異常検知
ダッシュボードを手作業で確認するだけでは、緩やかなリグレッションを見逃します。自動異常検知では、移動ウィンドウを過去のベースラインと比較し、乖離がしきい値を超えたときにアラートを発生させます。
import statistics
def detect_anomaly(recent_values, baseline_values, threshold_std=2.0):
if len(baseline_values) < 10:
return False # not enough data
baseline_mean = statistics.mean(baseline_values)
baseline_std = statistics.stdev(baseline_values)
recent_mean = statistics.mean(recent_values)
if baseline_std == 0:
return False
z_score = abs(recent_mean - baseline_mean) / baseline_std
return z_score > threshold_std
# Example: detect quality regression
baseline_quality = [4.1, 4.0, 4.2, 4.1, 4.0, 3.9, 4.1, 4.2, 4.0, 4.1]
recent_quality = [3.2, 3.1, 3.4, 3.0]
if detect_anomaly(recent_quality, baseline_quality):
print('ALERT: Quality score anomaly detected!')
# fire_pagerduty_alert(...)
else:
print('Quality within normal range')アラートルールとしきい値
アラートルールはコードとして定義し、バージョン管理とレビューができるようにします。プロンプト監視でよく使われるアラートは次のとおりです。
- エラー率が5%を超えた状態が5分間連続した場合
- P95レイテンシーが10秒を超えた状態が3分間続いた場合
- 1日あたりのコストが週平均の2倍を超えた場合(コスト急増)
- 品質スコアがベースラインから20%を超えて低下した場合
# alerts.yaml (Grafana alerting or custom)
alerts:
- name: HighErrorRate
condition: error_rate > 0.05
for: 5m
severity: critical
message: 'Prompt {prompt_id} error rate {error_rate:.1%} exceeds 5%'
- name: HighLatencyP95
condition: p95_latency_ms > 10000
for: 3m
severity: warning
message: 'P95 latency {p95_latency_ms}ms exceeds 10s for {prompt_id}'
- name: CostSpike
condition: daily_cost_usd > weekly_avg_daily_cost * 2
for: 1h
severity: warning
message: 'Daily cost ${daily_cost_usd:.2f} is 2x the weekly average'
- name: QualityRegression
condition: rolling_quality_avg < baseline_quality_avg * 0.80
for: 15m
severity: critical
message: 'Quality dropped {pct_drop:.0%} for prompt {prompt_id}'ユーザー満足度のシグナル
自動化されたメトリクスだけでは、すべてを捉えられません。品質スコアを補完するため、ユーザーから明示的および暗黙的なシグナルを収集します。
- サムズアップ評価:AIの応答に対する明示的な👍/👎評価
- 再試行率:ユーザーが同じクエリを直ちに再送信する割合(暗黙的な不満)
- コピー・利用率:ユーザーがAIの出力をコピーする割合(暗黙的な満足)
- 修正率:ユーザーがAIの出力を使用する前に編集する割合
# feedback_collector.py
def record_feedback(prompt_id, version, call_id, signal_type, value):
'''
signal_type: 'thumbs' | 'retry' | 'copy' | 'edit'
value: for thumbs: 1 (up) or -1 (down); others: 1 (occurred)
'''
db.execute(
'INSERT INTO prompt_feedback '
'(prompt_id, version, call_id, signal_type, value, ts) '
'VALUES (%s, %s, %s, %s, %s, NOW())',
(prompt_id, version, call_id, signal_type, value)
)
# Aggregate satisfaction score
def satisfaction_score(prompt_id, version):
rows = db.fetch(
'SELECT signal_type, AVG(value) as avg_val FROM prompt_feedback '
'WHERE prompt_id=%s AND version=%s GROUP BY signal_type',
(prompt_id, version)
)
return {r['signal_type']: round(r['avg_val'], 3) for r in rows}バージョン比較レポート
カナリアを昇格させるかロールバックするかを評価するときは、新しいバージョンとベースラインのすべてのメトリクスを並べて比較したレポートを生成します。このレポートをもとに昇格を判断します。
def version_comparison_report(prompt_id, version_a, version_b, hours=48):
stats_a = get_dashboard_stats_for_version(prompt_id, version_a, hours)
stats_b = get_dashboard_stats_for_version(prompt_id, version_b, hours)
print(f'=== Comparison: {version_a} vs {version_b} ===')
metrics = ['avg_latency', 'p95_latency', 'avg_cost', 'avg_quality', 'error_rate']
for m in metrics:
va = stats_a.get(m, 0)
vb = stats_b.get(m, 0)
delta = vb - va
pct = (delta / va * 100) if va else 0
direction = '+' if delta > 0 else ''
print(f'{m:20s}: {va:.4f} -> {vb:.4f} ({direction}{pct:.1f}%)')
# Example output:
# avg_latency : 1234.5000 -> 1189.2000 (-3.7%)
# p95_latency : 3210.0000 -> 3050.0000 (-5.0%)
# avg_cost : 0.000240 -> 0.000255 (+6.2%)
# avg_quality : 4.1000 -> 4.3000 (+4.9%)
# error_rate : 0.0120 -> 0.0080 (-33.3%)確認テスト
ダッシュボードを手作業で確認せずに、品質のリグレッションを自動検出したいとします。これを最も適切に実現する方法はどれですか?
監視のまとめ
本番環境でのプロンプト監視では、バージョンごとに次の5つの側面を追跡します。
- レイテンシー(P50/P95/P99) — ユーザー体験
- 1回あたりのコスト — 財務面の健全性
- 品質スコア — LLMジャッジによる自動サンプリング評価
- エラー率 — 信頼性
- ユーザー満足度 — サムズアップ評価、再試行、コピーのシグナル
メトリクスを時系列データベースに保存し、ダッシュボードで可視化して、しきい値を超えたときにアラートを発生させます。バージョン比較レポートは、昇格やロールバックの判断に役立ちます。
よくある質問
「本番環境でのプロンプト性能監視」レッスンは無料ですか?
はい。「本番環境でのプロンプト性能監視」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Prompt Engineeringコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Prompt Engineeringコースには全4レッスンが含まれています。
「本番環境でのプロンプト性能監視」で何を学びますか?
プロンプトのバージョンごとに、レイテンシ、コスト、品質スコア、失敗率を追跡します。 ブラウザで直接実行するハンズオンコードでAI Prompt Engineeringを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
AI Prompt Engineeringを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAI Prompt Engineeringは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「本番環境でのプロンプト性能監視」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAI Prompt Engineeringレッスンでコードを書いて実行できますか?
はい。すべてのAI Prompt Engineeringレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- プロンプトレジストリのアーキテクチャ
- プロンプトのバージョン管理
- デプロイとロールバックの戦略
- 本番環境でのプロンプト性能監視