실시간 음성을 한 줄로 엽니다 — 오늘은 ADK LiveRequestQueue부터 붙이십시오 | DAKER 커뮤니티

해커톤·데모 앱에 음성을 붙일 때, 많은 팀이 먼저 음성 인식 → 모델 → 음성 합성 파이프라인을 이어 붙입니다. 각 단계가 끝나야 다음이 시작되므로, 짧은 침묵만 생겨도 대화가 끊긴 것처럼 느껴집니다. Google Cloud Tech 채널의 「Build a real-time voice AI agent with Google ADK and Gemini Live API」에서는 이 구조를 전화 통화형 연결로 바꿉니다. 오늘은 그 핵심인 한 줄로 열린 양방향 스트림과 ADK의 LiveRequestQueue를 정리하고, 참가자가 바로 적용할 첫 작업을 남깁니다.

실시간 음성을 한 줄로 — ADK LiveRequestQueue

왜 파이프라인이 실시간에서 약해지는가

채팅 UI에서는 한두 초의 대기도 받아들일 수 있습니다. 사용자는 입력 버튼을 누른 뒤 답이 오기를 기다립니다. 음성은 다릅니다. 상대가 말을 멈춘 뒤에도 침묵이 이어지면, 연결이 끊긴 것처럼 느껴집니다. 영상은 이 차이를 분명히 합니다. 기존 파이프라인은 무전기에 가깝고, Gemini Live API가 제공하는 형태는 전화에 가깝습니다. 마이크 오디오와 모델 음성이 같은 연결 위에서 동시에 흐릅니다.

이 구분은 해커톤 심사·데모 데이에서도 중요합니다. 데모 중에 사용자가 「잠깐, 그거 말고」라고 끼어들었을 때, 파이프라인형 앱은 이미 생성된 음성을 끝까지 재생하거나, 다음 STT 구간을 기다리느라 반응이 늦습니다. 라이브 연결형 앱은 interrupted 이벤트로 재생을 즉시 끊을 수 있습니다. 참가자가 체감하는 「살아있는 대화」는 모델 크기보다 이 연결 모양에서 갈립니다.

영상이 바꾸는 실무

발표자 Annie는 실시간으로 대화하고 요청을 받는 비디오 DJ 에이전트를 예로 듭니다. 사용자는 중간에 끼어들 수 있고, 에이전트는 요청을 받아 동작을 이어 갑니다. 핵심은 모델을 더 크게 키우는 것이 아니라, 연결의 모양을 바꾸는 일입니다.

브라우저에는 마이크·스피커·플레이어가 있습니다. 작은 백엔드가 WebSocket으로 브라우저와 붙으며, 그 안에서 Agent Development Kit(ADK)가 Gemini Live와 대화합니다. 왼쪽에 사용자 기기, 가운데에 백엔드, 오른쪽에 Gemini Live가 있는 한 장의 구조도만 기억해도 이후 코드 위치가 헷갈리지 않습니다.

ADK에서 에이전트를 나누는 방식

영상은 ADK 구성을 세 덩어리로 설명합니다. 이 분리를 지키면 「모델 호출 코드」와 「오디오 전송 코드」가 한 파일에 섞이는 일을 줄일 수 있습니다.

해커톤 참가자에게 바로 쓸 수 있는 문장은 이렇습니다. 에이전트는 설정으로 정의하고, 실행은 Runner에 맡기며, 라이브 음성의 세션은 메모리에 둡니다. 도구를 늘리기 전에 이 세 자리가 코드에 분리되어 있는지부터 확인하십시오.

LiveRequestQueue가 막는 충돌

브라우저가 수 밀리초마다 마이크 조각을 보내고, Gemini Live도 같은 속도로 음성을 돌려보냅니다. 한쪽이 멈추면 다른 쪽까지 멈추면 안 됩니다. ADK의 LiveRequestQueue가 이 두 방향을 분리합니다. 업스트림은 브라우저에서 큐로, 다운스트림은 이벤트로 브라우저로 돌아갑니다. 영상은 이를 컨베이어처럼 한쪽으로 올리고 다른 쪽에서 꺼내는 구조로 설명합니다.

서버는 사실상 두 개의 병렬 작업이 됩니다. 하나는 클라이언트 메시지를 받아 큐에 올리는 일이고, 다른 하나는 모델 이벤트를 받아 브라우저에 돌려주는 일입니다. asyncio 같은 동시성 도구로 두 작업을 함께 돌리는 패턴은 Google Cloud의 ADK·Live 가이드에서도 같은 방향으로 설명합니다. 공개 본문에는 외부 URL을 넣지 않으니, 구현 세부는 공식 문서에서 확인하십시오.

입력을 넣는 방법도 둘로 나뉩니다.

규칙만 기억하면 됩니다. 계속 흐르는 것은 send_realtime, 끝난 덩어리는 send_content입니다. 마이크 루프의 모든 청크는 WebSocket에서 큐로 바로 send_realtime에 올립니다.

이벤트로 반응하는 라이브 루프

Runner의 run_live를 큐에 연결하면 풀듀플렉스 세션이 열립니다. 돌아오는 것은 한 번에 끝나는 답이 아니라 이벤트 흐름입니다. 영상에서 다루는 대표 이벤트는 다음과 같습니다.

한 문장을 따라가면 흐름이 선명해집니다. 「드림팝 틀어 줘」라고 말하면 마이크 청크가 WebSocket으로 백엔드에 가고, 업스트림이 send_realtime으로 큐에 올리고, Runner가 Gemini Live에 넘깁니다. 음성 감지 후 이벤트가 내려와 음성·자막·재생 명령이 나갑니다. 사용자가 중간에 말하면 interrupted가 오고 재생이 멈춥니다. 이것이 영상이 말하는 전체 동작입니다.

다음 에피소드에서는 도구 호출로 앱을 실제로 제어하는 단계를 다룹니다. 오늘은 「말하기」와 「끼어들기」가 안정적인지부터 확인하는 편이 안전합니다. 도구를 먼저 붙이면, 지연의 원인이 모델인지 큐인지 도구인지 구분이 어려워집니다.

참가자가 오늘 할 일

제목의 다음 행동은 이것입니다. 오늘은 기능 목록을 늘리기 전에 LiveRequestQueue부터 붙이십시오.

  1. 데모·제출 앱에서 음성 경로가 STT→모델→TTS로 직렬인지 확인합니다. 직렬이면 라이브 연결로 바꿀 후보입니다.
  2. 백엔드에 ADK Agent(모델·지시문·도구)와 Runner, 인메모리 Session을 둡니다. 세션 저장소를 먼저 원격으로 두지 마십시오.
  3. 브라우저↔백엔드를 WebSocket으로 유지하고, 마이크 청크를 send_realtime으로 큐에 올립니다. 무음 구간도 끊지 않습니다.
  4. run_live 이벤트에서 음성 재생·자막·interrupted를 먼저 처리합니다. 사용자가 말하는 즉시 재생이 멈추는지 팀원이 교차 확인합니다.
  5. 통과한 뒤에만 도구(재생 목록, 검색, 앱 버튼)를 추가합니다. 영상도 도구는 다음 편으로 미룹니다.

체크리스트를 이슈 한 줄로 남기면 팀 병합·데모 전날에 다시 쓰기 쉽습니다. 「LiveRequestQueue + 인메모리 Session + interrupted 처리 완료」가 오늘의 완료 조건입니다.

다른 각도와의 차이

최근 커뮤니티에는 관리형 에이전트, 파일 검색 도구, 전사 API처럼 「무엇을 붙일까」에 초점을 둔 글이 있었습니다. 이 영상은 「어떻게 실시간으로 열어 둘까」에 초점을 둡니다. 같은 에이전트라도, 채팅형 요청-응답과 라이브 음성형은 전송 계층이 다릅니다. 해커톤에서 음성 데모를 넣는 팀은 기능 목록보다 전송 계층을 먼저 고정하는 편이 안전합니다.

공식 문서와 에피소드 코드는 Google Cloud Tech 영상 설명과 Gemini Live API·ADK 문서에서 확인할 수 있습니다. 공개 본문에는 외부 링크를 넣지 않습니다. 영상 제목과 채널명만 인용합니다.

구현 시 자주 생기는 오해

첫 번째 오해는 「음성 품질만 올리면 체감이 좋아진다」입니다. 품질이 좋아도 직렬 파이프라인이면 끼어들기 반응이 늦습니다. 두 번째 오해는 「세션을 원격에 두면 장애 복구가 쉬우니 처음부터 원격이 맞다」입니다. 영상은 라이브 음성 경로에서 청크마다 네트워크 기록이 쌓이는 비용을 지적합니다. 복구 전략은 데모 안정화 이후에 설계해도 늦지 않습니다. 세 번째 오해는 「말할 때만 오디오를 보내면 대역폭을 아낀다」입니다. send_realtime에서는 무음도 문장 끝 판별에 필요합니다.

팀 내에서 역할을 나눌 때는 프론트(마이크·재생·WebSocket), 백엔드(큐·Runner·이벤트 매핑), 에이전트 설정(지시문·도구)으로 나누면 충돌이 줄어듭니다. 한 사람이 전부 맡더라도, 폴더를 이 세 층으로 나누어 두면 나중에 도구를 추가할 때 수정 범위가 작아집니다.

데모 스크립트에 넣을 검증 문장

심사자나 팀원에게 보여줄 때 아래 순서를 그대로 말하면 전달이 쉽습니다.

  1. 「지금은 인식-생성-합성을 기다리지 않고, 한 연결에서 양방향으로 오디오가 흐릅니다.」
  2. 「제가 말하는 중에도 에이전트 음성을 끊을 수 있습니다.」라고 말한 뒤, 실제로 끼어들어 interrupted를 보여 줍니다.
  3. 「요청은 도구로 넘기고, 대화는 끊지 않습니다.」는 도구를 붙인 뒤에 추가합니다. 오늘은 1·2만으로도 충분합니다.

이 세 문장은 슬라이드보다 시연이 중요합니다. 시연이 실패하면 아키텍처 설명이 아무리 정확해도 설득력이 떨어집니다. 그래서 오늘의 완료 조건을 기능 수가 아니라 큐·세션·interrupted로 고정한 것입니다.

관련 자료 읽는 순서

영상을 본 뒤 공식 자료를 볼 때는 순서를 단순화하십시오. 먼저 Gemini Live API 개요에서 양방향 스트림과 지원 모델 개념을 확인하고, 이어서 ADK로 Live를 시작하는 가이드에서 Agent 정의와 스트리밍 실행을 확인합니다. 그다음 에피소드 코드로 브라우저-백엔드 WebSocket과 큐 연결을 대조합니다. 공개 커뮤니티 글에는 링크를 넣지 않으니, 검색어로는 영상 제목과 「Google ADK」「Gemini Live API」를 함께 쓰면 됩니다.

가격·할당량·리전 같은 수치는 이 글에서 적지 않습니다. 플랜과 시점에 따라 달라지므로, 제출 전에 콘솔과 공식 요금 페이지를 직접 확인하십시오. 이 글의 목적은 숫자 공지가 아니라, 참가자가 오늘 코드에 넣을 구조 한 줄입니다.

정리

실시간 음성은 모델을 더 많이 호출하는 문제가 아니라, 한 줄로 열린 양방향 스트림을 유지하는 문제입니다. Google Cloud Tech의 이 영상은 Agent·Runner·Session·LiveRequestQueue로 그 줄을 ADK 안에서 어떻게 나누는지 보여 줍니다. 해커톤·쇼케이스·데모 데이 전에, 오늘은 큐와 인메모리 세션부터 붙이고, 끼어들기(interrupted)가 재생을 바로 끊는지 확인하십시오.

참고 영상: Build a real-time voice AI agent with Google ADK and Gemini Live API · 채널 Google Cloud Tech

#ADK #GeminiLive #실시간음성 #해커톤 #잡담