איך מתחילים ומנהלים סשנים בשידור חי

‫Gemini Live API מאפשר אינטראקציות קוליות וטקסטואליות עם זמן אחזור קצר, על ידי עיבוד של סטרימינג רציף של אודיו או טקסט שנקרא סשנים, כדי לספק תשובות קוליות מיידיות שנשמעות אנושיות. המפתח שולט בניהול מחזור החיים של הסשן, מהלחיצת היד הראשונית ועד לסיום תקין.

בדף הזה מוסבר איך להתחיל שיחה עם מודלים של Gemini באמצעות Gemini Live API. אתם יכולים להתחיל סשן באמצעות Vertex AI Studio,‏ Google Gen AI SDK או WebSockets.

בדף הזה מוסבר גם איך:

  • הארכת סשן מעבר למגבלת הזמן שמוגדרת כברירת מחדל
  • איך ממשיכים סשן קודם
  • עדכון הוראות המערכת במהלך סשן
  • עדכון הוראות המערכת והכלים במהלך שיחה עם Gemini 3.8 Live
  • הגדרת חלון ההקשר של סשן
  • הפעלת התמלול בפגישה
  • הצפנת נתוני סשן באמצעות מפתח הצפנה בניהול הלקוח (CMEK)

משך החיים של הסשן

בלי דחיסת חלון ההקשר, הפעלות של אודיו בלבד מוגבלות ל-15 דקות, והפעלות של אודיו-וידאו מוגבלות ל-2 דקות בגלל מגבלות על הטוקנים. חריגה מהמגבלות האלה תסיים את הסשן, אבל אתם יכולים להשתמש בדחיסת חלון ההקשר כדי להאריך את הסשנים לזמן בלתי מוגבל.

משך החיים של חיבור מוגבל לכ-10 דקות בגלל מגבלות החיבור של WebSocket. כשהחיבור מסתיים, גם הסשן מסתיים. במקרה כזה, אתם יכולים להגדיר סשן יחיד שיישאר פעיל בכמה חיבורים באמצעות חידוש סשן. תקבלו גם הודעה מ-GoAway לפני שהחיבור יסתיים, כדי שתוכלו לבצע פעולות נוספות.

מספר מקסימלי של סשנים בו-זמניים

בתוכנית בתשלום לפי שימוש (PayGo), אפשר להפעיל עד 1,000 סשנים בו-זמנית בכל פרויקט. המגבלה הזו לא חלה על לקוחות שמשתמשים בהקצאת משאבים לפי התפוקה שנקבעה.

התחלת סשן

בכרטיסיות הבאות מוסבר איך להתחיל שיחה במצב Live באמצעות Vertex AI Studio,‏ Google Gen AI SDK או WebSockets:

המסוף

  1. פותחים את Vertex AI Studio > Stream realtime.
  2. כדי להתחיל את השיחה, לוחצים על התחלת סשן.

כדי לסיים את הסשן, לוחצים על הפסקת הסשן.

Python

לפני שמתחילים, צריך לבצע אימות ב-Gemini Enterprise Agent Platform באמצעות מפתח API או פרטי כניסה של אפליקציה כברירת מחדל (ADC):

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

כשמשתמשים ב-WebSockets, החיבור נוצר באמצעות לחיצת יד רגילה של 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. התראה של goAway (BidiGenerateContentServerMessage.goAway) נשלחת ללקוח 60 שניות לפני שהסשן מסתיים.

כדי להאריך סשן מעבר למגבלת החיבור של 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 שעות. כדי להמשיך סשן, המערכת שומרת נתונים במטמון, כולל הנחיות בטקסט, בווידאו ובאודיו, ופלט מהמודל. הפרטיות ברמת הפרויקט נאכפת על הנתונים האלה שנשמרו במטמון.

כברירת מחדל, חידוש הסשן מושבת. כדי להפעיל את המשך הסשן, מגדירים את השדה sessionResumption של ההודעה BidiGenerateContentSetup. אם האפשרות מופעלת, השרת שולח מדי פעם הודעות SessionResumptionUpdate שמכילות session_id ואסימון להמשך. אם החיבור ל-WebSocket מתנתק, הלקוח יכול להתחבר מחדש ולכלול את פרטי הכניסה האלה בהודעת ההגדרה החדשה. השרת משחזר את ההקשר הקודם, והשיחה יכולה להמשיך בלי הפרעה.

חלון הזמן להמשך ההעלאה מוגבל (בדרך כלל כ-10 דקות). אם הלקוח לא מתחבר מחדש בפרק הזמן הזה, מצב הסשן נמחק כדי לפנות משאבים בשרת.

בדוגמה הבאה מתבצע חיבור לשירות, מתקבל handle להמשך הסשן, מתבצעת סימולציה של ניתוק ואז מתבצע חיבור מחדש באמצעות ה-handle כדי להמשיך את הסשן:

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 מצפינה את הנתונים באופן אוטומטי – הגדרת הסשן ופורמט הבקשה לא משתנים.

אפשר להשתמש ב-CMEK לפרופיל הצגת המודעות ב-Gemini Live API באזורים us ו-eu. האזור הגלובלי לא נתמך.

כדי להגדיר CMEK ל-Gemini Live API:

  1. מפעילים בפרויקט את Cloud KMS API ואת Agent Platform API. לפני שמתחילים
  2. יוצרים מפתח Cloud KMS במיקום us או eu שכולל מספר אזורים. איך יוצרים אוסף מפתחות ומפתח
  3. מקצים לסוכן השירות של Gemini Enterprise Agent Platform את התפקיד roles/cloudkms.cryptoKeyEncrypterDecrypter במפתח. איך נותנים הרשאות ל-Agent Platform
  4. יוצרים פרופיל הצגה שבו מגדירים את scope ל-GEMINI_LIVE ואת cmekConfig.encryptionSpec.kmsKeyName למפתח שלכם. איך יוצרים פרופיל הצגה

עדכון הוראות המערכת במהלך סשן

‫Gemini Live API מאפשר לעדכן את ההוראות למערכת במהלך סשן פעיל. אפשר להשתמש בהוראות כדי להתאים את התשובות של המודל, למשל לשנות את שפת התשובה או את הטון.

השיטה הבאה רלוונטית לאודיו מקורי ב-Gemini 2.5 Flash Live API. ב-Gemini 3.8 Live, קראו את המאמר עדכון של הוראות המערכת והכלים ב-Gemini 3.8 Live.

כדי לעדכן את הוראות המערכת באמצע הסשן, אתם יכולים לשלוח תוכן טקסט עם התפקיד system. ההוראה המעודכנת למערכת תישאר בתוקף עד סוף הסשן.

Python

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

עדכון הוראות המערכת והכלים באמצעות Gemini 3.8 Live

ב-Gemini 3.8 Live, אתם יכולים לעדכן את ההוראות למערכת ואת הכלים של סשן פעיל על ידי שליחת הודעת BidiGenerateContentContextUpdate. לדוגמה, אתם יכולים לשנות את השפה או את הטון של התשובה, או לתת למודל קבוצה אחרת של פונקציות כשהשיחה עוברת למשימה חדשה. באמצעות Google Gen AI SDK, מפעילים את send_context_update. ב-WebSockets, מגדירים את השדה context_update של הודעת הלקוח. אל תשלחו תוכן של לקוחות עם התפקיד system ל-Gemini 3.8 Live.

מגדירים את השדות שרוצים לשנות:

  • ‫system_instruction: מחליפה את הוראת המערכת מהודעת ההגדרה למשך שארית הסשן.
  • ‫tools: מחליף את כל רשימת הכלים של הסשן. צריך לכלול כל כלי שהמודל עדיין אמור להיות מסוגל להשתמש בו. כדי להסיר את כל הכלים, שולחים רשימה ריקה.

שדות שלא תגדירו ישמרו על הערכים הנוכחיים שלהם. העדכונים מעובדים לפי הסדר עם שאר הקלט של הסשן.

Python

from google.genai import types

# Replace the system instruction.
await session.send_context_update(
    system_instruction="Respond only in Spanish."
)

# Replace the tool list.
get_current_weather = types.FunctionDeclaration(
    name="get_current_weather",
    description="Get the current weather in a given location",
    parameters=types.Schema(
        type=types.Type.OBJECT,
        properties={"location": types.Schema(type=types.Type.STRING)},
    ),
)
await session.send_context_update(
    tools=[types.Tool(function_declarations=[get_current_weather])]
)

# Remove all tools.
await session.send_context_update(tools=[])
      

הכלים בצד השרת מוגדרים כשהסשן מתחיל, לכן המגבלות הבאות חלות כשעדכון הכלים כולל אותם. הצהרות על פונקציות לא מושפעות, ואפשר להוסיף אותן בכל עדכון של הכלים.

  • כדי להשתמש ב'עיגון באמצעות חיפוש Google' אחרי עדכון הכלים, צריך גם להצהיר על google_search בהודעת ההגדרה.
  • אפשר להצהיר על הכלים Web Grounding for Enterprise,‏ Agent Search ו-RAG Engine רק בהודעת ההגדרה. אם תשלחו context_update שכוללת אותם, תקבלו את השגיאה INVALID_ARGUMENT.

הגדרת חלון ההקשר של הסשן

חלון ההקשר של Gemini Live API משמש לאחסון נתונים שמועברים בסטרימינג בזמן אמת (25 טוקנים לשנייה (TPS) לאודיו ו-258 טוקנים לשנייה לווידאו) ותכנים אחרים, כולל קלט טקסט ופלט מהמודל. לכל המודלים של Gemini Live API יש מגבלה של 128,000 טוקנים בחלון ההקשר.

בסשנים ארוכים, ככל שהשיחה מתקדמת, ההיסטוריה של הטוקנים של האודיו והטקסט מצטברת. אם ההיסטוריה הזו חורגת מהמגבלה של המודל, יכול להיות שהמודל יחווה הזיות, יאט או שהסשן יסתיים באופן פתאומי. כדי לאפשר סשנים ארוכים יותר, אתם יכולים להפעיל דחיסה של חלון ההקשר על ידי הגדרת השדה contextWindowCompression כחלק מהגדרות הסשן.

כשההגדרה "דחיסת חלון ההקשר" מופעלת, המערכת משתמשת בחלון הזזה בצד השרת כדי לחתוך את התורות הישנים ביותר. כשהאסימונים שנצברו חורגים מהאורך המקסימלי שהוגדר (באמצעות פס ההזזה Max content size ב-Vertex AI Studio, או trigger_tokens ב-API), השרת מקצר באופן אוטומטי את התורות הישנים ביותר או מסכם אותם כדי לשמור על ההקשר במסגרת המגבלה. ב-ContextWindowCompressionConfig, אתם יכולים להגדיר מנגנון של חלון הזזה ואת מספר הטוקנים שמוגדר בפרמטר target_tokens שמפעיל את הדחיסה.

כך אפשר לנהל משכי סשנים באורך תיאורטי אינסופי מנקודת המבט של המשתמש, כי "הזיכרון" מנוהל כל הזמן. בלי דחיסה, סשנים של אודיו בלבד עשויים להיות מוגבלים לכ-15 דקות לפני שהם מגיעים למגבלות קשיחות.

האורך המינימלי והמקסימלי של חלון ההקשר וגודל היעד הם:

הגדרה (דגל API) ערך מינימלי ערך מקסימלי
אורך חלון ההקשר המקסימלי (trigger_tokens) 5,000 128,000
גודל ההקשר של היעד (target_tokens) 0 128,000

כדי להגדיר את חלון ההקשר:

המסוף

  1. פותחים את Vertex AI Studio > Stream realtime.
  2. לוחצים כדי לפתוח את התפריט מתקדם.
  3. בקטע Session Context, משתמשים בפס ההזזה Max context size כדי להגדיר את גודל ההקשר לערך בין 5,000 ל-128,000.
  4. (אופציונלי) באותו קטע, משתמשים בפס ההזזה Target context size כדי להגדיר את גודל היעד לערך בין 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.")

המאמרים הבאים