
Vercel で AI Agent を本番投入しようとして、最初に壁にぶつかるのはたいてい同じ場所です。
LLM を複数回呼び出すループを走らせたら途中でタイムアウトした。リトライしたら副作用が重複した。待機時間が長いのに課金だけは走り続けた——そういった経験が積み重なると、「Serverless と Agent は根本的に相性が悪いのでは」という疑念が生まれます。
その疑念は、実はかなり正しい。ただし、Vercel が 2025 年の Ship AI イベントで発表した Fluid compute と Workflows は、その構造的な問題に直接手を入れてきました。「なぜ今まで辛かったか」を整理したうえで、Workflows が Agent アーキテクチャのどこにフィットするかを具体的に掘り下げます。
Serverless Functions と AI Agent の相性問題
Serverless Functions の設計思想は「短命なリクエスト処理」です。 リクエストが来て、処理して、レスポンスを返す——その前提でチューニングされているため、実行時間にはプランごとの上限があります。
LLM 呼び出し1回で数秒から十数秒かかることは珍しくありません。 そこにツール呼び出し(外部 API、検索、コード実行)が挟まり、その結果を受けて次の LLM 呼び出しが走る。
plan → tool call → observe → next step のループを3〜4周するだけで、あっさり数分を超えます。
「1リクエスト = 1 LLM 呼び出し」という前提で設計されたインフラに、「1リクエスト = 複数 LLM 呼び出し × ツール呼び出し連鎖」を押し込もうとしているのが、そもそもの構造的なずれです。
タイムアウトだけが問題ではありません。Serverless Functions はステートレスです。 関数の実行が終わると、メモリ上の状態はすべて消えます。Agent ループの途中経過——どのツールを呼んだか、LLM が何を判断したか——はリクエスト終了の瞬間に失われます。
ここで厄介なのがリトライです。 タイムアウト後に再実行すると、途中まで完了していた処理が最初からやり直しになります。外部 API への書き込みやメール送信といった副作用を持つツール呼び出しが重複実行される危険があり、冪等性の担保が難しい。
コスト面でも問題がありました。Fluid compute 以前の課金モデルでは、LLM のレスポンス待ちという「何もしていない待機時間」にも実行時間としてカウントされ、課金が走り続けていました。 Agent ループは LLM の推論待ちが大半を占めるため、実際の計算量に対してコストが割高になりやすい構造でした。
従来の Serverless Functions が Agent と噛み合わない理由は、次の4点に集約されます。
- 実行時間上限:多段 LLM 呼び出しがプランの上限に当たる
- ステートレス性:ループ途中の状態がリクエスト終了とともに消える
- 重複副作用:タイムアウト後の再実行で冪等性が崩れる
- 待機課金:LLM レスポンス待ちの時間にも従量課金が走る
Vercel Workflows の仕組みと何が変わるか
Vercel が Ship AI 2025 で発表した Workflows は、上記の問題を「ワークアラウンドで回避する」のではなく、実行モデルを変えることで解決しています。
コアコンセプトは「ステップ分割と永続化」です。 Workflow は複数のステップで構成され、各ステップが独立した実行単位になります。
あるステップが完了すると、その結果が永続化されて次のステップへ引き継がれます。 これがタイムアウト問題に対して意味するのは、「上限はループ全体ではなく各ステップに対して適用される」ということです。
LLM 呼び出し1回を1ステップとして切り出せば、長大な Agent ループも構造的にタイムアウトを回避できます。
リトライの挙動も根本的に変わります。 あるステップが失敗した場合、失敗したステップだけがリトライされます。それ以前のステップは再実行されません。
これにより副作用の重複実行を防ぎやすくなります。 ステップ単位で冪等性を担保すればよく、ループ全体を冪等にする必要がなくなります。
Fluid compute との組み合わせがコスト面での変化をもたらします。 ステップとステップの間の待機時間——LLM のレスポンス待ちや外部 API の応答待ち——はアイドル状態として扱われ、課金されません。 Agent ループの大半を占める「待ち時間」がコストから外れるため、実際の計算量に近い課金になります。
実装のイメージを掴むために、概念的な擬似コードを示します。実際の API 仕様は Vercel 公式ドキュメント を参照してください。
// 以下は概念的な擬似コードです。実際の API とは異なる場合があります。
// ステップ1: LLM に次のアクションを計画させる
const planStep = createStep({
id: 'plan',
execute: async ({ input }) => {
const { text } = await generateText({
model: openai('gpt-4o'),
prompt: `タスク: ${input.task}\n次に実行すべきアクションを決定してください。`,
});
return { plan: text };
},
});
// ステップ2: 副作用を持つツール呼び出しを独立させる
const toolCallStep = createStep({
id: 'tool-call',
execute: async ({ input }) => {
const result = await callExternalApi(input.plan);
return { toolResult: result };
},
});
// Workflow としてステップを組み合わせる
export const agentWorkflow = createWorkflow({
id: 'agent-workflow',
steps: [planStep, toolCallStep],
execute: async ({ steps }) => {
const planResult = await steps.plan({ task: 'リサーチレポートを生成する' });
const toolResult = await steps.toolCall({ plan: planResult.plan });
return toolResult;
},
});
重要なのは、各ステップが独立して実行・永続化される点です。
steps.plan() の結果は次の steps.toolCall() に明示的に渡され、途中でプロセスが落ちても完了済みステップは再実行されません。
Agent ループを Workflow ステップに落とし込む
Workflows の仕組みが分かったところで、Agent ループの各フェーズをどのステップに対応させるかという設計の話に入ります。
plan → tool call → observe → next step という Agent ループは、Workflow のステップモデルと自然に対応します。 ただし「どこにステップ境界を引くか」は設計判断が必要で、ここが実装上のポイントになります。
基本的な指針は2軸です。LLM を呼ぶたびにステップを切る、そして副作用を持つ処理は独立したステップにする。 この方針で設計すると、冪等性を保ちやすくなります。
// 以下は概念的な擬似コードです。実際の API とは異なる場合があります。
// Plan ステップ: LLM に次のアクションを決めさせ、出力を永続化
const planStep = createStep({
id: 'plan',
execute: async ({ input }) => {
const { text } = await generateText({
model: openai('gpt-4o'),
prompt: `タスク: ${input.task}\n利用可能なツール: search, summarize\n次のアクションを JSON で返してください。`,
});
const action = JSON.parse(text); // { tool: 'search', query: '...' }
return { action };
},
});
// Tool call ステップ: 副作用を持つ処理を独立させる
const toolCallStep = createStep({
id: 'tool-call',
execute: async ({ input }) => {
const { action } = input;
if (action.tool === 'search') {
const results = await searchWeb(action.query);
return { toolResult: results };
}
throw new Error(`Unknown tool: ${action.tool}`);
},
});
// Observe ステップ: ツール結果を LLM に渡してループ継続か終了かを判定
const observeStep = createStep({
id: 'observe',
execute: async ({ input }) => {
const { task, toolResult } = input;
const { text } = await generateText({
model: openai('gpt-4o'),
prompt: `タスク: ${task}\nツール結果: ${JSON.stringify(toolResult)}\nタスクは完了しましたか?`,
});
return JSON.parse(text); // { done: true, answer: '...' } or { done: false, nextAction: '...' }
},
});
// ヒューマン承認が必要な場合のサスペンド(概念的表現)
const approvalStep = createStep({
id: 'human-approval',
execute: async ({ input, suspend }) => {
if (input.requiresApproval) {
const approval = await suspend({ reason: '人間の承認が必要です', data: input });
return { approved: approval.approved };
}
return { approved: true };
},
});
この構造で特に重要なのが observeStep です。
ツール結果を受け取った LLM が「まだ続ける必要があるか」を判断し、その結果を次のループに引き継ぎます。オーケストレーション層でこの判定結果を見て、plan ステップに戻るかループを終了するかを制御します。
ヒューマン・イン・ザ・ループは Workflows が特に強みを発揮するシナリオです。 サスペンド機能を使うと、ワークフローの実行を一時停止し、状態を保持したまま外部からの入力(人間の承認・レビュー結果)を待てます。
従来の Serverless では「承認待ち」の間も Function を起動し続けるか、状態を外部 DB に書き出してポーリングするかという苦しい実装が必要でした。 Workflows ではサスペンド中は課金されず、状態も失われません。
向いているユースケース、向いていないユースケース
Workflows は強力ですが、すべての AI 機能に使うべきかというと、そうではありません。
向いているのは、複数の LLM 呼び出しとツール呼び出しが連鎖する処理です。
バッチ型のリサーチ・レポート生成は典型例です。複数の検索クエリを投げ、結果を要約し、最終レポートを生成するまでに複数の LLM 呼び出しが発生します。 各フェーズを独立したステップにすることで、途中の失敗を安全にリトライできます。
コードレビュー Agent も同様です。ファイルを読む・問題を特定する・修正案を生成する・レビューコメントを投稿するという一連のフローが、ステップに自然に対応します。
ヒューマン・イン・ザ・ループが必要なワークフローも得意領域です。 法務文書のドラフト生成後に人間がレビューして承認する、コードの自動修正を人間が確認してからマージするといったシナリオでは、サスペンド機能が実装を大幅に簡略化します。
一方、向いていないケースも明確にあります。
ストリーミング応答が必要なチャット UI には向きません。
ユーザーがリアルタイムでトークンが流れてくる体験を期待している場合、Workflow のステップモデルはレイテンシの観点でミスマッチです。この用途は従来の Serverless Functions + streamText の組み合わせが適切です。
ステップが1〜2個で完結するシンプルな LLM 呼び出しにも Workflows は不要です。 「ユーザー入力を受け取って LLM に渡し、結果を返す」だけの処理に Workflow を導入するのは複雑さが増すだけで、オーバーエンジニアリングになります。
整理すると、判断の分岐点はシンプルです。「複数ステップの連鎖か、単発の LLM 呼び出しか」——この一問で大半のケースは仕分けられます。
なお、同様の課題を解決する選択肢として Inngest や Temporal も存在します。Temporal は特に耐久性と複雑なオーケストレーションに強く、Vercel AI SDK との統合例 も公開されています。 ただし Next.js + Vercel スタックで完結させたい場合、インフラの追加管理コストなしに同じプラットフォームで完結できる Workflows の利点は無視できません。
Vercel Workflows と Fluid compute の組み合わせは、「Serverless で Agent を動かすのは無理」という前提を変えつつあります。 タイムアウト・状態消失・重複副作用・待機課金という4つの痛みが、実行モデルの変更によって構造的に解消される——Next.js + Vercel スタックで AI 機能を本番投入しようとしているなら、まず自分のユースケースがどちらに当てはまるかを確認するところから始めてみてください。
株式会社ホコサキは、山口県宇部を拠点に Web 制作・業務システム開発・AI 活用支援を手がけています。Vercel や AI SDK を使った実装支援・技術検証のご相談は、お問い合わせページ からどうぞ。

