1. ChatGPT App における workflow とは
さて、もしあなたが認可まわりを理解できたなら、もうご褒美ものです。ここからはとても面白いテーマ — ChatGPT App における workflow に進みましょう。そもそも「workflow」という言葉で、BPMN ダイアグラムや退屈な企業ソフトのフラッシュバックが出る人もいるでしょう。ご安心を。ChatGPT App の文脈では、もっと軽量なバージョンを対象にします。
本講座では、workflow を 多段階のシナリオ として考えます。そこでは:
- 明確なゴールがある(例: ギフトを選んで購入まで導く)、
- 連続したステップがある(ヒアリング → 候補生成 → 絞り込み → 完了)、
- 各ステップで GPT・ウィジェット・ツールの役割が決まっている。
重要な点: workflow は「MCP サーバの単一メソッド」ではありません。これはコンポジションです:
- モデルの推論(どの質問をするか、どのツールを呼ぶか)、
- tools(MCP/Agents)の呼び出し、
- ウィジェットの UI ステップ、
- バックエンドの状態。
つまり、solve_everything のような「スーパー・ツール」が1つだけあるのではなく、各段階で使い分ける複数のシンプルなツールがある。また「メガ・ウィジェット」ではなく、各サブタスクに特化した小さな画面/状態の集合です。
「責務の三角形」: workflow を担う3者
workflow は3人の参加者によるダンスだと考えると便利です:
| 役割 | workflow における任務 | GiftGenius の例 |
|---|---|---|
| GPT | 頭脳。ユーザーの意図を理解し、ステップが完了したか・次に進むべきかを判断する。tools を呼び出せる。 | 「ギーク向けが欲しい」を理解して search_items(category="geek") を呼ぶと判断する。 |
| Widget | 顔(UI)。現在のステップだけをレンダリングし、関連情報のみを見せ、クリックや入力を収集する。UI 状態を保持する。 | 「誰へのギフト?」フォームを見せ、次に候補カード、最後に「購入」ボタンを見せる。 |
| MCP/Agent | 手。重く構造的な作業を行い、データを検証し、ビジネス状態を保持する。 | 受け取り相手のプロファイルを保存し、ギフトカタログに問い合わせ、予算でフィルタする。 |
この3つの役割は同じシナリオを、異なるレイヤーで共同実装します。GPT は「次に何をするか」を決め、ウィジェットは「今何を見せるか」を担当し、MCP はデータに対して実際に起きることを司ります。
2. GiftGenius をベースにした workflow の例
既におなじみの GiftGenius(ギフト選びのアシスタント)を取り上げます。最も簡単には線形のウィザードとして表せます。
ステップの流れは次のようになります:
- 受け取り相手の基本情報を集める。
- 予算と制約を決める。
- ギフトのアイデアを生成・フィルタする。
- 候補を見せ、いいね/非表示をできるようにする。
- チェックアウトへ進むか、候補を保存する。
同じシナリオを小さな「状態機械」としても示せます:
stateDiagram-v2
[*] --> Profiling
Profiling --> ProfilingDone: プロフィール入力完了
ProfilingDone --> Browsing: アイデアを生成
Browsing --> Refining: ユーザーがフィルターを調整
Refining --> Browsing: 更新済みリスト
Browsing --> Checkout: ギフトを選択
Checkout --> Success: 注文完了
Success --> [*]
ここで:
- Profiling — 受け取り相手に関する回答の収集ステップ、
- Browsing/Refining — 候補リストの操作、
- Checkout — 購入手続き、
- Success — 最終確認。
注目すべきは、図にはボタンも fetch も1つも無い点です。これはあくまで論理的なステップであり、その上に具体的な UI 画面や tools、API 呼び出しを紐付けていきます。
3. なぜタスクをステップに分割するのか
かつて「1画面に25問のアンケート」を作ったことがあるなら、理由は既に体感済みでしょう。あらためて要素に分解してみます。
ユーザーの認知負荷
人の注意資源は有限です。心理学では短期記憶の 7±2(ミラーの法則)をよく引き合いに出します。UX デザインでは、「一度に見せる項目や選択肢が多いほど、ユーザーは固まりやすく、疲れやすく、タブを閉じやすい」という実務的なルールに翻訳されます。
ChatGPT の小さなインライン・ウィジェットで、1画面に12個の入力フィールドがあるフォームは、ほぼ確実にレイジクイットの引き金になります。ユーザーは「会話しに」来ているのであって、試験を受けに来ているわけではありません。
一方、タスクをステップに分けると:
- 「ステップ 1/4: 相手について教えてください」
- 「ステップ 2/4: 予算を選んでください」
- 「ステップ 3/4: 候補を確認してください」
- 「ステップ 4/4: 選択内容を確定してください」
という具合に、各時点で取り組むべきことが手頃に見えます。プログレスバーやステップ表示があると、今どこにいて、あとどれくらいかが分かり、コントロール感が生まれます。
モデル側の認知負荷
驚くかもしれませんが、モデルにも似た問題があります。LLM は人間ではありませんが、「注意」とコンテキストウィンドウは有限です。もしあなたが GPT に一度のプロンプトで次をすべて求めると:
- 相手の情報をすべて聞き出す、
- 予算を決める、
- 配送の詳細を考慮する、
- 10個の候補を選ぶ、
- その理由を説明する、
各小課題にモデルの注意とトークンが割かれます。1つの要求に無関係なタスクが多いほど、どれかが表面的になったり、誤りが増えるリスクが高まります。
逆にステップの連鎖を作れば — 実質 chain-of-thought を UI に明示的に埋め込んだ形 — まずは「プロファイル抽出」という狭いタスク、次に「予算の調整」、その後「候補選定」という順に進められます。各段階でのモデルの推論品質(reasoning)が目に見えて向上します。
保守性とデバッグ
すべてを1つのツールと1つの画面に押し込むと、デバッグは「どこで崩れたのか?」という探索ゲームになりがちです。
多段階の workflow では、ほぼ自動的に次のものが得られます:
- ロギングのフック: step_started、step_completed、step_failed
- コンバージョン計測の明確なポイント(何人がステップ3まで到達したか)
- 局所化された問題切り分け(「アイデア生成のステップでだけ落ちる」など)
これらは workflow 分析のモジュールでさらに掘りますが、今のうちから「ステップ思考」に慣れておくと有益です。
4. workflow のステップ種別と UI での見え方
なぜステップに分割するかは既に話しました。次はステップ自体を整理し、ChatGPT App に頻出する典型的な「ブロック」を見ていきます。行き当たりばったりな画面の寄せ集めにしないためにも、ステップ種別の「ライブラリ」を持つと便利です。多くの App でいくつかのパターンが繰り返し登場します。
基本的な表は次のとおりです:
| ステップ種別 | 目的 | ChatGPT App ではどう見えるか | GiftGenius の例 |
|---|---|---|---|
| データ収集(ウィザード) | 複雑なオブジェクトを分割して入力する | 小さなフォーム、チップ、オプション選択、進捗インジケータ | 「誰へのギフト?」「年齢は?」「興味は?」 |
| 分岐 | 次にどの道を進むか決める | チャットでの質問 + UI の簡単な選択肢 | 「子ども向けギフト → 子どもカテゴリへ」 |
| レビュー/確認 | ユーザーが結果を見直して確認できるようにする | サマリーカード + 「戻る」/「確認」ボタン | 「理解した内容はこうです。正しいですか?」 |
| 最終ステップ | シナリオを完了し、次のアクションを提案する | 結果の最終画面 + チャットでのフォローアップ | 「こちらが候補です。注文に進みますか?」 |
忘れてはいけないのは、同じ論理ステップが UI とテキスト対話の両方で表現されうるということです。たとえば「興味の収集」ステップは次のどちらでもありえます:
- 「スポーツ」「ボードゲーム」「料理」といったタグのフォーム、
- あるいは GPT が丁寧に尋ねる会話「どんなことに興味がありますか?」。
最適解はしばしばハイブリッドです。GPT が質問し、ユーザーはテキストで答えつつ、同時にウィジェットのチップをクリックできる、といった形です。
5. workflow を「リード」するのは誰か: GPT、ウィジェット、サーバ?
直感的には「もちろんウィジェット。フロントエンドで state を握って全部制御する」と言いたくなります。しかし ChatGPT App の世界ではそうはなりません。workflow は3者の共同作業です。
オーケストレーターとしての GPT
GPT は:
- 対話をリードし、質問を投げ、
- ステップ完了の判断を行い、
- いつ tool を呼ぶかを選ぶ(例: 「ギフト生成のタイミング」)。
GPT にとってあなたの workflow はサブタスクの集合です。system‑prompt には、どんなサブタスクがあり通常はどの順で行うかを書けますが、モデルが少し順序を適応させる自由は残しておきます。
GiftGenius 向けの system‑prompt 内ミニ指示(疑似コード、正確なシンタックスではありません):
1. まず受け取り相手のプロファイル(年齢、関係性、興味)を確認する。
2. 次に予算を確認する。
3. データが十分になったら、ツール suggest_gifts を呼ぶ。
4. 候補が返ってきたら、ユーザーの選択を手助けする。
重要なのは、GPT はあなたの React コンポーネントの詳細を知る必要も義務もないという点です。GPT は「プロファイル収集」「アイデア選定」といった目的ベースのステップを扱います。
ステップの「顔」としてのウィジェット
ウィジェットは:
- 今関連するステップだけを表示し、
- UI 状態(選択中のカード、開いているタブ、ローカルなフォーム値)を保持し、
- ステップ進捗のインジケータを見せられます。
UI workflow の最小表現をコードにすると次のようになります:
type GiftWorkflowStep =
| "profiling"
| "budget"
| "candidates"
| "checkout";
type GiftWidgetState = {
step: GiftWorkflowStep;
selectedGiftId?: string;
};
React ウィジェット内では、これを通常の useState に持たせてもいいですし、ChatGPT のウィジェットライフサイクルに紐づけたい場合は Apps SDK の useWidgetState を使えます。
const [widgetState, setWidgetState] = useState<GiftWidgetState>({
step: "profiling",
});
ウィジェットのハンドラ関数は、直接「ギフトを購入する」のではなく、ステップを切り替えつつ必要なデータをモデル/バックエンドへ返す役割を担います。
MCP-tools は workflow の「手」
MCP サーバは:
- ビジネス状態(プロファイル、選択履歴)を保持し、
- ステップを検証する(「選択済みギフトが無ければ Checkout に進めない」など)、
- 重い仕事を担う: カタログ検索、価格計算、ACP との統合。
たとえば「どのギフトを見せるか」の判断はウィジェットではなく MCP の suggest_gifts tool で行う方が理にかなっています。モデルは絞り込みのたびに何度でもそれを呼び出せます。
このように役割分担ができます:
- GPT — テキストとシーケンス、
- ウィジェット — 現在ステップの視覚表現、
- MCP — データと不変条件。
6. コードで workflow を記述する: ミニ state‑machine
冒頭の GiftGenius の状態図を覚えていますか? ここでは同じロジックをシンプルな型と関数(ミニ state‑machine)としてコードに落とします。理論的なオートマトン講座にするつもりはありませんが、少しの型と関数でだいぶ楽になります。
ステップ型と設定
まずステップを宣言的に記述します。既出の GiftWorkflowStep 型(分かりやすくここでも再掲)に対して設定を用意します:
type GiftWorkflowStep =
| "profiling"
| "budget"
| "candidates"
| "checkout";
type StepConfig = {
label: string;
isFinal?: boolean;
};
export const GIFT_WORKFLOW_STEPS: Record<GiftWorkflowStep, StepConfig> = {
profiling: { label: "受け取り相手" },
budget: { label: "予算" },
candidates: { label: "候補" },
checkout: { label: "手続き", isFinal: true },
};
次に、簡単な遷移関数を追加します:
export function getNextStep(
current: GiftWorkflowStep
): GiftWorkflowStep | null {
switch (current) {
case "profiling":
return "budget";
case "budget":
return "candidates";
case "candidates":
return "checkout";
default:
return null; // 終端
}
}
これだけで次が得られます:
- ステップの集中管理、
- 明示的な遷移ルール、
- 順序やロジック変更の容易さ。
ウィジェットでの利用
ウィジェット内の「ウィザード」の最小版は次のように書けます:
function GiftWizard() {
const [step, setStep] = useState<GiftWorkflowStep>("profiling");
const handleStepComplete = () => {
const next = getNextStep(step);
if (next) setStep(next);
};
return (
<div>
<ProgressBar step={step} />
<StepContent step={step} onComplete={handleStepComplete} />
</div>
);
}
StepContent コンポーネントは、ステップに応じて異なるサブフォームを描画します:
function StepContent(props: {
step: GiftWorkflowStep;
onComplete: () => void;
}) {
const { step, onComplete } = props;
if (step === "profiling") {
return <ProfilingStep onNext={onComplete} />;
}
if (step === "budget") {
return <BudgetStep onNext={onComplete} />;
}
if (step === "candidates") {
return <CandidatesStep onNext={onComplete} />;
}
return <CheckoutStep />;
}
ここではまだ GPT がどうやってステップを選ぶかには触れていません。これはローカルな UI ロジックです。後でこの step をサーバ状態や tools からのメッセージと同期できますが、多段階性の理解にはこれで十分です。
7. 学習用アプリを進化: 「メガフォーム」からウィザードへ
この講義の前まで、あなたの GiftGenius ウィジェットが「巨大なフォーム」だったと想像してみましょう:
- 受け取り相手の名前、
- 年齢、
- 興味、
- 予算、
- イベント種類、
- 「配送が必要」チェックボックスとその他5項目、
- そして最後に「ギフトを選ぶ」の大きなボタンが1つ。
プロトタイピングとしては悪くありませんが、プロダクトとしてのシナリオを目指すなら — ステップに切り分ける時です。
「前」の姿
風刺的な例:
// アンチパターン: 巨大な単一フォーム
function GiftFormAllInOne() {
return (
<form>
{/* 10個以上のフィールドが混在 */}
{/* ... */}
<button type="submit">ギフトを選ぶ</button>
</form>
);
}
典型的な問題:
- 必須項目が何か分からない、
- どれくらい時間がかかるか不明、
- GPT がユーザーに何が起きたかを説明し、フォローアップするのが難しい。
「後」の作り方: 3画面のウィザード
ステップ1 — プロファイルと予算を分離する:
function ProfilingStep(props: { onNext: () => void }) {
const [recipientType, setRecipientType] = useState("");
const [interests, setInterests] = useState<string[]>([]);
const handleSubmit = () => {
// ここでプロファイル保存の tool を呼べる
props.onNext();
};
return (
<div>
<h3>誰へのギフトを探していますか?</h3>
{/* タイプや興味のためのラジオ/チップの組み合わせ */}
<button onClick={handleSubmit}>次へ</button>
</div>
);
}
ステップ2 — 予算:
function BudgetStep(props: { onNext: () => void }) {
const [budget, setBudget] = useState<number | null>(null);
const handleSubmit = () => {
// 予算検証の tool を呼べる
props.onNext();
};
return (
<div>
<h3>ご予算はいくらですか?</h3>
{/* スライダーまたは input */}
<button onClick={handleSubmit} disabled={!budget}>
候補を探す
</button>
</div>
);
}
ステップ3 — 候補一覧:
function CandidatesStep(props: { onNext: () => void }) {
const [selectedId, setSelectedId] = useState<string | null>(null);
// ここでギフトのカードを表示し、
// 1つ選べるようにする
return (
<div>
<h3>最適な候補を選んでください</h3>
{/* カードで onClick = setSelectedId */}
<button onClick={props.onNext} disabled={!selectedId}>
手続きへ進む
</button>
</div>
);
}
コードは少し増えましたが、ロジックは簡単になりました:
- 各ステップが小さなタスクを解決する、
- モデルがステップ間の遷移を個別にコメントできる、
- 各ステップを個別にログ/計測できる。
8. アンチパターン: workflow をモンスターにしないために
実務と類似 App の観察から、避けたい典型的な誤りがいくつか見えてきます。
まず、30の状態・40の矢印・A0 サイズの巨大な BPMN ダイアグラムで「すべてを描き切る」ことは避けましょう。ChatGPT App の文脈で大切なのは、形式的な記法ではなく直感的に分かる段階的なステップです。GiftGenius の図のようなもので十分です。
次に、特にインライン・ウィジェットの中で App を巨大な単一フォームにしてはいけません。ユーザーはすでにチャット上にいます。密度の高い UI ブロックを足すなら、負荷を下げる方向であるべきです。「12個のフィールドは全部重要だから…」と思ったら、それはタスクを分割すべきサインです。
さらに、見栄えだけのステップを作らないこと。各ステップには明確な目的が必要です。データ収集か、選択の絞り込みか、確認してもらうのか。たとえば「もう少しで終わりです」とだけ表示して「次へ」ボタンが1つあるような空虚な画面は、まず役に立ちません。
最後に、App の全機能を最初のステップに詰め込もうとしないこと。「詳細フィルター」「特殊な配送条件」といった詳細は、本当に必要な人だけに追加ステップとして出せば十分です。
9. workflow 設計の簡単な練習
理解を深めるために、紙(または IDE。コードは不要)で次をやってみてください。
1つタスクを選びます。たとえば:
- ギフト選び(GiftGenius)、
- 旅行の予約、
- 学習計画の作成。
それを 3〜5 ステップに分割します。各ステップについて次を記述します:
- 目的: このステップの後に何が分かっている/完了しているべきか、
- 形式: GPT だけのテキストか、ウィジェットか、両者の組み合わせか。
簡単な「TypeScript 学習計画」の例:
- 「レベル診断」— 対話(GPT が2〜3問)+ 自己評価の短いフォーム。
- 「目標」— テキストでの議論 + ウィジェットの目標チェックボックス。
- 「計画」— 計画(リスト)の生成 + 「難しくする/易しくする」ボタン。
- 「確認」— 簡潔な要約と「計画を保存」ボタン。
各ステップでどんな tools を使えそうかも検討してみてください。ただし深入りは不要です。ツールの有効化/無効化や状態保持は、このモジュールの次回講義のテーマです。
10. 多段階 workflow でよくある誤り
誤り №1: 1つのステップと1つの tool で全部解決しようとする。
「質問も分析も選定も購入手続きも全部やる大きな賢いツール」を作りたくなるものです。現実には、UX(重い単一画面)もモデルの推論品質(reasoning)も悪化します。1回の呼び出しに責務が多すぎるからです。3〜5 のシンプルなステップの連鎖に分割する方が、簡単・堅牢・保守が楽です。
誤り №2: 開発者の頭の中に隠れた暗黙のステップ。
コード上には手順があるように見えても、明示されていないことがあります。ステップの型がない、設定がない、図がない。その結果、チームの誰も「この App は最初から最後まで何が起きるのか」を説明できません。最小限の宣言的なステップ記述と遷移定義は、デバッグの時間を大幅に節約します。
誤り №3: UI ステップとビジネスロジックの混同。
ステップ間の遷移ロジックが React コンポーネントの奥深くに埋め込まれていると(if (isValid && hasBudget && !needsShipping) をボタンの onClick に書くような形)、再利用やテストが難しくなります。比較的明示的な「状態機械」や getNextStep のような関数を用意し、UI はそれを呼んで結果を表示するだけにするのが良いでしょう。
誤り №4: オーケストレーターとしての GPT の役割を無視する。
ウィジェット側でシナリオを完全に支配しようとする(「必要なことは全部自分で聞く。モデルは選定だけしてればいい」)ケースがあります。これでは ChatGPT が生きたアシスタントではなく、フォームの裏で動く計算エンジンに見えてしまいます。GPT が積極的に会話し、次のステップへ促し、tools の呼び出しを自ら開始する方が、ずっと心地よい体験になります — あなたはステップ設計と指示でそれを支援します。
誤り №5: 目的が曖昧なステップ。
ウィザードに「余分な」ステップが紛れ込むことがあります。正直、デザイン上その方が美しく見えるからという理由で。ユーザーは「ステップ 2/5」と表示を見るものの、そのステップで実際には何も求められず、何も起きない。こうした空の画面は、複雑に感じさせるだけです。「このステップの後には X が確実に分かる」「このステップの後にユーザーが Y を実行した」と言い切れないなら、そのステップはおそらく不要です。
誤り №6: 進捗表示を忘れ、道筋の感覚を与えない。
視覚的な支援なしの多段階は「ブラックボックス」になり、ユーザーは自分がどこにいて、あとどれくらいかを理解できません。単純な「ステップ 2/4」といったテキスト指標や、ウィジェットのヘッダーに横並びのステップ表示を置くだけでも、不安は大きく減ります。これを無視すると、実際にはさほど難しくない場所でも、途中離脱が増える一因になります。
GO TO FULL VERSION