실시간 음성 에이전트를 빌드할 때 일부 함수 호출이 모델의 실행을 차단하여 오디오 스트림이 조용해지고 사용자가 조용히 기다리게 될 수 있습니다. Gemini Live API를 사용하면 모든 함수 호출이 기본적으로 차단되지 않으므로 기본 대화 흐름과 병렬로 함수를 실행할 수 있습니다. 이 프로세스를 비동기 함수 호출이라고 합니다. 모델이 계속해서 듣고, 말하고, 사용자와 자연스럽게 대화하는 동안 백엔드에서 실시간 항공편 가격 검색이나 복잡한 외부 API 쿼리와 같은 무거운 작업을 백그라운드에서 처리할 수 있습니다. Gemini Live API를 사용하면 함수 호출이 백그라운드에서 처리되어 사용자와 모델 간의 상호작용이 중단되지 않으므로 더 유연한 실시간 상호작용이 가능합니다.
비동기 함수 호출을 사용하면 대화를 일시중지하지 않고 약속 예약, 알림 설정, 데이터 가져오기와 같은 작업을 완료할 수 있습니다. 예를 들어 사용자가 항공편 예약을 요청하고 백그라운드에서 예약이 처리되는 동안 즉시 날씨 정보를 요청할 수 있습니다.
비동기 함수 호출의 예
이 예시에서는 사용자가 항공편을 예약하고 뉴욕 시간을 묻는 동안 book_ticket 함수가 백그라운드에서 비동기적으로 실행됩니다.
User: Please book the 2:00 PM flight to New York for me.
Model: function_call: {name: "book_ticket"}
//(The "book_ticket" function call is sent to the client.)
//(Right after the "book_ticket" function call is received, the client sends a text message to the model: "repeat this sentence 'I'm booking your ticket now, please wait.'")
//(The client runs the function call asynchronously in the background.)
Model: I'm booking your ticket now, please wait.
User: What is the current time in New York?
Model: The current time in New York is 12:00pm.
//(Once the book_ticket function finishes, the client sends the result.)
Function_response: {name: "book_ticket", response: {booking_status: "booked"}}
Model: Your flight has been booked. Expect a confirmation text on your phone within 5 minutes.
비동기 함수 호출 구현
이 섹션에서는 Python 버전의 에이전트 플랫폼 SDK를 사용하여 Gemini Live API의 비동기 함수 호출 기능을 사용하는 응답성이 뛰어난 동시 아키텍처를 빌드하는 일련의 예를 제공합니다. 예는 다음 작업으로 분류됩니다.
도구 정의
비동기 함수 호출은 모델 수준에서 사용 설정되므로 Gemini Enterprise 에이전트 플랫폼 호출에서 표준 Gemini API와 마찬가지로 요청 구성에서 사용할 도구를 지정할 수 있습니다. 이렇게 하면 도구가 실행되는 동안 모델이 계속 대화할 수 있습니다.
from google import genai
from google.genai import types
# 1. A tool that takes a long time to execute
search_live_flights = {
"name": "search_live_flights",
"description": "Searches airlines for current flight prices. Can take up to 10 seconds."
}
# 2. A tool that executes instantly
get_current_weather = {
"name": "get_current_weather",
"description": "Gets the current weather for a given city."
}
tools = [{"function_declarations": [search_live_flights, get_current_weather]}]
메시지 스트림에서 함수 호출 처리
모델이 하나 이상의 함수를 호출해야 하는 경우 Gemini Live API는 실시간 메시지 스트림을 통해 tool_call 이벤트를 전송합니다.
모델이 계속 실행되기를 기대하므로 백엔드에서 스트림을 차단해서는 안 됩니다. 느린 함수 (예: search_live_flights)에 대한 호출을 수신하면 백그라운드 작업자에게 전달해야 합니다. 10초 태스크의 기본 메시지 루프에서 await를 직접 사용하면 연결이 중지됩니다. 빠른 작업 (예: get_current_weather)은 안전하게 기다릴 수 있습니다.
import asyncio
async def handle_stream(session):
async for response in session.receive():
# Check if the model is asking to use a tool
if response.tool_call is not None:
for fc in response.tool_call.function_calls:
if fc.name == "search_live_flights":
# Pass to a background task so we don't block the receive loop!
asyncio.create_task(background_flight_search(fc.id, fc.args, session))
elif fc.name == "get_current_weather":
# Instant lookups can be safely awaited directly
await instant_weather_lookup(fc.id, fc.args, session)
사용자 기대치 관리
장기 실행 비동기 함수 호출 중에 기대치를 관리하려면 클라이언트가 문자 메시지를 시작하는 것이 좋습니다. 이 메시지는 시스템에 요청이 처리되고 있음을 사용자에게 알리고 기다려 달라고 요청해야 합니다. 예를 들어 클라이언트가 함수 호출을 수신한 후 클라이언트는 모델에 '이 문장을 반복해 줘: '지금 티켓을 예약하고 있으니 잠시 기다려 주세요.''과 같은 문자 메시지를 보낼 수 있습니다.
다음 예시 대화상자에는 이 교환이 표시되어 있습니다.
User: Please book the 2:00 PM flight to New York for me.
Model: function_call: {name: "book_ticket"}
//(The "book_ticket" function call is sent to the client.)
//(Right after the "book_ticket" function call is received, the client sends a text message to the model: "repeat this sentence 'I'm booking your ticket now, please wait.'")
//(The client runs the function call asynchronously in the background.)
Model: I'm booking your ticket now, please wait.
User: What is the current time in New York?
Model: The current time in New York is 12:00pm.
//(Once the "book_ticket" function call finishes, the client sends in the response.)
Function_response: {name: "book_ticket", response: {booking_status: "booked"}}
Model: Your flight has been booked. Expect a confirmation text on your phone within 5 minutes.
이 선제적 메시지 전략에는 다음과 같은 이점이 있습니다.
- 장기 실행 함수 호출 중에 기대치를 관리하는 현재 시스템 작업을 사용자에게 알립니다.
- '여보세요?' 또는 '거기 계세요?'와 같은 중복된 짧은 사용자 프롬프트의 빈도를 줄입니다. 이러한 문제는 비동기 함수 호출이 처리되는 동안 시스템이 장시간 무음 상태일 때 자주 발생합니다. 이렇게 하면 이러한 반복적인 사용자 문의로 인해 트리거되는 중복 함수 호출의 위험을 최소화할 수 있습니다.
- 추가 시스템 프롬프트를 제공하면 후속 상호작용에서 중복 호출이 생성될 가능성을 낮출 수 있습니다.
중복 함수 호출 처리
첫 번째 호출에 대한 응답을 받기 전에 모델이 중복된 함수 호출을 생성할 가능성은 낮습니다. 사용 사례에서 허용하는 경우 동일한 함수 호출에 대한 응답이 아직 대기 중이면 애플리케이션이 중복 함수 호출을 무시할 수 있습니다.
다음 예는 클라이언트가 중복 함수 호출을 무시하는 방법을 보여줍니다.
User: Please book the 2:00 PM flight to New York for me.
Model: function_call: {name: "book_ticket"}
//(The "book_ticket" function call is sent to the client. It is running asynchronously in the background.)
User: What is the current time in New York?
Model: The current time in New York is 12:00pm. + function_call: {name: "book_ticket"}
//(The duplicated "book_ticket" can be ignored by the client since the response for the first "book_ticket" has not been sent to the model yet.)
//(The first "book_ticket" function call finishes, and client sends in the response.)
Function_response: {name: "book_ticket", response: {booking_status: "booked"}}
Model: Your flight has been booked. Expect a confirmation text on your phone within 5 minutes.
비동기 함수 응답 처리
비동기 함수 호출이 완료되면 애플리케이션은 function_response에서 결과를 모델에 전송합니다. 백엔드에서 항공편 검색과 같은 함수 호출을 처리하는 동안 사용자가 모델에 '런던 날씨는 어때?'와 같이 완전히 다른 질문을 할 수 있습니다. 모델은 함수 호출 실행과 동시에 요청에 실시간으로 응답합니다. 함수 실행이 완료될 때 사용자가 모델과 계속 상호작용하고 있을 수 있으므로 모델이 이 수신 응답을 처리하는 방법을 정의하는 정책을 지정할 수 있습니다. 다음 정책 중 하나를 지정할 수 있습니다.
정책을 지정하려면 function_response 페이로드에 scheduling 필드를 포함합니다.
{
"name": "book_ticket",
"scheduling": "WHEN_IDLE",
"response": {
"booking_status": "booked"
}
}
scheduling 필드를 생략하면 Gemini Live API는 하위 호환성을 위해 함수 응답을 처리하는 원래 메서드를 사용합니다.
다음 Python 예에서는 결과를 발표하기 전에 대화의 자연스러운 일시중지를 기다리기 위해 scheduling="WHEN_IDLE"을 사용하여 function_response을 포맷하고 전송하는 방법을 보여줍니다.
aearcync def background_flight_search(call_id, args, session):
# 1. Simulate a slow API call taking 5 seconds
await asyncio.sleep(5)
flight_data = ["Air Canada AC758: $350", "WestJet WS12: $290"]
# 2. Format the response
function_response = types.FunctionResponse(
id=call_id,
name="search_live_flights",
response={ "status": "success", "flights": flight_data },
scheduling="WHEN_IDLE" # Wait for a moment to tell the user
)
# 3. Send it back into the live session
await session.send_tool_response(function_responses=[function_response])
함수 응답을 관리하기 위해 scheduling 필드에 다음 정책을 지정할 수 있습니다.
SILENT 응답 정책
SILENT 정책을 사용하면 함수 응답이 모델의 컨텍스트에 추가되지만 모델은 이에 대한 응답을 생성하지 않으며 진행 중인 사용자 상호작용이 중단되지 않습니다.
User: Please book the 2:00 PM flight to New York for me.
Model: function_call: {name: "book_ticket"}
//(The book_ticket function call is sent to the client and starts running asynchronously in the background.)
User: What is the current time in New York?
Model: The current time in New York is 12:00pm.
//(The book_ticket function finishes, and client sends the result with scheduling: "SILENT".)
Function_response: {name: "book_ticket", scheduling: "SILENT", response: {booking_status: "booked"}}
//(The model doesn't generate a response for the function response.)
User: Is my flight ticket booked?
Model: Yes. Your flight has been booked.
WHEN_IDLE 응답 정책
WHEN_IDLE 정책을 사용하면 활성 사용자 상호작용이 없을 때만 모델이 함수 응답에 대한 응답을 생성합니다. 사용자 상호작용이 진행 중인 경우 모델은 중단을 방지하기 위해 상호작용이 완료될 때까지 기다린 후 응답을 생성합니다.
User: Please book the 2:00 PM flight to New York for me.
Model: function_call: {name: "book_ticket"}
//(The book_ticket function call is sent to the client and starts running asynchronously in the background.)
User: What is the current time in New York?
//(The book_ticket function finishes, and client sends the result with scheduling: "WHEN_IDLE".)
Function_response: {name: "book_ticket", scheduling: "WHEN_IDLE", response: {booking_status: "booked"}}
//(The ongoing interaction about the time is not interrupted.)
Model: The current time in New York is 12:00pm.
//(After responding to the user's time query, the model issues the response for the book_ticket function.)
Model: Your flight has been booked. Expect a confirmation text on your phone within 5 minutes.
인터럽트 응답 정책
INTERRUPT 정책을 사용하면 모델이 함수 응답에 대한 응답을 즉시 생성하여 진행 중인 사용자 상호작용을 중단합니다.
User: Please book the 2:00 PM flight to New York for me.
Model: function_call: {name: "book_ticket"}
//(The book_ticket function call is sent to the client and starts running asynchronously in the background.)
User: What is the current time in New York?
//(The book_ticket function finishes, and client sends the result with scheduling: "INTERRUPT".)
Function_response: {name: "book_ticket", scheduling: "INTERRUPT", response: {booking_status: "booked"}}
//(The ongoing interaction about the time is interrupted, and model skips responding to it.)
Model: Your flight has been booked. Expect a confirmation text on your phone within 5 minutes.
권장사항
- 동시성 설계: 항상 느린 도구 (예: 외부 API 쿼리 또는 RAG 파이프라인 실행)를 백엔드의 백그라운드 작업으로 오프로드합니다. 모델이 활성 오디오 스트림을 계속 처리하도록 합니다.
- 필요한 경우에만 인터럽트 사용: 중요한 알림에는
INTERRUPT를 사용합니다. 백그라운드 작업의 경우SILENT또는WHEN_IDLE를 사용하면 훨씬 더 원활하고 정중한 사용자 환경을 제공할 수 있습니다. - 독립적인 채팅 턴: Gemini Live API에서 도구 실행은 채팅 턴과 완전히 독립적입니다. 도구가 백그라운드에서 처리되는 동안 대화가 분기되고, 계속되고, 자연스럽게 이어질 수 있습니다.
- '무음' 주의사항:
SILENT로 예약된 경우에도 모델이 도구 실행을 구두로 설명하려고 시도할 수 있습니다. 완전한 무음을 적용하려면 시스템 안내에 명시적인 가이드라인을 추가하거나('[도구 이름]을 사용할 때는 무음 실행을 수행하고 아무 말도 하지 마세요' 등) 모델에FunctionResponse를 전혀 다시 보내지 않는 'fire-and-forget' 백엔드 패턴을 사용하세요.