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(),
)
),
)
자바스크립트
const config = {
responseModalities: [Modality.AUDIO],
contextWindowCompression: { slidingWindow: {} }
};
세션 재개
서버가 주기적으로 WebSocket 연결을 재설정할 때 세션 종료를 방지하려면 설정 구성 내에서 sessionResumption 필드를 구성합니다.
이 구성을 전달하면 서버가 SessionResumptionUpdate 메시지를 전송합니다. 이 메시지는 마지막 재개 토큰을 후속 연결의 SessionResumptionConfig.handle
로 전달하여 세션을 재개하는 데 사용할 수 있습니다.
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())
자바스크립트
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)
자바스크립트
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
자바스크립트
const turns = await handleTurn();
for (const turn of turns) {
if (turn.serverContent && turn.serverContent.generationComplete) {
// The generation is complete
}
}
다음 단계
전체 기능 가이드, 도구 사용 페이지 또는 Live API 레시피북에서 Live API를 사용하는 다양한 방법을 살펴보세요.