0Pricing
AI Prompt Engineering · レッスン

本番環境でのプロンプト性能監視

プロンプトのバージョンごとに、レイテンシ、コスト、品質スコア、失敗率を追跡します。

「本番環境でのプロンプト性能監視」は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 response

1回あたりのコストの計算

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フィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. プロンプトレジストリのアーキテクチャ
  2. プロンプトのバージョン管理
  3. デプロイとロールバックの戦略
  4. 本番環境でのプロンプト性能監視
← AI Prompt Engineeringに戻る