AIコーディング 2026.04.23

Claude Codeでプロンプト自動A/BテストするPythonコード【5分実装】

タグ:Claude / ClaudeCode / Python / プロンプト / 生成AI

プロンプトA/Bテストの仕組み

Step 1: テストしたいプロンプトバリエーションを定義
Step 2: 各プロンプトを同じテストケースで実行(並列)
Step 3: 結果を自動スコアリングして最優秀プロンプトを選定

基本実装(シングルテスト)

# prompt_ab_test.py
# 複数プロンプトを自動A/Bテストして最優秀を選ぶ

import anthropic
from concurrent.futures import ThreadPoolExecutor
from dataclasses import dataclass
from typing import Callable

client = anthropic.Anthropic()

@dataclass
class TestResult:
    prompt_name: str
    score: float
    answer: str
    cost_usd: float

def run_prompt(
    prompt_template: str,
    test_input: str,
    model: str = "claude-haiku-4-5-20251001"
) -> tuple[str, float]:
    """プロンプトテンプレートにテスト入力を埋め込んで実行する"""
    full_prompt = prompt_template.format(input=test_input)
    
    response = client.messages.create(
        model=model,
        max_tokens=512,
        messages=[{"role": "user", "content": full_prompt}]
    )
    
    inp = response.usage.input_tokens
    out = response.usage.output_tokens
    cost = (inp * 0.80 + out * 4.00) / 1_000_000  # Haiku料金
    
    return response.content[0].text, cost

def evaluate_response(answer: str, expected_keywords: list[str]) -> float:
    """回答をキーワード含有率でスコアリングする(0.0〜1.0)"""
    found = sum(1 for kw in expected_keywords if kw.lower() in answer.lower())
    return found / len(expected_keywords) if expected_keywords else 0.5

def ab_test(
    prompt_variants: dict[str, str],
    test_cases: list[dict],
    evaluator: Callable = None
) -> list[TestResult]:
    """複数プロンプトを全テストケースで並列実行してスコア比較する"""
    results = {name: [] for name in prompt_variants}
    
    def test_one(args):
        name, template, case = args
        answer, cost = run_prompt(template, case["input"])
        
        if evaluator:
            score = evaluator(answer, case.get("keywords", []))
        else:
            score = len(answer) / 500  # デフォルト: 文字数ベースのスコア
        
        return name, score, answer, cost
    
    # 全プロンプト×全テストケースを並列実行
    tasks = [
        (name, template, case)
        for name, template in prompt_variants.items()
        for case in test_cases
    ]
    
    with ThreadPoolExecutor(max_workers=5) as executor:
        for name, score, answer, cost in executor.map(test_one, tasks):
            results[name].append((score, answer, cost))
    
    # 集計してTestResultを作成
    summary = []
    for name, data in results.items():
        avg_score = sum(d[0] for d in data) / len(data)
        total_cost = sum(d[2] for d in data)
        summary.append(TestResult(name, avg_score, data[0][1], total_cost))
    
    return sorted(summary, key=lambda r: r.score, reverse=True)

# 使用例
PROMPTS = {
    "A_simple": "以下を3行で要約してください:\n\n{input}",
    "B_structured": "以下の文章を要約してください。\n要点: 3行以内\n数値: 具体的な数字を含める\n\n{input}",
    "C_expert": "あなたはプロの編集者です。以下を簡潔に要約してください(200文字以内):\n\n{input}",
}

TEST_CASES = [
    {"input": "AI市場は2026年に1兆ドルを超えると予測されている...", "keywords": ["AI", "兆"]},
    {"input": "Anthropicは2025年に30億ドルの資金調達を行った...", "keywords": ["Anthropic", "億"]},
]

results = ab_test(PROMPTS, TEST_CASES, evaluator=evaluate_response)
print("\n=== A/Bテスト結果 ===")
for i, r in enumerate(results):
    print(f"#{i+1} [{r.prompt_name}] スコア: {r.score:.2f} | コスト: ${r.cost_usd:.5f}")
print(f"\n最優秀プロンプト: {results[0].prompt_name}")

Batches APIで大規模A/Bテスト(50%オフ)

# batch_ab_test.py
# Batches APIで全パターンを一括送信してコストを半額にする

def batch_ab_test(prompt_variants: dict[str, str], test_cases: list[dict]) -> str:
    """Batches API(50%オフ)で全プロンプト×全テストケースを一括実行"""
    requests = []
    
    for prompt_name, template in prompt_variants.items():
        for i, case in enumerate(test_cases):
            full_prompt = template.format(input=case["input"])
            requests.append({
                "custom_id": f"{prompt_name}_case{i}",
                "params": {
                    "model": "claude-haiku-4-5-20251001",
                    "max_tokens": 256,
                    "messages": [{"role": "user", "content": full_prompt}]
                }
            })
    
    batch = client.messages.batches.create(requests=requests)
    
    total_tests = len(requests)
    estimated_cost = total_tests * 0.000002 * 0.5  # Haiku×Batches
    print(f"A/Bテスト開始: {len(prompt_variants)}パターン×{len(test_cases)}テストケース")
    print(f"合計{total_tests}リクエスト | 推定コスト: ${estimated_cost:.5f} (50%オフ適用)")
    print(f"Batch ID: {batch.id} (結果は~1時間後に取得可能)")
    
    return batch.id

batch_id = batch_ab_test(PROMPTS, TEST_CASES)

あわせて読みたい

参考ソース