開始及管理直播工作階段

Gemini Live API 會處理連續的音訊或文字串流 (稱為「工作階段」),並立即提供類似人類的口語回覆,實現低延遲的語音和文字互動。工作階段生命週期管理 (從初始信號交換到正常終止) 由開發人員控管。

本頁面說明如何使用 Gemini Live API,與 Gemini 模型啟動對話工作階段。你可以使用 Vertex AI Studio、Google Gen AI SDK 或 WebSocket 啟動工作階段。

本頁面也會說明如何執行下列操作:

  • 延長工作階段時間,超過預設時間限制
  • 繼續執行前一個工作階段
  • 在工作階段期間更新系統指令
  • 設定工作階段的內容視窗
  • 為工作階段啟用轉錄功能
  • 使用客戶自行管理的加密金鑰 (CMEK) 加密工作階段資料

工作階段生命週期

如果沒有內容視窗壓縮功能,由於權杖限制,僅限音訊的對話時間上限為 15 分鐘,音訊和視訊的對話時間上限則為 2 分鐘。超過這些限制會終止工作階段,但您可以使用內容視窗壓縮功能,將工作階段延長至無限時間。

由於 WebSocket 連線限制,連線的生命週期約為 10 分鐘。連線終止時,工作階段也會終止。在這種情況下,您可以設定單一工作階段,透過工作階段續傳功能在多個連線中保持有效。連線結束前,您也會收到GoAway訊息,以便採取進一步行動。

並行工作階段數量上限

在即付即用 (PayGo) 方案中,每個專案最多可有 1,000 個並行工作階段。使用佈建輸送量的客戶不受這項限制。

開始練習

下列分頁說明如何使用 Vertex AI Studio、Google Gen AI SDK 或 WebSocket 啟動即時對話工作階段:

控制台

  1. 開啟 Vertex AI Studio > Stream realtime。
  2. 按一下「 開始工作階段」即可開始對話。

如要結束工作階段,請按一下「停止工作階段」。

Python

開始之前,請先使用 API 金鑰或應用程式預設憑證 (ADC) 向 Gemini Enterprise Agent Platform 進行驗證:

gcloud auth application-default login
      

如要進一步瞭解如何設定驗證,請參閱快速入門導覽課程。

import asyncio
from google import genai

# Replace the PROJECT_ID and LOCATION with your Project ID and location.
client = genai.Client(vertexai=True, project="PROJECT_ID", location="LOCATION")

# Configuration
MODEL = "gemini-3.8-live"
config = {
   "response_modalities": ["audio"],
}

async def main():
   # Establish WebSocket session
   async with client.aio.live.connect(model=MODEL, config=config) as session:
       print("Session established. Sending audio...")

if __name__ == "__main__":
    asyncio.run(main())
      

Python

使用 WebSocket 時,系統會透過標準 WebSocket 握手建立連線。這個端點是區域性的,並使用 OAuth 2.0 持有人權杖進行驗證。在這種情況下,驗證權杖通常會傳遞至 WebSocket 標頭 (例如 Authorization: Bearer [TOKEN])。

import asyncio
import websockets

# Replace the PROJECT_ID and LOCATION with your Project ID and location.
PROJECT_ID = "PROJECT_ID"
LOCATION = "LOCATION"

# Authentication
token_list = !gcloud auth application-default print-access-token
ACCESS_TOKEN = token_list[0]

# Configuration
MODEL_ID = "gemini-3.8-live"
MODEL = f"projects/{PROJECT_ID}/locations/{LOCATION}/publishers/google/models/{MODEL_ID}"
config = {
   "response_modalities": ["audio"],
}

# Construct the WSS URL
HOST = f"{LOCATION}-aiplatform.googleapis.com"
URI = f"wss://{HOST}/ws/google.cloud.aiplatform.v1.LlmBidiService/BidiGenerateContent"

async def main():
   headers = {"Authorization": f"Bearer {ACCESS_TOKEN}"}

   async with websockets.connect(URI, additional_headers=headers) as ws:
       print("Session established.")

       # Send Setup (Handshake)
       await ws.send(json.dumps({
           "setup": {
               "model": MODEL,
               "generation_config": config
           }
       }))
    # Send audio/video ...

if __name__ == "__main__":
    asyncio.run(main())
      

延長工作階段

對話工作階段的預設時間上限為 10 分鐘,您可以使用 goAway 通知延長時間。系統會在工作階段結束前 60 秒,向用戶端傳送goAway通知 (BidiGenerateContentServerMessage.goAway)。

如要延長工作階段,超過 10 分鐘的連線時間限制,請使用工作階段續傳功能重新連線。收到 goAway 通知,或連線因其他原因終止時,您可以使用在工作階段期間取得的工作階段控制代碼,啟動新的連線。這樣一來,工作階段就會在新連線中繼續進行,且內容不會遺失。這類操作的次數沒有上限。如需繼續工作階段的範例,請參閱「繼續執行前一個工作階段」。

以下範例說明如何監聽 goAway 通知,偵測即將終止的會話:

Python

async for response in session.receive():
    if response.go_away is not None:
        # The connection will soon be terminated
        print(response.go_away.time_left)
      

繼續執行前一個工作階段

Gemini Live API 支援工作階段續傳功能,可避免使用者在短暫中斷連線期間 (例如從 Wi-Fi 切換至 5G) 遺失對話內容。你可以在 24 小時內繼續執行前一個工作階段。系統會儲存快取資料 (包括文字、影片、音訊提示和模型輸出內容),以便恢復工作階段。系統會對這項快取資料強制執行專案層級的隱私權設定。

根據預設,系統會停用工作階段續傳功能。如要啟用工作階段續傳功能,請設定 BidiGenerateContentSetup 訊息的 sessionResumption 欄位。啟用後,伺服器會定期傳送包含 session_id 和恢復權杖的 SessionResumptionUpdate 訊息。如果 WebSocket 中斷連線,用戶端可以重新連線,並在新設定訊息中加入這些憑證。接著,伺服器會還原先前的脈絡,讓對話順暢接續。

繼續播放的時間有限 (通常約 10 分鐘)。如果用戶端未在指定時間內重新連線,系統就會捨棄工作階段狀態,釋出伺服器資源。

以下範例會連線至服務、取得工作階段續傳控制代碼、模擬中斷連線,然後使用控制代碼重新連線,以續傳工作階段:

Python

import asyncio
from google import genai
from google.genai import types
import websockets

# Replace the PROJECT_ID and LOCATION with your Project ID and location.
client = genai.Client(vertexai=True, project="PROJECT_ID", location="LOCATION")

# Configuration
MODEL = "gemini-3.8-live"

async def resumable_session_example():
    """Demonstrates session resumption by connecting, disconnecting, and reconnecting."""
    session_handle = None

    print("Starting a new session...")
    try:
        async with client.aio.live.connect(
            model=MODEL,
            config=types.LiveConnectConfig(
                response_modalities=["audio"],
                session_resumption=types.SessionResumptionConfig(handle=None),
            ),
        ) as session:
            await session.send_content(
                content=types.Content(role="user", parts=[types.Part(text="Hello!")])
            )
            async for message in session.receive():
                if message.session_resumption_update:
                    update = message.session_resumption_update
                    if update.resumable and update.new_handle:
                        session_handle = update.new_handle
                        print(f"Received session handle: {session_handle}")
                        # For demonstration, we break to simulate a disconnect
                        # after receiving a handle.
                        break
                if message.server_content and message.server_content.turn_complete:
                    break
    except websockets.exceptions.WebSocketException as e:
        print(f"Initial connection failed: {e}")
        return

    if not session_handle:
        print("Did not receive a session handle. Cannot demonstrate resumption.")
        return

    print(f"\nSimulating disconnect and reconnecting with handle {session_handle}...")

    try:
        async with client.aio.live.connect(
            model=MODEL,
            config=types.LiveConnectConfig(
                response_modalities=["audio"],
                session_resumption=types.SessionResumptionConfig(handle=session_handle),
            ),
        ) as session:
            print("Successfully resumed session.")
            await session.send_content(
                content=types.Content(role="user", parts=[types.Part(text="I am back!")])
            )
            async for message in session.receive():
                if message.session_resumption_update:
                    update = message.session_resumption_update
                    if update.resumable and update.new_handle:
                        session_handle = update.new_handle
                        print(f"Received updated session handle: {session_handle}")
                if message.server_content:
                    print(f"Received server content: {message.server_content}")
                    if message.server_content.turn_complete:
                        break
            print("Resumed session finished.")
    except websockets.exceptions.WebSocketException as e:
        print(f"Failed to resume session: {e}")

if __name__ == "__main__":
    asyncio.run(resumable_session_example())
      

啟用環境音模式,順暢地繼續工作階段

啟用工作階段續傳功能後,您也可以啟用透明模式,讓使用者續傳工作階段時更流暢。啟用透明模式後,系統會明確傳回與內容快照相應的用戶端訊息索引。當您從恢復控點恢復工作階段時,這有助於識別需要再次傳送的用戶端訊息。

如要啟用環境音模式,請按照下列步驟操作:

Python

config = {
   "response_modalities": ["audio"],
   "session_resumption_config": {
    "transparent": True,
   }
}
      

使用 CMEK 加密工作階段資料

工作階段續傳功能最多會將快取的工作階段資料儲存在靜態狀態 24 小時。如要使用自己的金鑰 (而非Google Cloud-powered encryption key) 保護資料,請使用服務設定檔。服務設定檔會將 Cloud KMS 金鑰連結至專案、位置和 API 範圍。只要有服務設定檔,Agent Platform 就會自動加密資料,您的工作階段設定和要求格式不會變更。

Gemini Live API 的服務設定檔 CMEK 支援 us 和 eu 多區域。系統不支援全域區域。

如要為 Gemini Live API 設定 CMEK,請按照下列步驟操作:

  1. 在專案中啟用 Cloud KMS API 和 Agent Platform API。請參閱事前準備一節。
  2. 在 us 或 eu 多區域中建立 Cloud KMS 金鑰。請參閱「建立金鑰環和金鑰」。
  3. 在金鑰上授予 Gemini Enterprise Agent Platform 服務代理程式 roles/cloudkms.cryptoKeyEncrypterDecrypter 角色。請參閱「授予 Agent Platform 權限」。
  4. 建立服務設定檔,將 scope 設為 GEMINI_LIVE,並將 cmekConfig.encryptionSpec.kmsKeyName 設為金鑰。請參閱「建立放送設定檔」。

在工作階段期間更新系統指令

透過 Gemini Live API,您可以在進行中的工作階段更新系統指令。你可以使用這項功能調整模型的回覆,例如變更回覆語言或修改語氣。

如要在工作階段中更新系統指令,可以傳送具有 system 角色的文字內容。更新後的系統指令會在剩餘的工作階段中生效。

Python

session.send_client_content(
      content=types.Content(
          role="system", parts=[types.Part(text="new system instruction")]
      ),
      turn_complete=False
  )
      

設定工作階段的內容視窗

Gemini Live API 內容視窗用於儲存即時串流資料 (音訊每秒 25 個權杖,影片每秒 258 個權杖) 和其他內容,包括文字輸入內容和模型輸出內容。所有 Gemini Live API 模型都有 12.8 萬個詞元的脈絡窗口限制。

在長時間的對話中,隨著對話進行,音訊和文字權杖的記錄會不斷累積。如果這類記錄超出模型上限,模型可能會產生幻覺、速度變慢,或強制終止對話。如要延長工作階段時間,您可以啟用脈絡視窗壓縮功能,方法是在工作階段設定中設定 contextWindowCompression 欄位。

啟用後,內容視窗壓縮功能會使用伺服器端滑動視窗,截斷最舊的對話。當累積的權杖超過定義的長度上限 (在 Vertex AI Studio 中使用「內容大小上限」滑桿設定,或在 API 中使用 trigger_tokens),伺服器會自動修剪或摘要最舊的輪次,以將內容維持在限制內。在 ContextWindowCompressionConfig 中,您可以設定滑動視窗機制,以及 target_tokens 參數中定義的權杖數量,以觸發壓縮作業。

從使用者的角度來看,由於「個人化記憶」會持續管理,因此理論上工作階段持續時間無限。如果沒有壓縮,純音訊工作階段可能在達到硬性限制前,只能持續約 15 分鐘。

脈絡長度和目標大小的長度下限和上限如下:

設定 (API 標記) 最小值 最大值
脈絡長度上限 (trigger_tokens) 5,000 128,000
脈絡長度目標 (target_tokens) 0 128,000

如要設定脈絡窗口,請按照下列步驟操作:

控制台

  1. 開啟 Vertex AI Studio > Stream realtime。
  2. 按一下開啟「進階」選單。
  3. 在「工作階段內容」部分,使用「內容大小上限」滑桿,將內容大小設為介於 5,000 到 128,000 之間的值。
  4. (選用) 在同一部分中,使用「目標內容大小」滑桿將目標大小設為介於 0 到 128,000 之間的值。

Python

在設定訊息中設定 context_window_compression.trigger_tokens 和 context_window_compression.sliding_window.target_tokens 欄位:

config = {
   "response_modalities": ["audio"],
   # Configures compression
   "context_window_compression" : {
    "trigger_tokens": 10000,
    "sliding_window": {"target_tokens" : 512}
   }
}
      

為工作階段啟用音訊轉錄功能

你可以啟用輸入和輸出音訊的轉錄功能。

如要接收轉錄內容,請更新工作階段設定。您需要新增 input_audio_transcription 和 output_audio_transcription 物件,並確保 text 包含在 response_modalities 中。

如要提升多語言自動語音辨識 (ASR) 的轉錄品質,可以使用 language_codes 欄位提供語言提示,方法是在 input_audio_transcription 或 output_audio_transcription 中設定。建議提供提示,以提升轉錄品質,並降低語言偵測錯誤的風險,尤其是簡短提示。language_codes 欄位接受 BCP-47 語言代碼清單 (例如「en-US」、「es-US」)。

config = {
    "response_modalities": ["audio", "text"],
    "input_audio_transcription": {
        "language_codes": ["en-US"]
    },
    "output_audio_transcription": {},
}

處理回應

下列程式碼範例示範如何使用設定的會話連線,並擷取文字部分 (轉錄內容) 和音訊資料。

# Receive Output Loop
async for message in session.receive():
    server_content = message.server_content
    if server_content:
        # Handle Model Turns (Audio + Text)
        model_turn = server_content.model_turn
        if model_turn and model_turn.parts:
            for part in model_turn.parts:
                # Handle Text (Transcriptions)
                if part.text:
                    print(f"Transcription: {part.text}")
                # Handle Audio
                if part.inline_data:
                    audio_data = part.inline_data.data
                    # Process audio bytes...
                    pass

        # Check for turn completion
        if server_content.turn_complete:
            print("Turn complete.")

後續步驟