1. なぜ指示で UX を制御するのか
ChatGPT の視点では、あなたの App は追加のツールやウィジェットにすぎません。ですが、ユーザーにとっては会話の途中に突然現れる独立したインターフェースです。モデルのふるまいを管理しないと、極端な2つのシナリオに陥りがちです。
一方では、GPT が App を無視し、「すべて言葉で解決しよう」とします。ユーザーがプレゼント選びを依頼しているのに、モデルは GiftGenius を起動せず、独自の長文エッセイでおすすめを書き出してしまう。ときには悪くないのですが、せっかく作った App を棚に眠らせるためではありませんよね。
もう一方では、GPT が逆に App を乱用します。「このサービスは何ができますか?」のような軽い質問でも、すぐにウィジェットを起動して曖昧なフォームを描画し、ユーザーは驚いて閉じてしまう。UX の観点ではとても押しつけがましい状態になります。
だからこそロジックはシンプルです。ツールの JSON スキーマや React コンポーネントの props を固定するのと同じように、ふるまいも明示的に固定する。システムプロンプト(および付随する指示)はここでいう「UX プロトコル」です。そこでアシスタントが次のように、いつ・どのように振る舞うかを記述します。
- App の起動をアナウンスする;
- 意図的に App を起動せず、テキストで回答する;
- ウィジェットが結果を表示した後のふるまい;
- ユーザーからの「アプリなしで」という依頼を尊重する。
これはマーケティングや話し方の問題ではありません。実際に、App がどれくらいの頻度で呼び出されるか、ユーザーがどれだけ快適に感じるかに影響します。
この後は、App の起動をアシスタントがどうアナウンスすべきか、どんな場合はウィジェットを提案しない方がよいか、アプリが動作した後にどう振る舞うか、ユーザーの明確な対話形式の希望をどう尊重するか、そしてこれらのルールをシステムプロンプトにどう整然と落とし込むかを、順を追って説明します。
2. App のアナウンス: モデルはどう「ウィジェットの登場を知らせる」べきか
ChatGPT が App を使うと決めたとき、UI は変化します。チャットにウィジェットのカードが現れ、時にはフルスクリーン表示になり、ボタンなど UI 要素が出現します。アシスタントが説明もなくウィジェットを見せると、ユーザーは「何が起きたのか」「なぜこのブロックが現れたのか」が分からないままになります。
そのため、まずテキストでこれから起きることを説明し、その後で App を起動するのが良い作法です。ブラウザが「新しいウィンドウを開きますか?」と訊く、モバイルアプリが「これからカメラの許可を求めます」と事前に知らせる、あの感じです。
アナウンスのタイプ
おおまかに3つのスタイルに分けられます。
1つ目は ソフトな提案。アシスタントが「プレゼント選び用のアプリ GiftGenius を開けます。お好みに合わせて候補を出します。開きますか?」のように伝え、「はい/いいえ」の返事を待ちます。サービスに初めて触れる場面や、インターフェースの切り替えに敏感なユーザーに有効です。
2つ目は 自信ある推奨。あなたの App が製品の主要な UI であるなら、「これから GiftGenius を起動して、カード形式でいくつかの候補をお見せします。」のように書けます。拒否には配慮しつつ、基本は積極的に動きます。
3つ目は ニュートラルな通知。この場合は「プレゼント選びのために GiftGenius を起動します…」とだけ伝え、長い説明はしません。ユーザーがすでに何度も App を見ており、登場を期待しているときに適しています。
重要なのは、これらのバリエーションをシステムプロンプトに織り込めるし、そうすべきだという点です。スケルトンを渡しておけば、モデルは UX の文言をゼロから捻り出す必要がありません。
ミニコード例: システムプロンプトのアナウンス節
Next.js のテンプレートに appDefinition.ts というファイルがあり、そこに App 用のシステムプロンプトを定義しているとします:
// app/appDefinition.ts
export const systemPrompt = `
# 役割
あなたは ChatGPT App GiftGenius。プレゼント選びを手伝う。
# 対話と UX — アプリのアナウンス
GiftGenius ウィジェットを起動することを決めた場合は、
まず 1〜2 文で、
これからプレゼントの候補を提示するアプリが開くこと、
そしてそれがユーザーの役に立つ理由を説明する。
`;
これは完全な契約ではありませんが、この程度の挿入でもふるまいの予測可能性は大きく向上します。
アナウンスが特に重要なとき
UI が複雑であるほど、起動の事前説明は重要になります。ウィジェットがプレゼントのカードを 3 つ見せるだけなら、比較的ソフトな文脈変更です。しかし、フィルター・予算・カテゴリなどを伴う多段のウィザードを開くなら、会話が突然「チャット内の小さな Web アプリ」に変わる理由を、ユーザーが理解できる必要があります。
公式の UX ガイドラインでも、アシスタントはテキストと UI を明示的に結びつけるべきで、回答にウィジェットを無言で添えるべきではないと強調されています。
3. いつあえて App を提案しないか
App 開発初期の最もよくある失敗は、「手にハンマーがあるとすべてが釘に見える」現象です。見栄えの良い GiftGenius があるからと、モデルがあらゆる対話に引っ張り込もうとします。ユーザーが「アプリは何ができるの?」と訊いているのに、ChatGPT はもう「GiftGenius を起動します…」と言い出す。本当は 2 行の説明だけでよかったのに、という場面です。
これを避けるには、システムプロンプトで App を提案しない方がよい状況を記述しておきます。典型的なシナリオをいくつか挙げます。
- まずは 紹介・概説的な質問。たとえば「GiftGenius は何をしますか?」「どう動くのですか?」といった書き出しでは、まず短くテキストで説明し、UI は起動しないという指示にすべきです。ここでウィジェットはただの気晴らしです。
- 次に 漠然とした・広すぎる依頼。ユーザーが「新年の人気プレゼントを教えて」と書いたら、それは具体的な選定というより学習的な質問です。アシスタントは原則を簡単に説明し、必要なら確認質問をし、予算・贈る相手・カテゴリといった具体条件が揃ってから App を提案します。
- 3 つ目は App のドメイン外の依頼。たとえば「履歴書づくりを手伝って」と言われたのに、あなたの App がプレゼント選び専用なら、正しいふるまいは普通の ChatGPT として率直に答え、何も起動しないことです。App の用途に軽く触れるのは構いませんが、明らかに無関係なときは押しつけないでください。
- 最後に UI の明確な拒否。ユーザーが「アプリは開かないで。テキストで説明して」と書いたら、理想的な App の出番だとモデルが感じても、その指示に必ず従うべきです。
表: 依頼タイプとアシスタントのふるまい
| 依頼のシナリオ | アシスタントの対応 |
|---|---|
| 「あなたのサービスは何ができますか?」 | 短くテキストで説明し、App は起動しない |
| 「同僚向けで $50 以内のプレゼントを選んで」 | App の起動を提案し、何をするか説明する |
| 「新年の人気プレゼントを教えて」 | テキストで説明し、必要なら確認質問をする |
| 「履歴書を手伝って」 | 普通の ChatGPT として回答し、App は提案しない |
| 「アプリは使わないでください」 | 依頼を尊重し、ウィジェットを起動しない |
App を使わないルールをシステムプロンプトに追加
同じ systemPrompt に、App を起動しない条件のブロックを足してみます:
export const systemPrompt = `
# 役割
あなたは ChatGPT App GiftGenius。プレゼント選びを手伝う。
# ウィジェットを起動しないとき
ユーザーがサービスの機能だけを尋ねている場合や、
プレゼントに関する一般的・理論的な質問だけをしている場合は、
まずテキストで回答し、アプリは起動しない。
依頼がプレゼント選びと無関係な場合は、
普通の ChatGPT として回答し、GiftGenius を提案しない。
ユーザーが明確にアプリを使わないよう求めた場合は、
必ずそれを尊重し、チャット内だけで対応する。
`;
この文面は、モデルが UI に「引っ張られがち」な境界状況での具体的判断に変換されます。これで App が不要な場面を固定できました。次は逆方向、ウィジェットが動作して結果を見せた後に、アシスタントがどうすべきかを記述します。
4. App 使用後のふるまい: follow‑up とシナリオの締め
ウィジェットのモジュールで、follow‑up メッセージが UI の後に対話を続ける助けになるのを見ました。ウィジェットがカードを表示し、その下でアシスタントが「同僚向け、$50 以内でこういった候補が見つかりました。もっと安い候補にしますか?それともカテゴリを変えますか?」のように書き、よくある操作のボタンを提案します。
ここでは、そのふるまいをモデルの「勘」に頼らず、指示として固定します。
ウィジェットの後にアシスタントがすべきこと
理想的なシナリオでは、次のことが起こります。
- まずアシスタントが App の結果を短く言葉で要約します。ウィジェットが 10 枚のカードを見せたとしても、「同僚向け、$50 以内で 4 件の候補を選びました。名入れマグ、卓上のグリーン、上質なコーヒーセット、スタイリッシュなノートなどがあります。」のように書くと有用です。
- 次に、次のステップを提案します。ここで役立つのが、あらかじめ考えておいた フォローアップ のフレーズです。「もっと安い候補を見たいですか?」「興味で絞り込みますか?」「お住まいの地域で購入可能なものだけにしますか?」など。これらのフレーズはウィジェット内の sendFollowUpMessage にも使えますし、システムプロンプトでモデルに推奨することもできます。
- そして、ユーザーが明確にシナリオを終えるとき(「ありがとう、十分です」など)、アシスタントは丁寧に「締め」ます。タスクが解決されたことを認め、別の手伝いを提案します。
フロー図: 質問 → ウィジェット → follow‑up
アシスタントのふるまいは、簡単な状態機械としてイメージできます。
flowchart TD
U[ユーザーがタスクを依頼する] --> G[GPT が判断: App を起動するか?]
G -->|はい| A[App の起動をアナウンス]
A --> W[GiftGenius ウィジェットが候補を選定]
W --> S[アシスタントが結果を要約]
S --> F[アシスタントがフォローアップの選択肢を提示]
F -->|ユーザーが操作を選ぶ| G
G -->|いいえ、App を起動しない| T[UI なしのテキスト回答]
F -->|"ユーザーが \"ありがとう\" と言う"| E[アシスタントがシナリオを完了し、別の支援を提案]
この流れを、実質的にシステムプロンプトで文章化しているわけです。
コード例: ウィジェットからの follow‑up
UI 側ではすでに follow‑up メッセージを送る方法を知っています。参考として、ボタンを押したらモデルに「予算を広げる」よう促す簡単なコンポーネント例を示します:
// components/ExpandBudgetButton.tsx
export function ExpandBudgetButton() {
const onClick = () => {
window.openai?.sendFollowUpMessage(
"少し高めの予算での候補を見せて"
);
};
return <button onClick={onClick}>もっと高い候補が見たい</button>;
}
次に、こうした follow‑up メッセージをモデルがどう扱うかを示す文面をシステムプロンプトに追加します。
// systemPrompt の続き
const followUps = `
# アプリ起動後のふるまい
ウィジェットがプレゼントの一覧を表示したら、
結果を簡潔にテキストで記述する。
その後、分かりやすい次の一手を 1〜3 個提案する
(例: もっと安いものを見せる、予算を変更、カテゴリを変更)。
ウィジェットが follow-up メッセージを送った場合は、
それを次のステップの手がかりとして使う。
`;
技術的には単なる文字列ですが、UX の観点では予測可能なシナリオの土台になります。
5. ユーザーの意図を尊重する
前述した内容は、App のふるまいに対するプロダクト上の期待です。ユーザーを「聞く」力がなければ、UX 指示はうまく機能しません。完璧に設計された App でも、ユーザーが明確に形式の変更を望まないなら、譲るべきです。
典型的な状況がいくつかあります。
- ユーザーが「UI は不要。買うべきものをテキストで説明して」と明言したら、それは強い制約として扱い、抜け道を探さないこと。「分かりました。テキストだけで回答します。」のように丁寧に伝え、その後は本当に言葉通りに振る舞います。
- ユーザーが「勝手に何かが起動しないか不安」と感じているなら、コントロール感を与えるのが有効です。例えば「プレゼント選び用のアプリを開けますが、ご希望ならチャットだけで選択肢を話し合えます。どちらがよいですか?」のように、選択肢を明示します。
- 「今はスマホなので、複雑なフォームは開かないで」と書かれたら、それも文脈の一部です。アシスタントはそれを受け入れ、短いアイデアのリストと確認質問にとどめる、などの対応をとります。
尊重の規範を契約に織り込む
これらはシステムプロンプトに簡潔に反映できます:
export const respectBlock = `
# ユーザー意図の優先
対話の形式に関するユーザーの明確な依頼を
常に優先して扱う。
アプリやウィジェットを起動しないよう求められたら、
GiftGenius を提案・起動しない。
それが課題解決に役立つ場合でも同様。
その代わり、テキストで支援する。
`;
こうして「対話の主役が誰か」を明確に固定します。種明かしをすると、それは美しい UI への自負ではなく、画面の向こう側にいる生身の人です。
6. システムプロンプトとドキュメントで UX 指示をどう整えるか
すでに、App のアナウンスから follow‑up メッセージ、対話形式の尊重まで、多くのルールを書き出しました。ここで重要なのは、モデルに何を伝えるかだけでなく、システムプロンプトとドキュメントでそれをどう表現するかです。
実運用の App では、システムプロンプトはすぐ大きくなります。散文のように書くと、1 週間で誰も読めなくなります。技術仕様や README のように扱い、構造化しましょう。
よい実践は、プロンプトを「役割と責務」「App を使うとき」「App を使わないとき」「対話と UX」「セキュリティと制約」のようなセクションに分け、各セクション内は簡潔で一義的な文で書くことです。
さらに良いのは、システムプロンプトをコンポーネントの文字列リテラルに埋め込むのではなく、コードの近くの別ファイルに切り出すことです。そうすればレビュー・差分比較・プロダクト/法務との議論がしやすくなります。
コード内でのシステムプロンプトの構成例
一例として、プロンプトの断片を別々の文字列に保管し、最後に 1 つへ結合する方法です:
// app/prompt/role.ts
export const roleSection = `
# 役割
あなたは ChatGPT App GiftGenius。
ユーザーの課題と予算に合わせてプレゼント選びを支援する。
`;
// app/prompt/ux.ts
export const uxSection = `
# 対話と UX
GiftGenius ウィジェットを起動する前に、
これからプレゼントのカードが並ぶアプリを開くことを短く説明する。
一般的・理論的な質問にはアプリを起動しない。
ユーザーが明確に選定を求めない限りはテキストで答える。
ウィジェットの後は結果を要約し、
次の一手を 1〜3 個提案する。
`;
// app/appDefinition.ts
import { roleSection } from "./prompt/role";
import { uxSection } from "./prompt/ux";
export const systemPrompt = `
${roleSection}
${uxSection}
`;
この分割により、UX・セキュリティ・ツール連携など、指示をモジュールとして考えられます。新機能の追加時に複数チームでふるまいを整合する場面で特に役立ちます。
また、App のドキュメント(社内 README、Confluence、Notion)も、このセクション構成に合わせて同期しておくとよいでしょう。なぜこのように App をアナウンスするのか、なぜ試行的な依頼では起動しないのかを、人間の言葉で説明します。フォローアップ の定型句も明文化しておくと、新任メンバーが意図を知らずにプロンプトを「修理」しようとするのを防げます。
7. 実践: GiftGenius 向けに UX 部分を書き直す
ここまでを踏まえ、1 つの一貫したシステムプロンプト例にまとめましょう。たとえば、もともとはとても素朴なシステムプロンプトだったとします:
export const systemPrompt = `
あなたはアプリ GiftGenius。
ユーザーのプレゼント選びを行う。
`;
この文面だけでは、App をいつ起動するか、どうアナウンスするか、ウィジェットの後に何をするかが分かりません。UX 指示を段階的に追加していきます。
まず、責務と作業の形式を明確にします:
const role = `
# 役割
あなたは ChatGPT App GiftGenius。
与えられた予算・相手・シーンに合わせて、
関連性の高いプレゼントを 3〜7 件提案することが目的。
視覚的な選定のために GiftGenius ウィジェットを使ってよい。
`;
次に、起動のアナウンス方法を記述します:
const announce = `
# アプリのアナウンス
GiftGenius ウィジェットの方が適切だと判断したら、
まず 1〜2 文で説明する。
これからプレゼントのカードが並ぶアプリが開き、
ユーザーが閲覧やフィルタリングをできることを伝える。
その後でアプリを起動する。
`;
App を起動しないルールを追加します:
const noApp = `
# アプリを使わないとき
ユーザーがサービスの機能だけを尋ねる場合や、
プレゼントに関する一般的・理論的な情報だけを求める場合は、
テキストで回答し、GiftGenius は起動しない。
依頼がプレゼントに関係ない場合(例: 履歴書やコードなど)は、
普通の ChatGPT として回答し、アプリを提案しない。
ユーザーがアプリを使わないよう求めた場合は、
それを必須の制約として扱う。
`;
最後に、ウィジェット使用後のふるまいで締めます:
const afterWidget = `
# ウィジェット使用後のふるまい
ウィジェットが候補を表示したら、
結果を自分の言葉で簡潔に説明する。
次に、次の一手を 1〜3 個提案する
(例: 予算を変更、興味でフィルタ、より安い候補のみ表示)。
ウィジェットが follow-up メッセージを送ってきたら、
それを次のステップの主な手がかりとして使う。
`;
最終的なシステムプロンプトは次のようになります:
export const systemPrompt = `
${role}
${announce}
${noApp}
${afterWidget}
`;
これで、単なる「願い」ではなく、ふるまいの仕様に近づきました。次のモジュールでは、セキュリティ、ハルシネーション、収益化など大人の事情を加えますが、UX 部分はすでに基盤として整っています。
8. UX 指示を設定するときの典型的な落とし穴
落とし穴 1: 「App は常にテキストより優れている」
ウィジェットに自信がありすぎて、あらゆる場面で起動を要求してしまうことがあります。その結果、ユーザーは「そもそも何ですか?」という軽い質問でも App を押し付けられます。モデルは押しつけがましくなり、アプリは避けられるようになります。正しいアプローチは、App が不要なシナリオを明記し、それを尊重することです。
落とし穴 2: App 起動前の明示的なアナウンス不足
アシスタントが無言でウィジェットを起動すると、ユーザーは UI ブロックの出所や取り扱い方が分かりません。OpenAI のガイドラインと実務経験が示すとおり、「これから X を行うアプリを開きます」という 1〜2 文で、UX は大きく改善され、戸惑いが減ります。
落とし穴 3: App の過度な再提案
回答のたびに「もう一度アプリを開きますか?今はどうですか?では次は?」と繰り返すのは、すぐにスパム化します。最初の使用後は文脈を見る、と指示で固定しましょう。ユーザーが条件を明確に変えたとき、あるいは「もっと見せて」と自ら求めたときだけ、再提案します。
落とし穴 4: アプリ使用の明確な拒否の無視
「アプリは使わないでください」「スマホなのでフォームは使いにくいです」のような文言は、強い制約として扱うべきです。それでも App を押し付けると、ユーザーはアシスタントにも製品にも不信感を抱きます。システムプロンプトなら数文で固定できますが、これを忘れがちです。
落とし穴 5: ウィジェット後の要約と follow‑up の欠如
ウィジェットが候補をきちんと表示しても、その後アシスタントが黙ってしまうことがあります。ユーザーは UI を見ても、次に何をすべきか分かりません。テキストなし、問いかけなし、定番アクションのボタンもなし。これではシナリオが未完に見え、対話の連続性が壊れます。ウィジェットの後は必ず短い要約と 1〜3 の分かりやすい次の一手を指示で定めてください。
落とし穴 6: 製品 UX と「ChatGPT の文体」を 1 段落に混在
「フレンドリーに、絵文字を、適宜ユーモアを。あ、たまに App を起動してもよいです。」のような散文にすると、実質的な UX ルールが埋もれて見落とされます。「役割」「対話と UX」「App を使うとき」「App を使わないとき」のように見出しで分け、明確にしましょう。モデルにとっても、後からプロンプトを扱う人にとっても有益です。
GO TO FULL VERSION