How to Use the Gemini 3.8 Live API for Non-Blocking Voice Agents
Learn how to use the gemini-3.8-live model with ADK run_live to build non-blocking voice agents using AsyncGenerators and response scheduling.

Gemini 3.8 Live is Google's default model for low-latency, audio-to-audio voice agents as of September 2026. You use it with the Agent Development Kit (ADK) to run bidirectional voice sessions via run_live. To prevent the agent from going silent during long-running backend queries, you implement non-blocking tools using Python's AsyncGenerator.
If a user asks a question that triggers a 13-second database lookup, a standard blocking tool will freeze the conversation. By using AsyncGenerator to stream progress updates, ADK automatically marks the tool as NON_BLOCKING, allowing the model to acknowledge the request, narrate interim milestones, and deliver the final result when ready. In a benchmark sales-report workflow on gemini-3.8-live, switching from a blocking tool to a streaming tool cut the time to the agent's first words from 14.4 seconds to 1.2 seconds.
What is the Gemini 3.8 Live API#
The Gemini 3.8 Live API provides real-time, audio-to-audio interactions optimized for voice agents. The model supports interleaved reasoning, asynchronous function calling, full session client content updates, and built-in audio streaming. The input token limit is 131,072, and the output token limit is 65,536.
Google's models documentation states that gemini-3.8-live supports function calling and search grounding, but it does not support caching, code execution, file search, image generation, structured outputs, or URL context. It became generally available on September 15, 2026, replacing the legacy gemini-3.1-flash-live-preview model.
Why standard tools cause dead air#
In standard agent development, a tool is an async def function that completes its work and returns a single value. When passed directly to an Agent in ADK during a run_live bidirectional voice session, the execution loop awaits the tool's return before generating further model turns. If your function takes 13 seconds to fetch a sales report, the user hears 13 seconds of complete silence. Prompting instructions like "tell the user you are working on it" cannot resolve this because the model's turn is blocked waiting for the function response payload.
A web application that takes ten seconds to load is perceived as slow; a conversational voice agent that goes silent for ten seconds is perceived as broken. You cannot always make backend queries sub-second, especially when relying on RAG pipelines or external databases. The fix is architectural: decouple the tool execution from the conversation loop so the agent acknowledges the request immediately, continues talking, and delivers the result when the backend finishes.
Building a streaming tool with ADK#
When an operation consists of meaningful stages, a streaming tool lets the agent narrate progress as it happens. Turning a standard tool into a streaming tool requires changing only return to yield. By defining the function as an AsyncGenerator, ADK automatically marks the tool declaration as NON_BLOCKING and returns an immediate status acknowledgement to the model.
import asyncio
from typing import AsyncGenerator
from google.adk.agents import Agent
async def query_sales_database(region: str) -> AsyncGenerator[str, None]:
"""Runs the quarterly sales report. Call this ONCE; it pushes updates automatically.
Args:
region: Sales region to report on, e.g. "EMEA" or "APAC".
Yields:
Progress updates while the query runs, followed by the final summary.
"""
stages = [
("Connecting to the sales warehouse...", 1.5),
("Scanning order records...", 3.5),
("Aggregating revenue by product line...", 3.5),
("Formatting the report...", 1.5),
]
for message, delay in stages:
yield f"PROGRESS: {message}"
await asyncio.sleep(delay)
yield f"DONE: {region} Q2 revenue reached $4.81M, up 12.4% year over year."
agent = Agent(
name="sales_analyst",
model="gemini-3.8-live",
tools=[query_sales_database],
instruction=(
"You are a helpful sales assistant. When the user asks about sales data, "
"call query_sales_database once. Acknowledge the request immediately, "
"briefly paraphrase each progress update, and present the final figures "
"when completed. Keep answers conversational and concise."
),
)
To test the core logic of an AsyncGenerator without setting up the full ADK environment, you can run a standard Python script that consumes the generator. This demonstrates how the yields produce sequential updates without blocking the main event loop.
import asyncio
from typing import AsyncGenerator
async def mock_sales_query(region: str) -> AsyncGenerator[str, None]:
stages = [
("Connecting to the sales warehouse...", 0.05),
("Scanning order records...", 0.05),
("Formatting the report...", 0.05),
]
for message, delay in stages:
yield f"PROGRESS: {message}"
await asyncio.sleep(delay)
yield f"DONE: {region} Q2 revenue reached $4.81M"
async def main():
async for update in mock_sales_query("EMEA"):
print(update)
asyncio.run(main())
Controlling result delivery with response scheduling#
The response_scheduling attribute controls when the model reacts to an incoming tool response. ADK supports three scheduling behaviors: WHEN_IDLE, INTERRUPT, and SILENT.
Under WHEN_IDLE, an incoming tool result never cuts into a turn in progress. If the model is still speaking or the user is still talking, the result waits until that turn ends, and the model responds at the next natural pause. Under INTERRUPT, the incoming result cuts off current speech mid-sentence; the model then finishes its answer and appends the figures. Under SILENT, the result is added to the conversation history, available for subsequent turns without prompting an unrequested announcement.
Execution shape and delivery timing are independent and can be composed. Setting response_scheduling on a streaming tool stamps every partial update with that behavior. In ADK 2.8 and newer, streaming tools can dynamically specify scheduling per update by yielding types.FunctionResponse.
yield types.FunctionResponse(
response={"stage": "aggregating"},
scheduling=types.FunctionResponseScheduling.SILENT,
)
yield types.FunctionResponse(
response={"report": final_data},
scheduling=types.FunctionResponseScheduling.WHEN_IDLE,
)
If a user asks a simple question that takes two seconds to answer, WHEN_IDLE is polite and natural. If a critical alert arrives, such as a fraud detection trigger, INTERRUPT ensures the agent cuts off the current speech to deliver the alert immediately. SILENT is useful for background context updates where the model needs the data for a future turn, but the user does not need to hear it announced.
Migrating from gemini-3.1-flash-live-preview#
When migrating from gemini-3.1-flash-live-preview, update your model string to gemini-3.8-live. The Gemini 3.8 Live documentation notes that thinking_level is not supported; omit thinking_level or thinking_config from your session setup. Asynchronous execution with behavior: NON_BLOCKING is now the default function calling mode. You can still use synchronous blocking mode by setting behavior: BLOCKING on your tool declarations for backwards compatibility.
The send_client_content method is supported throughout the entire session lifecycle with explicit roles. Setting turn_complete=true unconditionally interrupts active model generation. If you send content without turn_complete, the server waits for subsequent messages before responding.
Affective dialogue is removed from the API. Remove any enable_affective_dialog configurations from your code. Proactive audio is now permanently enabled; setting proactive_audio: false returns an error. The default turn coverage is TURN_INCLUDES_AUDIO_ACTIVITY_AND_ALL_VIDEO, meaning video frames are sent to the model by default, so only send frames when needed to manage context and cost.
Costs and requirements#
To build with gemini-3.8-live, you need google-adk >= 2.10.0. Streaming tools and live scheduling require bidirectional live sessions via run_live. You also need an API key from Google AI Studio. If you are setting up your local environment, the Gemini API Python guide covers basic installation and chat streams.
Google's pricing page lists the Standard paid tier for gemini-3.8-live at $0.75 per 1M text input tokens, $3.00 or $0.005/min for audio input, and $1.00 or $0.002/min for image or video input. Output prices are $4.50 per 1M text tokens and $12.00 or $0.018/min for audio output. The free tier is available at no charge. Non-blocking tools do not reduce backend execution time; a 13-second query still takes 13 seconds. What changes is the conversational presence of your agent.
Gotchas and common mistakes#
Single-flight tool calls: Because streaming tools push updates across multiple turns, models may occasionally attempt to call the tool again if prompted repeatedly. Keep a clear "Call this ONCE" directive in your docstring, and consider implementing an in-memory latch or idempotency key in your tool implementation for production safety.
User cancellation: ADK provides a built-in escape hatch for long-running streaming tools. By including a function named stop_streaming(function_name: str) in your agent's tools list, ADK intercepts the call and cancels the generator's underlying asyncio.Task, raising asyncio.CancelledError within your function so you can cleanly close database connections or file handles.
User barge-in does not cancel tools: When the user talks over the agent, the Live API stops the model's output and ADK emits an event with interrupted=True so your client can stop audio playback. Running streaming or background tools are not cancelled, and their results are still delivered. To stop a tool, the model must call stop_streaming.
Structured outputs: gemini-3.8-live does not support structured outputs. If your backend requires strict JSON schemas, consider an alternative approach like the Claude Structured Outputs JSON Schema guide for tooling that enforces schema compliance.
Quick reference checklist#
- Model string:
gemini-3.8-live - Framework:
google-adk >= 2.10.0 - Use
AsyncGeneratorandyieldfor non-blocking tools. - Default scheduling is
WHEN_IDLE; useINTERRUPTfor urgent alerts. - Remove
thinking_levelandenable_affective_dialogfrom session setup. - Do not set
proactive_audio: false; it returns an error.
Quick answers
How much does the Gemini 3.8 Live API cost?
On the Standard paid tier, text input costs $0.75 per 1M tokens, and text output costs $4.50 per 1M tokens. Audio input costs $0.005 per minute, and audio output costs $0.018 per minute. A free tier is also available at no charge.
What are the requirements for the Gemini 3.8 Live API?
You need google-adk >= 2.10.0 and a Gemini API key. Streaming tools and live scheduling require bidirectional live sessions via run_live.
How do you use the Gemini app for voice agents?
You build voice agents using the Agent Development Kit (ADK) with the gemini-3.8-live model. ADK handles the bidirectional voice session and routes function calls through non-blocking tools.
Where should a Gemini live model be hosted?
The gemini-3.8-live model is hosted on Gemini Enterprise. You connect to it using ADK's run_live method.
Did this solve it?
One tap. No account.
Sorry about that. What was missing?
from 0 readers
Saved you an hour? Send a tip.
USDC or ETH on Base, Ethereum, Arbitrum and more. Keeps the notes free and the examples running.
Network
0xc783bc5c3fa14cEC3f09A22284bC91C5AF0d59e1
On a computer? Scan the code with your phone wallet, or copy the address.
Pick the network your wallet or exchange uses. USDC works on all six; ETH on Base, Ethereum, Arbitrum and Optimism. Don't send on Tron or Solana: this address doesn't exist there. Tips are optional and unlock nothing; every guide stays free.
Discussion
Start the discussion
Next note