教程
Gemini Live API 异步函数调用实战:实时语音 Agent 不再等待工具返回
实时语音 Agent 最容易被一个问题拖垮:模型说到一半需要查询 CRM、订单、数据库、搜索或工单系统时,如果工具调用采用阻塞模式,整个对话必须停下来等待外部系统返回。Google 在 Gemini Live API 的级联架构中支持异步函数调用,开发者可以把函数行为设置为 `NON_BLOCKING`,让模型在后台执行工具时继续保持会话。这并不意味着 Agent 可以无视工具结果继续“瞎说”,而是要求开发者重新设计对话状态、并发任务、超时、回写、打断和最终一致性。本文从实时语音架构出发,给出一套可直接用于客服、销售和助手类产品的异步工具调用方案。
# Gemini Live API 异步函数调用实战:实时语音 Agent 不再等待工具返回
## 文章摘要
实时语音 Agent 最容易被一个问题拖垮:模型说到一半需要查询 CRM、订单、数据库、搜索或工单系统时,如果工具调用采用阻塞模式,整个对话必须停下来等待外部系统返回。Google 在 Gemini Live API 的级联架构中支持异步函数调用,开发者可以把函数行为设置为 `NON_BLOCKING`,让模型在后台执行工具时继续保持会话。这并不意味着 Agent 可以无视工具结果继续“瞎说”,而是要求开发者重新设计对话状态、并发任务、超时、回写、打断和最终一致性。本文从实时语音架构出发,给出一套可直接用于客服、销售和助手类产品的异步工具调用方案。
---
## 一、为什么实时 Agent 最怕“工具等待”?
普通聊天用户可以接受几秒等待,语音对话不行。
一个自然的实时交互通常要求:
```text
用户说话
↓
AI 很快回应
```
如果每次查询 CRM、ERP、数据库、Web Search、工单、物流或支付系统时都出现数秒静默,用户会马上感觉系统“卡住了”。
这也是实时 Agent 和普通聊天机器人最大的工程差别之一。
## 二、传统阻塞式函数调用是什么样?
假设用户说:
> “帮我看一下昨天那个退款申请现在到哪一步了?”
传统流程:
```text
用户语音
↓
Live Model
↓
function_call: get_refund_status
↓
Agent 停止
↓
调用退款系统
↓
等待 4 秒
↓
返回结果
↓
模型继续回答
```
用户听到的体验可能是:
> “好的,我帮你查一下……”
>
> [静默 4 秒]
>
> “你的退款正在审核中。”
这就是阻塞式函数调用。
## 三、NON_BLOCKING 改变了什么?
Gemini Live API 的异步函数调用允许工具采用 `NON_BLOCKING` 行为。
概念上流程变成:
```text
用户请求
↓
模型发起工具调用
├── 后台执行工具
└── 对话继续
↓
工具结果返回
↓
模型获得结果
↓
补充或更新回答
```
于是模型可以先说:
> “我正在查询退款记录。顺便确认一下,你说的是尾号 3281 的订单吗?”
用户回答时,后台工具可能已经完成。
工具延迟不再必然等于对话停顿。
## 四、异步不等于可以编造结果
这是最重要的边界。
如果订单状态还没有返回,模型绝不能提前说:
> “退款已经完成。”
应用应该把信息分成三类:
```text
已知
等待中
未知
```
例如:
```text
已知:订单号、用户身份
等待中:refund_status
未知:到账时间
```
模型只能继续处理那些不依赖工具结果的部分。
## 五、哪些工具适合 NON_BLOCKING?
最适合的是只读、低风险、可以并行的查询工具。
例如:
- CRM 客户资料;
- 工单状态;
- 商品库存;
- 物流查询;
- 知识库补充;
- Web Search;
- 推荐数据;
- 历史订单。
多个独立查询也可以并行执行,例如:
```text
get_customer
get_recent_orders
get_open_tickets
```
## 六、哪些工具不适合简单 NON_BLOCKING?
支付、删除、生产变更以及任何会产生不可逆副作用的动作都不适合简单异步放行。
例如:
```text
charge_card
delete_account
deploy_production
create_refund
```
这些操作通常需要:
- 明确确认;
- 参数复核;
- 阻塞等待;
- 返回结果确认;
- 审计。
还有一类工具虽然是查询,但后续逻辑完全依赖它的结果,例如资格判断 `is_user_eligible`。如果结果没回来,就不能继续做最终决定。
## 七、推荐的实时 Agent 架构
可以设计为:
```text
Microphone
↓
Gemini Live Session
↓
Tool Router
├── Blocking Tools
├── Non-blocking Tools
└── Approval Tools
↓
Async Task Manager
├── timeout
├── retry
├── idempotency
└── cancellation
↓
Enterprise APIs
↓
Tool Result
↓
Live Session
```
同时还需要:
```text
Identity
Permission
Trace
Cost
Audit
```
## 八、工具元数据应该在业务层维护
不要让模型自己决定哪个工具是高风险。
例如查询工具:
```yaml
name: get_refund_status
mode: non_blocking
timeout_ms: 5000
retry: 1
idempotent: true
risk: read
requires_confirmation: false
```
退款创建工具:
```yaml
name: create_refund
mode: blocking
timeout_ms: 10000
retry: 0
idempotent: true
risk: financial
requires_confirmation: true
```
这类策略应该由应用和安全团队控制。
## 九、Gemini 端的核心概念
Google 的 Live API 支持在函数声明中指定行为。概念示意:
```python
tool = {
"function_declarations": [
{
"name": "get_order_status",
"description": "Get current order status",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string"}
},
"required": ["order_id"]
},
"behavior": "NON_BLOCKING"
}
]
}
```
实际字段应以当前 Gemini SDK 和 API 文档为准。
关键不是具体语法,而是工具调用不再强制整个 Live Session 停止。
## 十、应用层必须有 Async Task Manager
不要在 WebSocket 回调中直接同步调用外部 HTTP 接口。
可以采用:
```python
async def execute_tool(call):
task_id = create_task_id(call)
task = asyncio.create_task(
run_with_timeout(call)
)
registry[task_id] = task
```
工具完成后:
```python
async def on_tool_done(task_id):
result = await registry[task_id]
await send_tool_result_to_live_session(result)
```
这样语音流不会因为一个慢接口完全阻塞。
## 十一、每个工具都必须有 Timeout
外部系统延迟可能是:
```text
300ms
2s
8s
timeout
```
没有超时控制的异步工具会留下大量悬挂任务。
建议返回结构化状态:
```json
{
"status": "timeout",
"retryable": true,
"message": "CRM lookup did not complete"
}
```
然后由 Agent 决定如何向用户解释。
## 十二、超时后模型应该怎么说?
不要直接说“系统坏了”。
更好的话术是:
> “查询客户系统暂时有点慢,我可以先继续确认其他信息,结果出来后再补充。”
这正是异步调用改善体验的地方。
## 十三、并行工具调用要控制数量
用户说:
> “帮我总结这个客户最近发生了什么。”
Agent 可能想同时查:
```text
CRM
Orders
Tickets
Payments
Email
Analytics
```
不要无限并发。
建议设置:
```text
max_parallel_tools = 3
```
其余请求排队。
否则容易出现:
- API Rate Limit;
- 数据库压力;
- 成本失控;
- 返回顺序混乱;
- 状态难以管理。
## 十四、工具结果回来时如何重新注入对话?
每个调用必须保存:
```text
session_id
call_id
tool_name
arguments
started_at
conversation_turn
```
工具结果返回后:
```text
匹配 call_id
↓
确认 Session 仍有效
↓
判断结果是否仍相关
↓
发送回 Live Session
```
如果通话已经结束,不应该继续播放语音,可以把结果写入 CRM、会话摘要或者后续通知。
## 十五、用户改变话题怎么办?
实时语音里非常常见:
> “帮我查订单 A。”
工具开始。
随后用户说:
> “不用了,我说错了,是订单 B。”
如果工具支持取消,应取消 A。
如果无法取消,可以让任务后台结束,但标记为 `STALE`,不再把结果注入当前回答。
推荐状态机:
```text
PENDING
RUNNING
COMPLETED
TIMEOUT
FAILED
CANCELLED
STALE
```
## 十六、写操作必须使用幂等键
异步系统很容易出现:
```text
请求发出
↓
后台执行成功
↓
网络断开
↓
客户端以为失败
↓
重新调用
```
如果是 `create_ticket`,就可能创建两个工单。
所以写操作需要:
```text
idempotency_key
```
例如:
```text
session_id + call_id
```
服务端保证同一个调用只执行一次。
## 十七、用户打断 AI 时怎么办?
实时语音用户会自然插话。
Agent 正在说:
> “我正在查询——”
用户突然说:
> “等一下,我说错订单了。”
系统应该:
1. 停止当前语音输出;
2. 处理新输入;
3. 判断旧 Tool Task 是否还有意义;
4. 取消或标记 stale;
5. 根据新目标继续。
这也是实时 Agent 比普通 Chat Agent 更复杂的地方。
## 十八、Agent 在等待工具时可以做什么?
可以:
### 澄清
> “你说的是企业账户还是个人账户?”
### 收集信息
> “方便确认一下手机号后四位吗?”
### 解释流程
> “退款通常会经历审核和银行处理两个阶段。”
### 执行其他独立工具
例如订单状态在查,同时读取退款政策。
## 十九、等待期间不能做什么?
不能:
- 猜测工具结果;
- 承诺未确认事项;
- 说操作已经完成;
- 把“请求已提交”说成“业务已成功”。
建议在 System Prompt 中加入:
```text
Never state that a tool-dependent fact is confirmed
until the corresponding tool result is received.
```
## 二十、生产环境必须做权限校验
模型发出:
```text
get_customer_record
```
不代表它自动有权访问。
业务层仍然必须执行:
```text
User Identity
↓
Role
↓
Resource Permission
↓
Tool Permission
↓
Argument Validation
↓
Execute
```
否则实时 Agent 很容易变成越权查询入口。
## 二十一、敏感数据不要全部回传模型
如果 CRM 返回:
```json
{
"name": "...",
"phone": "...",
"address": "...",
"id_card": "...",
"bank_account": "...",
"order_status": "shipped"
}
```
用户只问订单状态,就只需要把 `order_status` 回给模型。
最小化模型看到的数据,是生产级 Agent 的基本原则。
## 二十二、如何做 Observability?
每个 Tool Call 建议记录:
```text
session_id
call_id
tool
mode
start
end
latency
status
retry_count
cancelled
token_usage
business_result
```
关键指标包括:
```text
Tool P50 / P95
Timeout Rate
Cancellation Rate
Parallel Tool Count
First Audio Latency
Conversation Silence Time
Task Success Rate
```
## 二十三、一个新指标:Conversation Silence Time
传统 API 只看后端 Latency。
实时语音 Agent 还要看用户实际经历了多久“没人说话”。
比如工具耗时 4 秒,但 AI 在等待期间继续澄清和解释,用户真正静默等待只有 0.8 秒。
这比单纯工具延迟更能反映真实体验。
## 二十四、客服场景示例
用户:
> “我的包裹为什么还没到?”
Agent:
> “我帮你查最新物流。方便确认一下,是昨天问过的那笔订单吗?”
后台同时执行:
```text
get_latest_order
get_shipping_status
```
用户:
> “对。”
Agent:
> “好的,我正在读取最新节点。跨省运输一般会经过分拨中心。”
工具返回后:
> “查到了,包裹今天凌晨已经到杭州分拨中心,预计今天下午进入派送。”
整个过程没有四秒完全静默。
## 二十五、销售场景示例
用户问:
> “这个客户最近是不是有续费风险?”
后台同时执行:
```text
get_contract
get_usage
get_tickets
```
Agent 可以继续问:
> “我正在汇总合同、使用量和工单。你这次更关心产品使用下降还是商务风险?”
用户给出方向后,工具结果也陆续返回,最终判断会更精准。
## 二十六、什么时候仍然应该 Blocking?
推荐原则:
### NON_BLOCKING
- 查询;
- 搜索;
- 丰富上下文;
- 独立后台分析。
### BLOCKING
- 后续逻辑必须依赖结果;
- 关键资格判断;
- 重要状态改变。
### APPROVAL
- 支付;
- 删除;
- 财务;
- 生产系统;
- 对外承诺。
## 二十七、推荐的工具分类
可以统一成:
```text
READ_FAST
READ_SLOW
WRITE_LOW_RISK
WRITE_HIGH_RISK
FINANCIAL
PRODUCTION
```
对应策略:
```text
READ_FAST → NON_BLOCKING
READ_SLOW → NON_BLOCKING + status
WRITE_LOW_RISK → confirm
WRITE_HIGH_RISK → BLOCKING + confirm
FINANCIAL → BLOCKING + strong approval
PRODUCTION → BLOCKING + multi-party approval
```
## 二十八、上线前测试清单
### 网络
- 慢响应;
- Timeout;
- 断线;
- 重连。
### 工具
- Success;
- Fail;
- Duplicate;
- Out-of-order。
### 用户
- 插话;
- 改需求;
- 取消;
- 长时间沉默。
### 安全
- 越权;
- Prompt Injection;
- 敏感字段;
- 高风险工具。
### 业务
- 最终状态正确;
- 不重复执行;
- 不虚假承诺。
## 总结
Gemini Live API 的异步函数调用解决的是实时 Agent 一个非常实际的问题:
> **工具慢,不应该等于对话也必须停。**
通过 `NON_BLOCKING`,开发者可以把查询型工具放到后台执行,同时让 Agent 继续澄清、收集信息、解释流程和处理其他独立任务。
但这要求更成熟的工程设计,包括 Async Task Manager、Timeout、Cancellation、Call ID、幂等、Tool State、并发限制、权限、敏感数据过滤和 Observability。
最重要的原则是:
> **Agent 可以在等待工具时继续交流,但不能在工具返回之前假装已经知道结果。**
这条边界做好以后,实时语音 Agent 才会真正从“会说话的聊天机器人”升级为能在真实业务系统中边交流、边工作的实时 Agent。
想继续了解 Gemini API、实时语音 Agent、Function Calling 和生产级 AI 工程实践,可以访问 **智元选**:https://www.zyentorpicks.com/。我们会持续发布可直接落地的 AI 开发内容。