生成AIに指示を出すという仕事は、ここ数年で急にありふれたものになりました。専業のエンジニアだけでなく、社内ツールを触るマーケター、ライター、コンサルタントまでが、日常的にプロンプトを書いています。
私自身も実務のなかで手を動かしてきましたが、試行錯誤を重ねるうちに、応答の再現性を安定させる要素が3つあることが見えてきました。「役割定義」「制約条件」「出力形式」の3つです。この3つを意識してプロンプトを組み立てるだけで、応答のばらつきがぐっと減り、後段のプログラム処理につなぎやすくなります。
本記事では、この3要素それぞれの書き方と、統合したテンプレートの例を、Node.jsから呼び出す想定でまとめます。API呼び出しのコード自体は別の記事で扱っているので、本記事ではプロンプト設計側に集中します。
前置き:20年前の「制作指示書」との共通点
3要素の話に入る前に、少し個人的な回想をさせてください。
私は20年ほど前、株式会社a-senseのメディア事業部というところに所属していて、広告制作補助やWebディレクションの業務をやっていました。当時の仕事の大きな比重を占めていたのが、外部のデザイナーさんやコピーライターさんに投げる「制作指示書」を書くことでした。
そのころ書いていた指示書の項目を、いま振り返ると、だいたい次のようなブロックに分かれていたと思います。
- どの立場で作業してほしいか(媒体の想定読者に向けて書く/既存ブランドのトーンに合わせて書く/等)
- 何をアウトプットしてほしいか(バナーAサイズ・ランディングページ・特集ページ)
- 絶対に外してはいけない条件(掲載NG表現・ロゴ規定・薬機法まわり・文字数)
- 納品時の形式(psd入稿・書き出し規定・ファイル命名規則)
これ、生成AIへのプロンプトに必要な要素と、驚くほど構造がよく似ています。ここから紹介する「役割定義・制約条件・出力形式」の3要素は、当時デザイナーさんに投げていた指示書の骨格を、そのまま生成AI向けに書き直したような形になっています。
相手が人間からAIに変わっても、「相手に、期待する成果物を、迷わず出してもらう」ための伝え方の原理は、ほとんど地続きです。この気づき自体は、生成AIを触りはじめて半年くらい経ったころに実感しました。
a-sense時代の実務経験については、また別のシリーズでもう少し詳しく書くつもりです。ここでは前置きに留めて、本題に戻ります。
3要素の全体像
改めて3要素を並べます。
| 要素 | 役割 | プロンプト内での位置 |
|---|---|---|
| 役割定義 | 生成AIに「誰として」応答してほしいかを指定する | プロンプトの最初のほう |
| 制約条件 | 何を守るべきか・何を外してはいけないかを指定する | タスク説明の後 |
| 出力形式 | どんな構造・体裁で応答を返してほしいかを指定する | プロンプトの最後のほう |
このうち、後段のプログラム処理と直接つながるのは「出力形式」で、応答の内容そのものの質を決めるのは「役割定義」と「制約条件」です。3つとも欠けてはいけない、というわけではなく、要件に応じて省略できるものもありますが、いずれかを意識的に省いた場合と、無自覚に省いた場合とでは、結果の安定度が変わってきます。
以下、それぞれを掘り下げます。
要素1:役割定義
役割を指定せずに漠然と質問を投げると、生成AIは「一般的な読者向けの、無難で平均的な回答」を返してきます。回答の平均化が悪いわけではないのですが、専門的な文脈や、特定の読み手を想定した回答が欲しいときには、この平均化が邪魔になります。
たとえば「Node.jsとは何かを説明してください」と聞くと、初心者向けの導入的な説明が返ってきます。しかし、経験10年のバックエンドエンジニアに向けて「Node.jsのイベントループの内部実装を、C++レイヤーまで踏み込んで説明してほしい」なら、そう指示しないと通じません。
役割定義の基本形はシンプルです。
# 役割
あなたは、〇〇の経験を〇年持つ、〇〇の専門家です。読者は〇〇であり、〇〇に関する意思決定を支援するために、この応答を書きます。
書き方のコツとして、私が意識していることが3つあります。
- 専門性の粒度を具体的に:「エンジニア」ではなく「Node.jsのAPIサーバ開発経験10年の実装者」
- 読者を明示する:応答の平均像を、読者の想定でコントロールする
- 応答の目的を書く:「この応答は何に使われるか」を書くと、AIが情報の取捨選択をしやすくなる
悪い例と良い例を比べます。
# 悪い例
あなたはプロのエンジニアです。
# 良い例
あなたは、Node.jsを使ったAPIサーバの実装経験を10年以上持つバックエンドエンジニアです。
読者は、Node.jsの入門書を読み終えたばかりの、Web開発2年目のエンジニアです。
この応答は、社内勉強会の資料として使われます。
差は明らかで、「良い例」の方が、応答の言葉の選び方・想定される深さ・省いてもよい前提が、AI側から見て判断しやすくなります。
要素2:制約条件
制約条件は、応答が明後日の方向に行くのを防ぐ役割を持ちます。書き方には、大きく3つのパターンがあります。
- 肯定的制約:「何を含めるべきか」を書く
- 否定的制約:「何を含めてはいけないか」を書く
- 数値制約:「文字数・件数・範囲」を書く
このうち、否定的制約は、書き方によって効いたり効かなかったりします。
たとえば「〜しないでください」という書き方は、応答内容を狭めるより、むしろその話題を想起させてしまうことがあります。人間相手でも「白熊のことを考えないでください」と言われると白熊を考えてしまう、あの構造と近いです。
私の経験則としては、否定的制約は「望まない挙動」を書くより、「望む挙動」を肯定形で書き直せないか、いったん検討してからプロンプトに乗せるようにしています。
# あまり効かないことがある書き方
- 専門用語を使わないでください
- 難しい表現を避けてください
# 効きやすい書き方
- 中学生でも理解できる言葉で書いてください
- 専門用語を使う場合は、直後にカッコ書きで平易な言い換えを添えてください
どちらの書き方でも意図は伝わるはずですが、後者のほうが応答のばらつきが小さくなる印象があります。
数値制約については、生成AIは厳密な文字数カウントが苦手なことを、頭に入れておいたほうがよいです。「200文字以内」と指定しても、実際には180〜250文字くらいの幅で返ってくることが普通にあります。厳密な文字数が要件なら、応答後にプログラム側でカウントして、規定超えなら再生成する、というループを組むのが現実的です。
要素3:出力形式
3要素のなかで、後段のプログラム処理に直接つながるのがこの出力形式です。ここの指定が甘いと、応答をパースする段階で毎回コケることになります。
主に使うパターンは以下です。
JSONで出させる
構造化データとしてプログラムに渡したいとき。
# 出力形式
以下のJSONスキーマに沿ってのみ応答してください。前後の説明文・コードブロック記号は付けないでください。
{
"summary": string, // 80文字以内の要約
"keywords": string[], // 3〜5個のキーワード
"sentiment": "positive" | "neutral" | "negative"
}
「前後の説明文・コードブロック記号は付けないでください」の一行は地味に効きます。これを書かないと、応答本体の前に「はい、こちらが応答です」的な前置きが付いたり、JSONを json〜 のマークダウンコードブロックで囲んでしまったりすることがあります。
なお、AnthropicもOpenAIも、応答フォーマットを構造化するための専用機能を提供しています(Structured Outputs、Tool Use など)。厳密な構造化が必要な用途では、プロンプトで書くよりこれらのAPI機能を使うほうが確実です。プロンプトでの出力形式指定は、そこまでガッチリでなくてもよい用途に向いています。
箇条書きで出させる
人間が目視で読む用途に。
# 出力形式
以下の形式で出力してください。
- 3〜5個の箇条書き
- 各項目は、1〜2文で完結する
- 各項目の冒頭に絵文字は付けない
マークダウン構造で出させる
そのままドキュメントに貼り付ける用途に。
# 出力形式
以下の構造のマークダウンで出力してください。
## タイトル
### 概要
### 詳細
### 参考リンク
3要素を統合したテンプレート
3要素を全部合わせると、次のような形になります。
# 役割
あなたは、Web媒体の編集経験を10年以上持つ編集者です。
読者は、企業広報担当者で、社内広報記事の書き方について助言を求めています。
この応答は、担当者が実際の記事執筆で参考にするために使われます。
# タスク
以下のテーマについて、記事構成の骨子を作成してください。
テーマ: 社内表彰制度の刷新について
# 制約条件
- 対象読者は社内の全従業員(新卒〜経営層)
- 記事全体は800〜1200文字を想定
- 数値目標や制度詳細は本文で必ず言及する
- 具体的な受賞者の氏名は含めない(想定段階のため)
# 出力形式
以下の構造でマークダウンで出力してください。
## タイトル案(3案)
## 記事の骨子
### 導入(100文字前後)
### 本文セクション1(見出し + 各200文字の要点)
### 本文セクション2(見出し + 各200文字の要点)
### 結び(100文字前後)
Node.jsから呼び出すコードは、次のようなイメージです。
import "dotenv/config";
import Anthropic from "@anthropic-ai/sdk";
import { readFileSync } from "node:fs";
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
// 上記テンプレートを prompts/article-outline.md として保存しておく
const template = readFileSync("./prompts/article-outline.md", "utf-8");
const message = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 2048,
messages: [{ role: "user", content: template }],
});
console.log(message.content[0].text);
テンプレート内の変数を差し替えたい場合は、プレースホルダを用意して、実行前に置換すればOKです。この置換の仕組みは、別の記事で紹介しています。
モデル間の応答傾向の違いについて
Claude系とChatGPT系では、同じプロンプトでも応答の傾向に違いがあります。
- 指示に対する厳密さの度合い
- 応答の冗長さ・簡潔さの初期値
- 箇条書きを好むかプロットを好むかの初期値
- 「わからない」と明示する傾向の強さ
これらはモデルの世代・パラメータ設定によっても変わるので、「Claudeはこう」「ChatGPTはこう」と固定的に語れる話ではありません。優劣を判定できる性質のものでもなく、単に応答傾向が違うだけです。
実務では、プロンプトを2〜3種類のモデルに投げてみて、案件の要件との相性で選ぶ、というやり方をしています。ここで役立つのが、先ほどの3要素で書いたテンプレートです。同じプロンプトを複数モデルに投げて比較する前提だと、プロンプトの構造が明示的に分かれているほうが、モデルごとに効いた要素・効かなかった要素を切り分けやすくなります。
まとめ
プロンプトエンジニアリングの3要素として、以下を紹介しました。
- 役割定義:誰として、誰に対して、何のために応答するかを指定する
- 制約条件:肯定形で書けるものは肯定形で。数値制約は厳密性を期待しすぎない
- 出力形式:後段の処理につなぐなら最も重要。構造化には専用API機能も検討する
3要素の意識は、大した準備なしに始められるわりに、応答の再現性を大きく改善します。手元のプロンプトを一度整理して、この3要素の観点で書き直してみると、案外「あ、ここの指示が曖昧だったんだ」という発見があるはずです。
冒頭で触れた「20年前の制作指示書との共通点」は、私にとってプロンプト設計を捉え直すきっかけでした。相手が人間かAIかによって、伝え方の細部は違うにしても、期待する成果物を明示的に言語化するという原理は、共通しています。プロンプトエンジニアリングというと新しい技術のように語られがちですが、根っこは古くからある「発注のリテラシー」の延長線上にあるように思っています。
これまでの投稿はこちらにまとめています。