Live API에서 세션은 동일한 연결을 통해 입력과 출력이 지속적으로 스트리밍되는 영구 연결을 의미합니다 (작동 방식 자세히 알아보기).
이 고유한 세션 설계는 지연 시간을 줄이고 고유한 기능을 지원하지만 세션 시간 제한 및 조기 종료와 같은 문제도 발생할 수 있습니다.
이 가이드에서는 Live API를 사용할 때 발생할 수 있는 세션 관리 문제를 해결하기 위한 전략을 다룹니다.
세션 수명
압축하지 않으면 오디오 전용 세션은 15분으로 제한되고 오디오-동영상 세션은 2분으로 제한됩니다. 이러한 한도를 초과하면 세션 (따라서 연결)이 종료되지만 컨텍스트 창 압축을 사용하여 세션을 무제한으로 연장할 수 있습니다.
연결 수명도 약 10분으로 제한됩니다. 연결이 종료되면 세션도 종료됩니다. 이 경우 세션 재개를 사용하여 여러 연결에서 활성 상태를 유지하도록 단일 세션을 구성할 수 있습니다.
연결이 종료되기 전에 GoAway 메시지도 수신되므로 추가 조치를 취할 수 있습니다.
컨텍스트 윈도우 압축
더 긴 세션을 사용 설정하고 갑작스러운 연결 종료를 방지하려면 세션 구성의 일부로 contextWindowCompression 필드를 설정하여 컨텍스트 창 압축을 사용 설정하면 됩니다.
importasynciofromgoogleimportgenaifromgoogle.genaiimporttypesclient=genai.Client()model="gemini-live-2.5-flash-preview"asyncdefmain():print(f"Connecting to the service with handle {previous_session_handle}...")asyncwithclient.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),),)assession:whileTrue:awaitsession.send_client_content(turns=types.Content(role="user",parts=[types.Part(text="Hello world!")]))asyncformessageinsession.receive():# Periodically, the server will send update messages that may# contain a handle for the current state of the session.ifmessage.session_resumption_update:update=message.session_resumption_updateifupdate.resumableandupdate.new_handle:# The handle should be retained and linked to the session.returnupdate.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.ifmessage.server_contentandmessage.server_content.turn_complete:breakif__name__=="__main__":asyncio.run(main())
자바스크립트
import{GoogleGenAI,Modality}from'@google/genai';constai=newGoogleGenAI({});constmodel='gemini-live-2.5-flash-preview';asyncfunctionlive(){constresponseQueue=[];asyncfunctionwaitMessage(){letdone=false;letmessage=undefined;while(!done){message=responseQueue.shift();if(message){done=true;}else{awaitnewPromise((resolve)=>setTimeout(resolve,100));}}returnmessage;}asyncfunctionhandleTurn(){constturns=[];letdone=false;while(!done){constmessage=awaitwaitMessage();turns.push(message);if(message.serverContent && message.serverContent.turnComplete){done=true;}}returnturns;}console.debug('Connecting to the service with handle %s...',previousSessionHandle)constsession=awaitai.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.}});constinputTurns='Hello how are you?';session.sendClientContent({turns:inputTurns});constturns=awaithandleTurn();for(constturnofturns){if(turn.sessionResumptionUpdate){if(turn.sessionResumptionUpdate.resumable && turn.sessionResumptionUpdate.newHandle){letnewHandle=turn.sessionResumptionUpdate.newHandle// ...Store newHandle and start new session with this handle here}}}session.close();}asyncfunctionmain(){awaitlive().catch((e)=>console.error('got error',e));}main();
세션 연결이 해제되기 전에 메시지 수신
서버는 현재 연결이 곧 종료된다는 신호를 보내는 GoAway 메시지를 전송합니다. 이 메시지에는 남은 시간을 나타내는 timeLeft이 포함되어 있으며 연결이 ABORTED로 종료되기 전에 추가 조치를 취할 수 있습니다.
Python
asyncforresponseinsession.receive():ifresponse.go_awayisnotNone:# The connection will soon be terminatedprint(response.go_away.time_left)
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["필요한 정보가 없음","missingTheInformationINeed","thumb-down"],["너무 복잡함/단계 수가 너무 많음","tooComplicatedTooManySteps","thumb-down"],["오래됨","outOfDate","thumb-down"],["번역 문제","translationIssue","thumb-down"],["샘플/코드 문제","samplesCodeIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-08-22(UTC)"],[],[],null,["# Session management with Live API\n\nIn the Live API, a session refers to a persistent\nconnection where input and output are streamed continuously over the same\nconnection (read more about [how it works](/gemini-api/docs/live)).\nThis unique session design enables low latency and supports unique features, but\ncan also introduce challenges, like session time limits, and early termination.\nThis guide covers strategies for overcoming the session management challenges\nthat can arise when using the Live API.\n\nSession lifetime\n----------------\n\nWithout compression, audio-only sessions are limited to 15 minutes,\nand audio-video sessions are limited to 2 minutes. Exceeding these limits\nwill terminate the session (and therefore, the connection), but you can use\n[context window compression](#context-window-compression) to extend sessions to\nan unlimited amount of time.\n\nThe lifetime of a connection is limited as well, to around 10 minutes. When the\nconnection terminates, the session terminates as well. In this case, you can\nconfigure a single session to stay active over multiple connections using\n[session resumption](#session-resumption).\nYou'll also receive a [GoAway message](#goaway-message) before the\nconnection ends, allowing you to take further actions.\n\nContext window compression\n--------------------------\n\nTo enable longer sessions, and avoid abrupt connection termination, you can\nenable context window compression by setting the [contextWindowCompression](/api/live#BidiGenerateContentSetup.FIELDS.ContextWindowCompressionConfig.BidiGenerateContentSetup.context_window_compression)\nfield as part of the session configuration.\n\nIn the [ContextWindowCompressionConfig](/api/live#contextwindowcompressionconfig), you can configure a\n[sliding-window mechanism](/api/live#ContextWindowCompressionConfig.FIELDS.ContextWindowCompressionConfig.SlidingWindow.ContextWindowCompressionConfig.sliding_window)\nand the [number of tokens](/api/live#ContextWindowCompressionConfig.FIELDS.int64.ContextWindowCompressionConfig.trigger_tokens)\nthat triggers compression. \n\n### Python\n\n from google.genai import types\n\n config = types.LiveConnectConfig(\n response_modalities=[\"AUDIO\"],\n context_window_compression=(\n # Configures compression with default parameters.\n types.ContextWindowCompressionConfig(\n sliding_window=types.SlidingWindow(),\n )\n ),\n )\n\n### JavaScript\n\n const config = {\n responseModalities: [Modality.AUDIO],\n contextWindowCompression: { slidingWindow: {} }\n };\n\nSession resumption\n------------------\n\nTo prevent session termination when the server periodically resets the WebSocket\nconnection, configure the [sessionResumption](/api/live#BidiGenerateContentSetup.FIELDS.SessionResumptionConfig.BidiGenerateContentSetup.session_resumption)\nfield within the [setup configuration](/api/live#BidiGenerateContentSetup).\n\nPassing this configuration causes the\nserver to send [SessionResumptionUpdate](/api/live#SessionResumptionUpdate)\nmessages, which can be used to resume the session by passing the last resumption\ntoken as the [`SessionResumptionConfig.handle`](/api/live#SessionResumptionConfig.FIELDS.string.SessionResumptionConfig.handle)\nof the subsequent connection.\n\nResumption tokens are valid for 2 hr after the last sessions termination. \n\n### Python\n\n import asyncio\n from google import genai\n from google.genai import types\n\n client = genai.Client()\n model = \"gemini-live-2.5-flash-preview\"\n\n async def main():\n print(f\"Connecting to the service with handle {previous_session_handle}...\")\n async with client.aio.live.connect(\n model=model,\n config=types.LiveConnectConfig(\n response_modalities=[\"AUDIO\"],\n session_resumption=types.SessionResumptionConfig(\n # The handle of the session to resume is passed here,\n # or else None to start a new session.\n handle=previous_session_handle\n ),\n ),\n ) as session:\n while True:\n await session.send_client_content(\n turns=types.Content(\n role=\"user\", parts=[types.Part(text=\"Hello world!\")]\n )\n )\n async for message in session.receive():\n # Periodically, the server will send update messages that may\n # contain a handle for the current state of the session.\n if message.session_resumption_update:\n update = message.session_resumption_update\n if update.resumable and update.new_handle:\n # The handle should be retained and linked to the session.\n return update.new_handle\n\n # For the purposes of this example, placeholder input is continually fed\n # to the model. In non-sample code, the model inputs would come from\n # the user.\n if message.server_content and message.server_content.turn_complete:\n break\n\n if __name__ == \"__main__\":\n asyncio.run(main())\n\n### JavaScript\n\n import { GoogleGenAI, Modality } from '@google/genai';\n\n const ai = new GoogleGenAI({});\n const model = 'gemini-live-2.5-flash-preview';\n\n async function live() {\n const responseQueue = [];\n\n async function waitMessage() {\n let done = false;\n let message = undefined;\n while (!done) {\n message = responseQueue.shift();\n if (message) {\n done = true;\n } else {\n await new Promise((resolve) =\u003e setTimeout(resolve, 100));\n }\n }\n return message;\n }\n\n async function handleTurn() {\n const turns = [];\n let done = false;\n while (!done) {\n const message = await waitMessage();\n turns.push(message);\n if (message.serverContent && message.serverContent.turnComplete) {\n done = true;\n }\n }\n return turns;\n }\n\n console.debug('Connecting to the service with handle %s...', previousSessionHandle)\n const session = await ai.live.connect({\n model: model,\n callbacks: {\n onopen: function () {\n console.debug('Opened');\n },\n onmessage: function (message) {\n responseQueue.push(message);\n },\n onerror: function (e) {\n console.debug('Error:', e.message);\n },\n onclose: function (e) {\n console.debug('Close:', e.reason);\n },\n },\n config: {\n responseModalities: [Modality.TEXT],\n sessionResumption: { handle: previousSessionHandle }\n // The handle of the session to resume is passed here, or else null to start a new session.\n }\n });\n\n const inputTurns = 'Hello how are you?';\n session.sendClientContent({ turns: inputTurns });\n\n const turns = await handleTurn();\n for (const turn of turns) {\n if (turn.sessionResumptionUpdate) {\n if (turn.sessionResumptionUpdate.resumable && turn.sessionResumptionUpdate.newHandle) {\n let newHandle = turn.sessionResumptionUpdate.newHandle\n // ...Store newHandle and start new session with this handle here\n }\n }\n }\n\n session.close();\n }\n\n async function main() {\n await live().catch((e) =\u003e console.error('got error', e));\n }\n\n main();\n\nReceiving a message before the session disconnects\n--------------------------------------------------\n\nThe server sends a [GoAway](/api/live#GoAway) message that signals that the current\nconnection will soon be terminated. This message includes the [timeLeft](/api/live#GoAway.FIELDS.google.protobuf.Duration.GoAway.time_left),\nindicating the remaining time and lets you take further action before the\nconnection will be terminated as ABORTED. \n\n### Python\n\n async for response in session.receive():\n if response.go_away is not None:\n # The connection will soon be terminated\n print(response.go_away.time_left)\n\n### JavaScript\n\n const turns = await handleTurn();\n\n for (const turn of turns) {\n if (turn.goAway) {\n console.debug('Time left: %s\\n', turn.goAway.timeLeft);\n }\n }\n\nReceiving a message when the generation is complete\n---------------------------------------------------\n\nThe server sends a [generationComplete](/api/live#BidiGenerateContentServerContent.FIELDS.bool.BidiGenerateContentServerContent.generation_complete)\nmessage that signals that the model finished generating the response. \n\n### Python\n\n async for response in session.receive():\n if response.server_content.generation_complete is True:\n # The generation is complete\n\n### JavaScript\n\n const turns = await handleTurn();\n\n for (const turn of turns) {\n if (turn.serverContent && turn.serverContent.generationComplete) {\n // The generation is complete\n }\n }\n\nWhat's next\n-----------\n\nExplore more ways to work with the Live API in the full\n[Capabilities](/gemini-api/docs/live) guide,\nthe [Tool use](/gemini-api/docs/live-tools) page, or the\n[Live API cookbook](https://colab.research.google.com/github/google-gemini/cookbook/blob/main/quickstarts/Get_started_LiveAPI.ipynb)."]]