Vertex AI Gemini Live - Realtime API
Vertex AI Gemini Live - Realtime API
LiteLLM의 통합 /realtime 엔드포인트를 통해 Vertex AI의 Gemini Live API(BidiGenerateContent)를 사용하는 방법을 알아봐요. OpenAI Realtime 프로토콜을 말해요.
출처: 문서
본문
Vertex AI의 Gemini Live API(BidiGenerateContent)를 OpenAI Realtime 프로토콜을 말하는 LiteLLM의 통합 /realtime 엔드포인트로 사용해요.
| 기능 | 지원 |
|---|---|
Proxy (/realtime) |
✅ |
| Voice in / Voice out | ✅ |
| Text in / Text out | ✅ |
| Server VAD | ✅ |
| Output transcription | ✅ |
설정
1. 인증
LiteLLM은 API 키가 아닌 Google Cloud 자격 증명(OAuth2 Bearer 토큰)을 사용해요.
gcloud auth application-default login
또는 서비스 계정 키 파일 설정:
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/sa-key.json
2. Proxy 구성
model_list:
- model_name: vertex-gemini-live
litellm_params:
model: vertex_ai/gemini-2.0-flash-live-001
vertex_project: your-gcp-project-id
vertex_location: us-east4 # or any supported region, or "global"
general_settings:
master_key: «redacted:sk-…» # your master key
3. Proxy 시작
litellm --config config.yaml --port 4000
사용법
Python (websockets)
import asyncio
import json
import websockets
PROXY_URL = "ws://localhost:4000/realtime?model=vertex-gemini-live"
API_KEY = "sk-your-key"
async def main():
async with websockets.connect(
PROXY_URL,
additional_headers={"api-key": API_KEY},
) as ws:
# Wait for session.created
event = json.loads(await ws.recv())
print(f"session.created: {event['session']['id']}")
# Send a text message
await ws.send(json.dumps({
"type": "conversation.item.create",
"item": {
"type": "message",
"role": "user",
"content": [{"type": "input_text", "text": "Say hello in one sentence."}],
},
}))
# Collect the response
async for raw in ws:
ev = json.loads(raw)
t = ev.get("type", "")
if t == "response.text.delta":
print(ev.get("delta", ""), end="", flush=True)
elif t == "response.done":
print("\n[done]")
break
asyncio.run(main())
Node.js
const WebSocket = require("ws");
const ws = new WebSocket(
"ws://localhost:4000/realtime?model=vertex-gemini-live",
{ headers: { "api-key": "sk-your-key" } }
);
ws.on("open", () => {
ws.send(JSON.stringify({
type: "conversation.item.create",
item: {
type: "message",
role: "user",
content: [{ type: "input_text", text: "Say hello." }],
},
}));
});
ws.on("message", (data) => {
const ev = JSON.parse(data);
if (ev.type === "response.text.delta") process.stdout.write(ev.delta);
if (ev.type === "response.done") ws.close();
});
OpenAI SDK (Python)
import asyncio
from openai import AsyncOpenAI
client = AsyncOpenAI(
base_url="http://localhost:4000",
api_key="sk-your-key",
)
async def main():
async with client.beta.realtime.connect(
model="vertex-gemini-live"
) as conn:
await conn.session.update(session={"modalities": ["text"]})
await conn.conversation.item.create(
item={
"type": "message",
"role": "user",
"content": [{"type": "input_text", "text": "Say hello."}],
}
)
async for event in conn:
if event.type == "response.text.delta":
print(event.delta, end="", flush=True)
elif event.type == "response.done":
print()
break
asyncio.run(main())
Voice in / Voice out
완전한 음성 예시는 voice_realtime_test.py를 참고해요.
오디오 핵심 설정:
- 마이크 입력: 16 kHz PCM16 (
audio/pcm;rate=16000) - 스피커 출력: 24 kHz PCM16 (Vertex AI가 24 kHz로 오디오 반환)
- Server VAD는 800ms 침묵 임계값으로 기본 활성화
# session.update with server VAD — the proxy ignores this for Vertex AI
# because VAD is already configured in the initial setup message.
await ws.send(json.dumps({
"type": "session.update",
"session": {
"modalities": ["audio"],
"turn_detection": {"type": "server_vad", "silence_duration_ms": 800},
},
}))
도구 호출
import asyncio
import json
import websockets
PROXY_URL = "ws://localhost:4000/v1/realtime?model=vertex-gemini-live"
TOOLS = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a location.",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string"},
"unit": {"type": "string", "enum": ["fahrenheit", "celsius"]},
},
"required": ["location"],
},
},
}
]
def get_weather(location: str, unit: str = "fahrenheit") -> dict:
return {
"location": location,
"temperature": 72 if unit == "fahrenheit" else 22,
"unit": unit,
"conditions": "sunny",
}
TOOL_FUNCTIONS = {"get_weather": get_weather}
async def main():
async with websockets.connect(
PROXY_URL,
additional_headers={
"Authorization": "Bearer sk-",
"X-Serverless-Authorization": "Bearer sk-",
},
) as ws:
_ = json.loads(await ws.recv()) # session.created
# Required for tool calling: send tools in session.update
await ws.send(
json.dumps(
{
"type": "session.update",
"session": {
"instructions": "Use get_weather for weather questions.",
"modalities": ["audio"],
"tools": TOOLS,
},
}
)
)
await ws.send(
json.dumps(
{
"type": "conversation.item.create",
"item": {
"type": "message",
"role": "user",
"content": [
{"type": "input_text", "text": "What's the weather in San Francisco?"}
],
},
}
)
)
await ws.send(json.dumps({"type": "response.create"}))
async for raw in ws:
ev = json.loads(raw)
t = ev.get("type", "")
if t == "response.text.delta":
print(ev.get("delta", ""), end="", flush=True)
elif t == "response.function_call_arguments.done":
fn_name = ev.get("name", "")
call_id = ev.get("call_id", "")
args = json.loads(ev.get("arguments", "{}"))
result = TOOL_FUNCTIONS[fn_name](**args)
await ws.send(
json.dumps(
{
"type": "conversation.item.create",
"item": {
"type": "function_call_output",
"call_id": call_id,
"output": json.dumps(result),
},
}
)
)
await ws.send(json.dumps({"type": "response.create"}))
elif t == "response.done":
print("\n[done]")
break
elif t == "error":
print(ev)
break
if __name__ == "__main__":
asyncio.run(main())
구성 + 실행
model_list:
- model_name: vertex-gemini-live
litellm_params:
model: vertex_ai/gemini-live-2.5-flash-native-audio
vertex_project: your-gcp-project-id
vertex_location: us-central1
litellm_settings:
# Required for tool calling with Gemini/Vertex Live:
# defer setup until client sends session.update (with tools)
gemini_live_defer_setup: true
litellm --config config.yaml --port 4000
python test_realtime_tool_calling.py
지원되는 OpenAI Realtime 이벤트
클라이언트 → Proxy (→ Vertex AI):
| OpenAI 이벤트 | 비고 |
|---|---|
input_audio_buffer.append |
realtime_input.audio로 전달 |
conversation.item.create |
realtime_input.text로 전달 |
session.update |
조용히 무시 — Vertex AI는 세션 중 재구성을 지원하지 않음 |
response.create |
조용히 무시 — Vertex AI가 각 턴 후 자동으로 응답 |
Vertex AI → Proxy (→ 클라이언트):
| 내보내는 OpenAI 이벤트 | Vertex AI 소스 |
|---|---|
session.created |
setupComplete 후 합성 |
response.text.delta |
serverContent.modelTurn.parts[].text |
response.audio.delta |
serverContent.modelTurn.parts[].inlineData |
response.audio_transcript.delta |
serverContent.outputTranscription.text |
conversation.item.input_audio_transcription.completed |
serverContent.inputTranscription.text |
response.done |
serverContent.turnComplete |
제한 사항
session.update는 전달되지 않음 (Vertex AI는 연결당 하나의 setup 메시지만 허용)- 오디오 전사에는 초기 setup에서
outputAudioTranscription: {}를 설정해야 함 (LiteLLM이 자동 수행)
주의 사항
- 도구 호출은
tools가 있는session.update에 의존 session.update를 건너뛰면 도구 호출이 트리거되지 않음gemini_live_defer_setup은 하위 호환을 위해 기본값false
더 알아보기 (Learn more)
- Gemini Live API 문서
- LiteLLM Realtime API