AI Prompt Engineering · レッスン

ログ記録とドキュメント化の戦略

再現性のあるデバッグに向けて、プロンプトのバージョン、入力、出力を記録します。

レッスン 4/413 ステップ

「ログ記録とドキュメント化の戦略」はCoddyKit上の無料AI Prompt Engineeringレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Prompt Engineering学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Prompt Engineeringコースには全4レッスンが含まれています。

プロンプトのログ記録が重要な理由

ログを記録しないと、ユーザーから報告を受けるまでプロンプトの失敗は見えません。ログを記録すると、次のことが可能になります:

  • リグレッションが発生した瞬間に検出する
  • 過去の失敗を発生時とまったく同じように再現する
  • プロンプトの進化に伴う経時的な改善を測定する
  • コンプライアンスや安全性の観点からモデルの動作を監査する

本番環境のプロンプトシステムでは、ログ記録は任意ではありません。信頼性の高いLLMアプリケーションの基盤です。

最小限必要なログエントリ

すべてのプロンプトのやり取りで、最低限次のフィールドを記録してください:

  • timestamp:ISO 8601 UTC
  • prompt_id:使用したプロンプトテンプレート
  • model:正確なモデル名とバージョン
  • temperature:サンプリングパラメータ
  • input:ユーザーメッセージ(またはPIIを含む場合はハッシュ)
  • output:モデルの応答
  • latency_ms:応答時間
  • tokens_used:入力トークン+出力トークン
import time, json
from datetime import datetime, timezone

def logged_call(prompt_id, system_prompt, user_message, model='gpt-4o', temperature=0.7):
    start = time.time()
    resp = client.chat.completions.create(
        model=model,
        messages=[
            {'role': 'system', 'content': system_prompt},
            {'role': 'user', 'content': user_message}
        ],
        temperature=temperature
    )
    latency = int((time.time() - start) * 1000)
    output = resp.choices[0].message.content
    log_entry = {
        'timestamp': datetime.now(timezone.utc).isoformat(),
        'prompt_id': prompt_id,
        'model': model,
        'temperature': temperature,
        'input': user_message,
        'output': output,
        'latency_ms': latency,
        'input_tokens': resp.usage.prompt_tokens,
        'output_tokens': resp.usage.completion_tokens
    }
    append_log(log_entry)
    return output

構造化ログの形式

ログファイルには改行区切りJSON(JSONL)を使用します。各行が完全で有効なJSONオブジェクトになります。この形式には次の利点があります:

  • ロックせずに簡単に追記できます
  • jq、pandas、すべてのログアグリゲーターで読み取れます
  • ストリーミングに適しており、各行を到着時に処理できます
import json

LOG_FILE = 'prompt_logs.jsonl'

def append_log(entry):
    with open(LOG_FILE, 'a') as f:
        f.write(json.dumps(entry) + '\n')

def read_logs():
    with open(LOG_FILE) as f:
        return [json.loads(line) for line in f if line.strip()]

# Query: all entries for prompt_id 'summarize_v3'
logs = read_logs()
summarize_logs = [e for e in logs if e['prompt_id'] == 'summarize_v3']
print(f'Total calls to summarize_v3: {len(summarize_logs)}')

プロンプトのバージョン管理

プロンプトは時間とともに変化します。バージョン管理をしないと、過去の動作を再現したり、プロンプトのバージョン間でモデルの出力を比較したりできません。すべてのログエントリにバージョン識別子を含めてください。

簡単なバージョン管理には、セマンティックバージョン文字列(例:v1.2.3)またはgit commit hashを使います。プロンプトのバージョンは専用ファイルに保存し、どのバージョンでも取得して再実行できるようにします。

PROMPTS = {
    'summarize': {
        'v1': 'Summarize the following text.',
        'v2': 'Summarize the following text in 3 sentences.',
        'v3': 'Summarize the following text in exactly 3 sentences. '
              'Start each sentence on a new line. No bullet points.'
    }
}

CURRENT_VERSIONS = {'summarize': 'v3'}

def get_prompt(prompt_id):
    version = CURRENT_VERSIONS[prompt_id]
    return version, PROMPTS[prompt_id][version]

version, prompt = get_prompt('summarize')
log_entry['prompt_version'] = version

ログ内のPIIの取り扱い

ユーザー入力には、個人を特定できる情報(PII)が含まれている可能性があります。入力をそのままログに記録すると、GDPRやCCPAに違反する可能性があります。選択肢は次のとおりです:

  • ハッシュ化:入力のSHA-256を保存します。重複排除には再現性がありますが、再実行には使えません
  • マスキング:正規表現またはNERモデルを使い、ログに記録する前にPIIを置き換えます
  • 分離保存:アクセス制御付きの暗号化ストレージにPIIを記録し、メインログには参照IDだけを記録します
import hashlib, re

def redact_pii(text):
    # Redact email addresses
    text = re.sub(r'[\w.-]+@[\w.-]+\.\w+', '[EMAIL]', text)
    # Redact phone numbers (US format)
    text = re.sub(r'\b\d{3}[-.]\d{3}[-.]\d{4}\b', '[PHONE]', text)
    return text

def hash_input(text):
    return hashlib.sha256(text.encode()).hexdigest()[:16]

log_entry['input'] = redact_pii(user_message)
log_entry['input_hash'] = hash_input(user_message)

レイテンシーとコストの追跡

ログを使うと、コストとレイテンシーのダッシュボードを作成できます。プロンプトの変更後にパフォーマンスやコストのリグレッションを検出できるよう、プロンプトのバージョンごとに指標を追跡します:

def compute_cost(entry, price_per_1m_input=5.0, price_per_1m_output=15.0):
    input_cost = entry['input_tokens'] / 1_000_000 * price_per_1m_input
    output_cost = entry['output_tokens'] / 1_000_000 * price_per_1m_output
    return input_cost + output_cost

def prompt_stats(prompt_id, version):
    logs = [e for e in read_logs()
            if e['prompt_id'] == prompt_id and e.get('prompt_version') == version]
    if not logs:
        return
    avg_latency = sum(e['latency_ms'] for e in logs) / len(logs)
    total_cost = sum(compute_cost(e) for e in logs)
    print(f'{prompt_id} {version}: {len(logs)} calls, avg {avg_latency:.0f}ms, total ${total_cost:.4f}')

出力評価のログ記録

生のログだけでなく、各ログエントリに評価スコアも保存します。これにより、傾向を分析できます。プロンプトのバージョンが進むにつれて、出力品質は向上しているでしょうか。

def evaluated_call(prompt_id, system_prompt, user_message, evaluator_fn):
    output = logged_call(prompt_id, system_prompt, user_message)
    score = evaluator_fn(user_message, output)
    # Update the last log entry with the evaluation score
    logs = read_logs()
    last = logs[-1]
    last['eval_score'] = score
    last['eval_pass'] = score >= 0.8
    # Rewrite the last line
    with open(LOG_FILE, 'a') as f:
        # In practice, use a DB or separate eval log
        pass
    return output, score

プロンプトのドキュメント作成

各プロンプトテンプレートには、次の内容を説明する付随ドキュメントを用意してください:

  • 目的:このプロンプトが実行するタスク
  • 変数:存在するプレースホルダーと、それぞれが期待する値
  • 既知の制限:失敗することが分かっている入力
  • バージョン履歴:各バージョンで何がなぜ変更されたか
  • テストケース:このプロンプトのテストスイートへのリンク
PROMPT_DOCS = {
    'summarize': {
        'purpose': 'Summarize a single text passage into 3 sentences.',
        'variables': {'text': 'The passage to summarize (max 2000 tokens)'},
        'known_limitations': [
            'Fails to preserve numbers accurately for texts with many statistics',
            'May not summarize correctly for non-English text'
        ],
        'versions': {
            'v1': 'Initial version — vague length instruction',
            'v2': 'Added 3-sentence limit',
            'v3': 'Added line-break and no-bullet formatting fix'
        },
        'test_suite': 'tests/test_summarize.py'
    }
}

集中ログサービスの利用

本番環境のシステムでは、ログをローカルファイルではなく集中ログサービスに書き込みます:

  • LangSmith:LangChainの標準トレースおよび評価プラットフォーム
  • Weights and Biases Prompts:プロンプトの実験追跡
  • Datadog / Grafana:カスタム指標に対応した標準的な運用ダッシュボード
  • Supabase / PostgreSQL:SQLを使ってログをアドホック分析できます

スキーマは同じで、保存先だけが変わります。

# Example: writing to Supabase
from supabase import create_client

supabase = create_client('https://xxx.supabase.co', 'your-anon-key')

def log_to_supabase(entry):
    supabase.table('prompt_logs').insert(entry).execute()

# Now query with SQL:
# SELECT prompt_id, prompt_version, AVG(latency_ms), COUNT(*)
# FROM prompt_logs
# WHERE timestamp > NOW() - INTERVAL '7 days'
# GROUP BY prompt_id, prompt_version
# ORDER BY COUNT(*) DESC;

失敗率の急増に対するアラート

失敗率がしきい値を超えて急増したときにアラートを設定します。たとえば、5分間の間にプロンプトへの呼び出しの10%を超える数が無効なJSONを返した場合に、アラートを送信します。

from collections import deque
from datetime import datetime, timezone, timedelta

recent_results = deque(maxlen=100)  # sliding window

def track_and_alert(prompt_id, success, alert_fn, threshold=0.10):
    recent_results.append({'success': success, 'time': datetime.now(timezone.utc)})
    window = [
        r for r in recent_results
        if r['time'] > datetime.now(timezone.utc) - timedelta(minutes=5)
    ]
    if not window:
        return
    fail_rate = sum(1 for r in window if not r['success']) / len(window)
    if fail_rate > threshold:
        alert_fn(f'ALERT: {prompt_id} failure rate {fail_rate:.0%} in last 5 min')

ログの保持とアーカイブ

ログの保持ポリシーを定義します。

  • 生の呼び出しログ:30日間(ローリング方式) — 大量に発生し、直近の問題のデバッグに必要です
  • 集計メトリクス:1年間 — 傾向分析とコスト予測に必要です
  • 失敗ログ:無期限 — 根本原因のパターンを把握するために必要です

30日後に生のログを圧縮してアーカイブします。失敗ログは決して削除しないでください。プロンプトエンジニアリングにおける組織の知見として役立つためです。

理解度チェック

大きな単一のJSON配列と比べて、プロンプトログに改行区切りJSON(JSONL)形式を使用する主な利点は何ですか。

まとめ:ログ記録とドキュメント

プロンプトのログ記録とドキュメント化における主な実践方法:

  • すべての呼び出しを記録する:タイムスタンプ、prompt_id、version、model、temperature、input、output、latency、tokens
  • JSONL形式を使用する:追記しやすく、標準ツールでクエリできます
  • プロンプトをバージョン管理する:変更ごとに新しいバージョンを作成し、ログからそのバージョンを参照します
  • PIIを適切に扱う:ログに記録する前に機密性の高い入力をマスキングまたはハッシュ化します
  • コストとレイテンシーを追跡する:プロンプト更新後のリグレッションを検出します
  • 失敗率の急増に対してアラートを出す:スライディングウィンドウで失敗率を監視します

これで、プロンプトの失敗のデバッグを扱うコース17は終了です。次は、プロンプトインジェクションと防御です。

無料で開始

AI チューターと学ぶ AI Prompt Engineering — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
53
レッスン
199

よくある質問

「ログ記録とドキュメント化の戦略」レッスンは無料ですか?

はい。「ログ記録とドキュメント化の戦略」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと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に戻る