プロンプトエンジニアリングとは?AIに組み立てさせるのをやめた

プロンプトエンジニアリングとは、AIから望む出力を得るために指示文を設計する技術です。ところが指示文そのものをAIに組み立てさせると、同じ入力でも毎回わずかに違う文面が生成され、結果が揺れます。原因を追うと、揺れているのはモデルではなくプロンプトのほうでした。CLIが変数を埋め込んだ全文を出力する方式に変えると、プロンプトはバージョン管理できる成果物になります。再現性をどこから取り戻すかを書きます。
Total
0
Shares
プロンプトエンジニアリングとは?プロンプトをAIに組み立てさせるのをやめた

母のカレーが、毎回味が違いました。

凄く美味しい日と、普通に美味しい日があります。つまり、実家のカレーっていうのはいつも美味しいのですが、理由を聞いたら「そのときの野菜と肉による」と言われました。

あるとき、レシピを書いてもらおうとしました。書けませんでした。 玉ねぎは「適当」、煮込みは「いい感じになるまで」。本人の中では一貫しているのに、外に出せない。

そして、味が違う日に原因を特定できません。 玉ねぎが少なかったのか、煮込みが短かったのか、そもそも何が変わったのかが記録されていないからです。

先に一行だけ置きます。プロンプトエンジニアリングとは、AIから望む出力を得るために、指示文の書き方や与える情報の構成を設計する技術のことです。

題材は、開発サイクルを自動で回すエージェントです。工程ごとに違う指示を出して、成果物を作らせます。

前置きはさておき、本題に入ります。

今日は、その指示文そのものを、AIに組み立てさせていた話をしていこうと思います。

① 教科書どおりに、上位のAIに指示文を作らせる

教科書どおりに、上位のAIに指示文を作らせる

構成は、こうでした。

上位のAIが状況を見る
次に何をやるかを決める
→ その工程に合った指示文を組み立てる
下位のAIに渡して実行させる

うまい設計に見えました。 状況に応じて指示文が変わるので、柔軟です。テンプレートを作り込む手間もありません。

動きました。 成果物も出ます。

ここまでは、教科書どおりです。

② そのとおりに回して、結果が揺れる

そのとおりに回して、結果が揺れる

ところが、同じような状況でも、成果物の質が揺れました。

良い回と、そうでもない回があります。母のカレーと同じです。

原因を探そうとして、手が止まりました。

→ モデルが揺れたのか
指示文が変わったのか
→ 状況の読み取りが違ったのか

切り分けられません。

というのも、そのとき実際に渡された指示文が、どこにも残っていなかったからです。会話の中で組み立てられて、そのまま渡されて、消えていました。

③ そして、揺れているのが指示文だと気づく

そして、揺れているのが指示文だと気づく

ログを掘って、実際に渡された文面を復元してみました。

毎回、違いました。

大きくは違いません。言い回しが少し違う。順番が入れ替わっている。ある回だけ一文が抜けている。

その程度の差で、成果物は変わります。

つまり、こうなっていました。

→ モデルの揺れ 指示文の揺れ
2つの揺れが掛かっている
→ どちらが原因か分からない

カレーのレシピが書けない状態でした。

④ 原因は「再現性を、いちばん揺れる場所に預けていた」こと

原因は「再現性を、いちばん揺れる場所に預けていた」こと

原因を一つに絞ると、これでした。

指示文の生成を、確率的な道具に任せていました。

指示文は、実験でいう手順書にあたります。手順書が毎回変わるなら、結果を比較する意味がありません。

そして、柔軟さのために揺らしていたつもりでしたが、必要だったのは柔軟さではありませんでした。 状況によって変えたかったのは中身の値であって、文面そのものではなかった。

⑤ 直してみる — CLIが、全文を出力する

直してみる — CLIが、全文を出力する

やったことは3つです。

1. 指示文をテンプレートとしてファイルに置いた。
工程ごとに1つ。文面はここにしかありません。

2. コマンドが、変数を埋め込んだ全文を出力するようにした。

プロンプトは組み立てない。コマンドが、変数注入済みの全文を出力する。

状況によって変わるのは、埋め込まれる値だけです。文面は変わりません。

3. どのテンプレートを使うかの解決も、コードに置いた。
工程名からファイルを引く対応表を作り、共有部分を持つ工程や、二重レビューを行う工程も、対応表の中で決定的に解決します。選ぶ判断も、モデルに渡していません。

そして、この方式には副産物がありました。プロンプトが、バージョン管理できる成果物になりました。

→ 差分が読める
レビューできる
コミットできる
→ 結果が変わったら、プロンプトの差分を見れば分かる

カレーのレシピが、書けるようになりました。
固定した対象を数えると、テンプレートが工程ごとに1つ、対応表が1つ、埋める値だけが可変という構成になりました。

要素可変か
テンプレート工程ごとに1つ固定
対応表1つ固定
埋め込む値状況による可変はここだけ

もう一つ、実装で判断した点を書いておきます。プロンプトを出力するだけのコマンドでも、排他制御をかけています。 状態は変えませんが、監査記録への追記という副作用があるからです。ロックの要否は、状態を変えるかどうかではなく、副作用があるかどうかで決めました。

⑥ あとで知った — これはプロンプトの話ではなく、実験の話だった

あとで知った — これはプロンプトの話ではなく、実験の話だった

素朴な対処のつもりでしたが、やっていたことを言い換えると、実験の基本でした。

変えるものを1つに絞る。

私は、モデルの調子と指示文の文面という2つの変数を同時に揺らして、結果を見ていました。それでは何も分かりません。理科の実験で最初に習うことです。

そして、この分野では最近、コンテキストエンジニアリングという言い方が使われるようになっています。指示文だけでなく、モデルに渡す文脈全体を設計対象として扱うという考え方です。

呼び名が広がったこと自体が、「渡すものを設計する」側に重心が移った証拠だと思っています。プロンプトを上手に書く技術から、何をどう渡すかを固定する技術へ。

固定できていないものは、設計されていません。毎回違う文面は、設計ではなく即興です。

即興が悪いわけではありません。探索の段階では、即興のほうが速い。 ただ、同じ結果を出したくなった瞬間に、即興は敵になります。
固定したあとの実測です。指示文が成果物としてバージョン管理に載りました。 変更が1行単位で追え、いつ誰が何を変えたかが残ります。載る前は、変更の記録がどこにも残っていませんでした。

新しい理屈は、ひとつも要りませんでした。
運用の規則にはこう書かれています。「プロンプトは組み立てない」「変数注入済みの全文を出力する」。ところで、この2行は指示ではなく仕様です。ただし、書いただけでは守られません。実際に守らせているのは、文面がファイルにしか存在しないという構造のほうです。

記録に残っている実例

2026年2月3日の決定。 指示文を、3段の合成で組み立てる形に変えました。

“`
[見出し] Agent Base Instructions
エージェントの基本指示


[見出し] Role Guidelines
役ごとの指針


[見出し] Task Instructions
工程ごとの技術的な指示
“`

区切りは `—` で固定し、各段に見出しを付けます。どこまでが誰の責任範囲かが、文字列の上で見えるようにするためです。

同時に、合成したあとの指示文を切り詰めた形でログへ出すようにしています。決定の文書にはこう書かれています。「システムプロンプトを、デバッグ用に記録する」。 出しておかないと、結果が悪かったときに、何を投げたのかが分かりません。

そして、4つの役すべてを、合成済みの指示文を受け取る形に一斉に変更しました。1つでも古い形が残ると、そこだけ再現できなくなるからです。

⑦ 何が変わったか

何が変わったか

事故の原因が、特定できるようになりました。

“`
前:結果が悪い → 原因が分からない → プロンプトを書き直す(勘)
後:結果が悪い → プロンプトの差分を見る → 変わっていなければモデル側
“`

「変わっていない」と言い切れることが、いちばん効きました。
原因の切り分けにかかる時間も変わりました。以前は半日、いまは5分です。差分を見て、変わっていなければモデル側だと分かるからです。
固定したことの副産物として、共有できるようになりました。 社内では実際に、指示文の断片が共有されています。「カスタム指示に以下のプロンプトを追加してみてください」という形で、効果が確認できたものが回ってきます。

ところで、これは文面がファイルに存在するからできることです。会話の中で組み立てていたら、共有する対象がありません。 固定は再現性のためだと思っていましたが、共有の単位を作る作業でもありました。

⑧ 現場で使うなら、この2枚

現場で使うなら、この2枚

表1:どこを固定し、どこを可変にするか

要素固定可変
文面(テンプレート)固定。ファイルで持つ
埋め込む値可変。ここが状況依存
どのテンプレートを使うか固定。対応表で解決
モデルの選択固定試すときだけ変える
温度などの設定固定

可変の行が1つだけになっているかを確認してください。 2つ以上あると、原因が切り分けられません。

表2:プロンプトをファイルで持つと得られるもの

得られるものどう効くか
差分結果が変わった原因を特定できる
レビュー変更前に人が見られる
履歴いつから悪くなったかが分かる
再現同じ入力で同じ出力になる

表3:固定した後にやること

手順内容
1テンプレートを1件だけ直す
2同じ入力を3回流す
3出力の差を見る
4差が出たらモデル側、出なければ直した箇所が効いていない

4行目が要点です。 固定していないと、この判定ができません。差が出た理由を、いつまでも推測で語ることになります。

補:固定してから測った数字

項目固定前固定後
同じ入力3回の一致0件3件
原因の切り分け半日5分
テンプレート0件工程ごとに1件
可変の要素多数1件のみ

もう2件、実務の言葉を残しておきます。「テンプレートは工程ごとに1件だけ持つ」「対応表で決定論的に解決する」。ところで、この2件を守ると、指示文がどこにあるかを探す時間がゼロになります。

運用では、次の5件に名前を付けて配りました。名前が付くと、会議の中で指差せるようになります。

1件目、「先に固定するのは、中身ではなく作り方」。 文面を磨く前に、同じ入力から同じ文面が出ることを保証します。ここが揺れていると、以降の比較が全部無効になります。

2件目、「プロンプトは、変数を埋めた全文で出す」。 組み立て途中ではなく、実際に投げた1行までを出力します。あとから原因を追える形はこれだけです。

3件目、「揺れる文面は、原因を隠す」。 結果が悪かったとき、モデルの問題か文面の問題かが切り分けられません。切り分けられない状態で改善はできません。

4件目、「プロンプトを、差分がレビューできる成果物にする」。 バージョン管理に載れば、変更が1行単位で見えます。誰がいつ何を変えたかが残ります。

5件目、「事故の原因が特定できる形にしておく」。 再現できない事故は、直したかどうかも確かめられません。

この5件は、1枚に印刷して配れる分量に収めています。増やすと、誰も覚えません。

⑨ この考え方が効き続ける理由

この考え方が効き続ける理由

モデルは、これからも変わります。新しい版が出て、挙動が変わります。 そのとき、自分の側が固定されていないと、変化を検知できません。

→ モデルが変わる → 結果が変わる
→ こちらも揺れている → どちらのせいか分からない
→ 分からない → 対応が勘になる

モデルの更新に備える最良の準備は、自分の側を固定しておくことです。

そして、これはプロンプトに限りません。渡す文脈、選ぶテンプレート、埋める値。渡すもの全部が対象です。 上位のAIに任せた部分が多いほど、モデルが変わったときに何が起きたか分からなくなります。

ただし、正直に書いておきます。固定すると、探索が遅くなります。 テンプレートを直してから試すので、思いついてすぐ試す軽さは失われます。探索の段階では即興のほうが速いのは、いまも変わりません。

どこで即興をやめるかを決めるのが、たぶんいちばん難しいところです。

固定したあとの実測です。同じ入力を3回流して、生成された指示文は3回とも完全に一致しました。固定前は、同じ条件で3回とも別の文面です。原因の切り分けにかかる時間も、半日から5分になりました。

そして、固定には副作用もあります。テンプレートを直すたびに、過去の出力と比較できなくなるという問題です。差分は追えますが、どの版で作った成果物かを記録していないと、後から突き合わせられません。いまは出力側に版を書き込んで対処していますが、きれいな形にはなっていません。

運用の規則から、もう2件引いておきます。「モデルはフォーマット検証をしない」「オーケストレーターに文面を任せない」。ところで、この2件はどちらも「やらせない」という書き方です。ただし、やらせないと決めた範囲は、必ず自分が持つことになります。実は、そこが固定のコストです。

関連して、プロンプトインジェクションをツール層で止める話と、LLMに自分の出力を検証させてはいけない話を別に書いています。AI機能を足しすぎて重くなる話はすでに公開しています。あわせて読むと、同じ判断が別の場所でも効いていることが分かると思います。

この判断を実際の案件で使う場面については、AIワークフロー自動化のページに整理しています。


同じ手順で同じ結果、といえば、同じレシピで作ったカレーの味が毎回違います。

理由ははっきりしていて、分量を一度も計っていないからです。揺れているのは腕ではありませんでした。

以上です。

You May Also Like

LLMとは?検算させたら拾い漏れと「拾いました」が並んだ

LLMとは大規模言語モデルの略で、大量の文章から言葉の続き方を学習したモデルです。指摘を全部反映したかの確認まで任せたところ、拾い漏れと「全部拾いました」という報告が同時に成立しました。判定をモデルに渡す限りこれは消えません。判定を一切LLMに渡さず、退屈な文字列一致で機械が検査する設計に変えました。全角空白の除去まで含めた実装と、判定に使ってよい出力・いけない出力の切り分けを書きます。
View Post

ベクトルデータベースとは?上位10件の壁に当たった話

ベクトルデータベースとは、文章を数値の並びに変えて、意味の近さで探せるようにした保存先です。日本語の全文検索が精度不足だったため、全文検索を避けてベクトル検索に寄せる判断をしました。ところが取得できるのは上位10件までで、そこに入らなかったものは存在しないのと同じになります。全体のナレッジグラフを作るのではなく、各チャンクに関係性のメタデータを持たせて局所的に推論させる方針まで書きます。
View Post

MCPとは?社内ナレッジ検索の画面を作るのをやめて、MCP接続にした話

MCPとはModel Context Protocolの略で、AIと社内の道具やデータを繋ぐための共通の作法です。社内ナレッジを全社に開くために専用のフロントエンドを作ろうとしていましたが、初期フェーズではそれを見送り、MCP接続を主軸にする設計変更をしました。理由は画面が要らないからではありません。画面を作ると、そこに認証も権限も検索体験も全部くっついてくるからです。残したのはAPIキーの発行とフォルダごとの権限管理だけでした。何を作らないと決めたのかを書きます。
View Post

プロンプトインジェクションとは?禁止をプロンプトに書かない

プロンプトインジェクションとは、AIへの指示文に別の指示を紛れ込ませて、本来の制約を外させる攻撃です。対策としてまず思いつくのは、システムプロンプトに禁止事項を書き足すことです。私たちもそうしました。そして守られませんでした。プロンプトによる禁止は確率的で、ツール層のフックは決定的です。44行のフックで守る側へ移した実装と、パスの正規化や失敗時に閉じる設計まで、そのまま書きます。
View Post