ブログ一覧

Gemini Live API のセッションが突然切れる 3 つの制限

更新: Web開発者向け

リアルタイム音声対話の検証中、Gemini Live API のセッションが切れました。切れること自体は仕様として知っていましたが、いざ切れると「今のはどの制限に当たったのか」が分かりません。調べていくと、切れる理由は 3 層あって、対処がそれぞれ違うことが分かりました。1 つの「タイムアウト」として扱うと、対処を取り違えます。

この記事は公式ドキュメント(2026-08 時点)の整理と、自前の検証で得た実測値・実装パターンをまとめたものです。数値は変わり得るので、各層に出典を付けています。

第 1 層: セッション時間そのものの上限

セッション管理のドキュメントにこうあります。

Without compression, audio-only sessions are limited to 15 minutes, and audio-video sessions are limited to 2 minutes.

既定では音声のみ 15 分、音声+映像だと 2 分です。映像を足した瞬間に 2 分になるのは、知らずに当たると短すぎて設定ミスを疑うレベルだと思います(私の検証は音声のみの構成なので、2 分の側は自分では踏んでいません。ドキュメントの記載です)。

対処は contextWindowCompression の有効化です。

{
  "setup": {
    "contextWindowCompression": { "slidingWindow": {} }
  }
}

これを有効にすると、コンテキストを sliding window で圧縮する代わりに、時間制限が外れます。ドキュメントの表現では "To enable longer sessions, and avoid abrupt connection termination, you can enable context window compression"、延長後は無制限です。

第 2 層: WebSocket 接続の寿命

セッションの上限を外しても、WebSocket 接続そのものが約 10 分で切られます

The lifetime of a connection is limited as well, to around 10 minutes.

こちらの救済は 2 段構えになっています。

  • 予告: 切断前にサーバーから GoAway メッセージが届きます。残り時間(timeLeft)付きです
  • 引き継ぎ: sessionResumption を setup で有効にしておくと、サーバーから resumption ハンドルが随時届きます。切断後、そのハンドルを次の接続の setup に渡すと会話状態を引き継げます。ハンドルは最終切断から 2 時間有効です

つまり「接続は使い捨て、会話状態はハンドルで持ち回す」という設計が前提になっています。接続の確立自体は実測で 340〜480ms(Node 22、データセンター級回線、v1beta WebSocket 直結)なので、張り替えのコスト自体は小さいです。

GoAway を信じすぎない

ただし、GoAway が常に来るとは限りません。公式フォーラムには、2026-08-04 ごろから gemini-3.1-flash-live-preview で GoAway が来ないままコード 1006 でハード切断される回帰の報告があり、8 月中旬に部分的に回復した、という経過が記録されています。preview モデルではこういうことが起きます。

設計上の帰結はシンプルで、GoAway 起点の「行儀のよい張り替え」と、予告なし切断からの「無条件の再接続」の両方のパスを持つことです。GoAway は最適化であって、生存の前提にはしない方が安全です。

第 3 層: ephemeral token の寿命

クライアントから直接接続する構成では、API キーの代わりに ephemeral token を使います。この token に 3 つの時限が付いています(ephemeral tokens のドキュメント、2026-08 時点)。

  • expireTime: token 自体の有効期限。既定 30 分
  • newSessionExpireTime: その token で「新しいセッションを開始できる」期限。既定 1 分
  • 単回使用: 1 つの token で開始できるセッションは 1 つ

危ないのは newSessionExpireTime の 1 分です。「token を取っておいて、ユーザーが開始ボタンを押したら接続」という自然な実装は、取得から接続までが 1 分を超えた時点で接続を拒否されます。「取得→即接続」を 1 つの操作として実装する必要があります。

再接続との組み合わせには但し書きがあって、ドキュメントには「expireTime の範囲内なら、sessionResumption を使った 10 分ごとの再接続は同じ token でできる(uses: 1 でも)」という記載があります。とはいえ expireTime 既定 30 分を超えて会話が続く可能性があるなら、結局は再発行の経路が要ります。私は再接続のたびに新しい token を取得する設計に倒しました。分岐が 1 本減り、「この再接続は同じ token でよいか」を考えなくて済みます。

3 層をまとめると

  • セッション時間(音声のみ 15 分 / 映像あり 2 分)→ contextWindowCompression で解除
  • 接続寿命(約 10 分、GoAway 予告つき・ただし来ないこともある)→ sessionResumption ハンドルで張り替え
  • token 寿命(expireTime 30 分 / 新規セッション開始は 1 分 / 単回使用)→ 取得→即接続、再接続時は再発行

「切れた」ときの切り分けもこの順です。開始直後に接続すら張れないなら token(第 3 層)、10 分前後で切れたなら接続寿命(第 2 層)、映像ありで 2 分なら第 1 層です。

実装パターン: 張り替えの「継ぎ目」を会話の切れ目に寄せる

GoAway を受けてすぐ張り替えると、会話の途中で無音が挟まります。私は GoAway をアプリのイベントとして扱い、timeLeft の範囲内で会話の区切り(進行フェーズの切り替わり)まで粘ってから張り替える形にしました。張り替え中の無音時間は計測項目に入れています。無音がユーザーに知覚されるかどうかが、この設計の成否をそのまま表すからです。

この構成で気をつけること

  • 「セッションが切れる」は 1 つの現象ではない。3 層のどれに当たったかを先に切り分ける
  • contextWindowCompressionsessionResumption は、実用上ほぼ必須の setup オプションとして最初から入れておく
  • GoAway が来ない切断のパスを必ず用意する。preview モデルでは予告メカニズム自体が不安定になることがある
  • ephemeral token は「取得→即接続」。取り置きは newSessionExpireTime(既定 1 分)で腐る
  • 数値(15 分 / 10 分 / 2 時間 / 30 分 / 1 分)はすべて 2026-08 時点のドキュメント値。設計はこの数値に依存しすぎない形にしておく

関連

この記事をシェア