语音 Agent 最难的不是听懂,而是知道什么时候闭嘴:打断、确认与超时的实战指南
语音 Agent 最难的不是听懂,而是知道什么时候闭嘴:打断、确认与超时的实战指南
语音 Agent 最像真人的瞬间,不是它说得多聪明,而是你一开口,它就知道该停。很多语音 Agent 的识别率已经不低,回答也算准确,可用户聊上几轮,还是会产生一种强烈冲动:赶紧挂电话。
问题通常不是“没听懂”,而是“不会轮流说话”。
| 失败版本 | 优化版本 | | Agent:好的,我将为您介绍目前的套餐,第一种是—— | Agent:好的,我将为您介绍目前的套餐,第一种是—— | | 用户:等一下,我想先改地址。 | 用户:等一下,我想先改地址。 | | Agent:——每月包含100GB流量,并且…… | Agent:[立即停止播放] |
| 用户:你先停一下! | Agent:可以。您要修改哪个订单的地址? |
| Agent:抱歉,没有听清,请再说一遍。 | |
这组对话里,用户的话可能每个字都被正确识别了,但系统仍然失控:TTS继续播放,模型继续生成,麦克风甚至可能把扬声器里的声音再次识别成用户输入。
真正决定语音体验的,是下面四个判断:
1. 什么时候开始回答;
2. 什么时候停止回答;
3. 什么时候必须确认;
4. 等待多久后应该回退。
一句“请自然地与用户交流”,解决不了这些问题。因为 Prompt负责制定行为政策,音频层和状态机才负责执行政策。
一、让Agent真正可打断,而不是假装听见用户
用户在Agent说话时开口,系统不能只把新语音转成文字,还必须完成一条完整链路:
检测用户语音 → 判断是否有效插话 → 停止TTS → 取消生成 → 清空旧音频 → 处理最新意图
少任何一步,都可能出现“嘴上答应停,旧回答却又从缓冲区里冒出来”的情况。
不是所有声音都应该触发打断
实时场景中至少有三类输入:
- 真实插话:“等一下”“我想改地址”“不是这个订单”;
- 环境声音:咳嗽、电视声、旁人讲话、碰撞声;
- 反馈词:“嗯”“对”“好的”“你继续”。
如果检测到一点声音就立即停止,Agent会变得过度敏感;如果一定要等ASR输出完整句子,又会停得太晚。
更稳妥的方法是分层处理:
1. 短促声音出现时,进入“候选打断”状态,必要时降低播放音量;
2. 持续语音达到业务设定阈值后,暂停TTS;
3. 识别到新需求、纠正或停止意图后,取消当前生成;
4. 如果只是“嗯”“对”等反馈词,则恢复或继续播放。
具体时长不能照抄固定答案。电话线路、会议麦克风、车载环境和智能音箱的噪声条件完全不同,必须用真实录音调整。
async function onUserSpeechDetected(event) {
if (event.durationMs < BARGE_IN_THRESHOLD) return;
// 1. 停止用户当前能听见的输出
audioPlayer.stop();
// 2. 取消仍在生成的模型回复
currentGeneration?.abort();
// 3. 清空尚未播放的旧音频
ttsBuffer.clear();
conversationState = "USER_SPEAKING";
}
Prompt则负责规定“停下来之后怎么做”:
打断规则:
1. 用户开始表达新需求时,立即停止当前回答。
2. 不要重复被打断前已经说完的内容。
3. 优先处理用户最新一句话;新旧任务冲突时,以新任务为准。
4. “嗯”“好的”“你继续”等简短反馈默认不是新任务。
5. 无法判断是插话还是回应时,用一句短问题确认。
需要特别注意:Prompt不能直接关闭扬声器,也不能清空TTS缓冲区。模型再“听话”,底层没有停止播放和取消请求能力,Agent依然闭不上嘴。
二、确认不是越多越安全,而是要看出错代价
另一个常见误区,是让Agent复述用户说过的每一句话。
用户说:“帮我查一下明天的天气。”
Agent回答:“您是想查询明天的天气,对吗?”
这种确认没有增加多少安全性,反而多制造了一轮等待。更糟的是,过度确认会让用户随口说出“嗯”“行”,系统却未必知道这究竟是在确认哪个字段。
合理原则是:按照不可逆性和纠错成本确认,而不是逢输入必复述。
| 场景 | 风险等级 | 是否确认 | 推荐方式 | |---|---:|---|---| | 查询天气 | 低 | 通常不需要 | 直接回答 | | 修改称呼 | 低 | 不需要完整确认 | 自然接续 | | 输入地址 | 中 | 确认歧义字段 | “是16栋还是10栋?” | | 预约日期 | 中 | 确认日期与时段 | 局部总结 | | 下单、付款 | 高 | 必须确认 | 总结关键参数后执行 | | 删除数据 | 高 | 必须确认 | 明确说明操作后果 |判断是否需要确认,也不能只看模型自己的“信心”。还要同时检查:
- ASR识别置信度是否偏低;
- 当前结果是否与上下文冲突;
- 手机号、日期、金额等字段格式是否有效;
- 操作是否可撤销;
- 出错后用户需要付出多大纠错成本。
例如,ASR把“十五”识别成“五十”,文本本身可能很通顺,模型未必觉得可疑。但如果上下文中用户刚说过“预算不超过二十元”,系统就应该发现冲突并局部确认。
确认规则:
- 普通问答和可随时撤销的操作,不复述用户原话。
- 姓名、手机号、地址、日期、金额存在歧义时,只确认歧义字段。
- 付款、下单、删除、提交等不可逆操作,执行前总结关键参数并获得明确同意。
- 用户纠正某个字段后,只更新并确认该字段。
- 每次确认尽量控制在一句话内。
高效确认应该像真人对话:“门牌号是1608,对吗?”而不是每次都从“请问您刚才是否说……”开始。
三、沉默不是异常,不要用统一超时粗暴催促
很多系统只设置一个“无响应超时”,这是语音交互中最容易埋雷的设计之一。
以下沉默看起来相似,含义却完全不同:
- 用户还没开始说,可能正在思考;
- 用户说到一半停顿,可能在回忆门牌号;
- 用户分段报手机号,尚未结束;
- Agent提问后,用户去查看订单;
- 工具调用没有返回,用户其实正在等系统。
如果这些情况共用一个超时,Agent就会频繁抢话:“请问您还在吗?”
更合理的方式,是为不同状态设计渐进式回退:
第一次:“我在,您可以慢慢说。”
第二次:“您是在确认送货地址,还是想修改地址?”
第三次:“如果现在不方便,我们可以稍后继续,或者为您转人工。”
function onListeningTimeout(timeoutCount) {
if (timeoutCount === 1) {
return speak("我在,您可以慢慢说。");
}
if (timeoutCount === 2) {
return speak("您想继续当前操作,还是换一个问题?");
}
return speak("我们可以稍后继续,或者现在转人工。");
}
这不是把某个固定秒数奉为标准,而是改变回退逻辑:第一次不施压,第二次缩小范围,第三次提供出口。
尤其要禁止两种行为:用户刚停顿就抢答,以及每次超时都完整重复原问题。
四、用状态机管理“现在轮到谁说”
下面这张状态机图,可以作为语音Agent编排层的基础框架:
flowchart TD
L[Listening] -->|持续语音达到阈值| U[User Speaking]
L -->|首次等待超时| T[Timeout]
T -->|用户重新开口| U
T -->|连续超时| H[Handoff / Exit]
U -->|短暂停顿| U
U -->|端点确认| K[Thinking]
U -->|噪声或无有效文本| L
K -->|生成简短回复| A[Agent Speaking]
K -->|高风险操作| C[Confirming]
C -->|用户明确同意| K
C -->|用户纠正字段| U
C -->|取消操作| L
A -->|有效插话| I[Interrupted]
A -->|简短反馈词| A
A -->|播放结束| L
I -->|停止TTS、取消生成、清空缓冲区| U
这张图的价值在于,它把“自然对话”从形容词变成了可执行规则。
例如,系统处于 AGENT_SPEAKING 时,检测到“嗯”不一定要转入 INTERRUPTED;检测到“等一下,我要改地址”,则必须完成状态切换,并停止旧任务。
五、一份可以直接改的System Prompt
你是一个实时语音助手。你的首要目标是让对话自然、简短、可打断,
而不是一次性输出完整答案。
【回复节奏】
- 默认每次只说1~3句话。
- 先给当前最必要的信息,等待用户回应后再补充。
- 不要使用长段落、复杂列表或连续解释多个主题。
【用户打断】
- 用户提出新问题、纠正信息或要求停止时,立即放弃当前回复。
- 优先处理用户最新意图,不要继续完成旧回答。
- 被打断后不要从头重复已经说过的内容。
- “嗯”“对”“好的”“你继续”等简短反馈通常表示继续,不要改变任务。
【复述确认】
- 低风险信息不确认。
- 姓名、地址、日期、金额等关键字段存在歧义时,只确认歧义部分。
- 付款、下单、删除、提交等不可逆操作,执行前必须总结并获得明确同意。
- 用户纠正一个字段时,只更新该字段。
【沉默与超时】
- 用户短暂停顿时保持安静,不要立刻抢答。
- 首次超时只做简短提示。
- 再次超时时缩小问题范围或提供选项。
- 连续超时后提供退出、稍后继续或转人工选项。
- 不要连续重复同一句问题。
【无法判断时】
- 使用一句简短问题确认。
- 不要自行补全关键事实。
- 不要用长篇道歉占用对话时间。
它能约束回复长度、确认方式和打断后的语言行为,但还需要音频层与编排层配合。
六、别靠“听起来不错”,用对抗测试验证
上线前,至少测试以下八个场景:
1. Agent说到一半,用户改变需求;
2. 用户只说“嗯”“对”“你继续”;
3. 用户报地址时出现较长停顿;
4. 背景中出现电视声或他人说话;
5. ASR把“十五”识别成“五十”;
6. 用户纠正一个字段后再次插话;
7. 工具调用长时间无返回;
8. 用户连续沉默,但没有明确退出。
建议记录这些指标:
- 打断响应延迟:有效插话开始到TTS真正停播的时间;
- 误打断率:噪声、咳嗽和反馈词导致错误停播的比例;
- 漏打断率:用户明确插话但Agent没有停止的比例;
- 平均确认次数:完成一项任务需要确认多少次;
- 端点误判率:用户没说完,Agent就开始回答的比例;
- 超时恢复率:提示后用户重新进入对话的比例;
- 任务完成率与人工转接率。
没有真实项目数据时,不要写“体验提升XX%”。可以先用统一语料做三组对照:
| 测试方案 | 打断延迟 | 误/漏打断 | 确认次数 | 端点误判 | 任务结果 | | 仅优化Prompt | 记录实测值 | 记录实测值 | 记录实测值 | 记录实测值 | 完成/失败 | | Prompt+状态机 | 记录实测值 | 记录实测值 | 记录实测值 | 记录实测值 | 完成/失败 | | Prompt+状态机+音频层 | 记录实测值 | 记录实测值 | 记录实测值 | 记录实测值 | 完成/失败 |调试时还应保留音频时间轴、AGENT_SPEAKING → INTERRUPTED → USER_SPEAKING 状态日志、取消生成记录和TTS缓冲区清理记录。很多问题只听最终录音很难定位,日志却能直接告诉你:到底是没检测到插话,还是检测到了却没停播。
Prompt是行为政策,不是实时控制器。
结语:好的语音Agent,先学会让出发言权
回到开头的场景,真正有效的优化并不是让Agent说一句更长的道歉,而是让它完成三个动作:
立刻停播、放弃旧回答、处理最新需求。打断解决“什么时候停”,风险确认解决“什么时候问”,渐进式超时解决“什么时候等”和“什么时候退出”。四层能力缺一不可:
- 音频层负责听见插话;
- 编排层负责切换状态;
- Prompt层负责决定怎么回应;
- 评估层负责证明方案真的有效。
想验证这套策略,不必一开始就搭建完整电话系统。可以先到 api.884819.xyz 接入适合的模型,用同一组对抗测试分别运行“默认Prompt”和“节奏控制Prompt”,记录回复长度、确认次数、超时回退表现,以及插话后的意图处理结果。
8848AI平台注册只需要用户名和密码,不需要邮箱验证;没有月租和订阅,按量付费,平台内置AI对话,注册后即可使用,Deepseek、千问等国产模型完全免费。
新用户注册即送体验token。建议先测试三个场景:中途改需求、关键字段纠错、连续沉默。文本策略稳定后,再接入VAD、TTS停播和生成取消能力。
好的语音Agent不是永远知道该说什么,而是知道何时停、何时问,以及何时承认自己没听清。
但Agent学会闭嘴之后,下一道难题才真正出现:用户说“不是15号,是50号”时,旧字段应该保留、覆盖,还是全部作废?
下一篇,我们将拆解语音Agent的短期记忆、字段更新与上下文清理,解决那个更隐蔽的问题——嘴上说改好了,执行时却仍然使用旧地址。
本文由8848AI原创,转载请注明出处。关注8848AI,带你从零开始学AI。#语音Agent #AI教程 #Prompt技巧 #智能客服 #大模型应用 #人工智能 #8848AI