AIにコードを生成させる際のプロンプト設計パターン
概要
AIコーディングアシスタント(LLMベースのコード生成)を日常的に使うなかで、「どう書くか」以上に「何をどう指示するか」で成果物の質が決まることを強く実感するようになりました。本稿では、コード生成を依頼するときのプロンプトを、その場の思いつきではなく再現可能な設計パターンとして整理します。特定のツールやモデルに依存しない一般論として扱います。
対象読者は、AIにコードを書かせることが増えてきたエンジニアで、「出てきたコードがなんか惜しい」「毎回説明し直すのが面倒」と感じている方を想定しています。
なぜプロンプトを「設計」するのか
LLMは、与えられた文脈の範囲内でもっともらしい続きを生成します。つまり出力の質は入力の質に強く引きずられます。人間の同僚なら暗黙に補ってくれる前提(コーディング規約、既存の設計方針、使ってよいライブラリ、テストの書き方)を、AIは明示されない限り「平均的な正解」で埋めてしまいます。
結果として、
- プロジェクトの規約に合わないコードが出る
- 既に存在するユーティリティを使わず再発明する
- 動くが本番に出せない(例外処理・ロギング・認可が抜ける)
といった「惜しい」出力になります。これらは才能の問題ではなく、文脈設計の問題として捉えると打ち手が見えてきます。
パターン1: 役割と制約を先に固定する(コンテキスト先行)
最初に「あなたは何者で、何を守るべきか」を固定します。自由記述の依頼文より先に、守ってほしい制約を列挙する方が安定します。
あなたはこのプロジェクトのバックエンド実装担当です。 次の制約を厳守してください。 - 言語/FW: 既存の構成に合わせる - 既存のユーティリティを優先的に再利用する(新規実装の前に探す) - 例外は握りつぶさず、呼び出し元に伝播させる - 外部入力は必ずバリデーションする これから依頼する実装は、この制約の範囲内で行ってください。
ポイントは、制約を依頼の前に置くことです。後から付け足すより、先に枠を決めてしまう方が出力が枠に収まります。
パターン2: 入力・出力・制約を分けて書く(I/O契約)
曖昧な自然文1行ではなく、関数やモジュールの「契約」を明示します。
# 実装してほしいもの
注文金額から送料を計算する関数
# 入力
- items: { price: number; qty: number }[]
- destination: "domestic" | "overseas"
# 出力
- number(送料・円)
# 制約
- domestic: 合計1万円以上で送料0、未満は500
- overseas: 一律2000
- items が空配列なら 0 を返す
- 価格・数量が負なら Error を throw
「送料をいい感じに計算して」と頼むと、境界条件(空配列・負値・ちょうど1万円)の扱いがAI任せになります。境界値を仕様として渡すだけで、出力の抜けが激減します。
パターン3: Few-shotで「お手本」を示す
プロジェクト固有のスタイルは、言葉で説明するより既存コードを1つ見せる方が速いです。
このプロジェクトのサービスクラスは次のスタイルで書いています。 同じ流儀で UserService を実装してください。 (例として OrderService のコードを貼る)
命名規則・エラーハンドリング・DIの受け方・テストの書き方といった「言語化しづらい流儀」は、サンプルを渡すのが最短です。言葉で「クリーンに」と伝えても解釈が割れるのと同じで、AIにも具体例が効きます。
パターン4: 段階生成(まず設計、次に実装)
いきなり完成形を求めず、設計→合意→実装に分けます。
ステップ1: まず実装方針だけ提示してください(コードはまだ書かない)。 - 関数の分割 - 想定する例外ケース - テスト観点 私が方針にOKを出したら、ステップ2で実装してください。
一発で全部書かせると、方向性がズレたときの手戻りが大きくなります。方針の段階でズレを検知できれば、修正コストは一言で済みます。
パターン5: 自己検証を仕込む
実装だけでなく、確認方法をセットで出させます。
実装に加えて、次も出してください。 - この実装が満たすべきテストケース一覧(境界値を含む) - 上記を検証する単体テストコード - あなた自身が「ここは不安」と思う箇所の指摘
「不安な箇所を自分で挙げさせる」のが地味に効きます。レビュー前に怪しい箇所を浮かび上がらせられます。
パターン6: 出力フォーマットを固定する
生成物を機械的に扱いたい場合、フォーマットを縛ります。
出力は次の形式のみ。前置き・説明は書かない。 1. ファイルパス 2. コードブロック(完全なファイル内容) 差分ではなくファイル全体を出す。
実装例: パターンを合成した依頼テンプレート
上記を1つにまとめると、実務で使い回せるテンプレートになります。
# 役割 このプロジェクトのバックエンド実装担当。既存の構成・規約に従う。 # 守る制約 - 既存ユーティリティを再利用(新規実装前に探す) - 例外は握りつぶさない / 外部入力はバリデーション - 本番想定(ロギング・認可の抜けを作らない) # お手本 (既存の近いコードを1つ貼る) # 実装対象(I/O契約) - 目的: - 入力: - 出力: - 境界条件: # 進め方 1. まず実装方針(コードなし)。OKを待つ。 2. 実装 + テスト + 不安箇所の指摘。 # 出力形式 ファイル全体をコードブロックで。前置きなし。
確認方法
このテンプレートの効果は、同じ依頼を「自然文1行」と「テンプレート」で投げ比べると体感しやすいです。確認観点は以下。
- 境界条件(空・null・負値・上限)の扱いが仕様通りか
- 既存ユーティリティを再利用しているか、再発明していないか
- 例外処理・バリデーションが入っているか
- 生成されたテストが境界値を踏んでいるか
注意点
- AIの出力は必ずレビューします。本稿はレビューを省くためではなく、レビューで指摘する量を減らすための工夫です。
- プロンプトに秘密情報(APIキー・接続情報・顧客データ)を含めないこと。お手本コードを渡す際も匿名化・サンプル化します。
- モデルやツールのバージョンで挙動は変わります。パターンは「効きやすい傾向」であって保証ではありません。
まとめ
AIにコードを書かせるときの質は、プロンプトを「設計」できるかで決まります。本稿で挙げたのは次の6パターンです。
- コンテキスト先行(役割と制約を先に固定)
- I/O契約(入力・出力・境界を明示)
- Few-shot(お手本を見せる)
- 段階生成(設計→合意→実装)
- 自己検証(テストと不安箇所を同時要求)
- 出力フォーマット固定
要するに、新しくジョインしたメンバーに最初のタスクを渡すときの丁寧さをそのままプロンプトに落とすと考えると筋が通ります。
