はじめに
2026年5月14日に Google Developers Blog で Genkit Middleware が発表されました。
公式発表と公式ドキュメントを読んだので、まず「何が追加され、どこに効くのか」を整理するためのメモを残しておきます。手元での実装検証というより、これから Genkit で agentic app を作る前の事前確認という位置づけです。
本記事の前提です。
- 確認日: 2026年5月19日
- 主な情報源: Google Developers Blog と Genkit 公式ドキュメント
- コード例は公式情報の考え方をもとにした抜粋で、本文中ではAPI名はJavaScript / TypeScript向けドキュメントを中心に整理しています
- 公式発表では、middleware system は TypeScript / Go / Dart で利用可能、Python は coming soon とされています
- 実際のプロダクション適用では、利用している Genkit / SDK / モデルのバージョン確認が必要です
※本記事は個人の整理メモです。読み違えがあれば随時直すつもりで書いています。
公式発表で確認できること
Google Developers Blog の発表では、Genkit Middleware は agentic app の generate() 呼び出しに対して、追加の制御を差し込む仕組みとして説明されています。
発表日と公式リンクは以下です。
- 発表日: 2026年5月14日
- 公式発表: Announcing Genkit Middleware: Intercept, extend, and harden your agentic apps
- 公式ドキュメント: Middleware | Genkit
公式情報の範囲を「確認できること」と「この記事で扱わないこと」に分けて図にしておきます。
ポイントを文章で書くと、以下の3つです。
-
generate()の処理に middleware を挟める - generate / model / tool の各層で制御できる
- retry / fallback / toolApproval / skills / filesystem の5種類の組み込みmiddlewareが用意されている
何に対するmiddlewareなのか
Genkit の generate() は、単純な1回のLLM呼び出しだけでなく、ツール呼び出しを含むループとして動きます。
公式発表では、モデルが出力 → 要求されたツールが実行 → 結果が次のモデル呼び出しに戻る、というサイクルがモデルが終了と判断するまで繰り返される tool loop として説明されています (公式発表より要約)。
これを図にすると、以下のような流れです。
Genkit Middleware は、この流れの途中に制御を挟むための仕組みです。
公式発表では、middleware のhookは大きく次の3層に分けられています。
| hook | 実行タイミング | 使いどころ |
|---|---|---|
| generate | tool loop の各反復 | コンテキスト注入、メッセージ書き換え、会話全体の制御 |
| model | モデルAPI呼び出しごと | retry、fallback、キャッシュ、レイテンシ計測 |
| tool | ツール実行ごと | human-in-the-loop、sandboxing、ツール単位のログ |
ここが個人的にいちばん重要だと思いました。
プロンプトに「危ない操作はしないで」と書くだけではなく、ツール実行やモデル呼び出しの外側で制御できる、という見方ができます。
組み込みmiddlewareで何ができるか
公式ドキュメントでは、JavaScript / TypeScript向けの公式middlewareは @genkit-ai/middleware パッケージとして案内されています。
npm install @genkit-ai/middleware
確認できる組み込みmiddlewareは5種類です。図にまとめます。
| middleware | 概要 | 実務での使いどころ |
|---|---|---|
| filesystem | 指定root配下に限定してファイル操作ツールを注入 | ローカルワークスペース操作、コード生成支援 |
| skills |
SKILL.md をスキャンし、system promptにスキル情報を注入。必要に応じて use_skill ツールで詳細を取得 |
手順書・運用ルール・開発規約の注入 |
| toolApproval | 未承認ツール実行時に中断(interrupt)、手動承認後に再開 | 削除、送信、外部API実行などの確認 |
| retry | 一時的な失敗時に指数バックオフ + jitter で再試行 | quota、通信断、内部エラーへの耐性 |
| fallback | 指定エラー時に別モデルへ切り替え | quota超過時に軽量モデルへ逃がす、別プロバイダへ切替 |
なお、filesystem middleware が注入する具体的なツール名は言語版によって表記が少し異なります。
-
JavaScript / TypeScript版:
list_files/read_file/write_file/search_and_replaceが案内されています。なお、書き込み操作はallowWriteAccessの設定に依存し、公式ドキュメントでは既定でfalseとされています。 -
Go版(公式発表):
list_files/read_file/ 書き込み有効時のwrite_file/edit_file
このあたりは、実装時に利用言語の公式ドキュメントを見るのがよさそうです。
この中で、個人で試すなら toolApproval と retry がわかりやすそうだと感じました。
toolApprovalは「人間の確認」を挟むために使えそう
AIエージェントを作るときに怖いのは、モデルがツールを呼べるようになった瞬間です。
たとえば、次のような操作は勝手に実行されると困ります。
- ファイル削除
- メール送信
- チケット更新
- 外部APIへの書き込み
- 課金や購入につながる操作
toolApproval は、ツール実行を許可リストで制限し、未承認のツール呼び出しを中断できるmiddlewareです。公式発表のGo例では、空リストを渡せば「すべてのツール呼び出しでinterruptを発生させる」設定にできることが示されています。
イメージとしては、次のような流れになります。
JavaScript版の公式ドキュメントでは、interrupt 発生時の検知は response.finishReason === 'interrupted' で行い、restartTool で承認フラグ付きの tool request を作って resume する流れが紹介されています。
import { genkit, restartTool } from 'genkit';
import { toolApproval } from '@genkit-ai/middleware';
// 1. 最初の呼び出し
const response = await ai.generate({
prompt: 'write a file',
tools: [writeFileTool],
use: [
toolApproval({ approved: [] }) // 空 = すべての呼び出しでinterrupt
]
});
if (response.finishReason === 'interrupted') {
const interrupt = response.interrupts[0];
// 2. ユーザーに承認を求めたあと、承認フラグ付きで再構成
const approvedPart = restartTool(interrupt, { toolApproved: true });
// 3. 再開
const resumedResponse = await ai.generate({
messages: response.messages,
resume: { restart: [approvedPart] },
use: [
toolApproval({ approved: [] })
]
});
}
上記は公式ドキュメントMiddleware | Genkit のサンプルをもとにした抜粋です。実際の利用時は、利用しているバージョンのAPI挙動を確認してください。
この考え方は、AIエージェントを業務アプリに入れるときにかなり大事だと感じました。
「モデルを信頼するか」ではなく、「モデルが提案した操作をどこで止めるか」という設計にできるからです。
retryとfallbackは運用時の地味な安心材料
LLMアプリでは、モデルAPI呼び出しが必ず毎回成功するとは限りません。
公式発表では、retry middleware は一時的なエラー(RESOURCE_EXHAUSTED、UNAVAILABLEなど)に対して、指数バックオフとjitterを使って再試行すると説明されています。JavaScript版公式ドキュメントを見ると、既定の対象エラーは以下の5種類です。
UNAVAILABLEDEADLINE_EXCEEDEDRESOURCE_EXHAUSTEDABORTEDINTERNAL
また fallback middleware は、指定したエラー時に別モデルへ切り替える用途として説明されています。公式発表では、Gemini が quota 超過したときに Anthropic Claude のような別プロバイダへ逃がす例が紹介されています。
この2つは、派手ではないですが本番運用では重要です。
たとえば、次のような方針をmiddlewareで表現できそうです。
- 通信系の一時エラーなら最大3回だけretryする
- quota系のエラーなら軽量モデルへfallbackする
- 失敗時のログを残し、あとで観測できるようにする
ただし、retryを入れれば何でも安全になるわけではありません。公式発表では、retryについて次のように明記されています。
Only the model call is retried; the surrounding tool loop is not replayed.
つまり、retryはmodel呼び出しだけを再試行するもので、ツール実行を含むtool loop全体を巻き戻すわけではありません。このあたりは、実装時に挙動をきちんと確認したいところです。
カスタムmiddlewareでルールを外側に出せる
公式発表では、カスタムmiddlewareの例として、モデル応答に禁止語が含まれていないか確認する ContentFilter が紹介されています。Goでは20行程度のシンプルなコードとして示されています。
JavaScript版のドキュメントでも、generateMiddleware というヘルパーを使って model / tool / generate のいずれかのhookを実装する形でカスタムできることが説明されています。
ここで面白いのは、ルールをプロンプトだけに閉じ込めない点です。
たとえば、次のようなルールはmiddleware側に出した方が管理しやすいかもしれません。
- 特定キーワードを含む応答を拒否する
- 外部送信前に個人情報らしき文字列を検査する
- 特定ツールの引数をログに残す
- 操作対象のパスやIDを検証する
- 社内ポリシーに反する処理を止める
もちろん、middlewareだけで完全な安全性が得られるわけではありません。
ただ、AIエージェントの制御を「プロンプト」だけでなく**「コード上の明示的な制御点」**として扱えるのは、設計上かなりありがたいと感じます。
middlewareは「左から外側」にスタックされる
公式発表で個人的に印象的だったのが、middlewareのスタック順序が明示的だという点です。
公式発表の例では、以下のように Retry と ContentFilter を一緒に指定しています。
ai.WithUse(
&middleware.Retry{MaxRetries: 3},
&ContentFilter{ ForbiddenTerms: []string{"CompetitorCRM", "RivalCo", "internal price"} },
),
このとき、Retry が外側、ContentFilter が内側、その中に model 呼び出しが入る、という入れ子になります。
公式発表では次のように説明されています。
Here Retry wraps ContentFilter, which wraps the model call. Order matters, and Genkit makes it explicit.
つまり、内側の ContentFilter で発生したエラーを、外側の Retry が扱える配置になります。実際に再試行対象になるかは、retry middleware の対象エラーや実装に依存するため、順序を入れ替えると挙動が変わる点に注意が必要です。
middlewareをstackできて、その順序が「左から外側」と決まっていることが明示されているのは、設計時にかなり読みやすいです。
この記事時点で確認できていないこと
公式情報を見た範囲で、この記事では次の点は未確認、または今後確認が必要な点として扱います。
- 各言語版で利用できるmiddleware機能・API名・注入ツール名の完全な差分
- Python対応の具体的な提供時期(公式発表では coming soon とのみ表記)
- 実際の本番環境での推奨構成や運用事例
- Vertex AI / Gemini API の料金やquotaに対する直接的な変更
- 日本リージョンや国内提供条件に関する変更
特に、今回の発表は Genkit Middleware の話であり、Gemini API や Vertex AI の料金・モデル提供状況が変わったという発表ではありません。
ここは混ぜない方がよさそうです。
個人で試すなら何を作るか
最初に試すなら、次のような小さいデモがよさそうです。
テーマ: 危険操作だけ人間の確認を挟むTODOエージェント
機能案です。
- TODO一覧を読む
- TODOを追加する
- TODOを完了にする
- TODOを削除する
-
削除だけ
toolApprovalで人間の確認を求める - モデル呼び出しには
retryを入れる
このくらいなら、middlewareの意味がかなり見えやすいはずです。
実装記事にする場合は、次の構成にすると読みやすそうです。
- まず承認なしでツール実行できる状態を作る
- 削除操作だけ危ないことを確認する
-
toolApprovalを入れる - 中断、承認、再開の流れを見る
-
retryを追加する - ログを見ながら、どの層でmiddlewareが効いているか確認する
まとめ
Genkit Middleware は、AIエージェントに対して次のような制御点を追加する仕組みとして理解すると整理しやすそうです。
- モデル呼び出しを retry / fallback する
- ツール実行前に 人間の確認 (toolApproval) を挟む
- ファイル操作などの範囲を filesystem で制限する
- スキルやコンテキストを skills で注入する
- 独自の検査やログを カスタムmiddleware として追加する
- middleware は 左から外側 にスタックされる
👉 個人的には、toolApproval が特に重要だと感じました。
AIエージェントを業務や開発支援に入れるとき、「何を自動化するか」と同じくらい「どこで止めるか」が大事になります。Genkit Middleware は、その停止点や観測点をコードとして整理するための入口になりそうです。
試してみるなら、手始めに実際にTODOエージェントの小さいサンプルを作って、toolApproval と retry の挙動を確認してみるかもいいと思います。





