0Pricing
AI Prompt Engineering · レッスン

自己改善型プロンプトシステム

フィードバック → 批評 → 書き直しのループで、プロンプトを自動的に最適化します。

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

自己改善ループ

自己改善型のプロンプトシステムは、フィードバックループを作成します。テストケースに対してプロンプトを実行し、出力を評価し、プロンプトを批評し、書き換えるという処理を繰り返します。各反復では、測定可能な改善が得られるようにします。これは、各ループで人間が介入することなく行う自動プロンプト最適化です。

ループアーキテクチャの概要

自己改善ループには5つのコンポーネントがあります。プロンプトを実行するExecutor、出力を採点するEvaluator、プロンプトの弱点を特定するCritic、プロンプトを改善するRewriter、すべての反復を追跡するHistoryです。それぞれがLLM呼び出しとして実装されます。

import anthropic

client = anthropic.Anthropic(api_key='YOUR_API_KEY')

class SelfImprovingPromptSystem:
    def __init__(self, initial_prompt, test_cases, eval_fn, max_iterations=5):
        self.current_prompt = initial_prompt
        self.test_cases = test_cases
        self.eval_fn = eval_fn
        self.max_iterations = max_iterations
        self.history = []  # [(iteration, prompt, score, critique)]

    def run(self):
        for i in range(self.max_iterations):
            print(f'=== Iteration {i+1}/{self.max_iterations} ===')
            score = self._evaluate_prompt()
            print(f'Score: {score:.2f}')
            self.history.append((i, self.current_prompt, score))
            if score >= 0.95:
                print('Target score reached. Stopping.')
                break
            critique = self._critique_prompt(score)
            self.current_prompt = self._rewrite_prompt(critique)
        return self.best_prompt()

    def best_prompt(self):
        return max(self.history, key=lambda x: x[2])[1]

Executor:プロンプトの実行

Executorは現在のプロンプトをすべてのテストケースに適用し、出力を収集します。これは標準的なLLM呼び出しのループであり、特別な処理はありません。ただし、どのテストケースからどの出力が生成されたかを追跡することが不可欠です。

def _execute_prompt(self, prompt):
    outputs = []
    for case in self.test_cases:
        response = client.messages.create(
            model='claude-haiku-4-5',  # use cheaper model for execution
            max_tokens=500,
            messages=[
                {'role': 'user', 'content': prompt + '\n\nInput: ' + case['input']}
            ]
        )
        outputs.append({
            'case_id': case['id'],
            'input': case['input'],
            'expected': case['expected'],
            'actual': response.content[0].text
        })
    return outputs

# Bind method to class (demonstration)
SelfImprovingPromptSystem._execute = _execute_prompt

# Sample test cases
test_cases = [
    {'id': 1, 'input': 'The meeting was cancelled.', 'expected': 'negative'},
    {'id': 2, 'input': 'Great product, love it!', 'expected': 'positive'},
    {'id': 3, 'input': 'It arrived on time.', 'expected': 'neutral'},
]
print(f'Test suite: {len(test_cases)} cases')

Evaluator:出力のスコアリング

Evaluatorは、期待される回答と照らし合わせてExecutorの出力を採点します。完全一致、あいまい一致、または自由記述型のタスク向けに別のLLMジャッジを使用できます。

def _evaluate_prompt(self):
    outputs = self._execute(self.current_prompt)
    correct = 0
    failed_cases = []
    for out in outputs:
        # Exact match for classification tasks
        if out['expected'].lower() in out['actual'].lower():
            correct += 1
        else:
            failed_cases.append(out)
    score = correct / len(outputs)
    self._last_failed_cases = failed_cases
    return score

# For open-ended tasks: LLM-as-judge evaluator
JUDGE_PROMPT = '''Rate the quality of this AI response (1-5).
Task: {task_description}
Input: {input}
Expected approach: {expected}
Actual response: {actual}

Return only the integer score (1-5). No explanation.'''

def llm_judge_score(task_desc, input_text, expected, actual):
    response = client.messages.create(
        model='claude-haiku-4-5', max_tokens=5,
        messages=[{'role': 'user', 'content':
            JUDGE_PROMPT.format(
                task_description=task_desc, input=input_text,
                expected=expected, actual=actual
            )}]
    )
    try:
        return int(response.content[0].text.strip()) / 5.0
    except ValueError:
        return 0.5

Critic:プロンプトの弱点の特定

Criticは、失敗したケースと現在のプロンプトを分析し、具体的な弱点を特定します。ここがメタプロンプティングの重要なステップです。モデル自身が自分のプロンプトを批評します。

CRITIC_PROMPT = '''You are a prompt engineering expert analyzing why a prompt fails.

Current prompt:
{current_prompt}

Failed test cases (where the prompt gave wrong outputs):
{failed_cases}

For each failure, explain:
1. What went wrong in the output
2. Which part of the prompt caused or failed to prevent this
3. A specific, actionable fix

End with a prioritized list of the top 3 prompt improvements to make.
Be specific — quote the relevant prompt section and suggest the exact replacement.'''

def _critique_prompt(self, score):
    failed_json = '\n'.join(
        f'Input: {c["input"]}\nExpected: {c["expected"]}\nActual: {c["actual"]}'
        for c in self._last_failed_cases[:5]
    )
    response = client.messages.create(
        model='claude-opus-4-5', max_tokens=1000,
        messages=[{'role': 'user', 'content':
            CRITIC_PROMPT.format(
                current_prompt=self.current_prompt,
                failed_cases=failed_json
            )}]
    )
    return response.content[0].text

Rewriter:プロンプトの改善

RewriterはCriticの分析を受け取り、改善されたバージョンのプロンプトを生成します。重要な制約は、完全な書き換えではなく、対象を絞った改善にすることです。

REWRITER_PROMPT = '''You are a prompt engineer. Improve the prompt based on the critique below.

Current prompt:
{current_prompt}

Critique and suggested improvements:
{critique}

Rules for rewriting:
1. Make TARGETED changes based on the critique — do not rewrite everything
2. Keep all parts of the prompt that were working well
3. Apply all prioritized fixes from the critique
4. Do not add unnecessary verbosity — conciseness is a quality
5. Output ONLY the improved prompt, no explanation

Improved prompt:'''

def _rewrite_prompt(self, critique):
    response = client.messages.create(
        model='claude-opus-4-5', max_tokens=1000,
        messages=[{'role': 'user', 'content':
            REWRITER_PROMPT.format(
                current_prompt=self.current_prompt,
                critique=critique
            )}]
    )
    new_prompt = response.content[0].text.strip()
    print(f'Prompt updated. Length: {len(new_prompt)} chars '
          f'(was {len(self.current_prompt)} chars)')
    return new_prompt

完全なループ:組み合わせて実装する

ここでは、すべてのコンポーネントを接続し、基本的な収束検出を組み込んだ、完全な自己改善ループを示します。

def run_improvement_loop(initial_prompt, test_cases, max_iterations=5,
                          target_score=0.90):
    history = []
    current_prompt = initial_prompt
    last_failed_cases = []

    for i in range(max_iterations):
        print(f'\n--- Iteration {i+1} ---')

        # Execute
        outputs = execute_prompt(current_prompt, test_cases)

        # Evaluate
        score, failed_cases = evaluate_outputs(outputs)
        last_failed_cases = failed_cases
        print(f'Score: {score:.2f} ({len(failed_cases)} failures)')
        history.append({'iteration': i, 'prompt': current_prompt, 'score': score})

        if score >= target_score:
            print(f'Target score {target_score} reached!')
            break

        if not failed_cases:
            print('No failures to learn from. Stopping.')
            break

        # Critique and rewrite
        critique = critique_prompt(current_prompt, failed_cases)
        current_prompt = rewrite_prompt(current_prompt, critique)

    best = max(history, key=lambda x: x['score'])
    print(f'\nBest prompt at iteration {best["iteration"]+1} with score {best["score"]:.2f}')
    return best['prompt'], history

自己改善ループにおけるコスト管理

自己改善ループは、各反復で複数のAPI呼び出しを行うため、高額になる可能性があります。コスト管理の戦略によって、ループを手頃な費用で運用できます。

# Cost optimization strategies

# 1. Use cheap model for execution, expensive model for critique/rewrite
def execute_prompt(prompt, test_cases):
    # Use cheapest capable model
    model = 'claude-haiku-4-5'
    # ... execute ...
    pass

def critique_prompt(prompt, failed_cases):
    # Use best model for reasoning about why the prompt fails
    model = 'claude-opus-4-5'
    # ... critique ...
    pass

# 2. Limit test suite size (sample from larger set)
import random

def get_evaluation_sample(full_test_suite, sample_size=20):
    if len(full_test_suite) <= sample_size:
        return full_test_suite
    return random.sample(full_test_suite, sample_size)

# 3. Early stopping: stop if score doesn't improve
def has_converged(history, patience=2, min_delta=0.02):
    if len(history) < patience + 1:
        return False
    recent_scores = [h['score'] for h in history[-patience:]]
    best_recent = max(recent_scores)
    baseline = history[-(patience+1)]['score']
    return (best_recent - baseline) < min_delta

print('Cost optimization: cheap model for execution, expensive for critique')

プロンプトの系譜の追跡

自己改善ループでは、すべてのプロンプトバージョンを、それを生み出した失敗分析まで追跡できるようにする必要があります。この系譜情報は、予期しないリグレッションのデバッグに役立ち、人間によるレビューも支援します。

class PromptLineage:
    def __init__(self):
        self.lineage = []

    def record(self, iteration, prompt, score, critique=None,
                failed_case_ids=None):
        self.lineage.append({
            'iteration': iteration,
            'prompt': prompt,
            'score': score,
            'critique_summary': critique[:100] if critique else None,
            'failed_case_ids': failed_case_ids or [],
            'prompt_length': len(prompt.split())
        })

    def print_history(self):
        print('Prompt improvement history:')
        for entry in self.lineage:
            print(
                f'  Iter {entry["iteration"]}: '
                f'score={entry["score"]:.2f} '
                f'words={entry["prompt_length"]} '
                f'failures={len(entry["failed_case_ids"])}'
            )

    def get_best(self):
        return max(self.lineage, key=lambda x: x['score'])

lineage = PromptLineage()
lineage.record(0, 'Initial simple prompt', 0.60)
lineage.record(1, 'Improved with examples', 0.75, 'Missing edge cases')
lineage.record(2, 'Added edge case handling', 0.92, 'Minor format issue')
lineage.print_history()

プロンプトバージョン履歴の可視化

反復ごとのスコアの推移を可視化すると、ループが収束しているかどうかや、収束までの速さを把握できます。簡単なテキストチャートを使えば、グラフィックスライブラリなしで傾向をすぐに確認できます。

def visualize_improvement_history(history):
    '''
    history: list of (iteration, prompt, score)
    Prints an ASCII chart of score progression.
    '''
    if not history:
        print('No history to visualize.')
        return

    max_score = 1.0
    bar_width = 40
    print('\nScore Progression:')
    print('-' * (bar_width + 20))

    for iteration, prompt, score in history:
        filled = int(score * bar_width)
        bar = '#' * filled + '-' * (bar_width - filled)
        marker = ' <-- BEST' if score == max(h[2] for h in history) else ''
        print(f'Iter {iteration:2d}: [{bar}] {score:.3f}{marker}')

    final_score = history[-1][2]
    best_score = max(h[2] for h in history)
    gain = best_score - history[0][2]
    print('-' * (bar_width + 20))
    print(f'Initial: {history[0][2]:.3f} -> Best: {best_score:.3f} (gain: +{gain:.3f})')

# Example
sample_history = [
    (0, 'v0', 0.60),
    (1, 'v1', 0.72),
    (2, 'v2', 0.78),
    (3, 'v3', 0.77),
    (4, 'v4', 0.85)
]
visualize_improvement_history(sample_history)

リグレッション検出

書き換えたプロンプトによって一部の失敗が解消される一方、以前は成功していたケースが失敗することがあります。これがリグレッションです。各反復の後には、どのテストケースのステータスが変化したかを比較して、必ずリグレッションを確認してください。

def detect_regressions(old_outputs, new_outputs):
    old_results = {o['case_id']: o['correct'] for o in old_outputs}
    new_results = {o['case_id']: o['correct'] for o in new_outputs}

    regressions = []
    improvements = []

    for case_id in old_results:
        was_correct = old_results[case_id]
        is_correct = new_results.get(case_id, False)
        if was_correct and not is_correct:
            regressions.append(case_id)
        elif not was_correct and is_correct:
            improvements.append(case_id)

    print(f'Fixed: {len(improvements)} cases. Regressed: {len(regressions)} cases.')
    if regressions:
        print(f'WARNING: Regression on cases: {regressions}')
        print('Consider reverting to previous prompt version.')
    return regressions, improvements

# Example
old = [{'case_id': 1, 'correct': True}, {'case_id': 2, 'correct': False}]
new = [{'case_id': 1, 'correct': False}, {'case_id': 2, 'correct': True}]
detect_regressions(old, new)  # Fixed: 1, Regressed: 1

確認問題

自己改善型プロンプトループにおいて、Criticコンポーネントにはどのような目的がありますか。

自己改善型プロンプトシステムのまとめ

自己改善型プロンプトシステムは、プロンプト最適化のサイクルを自動化します。

  • ループ構造:実行 → 評価 → 批評 → 書き換えを繰り返します
  • Executor:テストケースに対してプロンプトを実行します(低コストのモデルを使用します)
  • Evaluator:完全一致またはLLMジャッジで出力を採点します
  • Critic:失敗から具体的なプロンプトの弱点を特定するメタプロンプトです
  • Rewriter:批評を使って対象を絞った改善を行います(最も優れたモデルを使用します)
  • 収束:目標スコアに到達したとき、またはスコアが改善しなくなったときに停止します
  • リグレッション検出:改善によって成功していたケースが壊れていないことを必ず確認します

よくある質問

「自己改善型プロンプトシステム」レッスンは無料ですか?

はい。「自己改善型プロンプトシステム」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Prompt Engineeringコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Prompt Engineeringコースには全4レッスンが含まれています。

「自己改善型プロンプトシステム」で何を学びますか?

フィードバック → 批評 → 書き直しのループで、プロンプトを自動的に最適化します。 ブラウザで直接実行するハンズオンコードでAI Prompt Engineeringを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

AI Prompt Engineeringを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのAI Prompt Engineeringは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「自己改善型プロンプトシステム」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このAI Prompt Engineeringレッスンでコードを書いて実行できますか?

はい。すべてのAI Prompt Engineeringレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. メタプロンプティングとは
  2. プロンプトを生成するプロンプト
  3. 自己改善型プロンプトシステム
  4. 自己改善における評価と選択
← AI Prompt Engineeringに戻る