iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
AI Engineering

從對話到照護:30 天打造高齡智慧健康 AI Companion系列 第 8 篇

Day 08|別等 AI 說完:加入 Barge-in 即時打斷

  • 分享至 

  • xImage
  •  

昨天完成 Streaming Voice Pipeline 之後,AI Companion 已經不用等整段回覆生成完成才開始說話,而是可以一邊接收 LLM 產生的內容,一邊進行 TTS 與播放。

不過實際對話時,我又發現另一個很明顯的問題:

如果 AI 已經開始說話,但使用者突然想插話,怎麼辦?

目前的系統只要進入播放狀態,就會持續把 Playback Queue 裡面的語音播完。即使使用者已經開始講下一句話,AI 還是可能繼續說自己的內容。

這種情況在一般文字 Chatbot 裡不太明顯,但到了語音互動就會變得很不自然。

因此今天要加入的功能,就是 Barge-in。


什麼是 Barge-in?

Barge-in 可以理解成:

AI 說話的過程中,允許使用者直接插話並打斷 AI。

真實的人類對話其實不會嚴格按照:

A 說完
↓
B 說完
↓
A 再說

有時候對方講到一半,我們就已經知道他想說什麼,因此會直接接話。

例如 AI 說:

好的,那我幫你整理今天的健康狀況,
首先你今天早上提到……

但使用者突然說:

等一下,我想先問別的。

理想情況下,AI 應該立刻停止原本的語音,重新進入 Listening 狀態,而不是把前面的回答全部播完。

因此 Barge-in 對即時語音系統來說,是非常重要的一部分。


Barge-in 的核心流程

今天先把流程設計成:

AI Speaking
↓
User Speech Start
↓
VAD Detect
↓
Stop Playback
↓
Clear Playback Queue
↓
Cancel TTS / LLM
↓
Listening
↓
STT
↓
重新回答

原本 VAD 主要用來判斷:

Speech Start
Speech End

也就是使用者什麼時候開始講話,以及什麼時候停止。

今天則進一步讓 VAD 在 AI Speaking 狀態下仍然持續監聽麥克風。

如果 AI 正在播放語音,但 VAD 又偵測到新的 Speech Start,就把它視為一次可能的 Barge-in。


偵測到使用者插話後,要停止的不只是播放器

一開始我原本以為只需要:

player.stop()

就可以完成打斷。

但真正串起 Streaming Pipeline 後才發現,事情沒有這麼簡單。

因為 Day 07 的流程其實是:

LLM Streaming
↓
Sentence / Chunk Buffer
↓
TTS
↓
Playback Queue
↓
Speaker

即使目前播放中的聲音停止了,後面的 LLM 可能還在繼續產生 Token,TTS 也可能正在生成新的 Audio Chunk。

如果只停止播放器,就可能變成:

目前聲音停止
↓
過一下子
↓
下一個 Audio Chunk 又開始播放

這顯然不是真正的打斷。

所以偵測到 Barge-in 後,目前會依序做:

Stop Playback
↓
Clear Playback Queue
↓
取消尚未完成的 TTS
↓
中止目前的 LLM Streaming
↓
切換回 Listening

這樣才能把整條上一輪的 Response Pipeline 停掉。

這也讓我更明顯感受到,Streaming 系統裡每個模組其實不是獨立的。

只要其中一個地方沒有正確取消,就可能產生舊資料繼續流進後面的問題。


最大問題:AI 自己的聲音也會被麥克風聽到

加入 Barge-in 後,很快遇到另一個問題:

VAD 怎麼知道麥克風收到的是使用者的聲音,還是 AI 自己正在播放的聲音?

如果直接使用筆電的 Speaker 和 Microphone,AI 播放的語音很可能又被麥克風收進去。

這時 VAD 可能判斷:

偵測到語音!

然後系統就誤以為使用者正在插話,自己把自己打斷。

比較完整的語音系統通常會進一步使用 AEC(Acoustic Echo Cancellation),將 Speaker 播放的聲音從麥克風訊號中消除。

不過第一版我先沒有把系統做到這麼複雜,而是先利用幾個條件降低誤觸。

例如:

Energy Threshold
最短語音持續時間
Cooldown

不是只要收到一點聲音就立刻觸發 Barge-in,而是要求聲音強度超過一定 Threshold,並且持續一小段時間。

另外,在 AI 剛開始播放的極短時間內也加入 Cooldown,避免 Speaker 剛出聲就馬上被判定成使用者插話。

這些方法還不是最完整的 Echo Cancellation,但已經可以讓第一版 Demo 穩定很多。


今天新的延遲指標

Day 06 我開始使用:

Speech End → First Audio

來衡量使用者說完話後,要等多久才能聽到 AI 開始回答。

Day 08 則加入另一個指標:

User Speech Start → AI Audio Stop

也就是:

使用者開始插話之後,AI 要多久才真的停止說話?

如果這個時間太長,即使系統最後有成功停止,使用者還是會覺得 AI 「搶話」。

因此 Barge-in 的重點不只是:

能不能停止

而是:

能不能夠快速停止

實作時我會分別記錄 VAD 偵測到 Speech Start 的時間,以及播放器真正停止的時間,再計算兩者之間的差距。

這個指標之後也可以拿來比較不同 VAD Threshold、Audio Buffer 與 Playback Queue 設定所造成的影響。


第一版 Barge-in Demo

目前完成的第一版效果是:

使用者說話
↓
AI 開始 Streaming 回答
↓
AI 正在說話
↓
使用者突然插話
↓
VAD Detect Speech Start
↓
AI 停止播放
↓
清除剩餘 Audio
↓
停止原本 LLM / TTS
↓
重新 Listening
↓
辨識新的語音
↓
產生新的回答

也就是從原本:

AI 一定要把話說完

變成:

AI 可以被使用者自然地打斷。

雖然只多了一個「停止」功能,但對實際對話體驗的影響其實非常大。


今天遇到的問題

今天最大的問題是:

怎麼判斷真的有人在插話,而不是 AI 聽到自己的聲音?

如果 Barge-in 太敏感,AI 很容易自己把自己打斷。

但如果 Threshold 設得太高,又可能出現使用者明明已經講話,AI 卻還繼續說的情況。

另外還有:

VAD Threshold 要設多少?
Speech Start 要持續多久才算有效?
Playback Queue 要怎麼安全清除?
正在執行的 TTS 如何取消?
LLM Streaming 中途取消後如何避免 Token 繼續進入 Buffer?

這些問題也讓我發現,即時語音系統除了「速度」之外,狀態管理與取消機制其實同樣重要。


Day 08 完成

Day 07 解決的是:

AI 能不能更早開始說。

Day 08 解決的則是:

AI 能不能在該停的時候馬上停。

目前整個語音互動開始從單純的:

說一句 → 等待 → AI 回一句

逐漸變成更接近真實對話的:

聽
↕
說
↕
插話
↕
重新理解

到了這裡,AI Companion 已經可以做到基本的即時語音互動。

不過目前每一輪對話仍然比較像獨立事件。

如果希望它真的變成一個長期陪伴系統,下一步就不能只讓 AI 「聽得到」,還需要讓它:

記得以前發生過什麼。

下一篇 Day 09,就開始加入 Memory。


上一篇
Day 07|讓 AI 邊生成邊說:打造 Streaming Voice Pipeline
下一篇
Day 09|讓 AI 開始記得你:建立第一版 Memory
系列文
從對話到照護:30 天打造高齡智慧健康 AI Companion 共 9 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言