T-CREATOR

Gemini CLI のプロンプト版管理設計:テンプレ・変数・バージョニングのルール

Gemini CLI のプロンプト版管理設計:テンプレ・変数・バージョニングのルール

Gemini CLI を活用したプロンプト設計において、適切な版管理は開発効率と品質を大きく左右します。プロンプトが複雑化するにつれて、テンプレート化、変数の効果的な利用、そして体系的なバージョニングが不可欠になってきました。

本記事では、Gemini CLI におけるプロンプトの版管理設計について、実践的なアプローチをご紹介します。テンプレート設計の原則から変数管理のベストプラクティス、そして継続的な改善を支えるバージョニングのルールまで、実際のコード例を交えながら詳しく解説していきますね。

背景

AI 開発におけるプロンプト管理の重要性

AI を活用した開発において、プロンプトは従来のコードと同等かそれ以上に重要な資産となっています。特に Gemini のような大規模言語モデルを CLI から利用する場合、プロンプトの品質が直接的にアプリケーションの性能に影響するのです。

従来のソフトウェア開発では、ソースコードの版管理に Git などのツールを利用してきました。しかし、プロンプトは自然言語で記述されるため、従来のコード管理手法をそのまま適用するだけでは不十分なケースが多いでしょう。

Gemini CLI の普及と課題

Gemini CLI は Google が提供する強力なツールで、コマンドラインから直接 Gemini モデルにアクセスできます。これにより、シェルスクリプトや自動化ワークフローへの統合が容易になりました。

以下の図は、Gemini CLI を中心とした開発フローを示しています。

mermaidflowchart TB
    developer["開発者"] -->|プロンプト作成| template["テンプレートファイル"]
    template -->|変数埋め込み| prompt["完成プロンプト"]
    prompt -->|CLI実行| gemini["Gemini API"]
    gemini -->|レスポンス| output["出力結果"]
    output -->|評価・改善| developer

    version["バージョン管理"] -.->|履歴追跡| template
    config["設定ファイル"] -->|変数定義| prompt

この図から分かるように、プロンプトは開発サイクルの中心に位置しており、適切な管理が求められます。

プロンプト版管理が必要になる場面

プロジェクトの規模が大きくなるにつれて、以下のような状況が発生しやすくなります。

複数の開発者が同じプロンプトを編集する場合、どのバージョンが最新で、どの変更が有効なのかを追跡する必要があります。また、A/B テストを実施する際には、異なるバージョンのプロンプトを並行して管理しなければなりません。

さらに、本番環境と開発環境で異なるプロンプトを使い分けるケースも多いでしょう。このような複雑な要件に対応するために、体系的な版管理設計が不可欠なのです。

課題

プロンプトの肥大化と可読性の低下

Gemini CLI でプロンプトを直接記述する場合、機能追加に伴ってプロンプトが長大化しがちです。特に、複雑な指示やコンテキスト情報を含める必要がある場合、一つのプロンプトが数百行に及ぶこともあります。

以下は、肥大化したプロンプトの典型例です。

typescript// 肥大化したプロンプトの例
const prompt = `
あなたは経験豊富なソフトウェアエンジニアです。
以下のコードをレビューしてください。
コードの品質、パフォーマンス、セキュリティの観点から評価してください。
改善点があれば具体的に指摘してください。
コーディング規約に違反している箇所があれば指摘してください。
テストコードが不足している場合は指摘してください。
...(さらに数百行続く)
`;

このようなプロンプトは、メンテナンスが困難になり、部分的な修正や再利用が難しくなってしまいます。

変数管理の複雑さ

プロンプト内で動的な値を扱う場合、変数の管理が課題となります。変数名の命名規則が統一されていないと、どの変数がどこで使われているのか追跡できなくなるでしょう。

typescript// 変数管理が複雑な例
const userName = '田中';
const userAge = 30;
const u_name = '佐藤'; // 命名規則が不統一
const age2 = 25; // 意味が不明確

また、変数のスコープや型定義が明確でないと、実行時エラーが発生しやすくなります。特に、複数のプロンプトテンプレートで同じ変数名を使用している場合、意図しない値の上書きが発生する可能性があるのです。

バージョン間の差分追跡の困難さ

プロンプトの改善を繰り返す過程で、どのバージョンがどのような変更を含んでいるのかを把握することが難しくなります。

以下の図は、バージョン管理が不適切な場合に発生する問題を示しています。

mermaidstateDiagram-v2
    [*] --> v1_initial: 初期プロンプト
    v1_initial --> v2_modified: 誰かが修正
    v1_initial --> v2_another: 別の人が修正
    v2_modified --> v3_merged: マージ試行
    v2_another --> v3_merged
    v3_merged --> error_state: 競合発生
    error_state --> [*]: 手動修正必要

従来のテキストファイルとして管理する場合、Git の差分表示だけでは、自然言語の微妙なニュアンスの変化を把握しにくいという問題もあります。

環境ごとの設定管理の煩雑さ

開発環境、ステージング環境、本番環境でそれぞれ異なるプロンプト設定を使用する場合、環境変数の管理が煩雑になります。特に、API キーやエンドポイント URL などの機密情報を含む場合、セキュリティ上の配慮も必要です。

環境ごとに異なるファイルを手動でコピーする運用では、ヒューマンエラーが発生しやすく、本番環境に誤った設定をデプロイしてしまうリスクがあるでしょう。

解決策

テンプレート設計の原則

プロンプトをテンプレート化することで、再利用性と保守性を大幅に向上させることができます。テンプレートは、固定的な指示部分と動的に変化する変数部分を明確に分離することが重要です。

テンプレートファイルの構造

プロンプトテンプレートは、以下のような階層構造で管理すると効果的です。

csharpprompts/
├── base/              # 基本テンプレート
│   ├── system.md     # システムプロンプト
│   └── common.md     # 共通指示
├── tasks/            # タスク別テンプレート
│   ├── code-review.md
│   ├── documentation.md
│   └── refactoring.md
└── versions/         # バージョン管理
    ├── v1.0/
    └── v2.0/

このディレクトリ構造により、目的別にテンプレートを整理できますね。

Markdown 形式でのテンプレート記述

テンプレートファイルは Markdown 形式で記述することをおすすめします。Markdown を使用することで、可読性が高く、バージョン管理システムとの相性も良好です。

markdown<!-- prompts/tasks/code-review.md -->

# コードレビュー用プロンプト

# 役割定義

あなたは{{experience_years}}年の経験を持つ{{language}}のエキスパートです。

# レビュー観点

以下の観点からコードをレビューしてください:

1. コードの品質
2. パフォーマンス
3. セキュリティ

このテンプレートでは、{{experience_years}}{{language}} といった変数をプレースホルダーとして定義しています。

テンプレートの部品化

大きなプロンプトは、再利用可能な部品に分割しましょう。これにより、複数のプロンプトで共通する指示を一元管理できます。

markdown<!-- prompts/base/common.md -->

# 出力形式の指定

- 回答は日本語で記述してください
- コードブロックには言語を明記してください
- 改善提案は具体的に記述してください

この共通部品は、他のテンプレートから参照することができるのです。

変数管理のベストプラクティス

型定義による変数の安全性確保

TypeScript を使用して、プロンプト変数の型を明確に定義します。これにより、実行時エラーを未然に防ぐことができますね。

typescript// types/prompt-variables.ts

/**
 * コードレビュー用プロンプトの変数型定義
 */
interface CodeReviewVariables {
  // レビュアーの経験年数
  experienceYears: number;
  // プログラミング言語
  language: string;
  // レビュー対象コード
  targetCode: string;
  // レビューの厳格度(1-5)
  strictness: 1 | 2 | 3 | 4 | 5;
}

この型定義により、変数の用途と制約が明確になります。

変数の命名規則

変数名は、以下の規則に従って統一的に命名しましょう。

#規則説明
1キャメルケースuserName基本的な命名形式
2接頭辞で用途を明示prompt_Languageプロンプト用変数
3真偽値は is/has で開始isProduction真偽値の明確化
4配列は複数形reviewPoints配列であることを示す

環境変数との統合

環境ごとに異なる値を持つ変数は、.env ファイルで管理します。

bash# .env.development
GEMINI_API_KEY=dev_key_xxxxx
PROMPT_STRICTNESS=3
REVIEW_LANGUAGE=TypeScript
bash# .env.production
GEMINI_API_KEY=prod_key_xxxxx
PROMPT_STRICTNESS=5
REVIEW_LANGUAGE=TypeScript

これらの環境変数を読み込むためのユーティリティ関数を作成します。

typescript// utils/env-loader.ts
import dotenv from 'dotenv';

/**
 * 環境変数を読み込み、プロンプト変数に変換
 */
export function loadPromptVariables(): CodeReviewVariables {
  dotenv.config();

  return {
    experienceYears: 10,
    language: process.env.REVIEW_LANGUAGE || 'JavaScript',
    targetCode: '',
    strictness: parseInt(
      process.env.PROMPT_STRICTNESS || '3'
    ) as 1 | 2 | 3 | 4 | 5,
  };
}

この関数により、環境に応じた変数の自動設定が可能になるのです。

バージョニングのルール

セマンティックバージョニングの適用

プロンプトのバージョン管理には、セマンティックバージョニング(SemVer)を適用します。バージョン番号は MAJOR.MINOR.PATCH の形式で表現しましょう。

#バージョン要素変更内容
1MAJORプロンプトの根本的な変更1.0.0 → 2.0.0
2MINOR機能追加(後方互換性あり)1.0.0 → 1.1.0
3PATCH軽微な修正・バグ修正1.0.0 → 1.0.1

バージョン情報の埋め込み

各プロンプトテンプレートには、バージョン情報をメタデータとして埋め込みます。

markdown## <!-- prompts/tasks/code-review.md -->

version: 2.1.0
updated: 2025-12-01
author: development-team
changelog:

- 2.1.0: セキュリティチェック項目を追加
- 2.0.0: 出力形式を JSON 化
- 1.0.0: 初版リリース

---

# コードレビュー用プロンプト

...

このメタデータにより、プロンプトの変更履歴を追跡できます。

Git タグによる版管理

プロンプトの重要なバージョンは、Git タグとして記録します。

bash# 新しいバージョンのタグを作成
git tag -a prompt-v2.1.0 -m "Add security check items to code review prompt"

# タグをリモートにプッシュ
git push origin prompt-v2.1.0

これにより、特定バージョンのプロンプトに簡単に戻ることができるのです。

バージョン互換性の管理

異なるバージョン間の互換性を管理するため、マイグレーション情報を記録します。

typescript// migrations/prompt-migrations.ts

/**
 * プロンプトバージョン間のマイグレーション定義
 */
export const promptMigrations = {
  'code-review': {
    '1.0.0_to_2.0.0': {
      description: '出力形式をJSON化',
      breaking: true,
      migration: (oldVariables: any) => {
        // 古い変数形式を新しい形式に変換
        return {
          ...oldVariables,
          outputFormat: 'json',
        };
      },
    },
  },
};

プロンプト管理システムの実装

テンプレートエンジンの選択

プロンプトテンプレートの変数展開には、Handlebars や Mustache などのテンプレートエンジンを使用します。

typescript// utils/template-engine.ts
import Handlebars from 'handlebars';
import fs from 'fs';
import path from 'path';

/**
 * テンプレートファイルを読み込み、変数を展開
 */
export class PromptTemplateEngine {
  private templatesDir: string;

  constructor(templatesDir: string) {
    this.templatesDir = templatesDir;
  }
typescript  /**
   * テンプレートをコンパイルして実行
   */
  render(templateName: string, variables: Record<string, any>): string {
    const templatePath = path.join(
      this.templatesDir,
      `${templateName}.md`
    );
    const templateContent = fs.readFileSync(templatePath, 'utf-8');

    const template = Handlebars.compile(templateContent);
    return template(variables);
  }
}

このクラスにより、テンプレートの読み込みと変数展開を統一的に処理できますね。

Handlebars ヘルパー関数の登録

テンプレート内で使用できるカスタムヘルパー関数を定義します。

typescript// utils/handlebars-helpers.ts
import Handlebars from 'handlebars';

/**
 * 条件分岐ヘルパー(厳格度によって出力を変える)
 */
Handlebars.registerHelper(
  'strictnessLevel',
  function (strictness: number) {
    if (strictness >= 4) {
      return '非常に厳格なレビューを実施してください。';
    } else if (strictness >= 2) {
      return '標準的なレビューを実施してください。';
    } else {
      return '基本的な確認を実施してください。';
    }
  }
);
typescript/**
 * 配列の結合ヘルパー
 */
Handlebars.registerHelper(
  'join',
  function (array: string[], separator: string) {
    return array.join(separator);
  }
);

/**
 * 日付フォーマットヘルパー
 */
Handlebars.registerHelper(
  'formatDate',
  function (date: Date) {
    return date.toISOString().split('T')[0];
  }
);

これらのヘルパー関数を使用することで、テンプレート内での複雑な処理が可能になります。

具体例

プロンプトテンプレートシステムの完全実装

ここからは、実際に動作するプロンプト版管理システムの実装例を見ていきましょう。全体のアーキテクチャは以下の図のように設計されています。

mermaidflowchart TB
    subgraph input["入力層"]
        vars["変数定義<br/>(variables.ts)"]
        env["環境設定<br/>(.env)"]
    end

    subgraph template["テンプレート層"]
        base["基本テンプレート<br/>(base/*.md)"]
        task["タスクテンプレート<br/>(tasks/*.md)"]
    end

    subgraph engine["処理エンジン"]
        loader["テンプレート<br/>ローダー"]
        compiler["コンパイラ<br/>(Handlebars)"]
        validator["バリデーター"]
    end

    subgraph output["出力層"]
        prompt_output["完成プロンプト"]
        gemini_cli["Gemini CLI"]
    end

    vars --> loader
    env --> loader
    base --> loader
    task --> loader
    loader --> compiler
    compiler --> validator
    validator --> prompt_output
    prompt_output --> gemini_cli

この図から分かるように、システムは入力層、テンプレート層、処理エンジン、出力層の 4 層構造になっています。

プロジェクト構造の設定

まず、プロジェクトのディレクトリ構造を以下のように構築します。

luagemini-prompt-manager/
├── prompts/
│   ├── base/
│   │   ├── system.md
│   │   └── output-format.md
│   ├── tasks/
│   │   ├── code-review.md
│   │   └── documentation.md
│   └── versions/
│       └── v2.0/
├── src/
│   ├── types/
│   │   └── prompt-variables.ts
│   ├── utils/
│   │   ├── template-engine.ts
│   │   └── version-manager.ts
│   └── index.ts
├── .env.development
├── .env.production
└── package.json

型定義ファイルの作成

プロンプト変数の型を厳密に定義します。

typescript// src/types/prompt-variables.ts

/**
 * 基本プロンプト変数の共通インターフェース
 */
export interface BasePromptVariables {
  // バージョン情報
  version: string;
  // 生成日時
  generatedAt: Date;
  // 環境(development/production)
  environment: 'development' | 'production';
}
typescript/**
 * コードレビュー用の拡張変数
 */
export interface CodeReviewVariables
  extends BasePromptVariables {
  // レビュアーの経験年数
  experienceYears: number;
  // 対象プログラミング言語
  language: string;
  // レビュー対象コード
  targetCode: string;
  // 厳格度(1: 緩い ~ 5: 厳格)
  strictness: 1 | 2 | 3 | 4 | 5;
  // 特に注目する観点
  focusAreas: string[];
}
typescript/**
 * ドキュメント生成用の変数
 */
export interface DocumentationVariables
  extends BasePromptVariables {
  // コードの種類(function/class/module)
  codeType: 'function' | 'class' | 'module';
  // ソースコード
  sourceCode: string;
  // 対象読者(beginner/intermediate/expert)
  audience: 'beginner' | 'intermediate' | 'expert';
  // 含める項目
  includeSections: string[];
}

これらの型定義により、コンパイル時に型安全性が保証されます。

テンプレートファイルの作成

実際のプロンプトテンプレートを Markdown 形式で作成しましょう。

markdown## <!-- prompts/base/system.md -->

version: 2.0.0
type: system

---

# システムプロンプト

あなたは{{experienceYears}}年の経験を持つ、{{language}}の専門家です。
現在の環境: {{environment}}
生成日時: {{formatDate generatedAt}}
markdown## <!-- prompts/tasks/code-review.md -->

version: 2.1.0
type: task
extends: base/system.md

---

# コードレビュータスク

# レビュー観点

{{strictnessLevel strictness}}

以下の観点に特に注目してください:
{{#each focusAreas}}

- {{this}}
  {{/each}}

# 対象コード

```{{language}}
{{targetCode}}
```
javascript
````markdown

# 出力形式

以下のJSON形式で回答してください:

````json
{
  "overall_score": 0-100,
  "issues": [],
  "suggestions": []
}
typescript
このテンプレートでは、Handlebars の構文を使って変数展開と条件分岐を実現しています。

## バージョン管理クラスの実装

プロンプトのバージョン情報を管理するクラスを実装します。

````typescript
// src/utils/version-manager.ts
import fs from 'fs';
import path from 'path';
import yaml from 'yaml';

/**
 * プロンプトのバージョン情報
 */
export interface PromptVersion {
  version: string;
  type: 'system' | 'task';
  extends?: string;
  changelog?: string[];
}
typescript/**
 * バージョン管理クラス
 */
export class PromptVersionManager {
  private versionsCache: Map<string, PromptVersion>;

  constructor() {
    this.versionsCache = new Map();
  }

  /**
   * テンプレートファイルからバージョン情報を抽出
   */
  extractVersion(templatePath: string): PromptVersion {
    const content = fs.readFileSync(templatePath, 'utf-8');
    const frontMatterMatch = content.match(/^---\n([\s\S]+?)\n---/);
typescript    if (!frontMatterMatch) {
      throw new Error(`No version metadata found in ${templatePath}`);
    }

    const metadata = yaml.parse(frontMatterMatch[1]);

    const versionInfo: PromptVersion = {
      version: metadata.version || '0.0.0',
      type: metadata.type || 'task',
      extends: metadata.extends,
      changelog: metadata.changelog
    };

    this.versionsCache.set(templatePath, versionInfo);
    return versionInfo;
  }
typescript  /**
   * バージョン比較(セマンティックバージョニング)
   */
  compareVersions(v1: string, v2: string): number {
    const parts1 = v1.split('.').map(Number);
    const parts2 = v2.split('.').map(Number);

    for (let i = 0; i < 3; i++) {
      if (parts1[i] > parts2[i]) return 1;
      if (parts1[i] < parts2[i]) return -1;
    }
    return 0;
  }
}

このクラスにより、テンプレートのバージョン情報を一元管理できますね。

統合プロンプトマネージャーの実装

すべての機能を統合したプロンプトマネージャーを実装します。

typescript// src/index.ts
import { PromptTemplateEngine } from './utils/template-engine';
import { PromptVersionManager } from './utils/version-manager';
import { CodeReviewVariables } from './types/prompt-variables';
import dotenv from 'dotenv';

/**
 * プロンプト管理の統合クラス
 */
export class GeminiPromptManager {
  private templateEngine: PromptTemplateEngine;
  private versionManager: PromptVersionManager;
  private environment: 'development' | 'production';
typescript  constructor(templatesDir: string) {
    // 環境変数の読み込み
    dotenv.config();

    this.templateEngine = new PromptTemplateEngine(templatesDir);
    this.versionManager = new PromptVersionManager();
    this.environment = (process.env.NODE_ENV as any) || 'development';
  }
typescript  /**
   * コードレビュー用プロンプトの生成
   */
  async generateCodeReviewPrompt(
    targetCode: string,
    options?: Partial<CodeReviewVariables>
  ): Promise<string> {
    const variables: CodeReviewVariables = {
      version: '2.1.0',
      generatedAt: new Date(),
      environment: this.environment,
      experienceYears: options?.experienceYears || 10,
      language: options?.language || 'TypeScript',
      targetCode,
      strictness: options?.strictness || 3,
      focusAreas: options?.focusAreas || [
        'コード品質',
        'パフォーマンス',
        'セキュリティ'
      ]
    };
typescript    // テンプレートのレンダリング
    const prompt = this.templateEngine.render(
      'tasks/code-review',
      variables
    );

    return prompt;
  }
typescript  /**
   * Gemini CLI でプロンプトを実行
   */
  async executeWithGemini(prompt: string): Promise<string> {
    const { exec } = require('child_process');
    const { promisify } = require('util');
    const execAsync = promisify(exec);

    const apiKey = process.env.GEMINI_API_KEY;
    if (!apiKey) {
      throw new Error('GEMINI_API_KEY is not set');
    }
typescript    // Gemini CLI コマンドの構築
    const command = `echo "${prompt.replace(/"/g, '\\"')}" | gemini-cli --api-key ${apiKey}`;

    try {
      const { stdout, stderr } = await execAsync(command);
      if (stderr) {
        console.error('Gemini CLI stderr:', stderr);
      }
      return stdout;
    } catch (error) {
      throw new Error(`Gemini CLI execution failed: ${error}`);
    }
  }
}

実用例:コードレビューの自動化

実際の使用例を見てみましょう。

typescript// example.ts
import { GeminiPromptManager } from './src/index';

async function main() {
  // プロンプトマネージャーの初期化
  const manager = new GeminiPromptManager('./prompts');

  // レビュー対象のコード
  const targetCode = `
function calculateTotal(items) {
  let total = 0;
  for (let i = 0; i < items.length; i++) {
    total += items[i].price;
  }
  return total;
}
  `.trim();
typescript// プロンプトの生成
const prompt = await manager.generateCodeReviewPrompt(
  targetCode,
  {
    language: 'JavaScript',
    strictness: 4,
    focusAreas: [
      '型安全性',
      'モダンな構文の使用',
      'エッジケースの処理',
    ],
  }
);

console.log('生成されたプロンプト:');
console.log(prompt);
console.log('\n---\n');
typescript  // Gemini CLI で実行
  try {
    const result = await manager.executeWithGemini(prompt);
    console.log('Gemini のレスポンス:');
    console.log(result);
  } catch (error) {
    console.error('エラーが発生しました:', error);
  }
}

main();

このコードを実行すると、自動的にプロンプトが生成され、Gemini CLI 経由でレビュー結果が取得できるのです。

環境別の設定管理

開発環境と本番環境で異なる設定を使用する例を示します。

bash# .env.development
NODE_ENV=development
GEMINI_API_KEY=dev_xxxxxxxxxxxxx
PROMPT_STRICTNESS=3
DEFAULT_LANGUAGE=TypeScript
LOG_LEVEL=debug
bash# .env.production
NODE_ENV=production
GEMINI_API_KEY=prod_xxxxxxxxxxxxx
PROMPT_STRICTNESS=5
DEFAULT_LANGUAGE=TypeScript
LOG_LEVEL=error
typescript// src/utils/config-loader.ts

/**
 * 環境別の設定を読み込むユーティリティ
 */
export class ConfigLoader {
  static load() {
    const env = process.env.NODE_ENV || 'development';
    const envFile = `.env.${env}`;

    require('dotenv').config({ path: envFile });

    return {
      apiKey: process.env.GEMINI_API_KEY!,
      strictness: parseInt(
        process.env.PROMPT_STRICTNESS || '3'
      ),
      language:
        process.env.DEFAULT_LANGUAGE || 'TypeScript',
      logLevel: process.env.LOG_LEVEL || 'info',
    };
  }
}

バージョン移行の自動化

プロンプトのバージョンアップ時に、古い変数形式を新しい形式に自動変換する仕組みを実装します。

typescript// src/utils/migration-handler.ts

/**
 * バージョン間のマイグレーション処理
 */
export class MigrationHandler {
  /**
   * v1.x から v2.x への変数変換
   */
  static migrateV1ToV2(oldVariables: any): CodeReviewVariables {
    return {
      version: '2.0.0',
      generatedAt: new Date(),
      environment: oldVariables.env || 'development',
      // v1では reviewerExp という名前だった
      experienceYears: oldVariables.reviewerExp || 5,
      language: oldVariables.lang || 'JavaScript',
typescript      targetCode: oldVariables.code || '',
      // v1では level(1-3)だったので変換
      strictness: this.convertStrictnessLevel(oldVariables.level || 2),
      // v1では単一文字列だったので配列化
      focusAreas: oldVariables.focus ? [oldVariables.focus] : []
    };
  }

  private static convertStrictnessLevel(oldLevel: number): 1 | 2 | 3 | 4 | 5 {
    const mapping: Record<number, 1 | 2 | 3 | 4 | 5> = {
      1: 2,
      2: 3,
      3: 5
    };
    return mapping[oldLevel] || 3;
  }
}

このマイグレーション処理により、バージョンアップ時の後方互換性を維持できます。

エラーハンドリングとバリデーション

プロンプト生成時のエラーハンドリングを実装します。

typescript// src/utils/validator.ts

/**
 * プロンプト変数のバリデーションエラー
 */
export class PromptValidationError extends Error {
  constructor(
    message: string,
    public field: string,
    public code: string
  ) {
    super(message);
    this.name = 'PromptValidationError';
  }
}
typescript/**
 * バリデータークラス
 */
export class PromptValidator {
  /**
   * コードレビュー変数の検証
   */
  static validateCodeReview(variables: CodeReviewVariables): void {
    // 必須フィールドの確認
    if (!variables.targetCode || variables.targetCode.trim() === '') {
      throw new PromptValidationError(
        'Target code is required',
        'targetCode',
        'VALIDATION_001'
      );
    }
typescript    // 厳格度の範囲確認
    if (variables.strictness < 1 || variables.strictness > 5) {
      throw new PromptValidationError(
        'Strictness must be between 1 and 5',
        'strictness',
        'VALIDATION_002'
      );
    }

    // 経験年数の妥当性確認
    if (variables.experienceYears < 0 || variables.experienceYears > 50) {
      throw new PromptValidationError(
        'Experience years must be between 0 and 50',
        'experienceYears',
        'VALIDATION_003'
      );
    }
  }
}

これらのエラーコード(VALIDATION_001 など)を定義することで、エラーの検索性が向上しますね。

まとめ

Gemini CLI におけるプロンプトの版管理設計について、テンプレート化、変数管理、バージョニングの 3 つの観点から解説してきました。

テンプレート設計では、Markdown 形式での記述と Handlebars によるテンプレートエンジンの活用により、再利用性と保守性を大幅に向上させることができました。プロンプトを部品化し、階層的に管理することで、複雑なプロンプトでも見通しよく管理できるようになりますね。

変数管理においては、TypeScript の型システムを活用することで、実行時エラーを未然に防ぎ、開発効率を高めることができました。環境変数との統合により、開発環境と本番環境で適切に設定を切り替えられる仕組みも整いましたね。

バージョニングでは、セマンティックバージョニングの適用と Git タグの活用により、プロンプトの変更履歴を明確に追跡できるようになりました。マイグレーション処理の実装により、バージョンアップ時の後方互換性も確保できます。

これらの設計原則と実装例を参考にすることで、チーム開発においても一貫性のあるプロンプト管理が実現できるでしょう。プロンプトもソースコードと同様に、適切な版管理とレビュープロセスを経ることで、品質の高い AI アプリケーション開発が可能になるのです。

今後は、これらの基盤の上に、A/B テストの自動化やプロンプトの性能測定など、より高度な機能を追加していくことをおすすめします。

関連リンク