Session management with Live API

在 Live API 中,会话是指通过同一连接持续传输输入和输出的持久连接(详细了解其工作原理)。这种独特的会话设计可实现低延迟并支持独特的功能,但也可能会带来一些挑战,例如会话时间限制和提前终止。本指南介绍了在使用 Live API 时可能会遇到会话管理方面的挑战,并提供了应对这些挑战的策略。

会话生命周期

如果不进行压缩,纯音频会话的时长上限为 15 分钟,音频-视频会话的时长上限为 2 分钟。超出这些限制会导致会话(以及连接)终止,但您可以使用上下文窗口压缩将会话延长至无限时长。

连接的生命周期也有限制,约为 10 分钟。当连接终止时,会话也会终止。在这种情况下,您可以使用会话恢复功能,将单个会话配置为在多个连接中保持活跃状态。在连接结束之前,您还会收到一条 GoAway 消息,以便您采取进一步的措施。

上下文窗口压缩

如需延长会话时长并避免连接突然终止,您可以在会话配置中设置 contextWindowCompression 字段来启用上下文窗口压缩。

ContextWindowCompressionConfig 中,您可以配置滑动窗口机制和触发压缩的令牌数量

Python

from google.genai import types

config = types.LiveConnectConfig(
    response_modalities=["AUDIO"],
    context_window_compression=(
        # Configures compression with default parameters.
        types.ContextWindowCompressionConfig(
            sliding_window=types.SlidingWindow(),
        )
    ),
)

JavaScript

const config = {
  responseModalities: [Modality.AUDIO],
  contextWindowCompression: { slidingWindow: {} }
};

会话恢复

为防止服务器定期重置 WebSocket 连接时会话终止,请在设置配置中配置 sessionResumption 字段。

传递此配置会导致服务器发送 SessionResumptionUpdate 消息,该消息可用于通过将上次恢复令牌作为后续连接的 SessionResumptionConfig.handle 来恢复会话。

恢复令牌在上次会话终止后 2 小时内有效。

Python

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

client = genai.Client()
model = "gemini-live-2.5-flash-preview"

async def main():
    print(f"Connecting to the service with handle {previous_session_handle}...")
    async with client.aio.live.connect(
        model=model,
        config=types.LiveConnectConfig(
            response_modalities=["AUDIO"],
            session_resumption=types.SessionResumptionConfig(
                # The handle of the session to resume is passed here,
                # or else None to start a new session.
                handle=previous_session_handle
            ),
        ),
    ) as session:
        while True:
            await session.send_client_content(
                turns=types.Content(
                    role="user", parts=[types.Part(text="Hello world!")]
                )
            )
            async for message in session.receive():
                # Periodically, the server will send update messages that may
                # contain a handle for the current state of the session.
                if message.session_resumption_update:
                    update = message.session_resumption_update
                    if update.resumable and update.new_handle:
                        # The handle should be retained and linked to the session.
                        return update.new_handle

                # For the purposes of this example, placeholder input is continually fed
                # to the model. In non-sample code, the model inputs would come from
                # the user.
                if message.server_content and message.server_content.turn_complete:
                    break

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

JavaScript

import { GoogleGenAI, Modality } from '@google/genai';

const ai = new GoogleGenAI({});
const model = 'gemini-live-2.5-flash-preview';

async function live() {
  const responseQueue = [];

  async function waitMessage() {
    let done = false;
    let message = undefined;
    while (!done) {
      message = responseQueue.shift();
      if (message) {
        done = true;
      } else {
        await new Promise((resolve) => setTimeout(resolve, 100));
      }
    }
    return message;
  }

  async function handleTurn() {
    const turns = [];
    let done = false;
    while (!done) {
      const message = await waitMessage();
      turns.push(message);
      if (message.serverContent && message.serverContent.turnComplete) {
        done = true;
      }
    }
    return turns;
  }

console.debug('Connecting to the service with handle %s...', previousSessionHandle)
const session = await ai.live.connect({
  model: model,
  callbacks: {
    onopen: function () {
      console.debug('Opened');
    },
    onmessage: function (message) {
      responseQueue.push(message);
    },
    onerror: function (e) {
      console.debug('Error:', e.message);
    },
    onclose: function (e) {
      console.debug('Close:', e.reason);
    },
  },
  config: {
    responseModalities: [Modality.TEXT],
    sessionResumption: { handle: previousSessionHandle }
    // The handle of the session to resume is passed here, or else null to start a new session.
  }
});

const inputTurns = 'Hello how are you?';
session.sendClientContent({ turns: inputTurns });

const turns = await handleTurn();
for (const turn of turns) {
  if (turn.sessionResumptionUpdate) {
    if (turn.sessionResumptionUpdate.resumable && turn.sessionResumptionUpdate.newHandle) {
      let newHandle = turn.sessionResumptionUpdate.newHandle
      // ...Store newHandle and start new session with this handle here
    }
  }
}

  session.close();
}

async function main() {
  await live().catch((e) => console.error('got error', e));
}

main();

在会话断开连接之前收到消息

服务器会发送一条 GoAway 消息,表示当前连接即将终止。此消息包含 timeLeft,用于指示剩余时间,并让您在连接因 ABORTED 而终止之前采取进一步的措施。

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)

JavaScript

const turns = await handleTurn();

for (const turn of turns) {
  if (turn.goAway) {
    console.debug('Time left: %s\n', turn.goAway.timeLeft);
  }
}

在生成完成后收到消息

服务器会发送 generationComplete 消息,表明模型已完成回答生成。

Python

async for response in session.receive():
    if response.server_content.generation_complete is True:
        # The generation is complete

JavaScript

const turns = await handleTurn();

for (const turn of turns) {
  if (turn.serverContent && turn.serverContent.generationComplete) {
    // The generation is complete
  }
}

后续步骤

如需详细了解如何使用 Live API,请参阅完整的功能指南、工具使用页面或 Live API 食谱