大規模言語モデル(LLM)を本番環境に導入する際、プロンプトの管理と最適化は避けて通れない課題です。私は複数のプロジェクトでLLM連携基盤を構築してきましたが、プロンプトのバージョン管理が形骸化したり、A/Bテストが恣意的に行われたりすることで、モデル效能の向上が頭打ちになるケースを何度も見てきました。本稿では、HolySheep AIをBackendとして活用し、プロンプトのバージョン管理とA/Bテストを体系的に実装するフレームワークを、実際のベンチマーク数据和包含めながら解説します。

なぜプロンプトのバージョン管理が必要か

従来のソフトウェア開発では、コードのバージョン管理(Git)が当然視されています。しかし、プロンプトは「コード以上の可変性」を持ちます。同じプロンプトでも、モデルのバージョンアップやシステムプロンプトの変更によって出力品質が劇的に変化します。私は某EC企業で、深層学習モデルの推論精度 향상을 목적으로プロンプト最適化を行っていた際、1ヶ月の間に3回のモデルアップデートがあり、過去の「最佳プロンプト」が全く機能しなくなるという経験をしました。

HolySheep AIの<50msレイテンシと¥1=$1の為替レート(公式¥7.3=$1比85%節約)は、高頻度での экспериментと反復改善を可能にします。このコスト優位性を活かすには、 체계的なバージョン管理体制が不可欠です。

全体アーキテクチャ

本フレームワークは4つの主要コンポーネントで構成されます:

実装:Prompt Registry システム

プロンプトのバージョン管理には、セマンティックバージョニングを採用し、各バージョンのスコープ(system/user/assistant)を分離して管理します。

"""
HolySheep AI を使用した Prompt Version Registry
バージョン管理、A/Bテスト、コスト追跡を統合
"""

import hashlib
import json
import time
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Optional
import httpx

class ExperimentStatus(Enum):
    DRAFT = "draft"
    RUNNING = "running"
    PAUSED = "paused"
    COMPLETED = "completed"
    ARCHIVED = "archived"

@dataclass
class PromptVersion:
    """プロンプトバージョンのデータクラス"""
    version_id: str
    prompt_scope: str  # 'system', 'user', 'assistant'
    content: str
    variables: list[str] = field(default_factory=list)
    created_at: datetime = field(default_factory=datetime.now)
    created_by: str = "system"
    description: str = ""
    model_name: str = "gpt-4o"
    temperature: float = 0.7
    max_tokens: int = 2048

    @property
    def content_hash(self) -> str:
        """プロンプトコンテンツのハッシュ値(変更検知用)"""
        content_for_hash = json.dumps({
            "scope": self.prompt_scope,
            "content": self.content,
            "model": self.model_name,
            "temp": self.temperature,
            "max_tokens": self.max_tokens
        }, sort_keys=True)
        return hashlib.sha256(content_for_hash.encode()).hexdigest()[:12]

@dataclass
class Experiment:
    """A/Bテスト実験の定義"""
    experiment_id: str
    name: str
    description: str
    status: ExperimentStatus
    variants: dict[str, str]  # variant_name -> prompt_version_id
    traffic_allocation: dict[str, float]  # variant_name -> ratio (0.0-1.0)
    target_metric: str  # 'latency', 'success_rate', 'cost_per_request', 'quality_score'
    started_at: Optional[datetime] = None
    completed_at: Optional[datetime] = None
    sample_size_per_variant: int = 1000

class PromptRegistry:
    """プロンプトレジストリ:バージョン管理と実験制御の中核"""

    BASE_URL = "https://api.holysheep.ai/v1"
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.versions: dict[str, PromptVersion] = {}
        self.experiments: dict[str, Experiment] = {}
        self.experiment_results: dict[str, list] = {}
        self.client = httpx.Client(
            base_url=self.BASE_URL,
            headers={
                "Authorization": f"Bearer {api_key}",
                "Content-Type": "application/json"
            },
            timeout=30.0
        )

    def create_version(
        self,
        prompt_scope: str,
        content: str,
        model_name: str = "gpt-4o",
        temperature: float = 0.7,
        max_tokens: int = 2048,
        description: str = ""
    ) -> PromptVersion:
        """新規プロンプトバージョンを作成"""
        timestamp = int(time.time() * 1000)
        version_id = f"{prompt_scope}_{timestamp}"
        
        # 変数を自動抽出
        import re
        variables = re.findall(r'\{(\w+)\}', content)
        
        version = PromptVersion(
            version_id=version_id,
            prompt_scope=prompt_scope,
            content=content,
            variables=variables,
            model_name=model_name,
            temperature=temperature,
            max_tokens=max_tokens,
            description=description
        )
        
        self.versions[version_id] = version
        print(f"✅ 新規バージョン作成: {version_id}")
        print(f"   コンテンツハッシュ: {version.content_hash}")
        print(f"   検出された変数: {variables}")
        return version

    def create_experiment(
        self,
        name: str,
        description: str,
        variant_configs: dict[str, dict],
        traffic_allocation: dict[str, float],
        target_metric: str = "latency"
    ) -> Experiment:
        """A/Bテスト実験を新規作成"""
        experiment_id = f"exp_{int(time.time() * 1000)}"
        
        # トラフィック比率の合計が1.0であることを確認
        total_ratio = sum(traffic_allocation.values())
        if abs(total_ratio - 1.0) > 0.001:
            raise ValueError(f"トラフィック比率の合計は1.0である必要があります: {total_ratio}")
        
        variants = {}
        for variant_name, config in variant_configs.items():
            # 各バリアントのバージョンを自動生成
            version = self.create_version(
                prompt_scope=config.get("scope", "user"),
                content=config["content"],
                model_name=config.get("model", "gpt-4o"),
                temperature=config.get("temperature", 0.7),
                max_tokens=config.get("max_tokens", 2048),
                description=f"Experiment variant: {variant_name}"
            )
            variants[variant_name] = version.version_id
        
        experiment = Experiment(
            experiment_id=experiment_id,
            name=name,
            description=description,
            status=ExperimentStatus.DRAFT,
            variants=variants,
            traffic_allocation=traffic_allocation,
            target_metric=target_metric
        )
        
        self.experiments[experiment_id] = experiment
        print(f"✅ 実験作成: {experiment_id}")
        print(f"   バリアント数: {len(variants)}")
        print(f"   ターゲットメトリクス: {target_metric}")
        return experiment

    def execute_prompt(
        self,
        version_id: str,
        user_variables: dict[str, str],
        return_metadata: bool = True
    ) -> dict:
        """HolySheep AI APIを使用してプロンプトを実行"""
        if version_id not in self.versions:
            raise ValueError(f"バージョンが見つかりません: {version_id}")
        
        version = self.versions[version_id]
        
        # 変数をプロンプトに注入
        prompt_content = version.content
        for var_name, var_value in user_variables.items():
            prompt_content = prompt_content.replace(f"{{{var_name}}}", var_value)
        
        start_time = time.perf_counter()
        
        try:
            response = self.client.post(
                "/chat/completions",
                json={
                    "model": version.model_name,
                    "messages": [
                        {"role": "user", "content": prompt_content}
                    ],
                    "temperature": version.temperature,
                    "max_tokens": version.max_tokens
                }
            )
            response.raise_for_status()
            result = response.json()
            
            end_time = time.perf_counter()
            latency_ms = (end_time - start_time) * 1000
            
            output_tokens = result.get("usage", {}).get("completion_tokens", 0)
            
            return {
                "success": True,
                "content": result["choices"][0]["message"]["content"],
                "latency_ms": round(latency_ms, 2),
                "input_tokens": result.get("usage", {}).get("prompt_tokens", 0),
                "output_tokens": output_tokens,
                "model": version.model_name,
                "version_id": version_id
            }
            
        except httpx.HTTPStatusError as e:
            return {
                "success": False,
                "error": f"HTTP {e.response.status_code}: {e.response.text}",
                "latency_ms": round((time.perf_counter() - start_time) * 1000, 2),
                "version_id": version_id
            }


使用例

registry = PromptRegistry(api_key="YOUR_HOLYSHEEP_API_KEY")

プロンプトバージョンを作成

base_version = registry.create_version( prompt_scope="user", content="以下の文章的 내용을{target_style}で要約してください:\n\n{input_text}", model_name="gpt-4o", description="基本サマリープロンプト v1.0" )

A/Bテスト実験を設定

experiment = registry.create_experiment( name="summarization_style_test", description="要約スタイルの比較実験", variant_configs={ "concise": { "scope": "user", "content": "簡潔に3文以内で{target_topic}を要約してください。", "temperature": 0.3, "max_tokens": 100 }, "detailed": { "scope": "user", "content": "{target_topic}について、背景・本題・結論の3段落で詳細に説明してください。", "temperature": 0.7, "max_tokens": 500 }, "bullet_points": { "scope": "user", "content": "{target_topic}の要点を箇条書きで5項目列出してください。", "temperature": 0.5, "max_tokens": 300 } }, traffic_allocation={"concise": 0.4, "detailed": 0.4, "bullet_points": 0.2}, target_metric="success_rate" ) print(f"\n実験ID: {experiment.experiment_id}") print(f"ステータス: {experiment.status.value}")

実装:A/B テスト実行エンジン

実験のトラフィック分割と実行を担当するEngineを実装します。HolySheep AIの¥1=$1為替レートメリットを 最大活用するため、各バリアントのコストも正確に追跡します。

"""
A/B Test Execution Engine - 本番レベルのトラフィック分割とメトリクス収集
"""

import random
import threading
from collections import defaultdict
from dataclasses import dataclass, field
from datetime import datetime, timedelta
from typing import Callable, Any
import statistics
import httpx

@dataclass
class RequestMetrics:
    """单个リクエストの詳細メトリクス"""
    request_id: str
    experiment_id: str
    variant_name: str
    version_id: str
    timestamp: datetime
    latency_ms: float
    success: bool
    input_tokens: int
    output_tokens: int
    error_message: str = ""

@dataclass 
class VariantStats:
    """バリアント単位の集計統計"""
    variant_name: str
    version_id: str
    total_requests: int = 0
    successful_requests: int = 0
    failed_requests: int = 0
    latencies: list[float] = field(default_factory=list)
    input_tokens_list: list[int] = field(default_factory=list)
    output_tokens_list: list[int] = field(default_factory=list)
    errors: list[str] = field(default_factory=list)
    
    @property
    def success_rate(self) -> float:
        if self.total_requests == 0:
            return 0.0
        return (self.successful_requests / self.total_requests) * 100
    
    @property
    def avg_latency_ms(self) -> float:
        if not self.latencies:
            return 0.0
        return statistics.mean(self.latencies)
    
    @property
    def p95_latency_ms(self) -> float:
        if len(self.latencies) < 20:
            return self.avg_latency_ms
        return statistics.quantiles(self.latencies, n=20)[18]  # 95th percentile
    
    @property
    def total_cost_usd(self) -> float:
        """HolySheep AI の pricing に基づくコスト計算"""
        # 2026年 pricing (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},
            "gemini-2.0-flash-exp": {"input": 0.00, "output": 0.00},  # Free tier
            "deepseek-chat": {"input": 0.27, "output": 1.10}
        }
        
        total = 0.0
        for inp, out in zip(self.input_tokens_list, self.output_tokens_list):
            model = "gpt-4o"  # Default
            price = PRICING.get(model, {"input": 2.50, "output": 10.00})
            total += (inp / 1_000_000) * price["input"]
            total += (out / 1_000_000) * price["output"]
        return round(total, 6)
    
    @property
    def cost_per_request_usd(self) -> float:
        if self.total_requests == 0:
            return 0.0
        return self.total_cost_usd / self.total_requests


class ABTestEngine:
    """A/Bテスト実行エンジン"""
    
    BASE_URL = "https://api.holysheep.ai/v1"
    
    def __init__(self, api_key: str, registry: 'PromptRegistry'):
        self.api_key = api_key
        self.registry = registry
        self.client = httpx.Client(
            base_url=self.BASE_URL,
            headers={
                "Authorization": f"Bearer {api_key}",
                "Content-Type": "application/json"
            },
            timeout=30.0
        )
        
        self.variant_stats: dict[str, dict[str, VariantStats]] = defaultdict(dict)
        self.request_log: list[RequestMetrics] = []
        self._lock = threading.Lock()
        self._request_counter = 0

    def _get_variant_for_request(self, experiment_id: str) -> tuple[str, str]:
        """リクエストに基づいてバリアントを選定(確率的分割)"""
        experiment = self.registry.experiments[experiment_id]
        allocation = experiment.traffic_allocation
        
        rand = random.random()
        cumulative = 0.0
        for variant_name, ratio in allocation.items():
            cumulative += ratio
            if rand < cumulative:
                version_id = experiment.variants[variant_name]
                return variant_name, version_id
        return list(allocation.keys())[0], experiment.variants[list(allocation.keys())[0]]

    def _record_metrics(self, metrics: RequestMetrics):
        """スレッドセーフにメトリクスを記録"""
        with self._lock:
            self.request_log.append(metrics)
            
            variant = metrics.variant_name
            if variant not in self.variant_stats[metrics.experiment_id]:
                self.variant_stats[metrics.experiment_id][variant] = VariantStats(
                    variant_name=variant,
                    version_id=metrics.version_id
                )
            
            stats = self.variant_stats[metrics.experiment_id][variant]
            stats.total_requests += 1
            if metrics.success:
                stats.successful_requests += 1
                stats.latencies.append(metrics.latency_ms)
                stats.input_tokens_list.append(metrics.input_tokens)
                stats.output_tokens_list.append(metrics.output_tokens)
            else:
                stats.failed_requests += 1
                stats.errors.append(metrics.error_message)

    def run_single_request(
        self,
        experiment_id: str,
        user_variables: dict[str, str],
        callback: Callable[[str, dict], Any] = None
    ) -> dict:
        """单个リクエストをA/Bテストとして実行"""
        self._request_counter += 1
        request_id = f"req_{experiment_id}_{self._request_counter}"
        
        variant_name, version_id = self._get_variant_for_request(experiment_id)
        experiment = self.registry.experiments[experiment_id]
        version = self.registry.versions[version_id]
        
        # 変数を注入
        content = version.content
        for var_name, var_value in user_variables.items():
            content = content.replace(f"{{{var_name}}}", str(var_value))
        
        start_time = time.perf_counter()
        
        try:
            response = self.client.post(
                "/chat/completions",
                json={
                    "model": version.model_name,
                    "messages": [{"role": "user", "content": content}],
                    "temperature": version.temperature,
                    "max_tokens": version.max_tokens
                }
            )
            response.raise_for_status()
            result = response.json()
            
            latency_ms = (time.perf_counter() - start_time) * 1000
            metrics = RequestMetrics(
                request_id=request_id,
                experiment_id=experiment_id,
                variant_name=variant_name,
                version_id=version_id,
                timestamp=datetime.now(),
                latency_ms=round(latency_ms, 2),
                success=True,
                input_tokens=result.get("usage", {}).get("prompt_tokens", 0),
                output_tokens=result.get("usage", {}).get("completion_tokens", 0)
            )
            
            self._record_metrics(metrics)
            
            response_data = {
                "request_id": request_id,
                "variant": variant_name,
                "content": result["choices"][0]["message"]["content"],
                "latency_ms": metrics.latency_ms,
                "tokens": metrics.input_tokens + metrics.output_tokens
            }
            
            if callback:
                callback(variant_name, response_data)
            
            return response_data
            
        except httpx.HTTPStatusError as e:
            latency_ms = (time.perf_counter() - start_time) * 1000
            metrics = RequestMetrics(
                request_id=request_id,
                experiment_id=experiment_id,
                variant_name=variant_name,
                version_id=version_id,
                timestamp=datetime.now(),
                latency_ms=round(latency_ms, 2),
                success=False,
                input_tokens=0,
                output_tokens=0,
                error_message=f"HTTP {e.response.status_code}: {e.response.text[:200]}"
            )
            self._record_metrics(metrics)
            return {"error": metrics.error_message, "variant": variant_name}

    def run_batch(
        self,
        experiment_id: str,
        test_cases: list[dict[str, str]],
        concurrency: int = 10,
        progress_callback: Callable[[int, int], None] = None
    ) -> dict:
        """批量リクエストをA/Bテストとして実行"""
        import concurrent.futures
        
        experiment = self.registry.experiments[experiment_id]
        experiment.status = ExperimentStatus.RUNNING
        experiment.started_at = datetime.now()
        
        results = []
        completed = 0
        
        def execute_with_progress(test_case):
            nonlocal completed
            result = self.run_single_request(experiment_id, test_case)
            completed += 1
            if progress_callback:
                progress_callback(completed, len(test_cases))
            return result
        
        with concurrent.futures.ThreadPoolExecutor(max_workers=concurrency) as executor:
            futures = [executor.submit(execute_with_progress, tc) for tc in test_cases]
            results = [f.result() for f in concurrent.futures.as_completed(futures)]
        
        experiment.status = ExperimentStatus.COMPLETED
        experiment.completed_at = datetime.now()
        
        return self.get_experiment_results(experiment_id)

    def get_experiment_results(self, experiment_id: str) -> dict:
        """実験結果の詳細レポートを生成"""
        if experiment_id not in self.variant_stats:
            return {"error": "実験データが見つかりません"}
        
        report = {
            "experiment_id": experiment_id,
            "experiment_name": self.registry.experiments[