← Blog
·10 blog.minutes

ソフトウェア開発のためのプロンプトエンジニアリングパターン

どんなプロンプトでも良いコードが生成されるわけではない。本記事で紹介する実戦で鍛えられたパターンを活用すれば、AIアシスタントから毎回より良い結果を得られるようになる。

プロンプトエンジニアリングは、現代のソフトウェア開発において最も価値のあるスキルのひとつになった。動作する保守可能なコードを生成するプロンプトと、壊れた混乱を生むプロンプトの違いは、往々にしてわずかだ——数語のコンテキスト、早い段階で示す制約、問題を正しく枠付けする例。本記事では、解決しようとするタスクの種類ごとに、一貫して良い結果を生むパターンをまとめる。

これらのパターンは理論ではない。実際のプロダクションコードベースにおける数千回のAIコーディングアシスタントとのやり取りから抽出されている。各パターンには具体的な例と、なぜ機能するのかの解説が含まれているため、自分のツールやワークフローに合わせて応用できる。

パターン1: コンテキストサンドイッチ

開発者がAIをプロンプトするときに最もよくやるミスは、コンテキストを提供しすぎないことだ。周辺のシステム、制約、期待する規約を説明せずに関数を依頼してしまう。するとAIは、その特定のコードベースにとっては間違った、もっともらしい仮定を置き、結果は大幅な編集が必要になる。

コンテキストサンドイッチは、すべてのプロンプトを3層に構造化することでこれを修正する——何を構築しているのか、どのような制約があるのか、成功とはどのような状態か。

  • 上層——目標: 1つの明確な文で何をしたいかを述べる。多くの開発者が含めるのはこの部分だけだ。
  • 中層——制約: 譲れない条件を列挙する。ライブラリのバージョン、スタイル規約、パフォーマンス要件、処理すべきエッジケース。
  • 下層——検証: どのように結果が正しいと判断するかを述べる。テストケース、期待する出力フォーマット、確認すべき特定の動作。
// 弱いプロンプト
const result = await ai.generate("Write a function that sorts an array of users by name");

// コンテキストサンドイッチのプロンプト
const result = await ai.generate([
  "Create a compare function for sorting an array of user objects by lastName, then firstName.",
  "Constraints: case-insensitive, handles missing names, TypeScript, no external libraries.",
  "Verify: users.sort(compare).map(u => u.lastName) should return ['Adams', 'adams', 'Brown'].",
].join("\n\n"));

コンテキストサンドイッチが機能するのは、あらゆるレベルでの曖昧さを減らすからだ。AIは何をしてほしいのか、何を受け入れないのか、結果をどう評価するのかを知る。このたった1つのパターンで、AI支援開発におけるやり取りの大半を削減できる。

パターン2: 否定制約

AIモデルは一般的に、何をしてほしいかを理解するのが得意だ。何をしてほしくないかを理解するのはもっと苦手である。「ログインフォームを書いて」というプロンプトはそれなりのものを生成するが、あなたのデザインが使っていないパスワード複雑性ルールや、プロダクトマネージャーが先週のスプリントで削除した「ログイン状態を保持する」チェックボックスを含めてしまうかもしれない。

否定制約パターンは、AIが避けるべきことを明示的に述べる。これは、モデルが排除すべき項目を正しく推測してくれるだろうと期待するより効果的だ。

// 否定制約なし
"Build a user settings page with tabs for profile, security, and notifications."

// 否定制約あり
"Build a user settings page with tabs for profile, security, and notifications.
DO NOT include: email verification flows, password strength meters, or social login buttons."

否定制約は、肯定文による説明のあと、プロンプトの末尾に置くのが最も効果的だ。これは人間が指示を処理するのと同じ順序——何が求められているかを理解してから、何が除外されているかを理解する——を反映している。AIも同じパターンに従う。肯定文の説明からメンタルモデルを構築し、その上に除外条件をフィルターとして適用する。

パターン3: 例示テンプレート

複数のAIインタラクションにわたって一貫した出力が必要なとき——ドキュメントの生成、テストケースの作成、APIレスポンスのフォーマットなど——AIに何をすべきか「言う」よりも「示す」ほうが効果的だ。例示テンプレートパターンは、望ましい出力の完全な例を1つか2つ提示し、同じフォーマットでさらに生成するよう依頼する。

これはチャットインターフェースを通じて利用できる、数ショット学習(few-shot learning)に最も近い方法だ。適切に選ばれた例は、フォーマット、トーン、詳細度、そして明示的に説明するには何段落もかかる暗黙の規約を伝えてくれる。

// エラーメッセージ生成のための例示テンプレート
const example = {
  code: "ERR_AUTH_TOKEN_EXPIRED",
  message: "Your session has expired. Please log in again.",
  severity: "warning",
  action: "redirect:/login",
};

const result = await ai.generate([
  "Generate 5 more error objects in the same format as this example:",
  JSON.stringify(example, null, 2),
  "Cover: rate limiting, permission denied, not found, validation error, server error.",
].join("\n\n"));

このパターンの鍵は、適切な例を選ぶことだ。代表的でありながら、エッジケースに偏りすぎていないものを——AIにあなたの例から一般化してほしいのであって、その癖を複製してほしいわけではない。出力フォーマットに複数のバリエーションがある場合は例が2つあると良いが、3つを超えると価値が薄れ、コンテキストウィンドウを圧迫し始める。

パターン4: 反復的洗練ループ

1回のプロンプトで完全な最終結果をAIに求めるのは、ジュニア開発者に一度のやりとりでプロダクションコードを出荷させるようなものだ。うまくいくこともあるが、大抵は大幅な手直しが必要なものができる。反復的洗練ループは、AIとのやり取りを会話として扱い、広いところから始めて絞り込んでいく。

  • ラウンド1——大まかな解決策または骨組みを生成する。まだ詳細は求めない。
  • ラウンド2——出力をレビューし、具体的な指示を与える。「この部分は良い、あの部分を変えて、このケースを追加して」という具合だ。
  • ラウンド3——詳細を磨く。エラーハンドリング、エッジケース、命名、ドキュメント。

各ラウンドは、AIが今まさに生成したコードに固有のフィードバックを提供するため、AIに実際に求めていることに関するより多くのコンテキストを与える。これは、最初のプロンプトで細部のすべてを先回りして指定しようとするよりもはるかに効率的だ。AIにとっても、問題のレベルを一度に1つ——まず構造、次に詳細、最後に仕上げ——に集中できるため良い。

パターン5: ロールプレフィックス

AIモデルはさまざまなドメインのテキストで学習されており、プロンプトに応じて異なるペルソナを採用できる。ロールプレフィックスパターンは、コードを依頼する前にAIに役割と視点を明示的に割り当てることで、そのコンテキストに適した出力を生成するよう準備する。

// 汎用的
"Review this function for security issues."

// ロールプレフィックス付き
"You are a security engineer reviewing a pull request. Focus on:
- Injection vulnerabilities in the SQL query construction
- Missing input validation on the user ID parameter
- Hardcoded credentials or secrets

Review this function:"

ロールプレフィックスパターンは、レビュー業務、リファクタリング、ドキュメント生成において特に強力だ。アクセシビリティ基準に従ったコードが必要なら「あなたはアクセシビリティの専門家です」と前置きする。パフォーマンス最適化が目的なら「あなたはパフォーマンスエンジニアです」と前置く。AIは要求された視点に合わせて推論と出力を調整する。

パターン6: 出力契約

AIコーディングで最もフラストレーションがたまる経験のひとつは、一見正しそうなレスポンスが返ってくるが、出力フォーマットが微妙に変わっていたり、頼んでもいない説明文が追加されていたり、重要な部分が欠けていたりすることだ。出力契約パターンは、レスポンスが含むべきものと、同じく重要なこととして、含むべきでないものを正確に指定することでこれを防ぐ。

"Generate a React component for a file upload button.

Output contract:
- Return ONLY the component code in a single code block
- No explanation text before or after
- Include TypeScript props interface
- Include CSS module import
- Do NOT include usage examples or test files
- File name: FileUpload.tsx"

出力契約は、AIの出力を別のツールやワークフローにパイプするときに特に価値がある。レスポンスが常に同じ構造に従えば、確実にパースできる。このパターンは、一貫したフォーマットを必要とする自動化されたAI支援パイプラインを構築するための基盤となる。

パターン7: コンテキストウィンドウ予算

どのAIモデルにも限られたコンテキストウィンドウがある。あまりに多くのコード、ドキュメント、会話履歴を貼り付けると、モデルは忘れたり幻覚を見たりし始める。コンテキストウィンドウ予算パターンは、コンテキストウィンドウを希少リソースとして扱い、意図的に割り当てる。

  • 予算の60%を、最も関連性の高いコードとタスクの説明に割り当てる。
  • 20%を、タスクを明確にする例と制約に割り当てる。
  • 20%をAIのレスポンス用に確保する——ウィンドウがいっぱいだと、出力が切り捨てられる。

ウィンドウに収まらないコンテキストがある場合は、最も具体的で関連性の高い部分を優先する。注意深く選んだ1つのファイルに焦点を当てたプロンプトは、漠然と関連する5つのファイルをばらまいたプロンプトより効果的だ。AIは必要に応じてさらにコンテキストを要求できる——その許可を会話の早い段階で与えておこう。

注意深く選んだ1つのファイルに焦点を当てたプロンプトは、AIがかろうじてしか見えない5つのファイルを散漫に使うプロンプトよりも、一貫して良い結果を生む。

パターン8: スキャフォールド→詳細の順序

複雑な機能には多くの可動部分がある。それらすべてを一度に生成するようAIに依頼すると、状態管理、API呼び出し、UIレンダリングが絡み合った、もつれた結果になる。スキャフォールド→詳細の順序は、問題を2つのフェーズに分割する。

まず、AIにスキャフォールド——実装の詳細なしの型定義、インターフェース、高レベルの構造——を生成させる。このスキャフォールドをレビューし、自分のメンタルモデルと一致することを確認する。その上で、AIに詳細——実装、エラーハンドリング、エッジケース——を1層ずつ埋めさせる。

// フェーズ1 — スキャフォールド
"Design the type structure for a multi-step checkout flow. List the interfaces, enums, and state machine transitions. Do not write implementation yet."

// フェーズ2 — 詳細(スキャフォールドレビュー後)
"Implement the checkout state machine from the types we agreed on. Include transition validation and error states."

このパターンは、最もコストのかかるやり直し——実装が完了した後の構造変更——を防ぐ。まずスキャフォールドで合意することで、AIがあなたのアーキテクチャに合致した基盤の上に構築されることを保証する。想像上のものではない。

パターンを組み合わせる

これら8つのパターンは、組み合わせることで最も効果を発揮する。典型的なセッションでは、コンテキストサンドイッチでリクエストを枠付けし、否定制約で望ましくないアプローチを除外し、反復的洗練ループで正しい解に収束させ、出力契約でクリーンでパース可能な結果を得る、という流れになる。

これらのパターンを練習すればするほど、自然に使えるようになる。数日もすれば、プロンプトを無意識にコンテキストサンドイッチで構造化し、考えるまでもなく否定制約を追加する自分に気づくだろう。そのとき、AI支援開発は「ときどき役立つツール」から「ワークフローの一貫して信頼できる一部」へと変わる。

AIアシスタントとの1回1回のやり取りは投資である。うまく構造化されたプロンプトは、書くのに30秒余分にかかるが、何時間ものやり取りを節約する。100回のやり取りを超えると、その30秒は数日分の節約時間に積み上がる——そして、フラストレーションとフローの違いになる。