2

プロンプトバージョニング設計|Git管理・A/B

プロンプトバージョニング設計|Git管理・A/B

この記事の結論

AIエージェントのプロンプトをGit管理。A/Bテスト・ロールバックの実装パターンを解説。

プロンプトを1行変えただけで、エージェントの応答が別物になった。

そういう経験は、AIエージェントを本番運用していれば必ず起きる。コードなら git diff で変更点が一目瞭然だが、プロンプトは「なんとなく変えた」が積み重なり、いつの間にか誰も正確な変更履歴を把握できなくなる。問題が起きても「どのバージョンのプロンプトが原因か」を追跡できない状態は、本番エージェントとしては危険だ。

2026年、プロンプトをコードと同じように管理するツールとプラクティスが急速に整備されている。この記事では、プロンプトバージョニングの設計思想と、Gitベース管理・A/Bテスト・ロールバック戦略を具体的に解説する。

プロンプトバージョニングが必要な本当の理由

「Gitでプロンプトファイルを管理すればいいのでは?」という声をよく聞く。それは正しいアプローチだが、コードのGit管理と決定的に違う点がある。

プロンプトは「本番に即座に影響する」。コードはビルド・テスト・デプロイのパイプラインを経るが、多くのエージェント実装ではプロンプトの変更が即座に全ユーザーに適用される。しかも変更の影響は定量的に測りにくい。

管理対象 変更の影響速度 影響の定量測定 ロールバックの容易さ
コード デプロイ後 エラーレート・パフォーマンス指標 git revert で即可
プロンプト(管理なし) 即座 困難(主観的品質評価が多い) 過去バージョンが不明
プロンプト(バージョニング有) 即座 A/Bテストで定量化可能 ワンクリックでロールバック

AIエージェントの設計全体については、AIエージェント構築完全ガイドで体系的に整理している。

Gitベース管理:最小構成から始める

外部ツールを使わず、まずGitでプロンプトを管理する構成を作る。重要なのは「プロンプトをコードから分離する」ことだ。


# ディレクトリ構造の例
# 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

prompts/
├── system/
│   ├── customer-support-v1.2.0.md      # バージョン番号をファイル名に含める
│   ├── customer-support-v1.3.0.md
│   └── customer-support-current.md     # シンボリックリンク or 最新版
├── tools/
│   ├── web-search-v2.0.0.md
│   └── data-analysis-v1.1.0.md
└── CHANGELOG.md                        # 変更理由を必ず記録

# プロンプトローダー: バージョン管理対応
# 動作環境: Python 3.11+
# 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

import os
from pathlib import Path
from functools import lru_cache

PROMPTS_DIR = Path(__file__).parent.parent / "prompts"

@lru_cache(maxsize=128)
def load_prompt(name: str, version: str = "current") -> str:
    """
    プロンプトをファイルから読み込む(コードハードコードNG)

    Args:
        name: プロンプト名(例: "customer-support")
        version: バージョン(例: "1.2.0")または "current"

    Returns:
        プロンプトテキスト
    """
    if version == "current":
        filepath = PROMPTS_DIR / "system" / f"{name}-current.md"
    else:
        filepath = PROMPTS_DIR / "system" / f"{name}-v{version}.md"

    if not filepath.exists():
        raise FileNotFoundError(f"Prompt not found: {filepath}")

    return filepath.read_text(encoding="utf-8")


# 環境変数でバージョンを切り替える(A/Bテスト用)
def get_active_prompt(name: str) -> str:
    """環境変数でバージョンを制御"""
    env_key = f"PROMPT_VERSION_{name.upper().replace('-', '_')}"
    version = os.getenv(env_key, "current")
    return load_prompt(name, version)

このパターンのポイントは2つ。プロンプトをコードから切り離すことで、エンジニア以外(プロダクトマネージャー、ドメイン専門家)でもプロンプトを更新できる。そして環境変数でバージョンを切り替えるため、コード変更なしにA/Bテストが実現できる。

A/Bテスト:プロンプト改善を定量化する

「感覚」でプロンプトを改善するのをやめるには、A/Bテストの仕組みが必要だ。


# シンプルなプロンプトA/Bテストフレームワーク
# 動作環境: Python 3.11+, redis>=4.0(分散環境の場合)
# 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

import random
import hashlib
import time
from dataclasses import dataclass, field
from typing import Optional
from openai import OpenAI

@dataclass
class ABTestConfig:
    """A/Bテスト設定"""
    experiment_id: str
    control_version: str      # 現行バージョン(例: "1.2.0")
    treatment_version: str    # 新バージョン(例: "1.3.0")
    traffic_split: float = 0.5  # 新バージョンに送るトラフィック割合
    metric_key: str = "quality_score"

@dataclass
class ABTestResult:
    """テスト結果の記録"""
    experiment_id: str
    user_id: str
    variant: str              # "control" or "treatment"
    prompt_version: str
    response_time_ms: float
    quality_score: Optional[float] = None  # 評価者がスコアリング

def assign_variant(user_id: str, config: ABTestConfig) -> str:
    """
    ユーザーIDで確定的にバリアント割り当て(同一ユーザーは常に同じバリアント)
    """
    hash_value = int(hashlib.md5(
        f"{config.experiment_id}:{user_id}".encode()
    ).hexdigest(), 16)

    return "treatment" if (hash_value % 100) < (config.traffic_split * 100) else "control"


def run_ab_test(
    user_id: str,
    prompt_name: str,
    user_message: str,
    config: ABTestConfig,
    client: OpenAI
) -> tuple[str, ABTestResult]:
    """A/Bテスト付きエージェント実行"""

    variant = assign_variant(user_id, config)
    version = config.treatment_version if variant == "treatment" else config.control_version
    system_prompt = load_prompt(prompt_name, version)

    start = time.time()
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_message}
        ]
    )
    elapsed_ms = (time.time() - start) * 1000

    result = ABTestResult(
        experiment_id=config.experiment_id,
        user_id=user_id,
        variant=variant,
        prompt_version=version,
        response_time_ms=elapsed_ms
    )

    return response.choices[0].message.content, result

ポイントは「ユーザーIDのハッシュで確定的に割り当てる」こと。同一ユーザーが毎回違うバリアントを見ると、体験の一貫性が失われる。ハッシュ方式なら同じユーザーは常に同じバリアントになる。

専用ツール:Langfuse・LangSmith・Promptfooの比較

Gitベース管理は最小構成として有効だが、チームが大きくなると専用ツールの導入が現実的だ。2026年現在の主要ツールを整理する。

ツール バージョン管理 A/Bテスト オブザーバビリティ 価格
Langfuse ○(ラベルベース) △(手動設定) ○(詳細トレース) オープンソース(セルフホスト可)
LangSmith ○(Prompt Hub) 有料(Developer無料枠あり)
Promptfoo ○(YAMLベース) ○(CLI中心) オープンソース
Maxim AI ○(自動追跡) ○(エージェントシミュレーション) 有料(無料枠あり)

※価格情報は2026年4月時点。最新は各社公式を確認。

個人・小規模チームならPromptfooかLangfuse(セルフホスト)から始めるのが低コストで始めやすい。チームが10人を超え、非エンジニアもプロンプト管理に関わるならMaxim AIやLangSmithのUIが有効になってくる。

ロールバック戦略:障害時の即時復旧

プロンプトの変更で品質が劣化した場合、素早くロールバックできる仕組みが必須だ。


# プロンプトロールバック管理
# 動作環境: Python 3.11+
# 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

import json
import os
from pathlib import Path
from datetime import datetime

class PromptVersionManager:
    """プロンプトのバージョン管理とロールバック"""

    def __init__(self, prompts_dir: Path):
        self.prompts_dir = prompts_dir
        self.version_log_path = prompts_dir / "version_log.json"
        self._load_log()

    def _load_log(self):
        if self.version_log_path.exists():
            self.log = json.loads(self.version_log_path.read_text())
        else:
            self.log = {}

    def deploy(self, name: str, version: str, reason: str, deployed_by: str):
        """バージョンをデプロイ(シンボリックリンクを更新)"""
        current_path = self.prompts_dir / "system" / f"{name}-current.md"
        target_path = self.prompts_dir / "system" / f"{name}-v{version}.md"

        if not target_path.exists():
            raise FileNotFoundError(f"Version {version} not found: {target_path}")

        # 現在のバージョンをログに記録(ロールバック用)
        if name not in self.log:
            self.log[name] = []

        self.log[name].append({
            "version": version,
            "deployed_at": datetime.utcnow().isoformat(),
            "deployed_by": deployed_by,
            "reason": reason
        })

        # current.md を上書き
        current_path.write_text(target_path.read_text(encoding="utf-8"), encoding="utf-8")

        # ログ保存
        self.version_log_path.write_text(json.dumps(self.log, ensure_ascii=False, indent=2))

        print(f"Deployed {name} v{version}")

    def rollback(self, name: str, steps: int = 1):
        """N個前のバージョンにロールバック"""
        history = self.log.get(name, [])

        if len(history) <= steps:
            raise ValueError(f"Cannot rollback {steps} steps: only {len(history)} entries")

        target = history[-(steps + 1)]
        print(f"Rolling back {name} to v{target['version']} (deployed at {target['deployed_at']})")

        self.deploy(
            name=name,
            version=target["version"],
            reason=f"Rollback from {history[-1]['version']}",
            deployed_by="system"
        )

【要注意】よくある失敗パターンと回避策

失敗1: プロンプトをコード内にハードコードする

❌ Pythonファイルの中に長いシステムプロンプト文字列
⭕ プロンプトは別ファイルで管理、コードからは読み込みのみ

なぜ重要か: ハードコードされたプロンプトは変更履歴が追えない。エンジニア以外が修正できず、変更の影響テストもできない。

失敗2: 変更理由を記録しない

❌ プロンプトファイルのgit commitメッセージが "update prompt"
⭕ "なぜ変えたか(問題と仮説)" を必ず記録する

なぜ重要か: 3ヶ月後に問題が起きたとき、変更理由がないと調査が困難になる。

失敗3: A/Bテストを感覚で終わらせる

❌ "なんとなく良くなった気がする" で新バージョンに切り替える
⭕ 統計的有意差(最低200サンプル)を確認してから切り替え

なぜ重要か: 少サンプルでの判断はプラシーボ効果に近い。定量的な指標がないと改善なのか劣化なのか判断できない。

失敗4: ロールバック手順を事前に準備しない

❌ 問題が起きてからロールバック方法を考え始める
⭕ デプロイ前にロールバック手順を文書化・テストしておく

なぜ重要か: 障害時は時間がない。手順が頭の中にしかないと、プレッシャー下で間違える。

参考・出典

まとめ:今日から始める3つのアクション

  1. 今日やること:既存のプロンプトをコードから切り出してMarkdownファイルにする。Gitでバージョン管理を始め、最初のコミットメッセージに「なぜこのプロンプトか」を記録する。
  2. 今週中:PromptVersionManagerを実装してデプロイ履歴を記録する。ロールバック手順をドキュメント化して、チームでテストしておく。
  3. 今月中:A/Bテストフレームワークを組み込んで、プロンプト変更の効果を定量測定できる状態にする。チームが5人を超えたらLangfuseかLangSmithの導入を検討する。

あわせて読みたい:


この記事はAIgent Lab編集部がお届けしました。AIエージェント設計・運用のご相談は Uravationお問い合わせフォーム からお気軽にどうぞ。

Need help moving from reading to rollout?

この記事を読んで導入イメージが固まってきた方へ

Uravationでは、AIエージェントの要件整理、PoC設計、社内導入、研修まで一気通貫で支援しています。

この記事をシェア

X Facebook LINE

※ 本記事の情報は2026年4月時点のものです。サービスの料金・仕様は変更される可能性があります。最新情報は各サービスの公式サイトをご確認ください。

関連記事