Gemini Live API를 사용한 비동기 함수 호출

실시간 음성 에이전트를 빌드할 때 일부 함수 호출은 모델의 실행을 차단하여 오디오 스트림이 조용해지고 사용자가 침묵 속에서 기다리게 할 수 있습니다. 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.

비동기 함수 호출 구현

이 섹션에서는 Agent Platform SDK의 Python 버전을 사용하여 Gemini Live API의 비동기 함수 호출 기능을 사용하는 응답성이 뛰어난 동시 아키텍처를 빌드하는 일련의 예를 제공합니다. 예는 다음 작업으로 분류됩니다.

도구 정의

비동기 함수 호출은 모델 수준에서 사용 설정되므로 표준 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 예에서는 대화가 자연스럽게 일시중지될 때까지 기다린 후 결과를 알리기 위해 function_response scheduling="WHEN_IDLE"로 포맷하고 전송하는 방법을 보여줍니다.

async 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 응답 정책

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 피하기: 중요한 알림에 INTERRUPT를 사용합니다. 백그라운드 작업의 경우 SILENT 또는 WHEN_IDLE이 훨씬 더 원활하고 정중한 사용자 환경을 제공합니다.
  • 독립적인 채팅 차례: Gemini Live API에서 도구 실행은 채팅 차례와 완전히 독립적입니다. 도구가 백그라운드에서 처리되는 동안 대화가 분기되고 계속되고 자연스럽게 진행될 수 있습니다.
  • '자동' 주의사항: SILENT로 예약된 경우에도 모델이 도구의 실행을 가끔 구두로 설명하려고 시도할 수 있습니다. 완전한 자동을 적용하려면 시스템 안내에 명시적 가드레일을 추가하거나(예: '[도구 이름]을 사용할 때는 자동 실행을 실행하고 아무 말도 하지 마세요') FunctionResponse를 모델에 전혀 다시 전송하지 않는 'fire-and-forget' 백엔드 패턴을 사용합니다.

다음 단계

개요

Live API의 개요를 확인합니다.

참조

Live API 참조 가이드입니다.

가이드

Live API로 라이브 세션을 시작하고 관리하는 방법을 알아봅니다.

가이드

Live API의 Gemini 기능을 구성하는 방법을 알아봅니다.