
圖說:簡單問候自然聆聽,真正複雜時才進入思考
前十四天一路談嘴型、微動、素材與表情仲裁,今天終於要拆解一個最能說明「功能有動,不等於角色自然」的真實 Bug。
每次我用文字或語音問墨寒,系統顯示「墨寒思考中」時,她幾乎都會固定切成同一組轉頭思考圖片。問複雜規劃也就算了,連一句早安、普通寒暄都像遇到千古難題。表面看來,程式只是很盡責地告訴我正在等待;實際感受卻像演員每次聽見場記喊「準備」就做同一個表情。
「墨寒思考中」本來是一段系統狀態,意思是請求已送出、回答尚未回來。它應該幫助使用者知道程式沒有當機。
問題在於舊邏輯把進入等待狀態和播放 thinking_front 綁在一起。只要送出 API 請求,就立刻換圖。程式沒有先問問題難不難、等待多久,也沒有確認 AI 是否真的表示需要斟酌。
換句話說,網路流程冒充了角色心理。這正是根因,不是思考圖片本身不好,也不是把動畫延遲零點幾秒就能根治。
這次我沒有只說「降低思考表情出現率」,而是先列出不能觸發的原因:不能只因送出 API、進入等待、顯示狀態文字,就直接播放思考;一般聊天與短暫等待應維持目前自然表情,或在較長敘述時使用中性聆聽。
真正允許思考的情境則比較有限:問題有明顯分析、比較、權衡與規劃內容;等待確實超過合理門檻;AI 回覆的內部情緒標籤明確指定 thinking;或她在語意上真的不確定、需要斟酌。
這些規則讓 Codex 不再猜「少一點」是多少,而能建立可檢查的等待計畫。
修正後,一句「早安,墨寒」或普通問題,在正常回覆時間內不安排任何特殊表情,角色維持原本狀態。較長但不一定複雜的敘述,可以在等待一小段時間後使用中性聆聽;包含分析、比較、風險、優先順序等明顯斟酌內容的問題,才可能在超過可感知延遲後出現思考。
另外設有真正的長等待門檻。即使問題本身普通,如果 API 很久沒有回覆,角色在數秒後露出思考神情也符合情境。重點是表情由「內容與實際等待」決定,不由狀態文字決定。
這些秒數不是永遠不可改的真理,而是可測量、可調整的起點。使用後如果仍太頻繁,可以調整門檻,不必再到每一條 API 路徑拆觸發碼。
墨寒有文字、非 Realtime 語音與 Realtime 三條主要對話路徑。非 Realtime 語音轉成文字後會進入一般文字佇列,所以它只顯示思考狀態時,同樣不能直接換表情。
Realtime 自己有即時事件與說話狀態,不使用一般等待排程。開始播放回答時,要取消先前可能存在的標準等待,立刻交給說話嘴型;回答停止後再回到合適待機。若只修文字按鈕,語音入口仍可能每次轉頭,Bug 就只是換地方出現。
API 失敗也很重要。失敗時要讓舊計時器全部失效,先清掉等待表情,再依錯誤情境顯示擔心或回復待機。否則幾秒後某個已排程的舊動作突然執行,墨寒會在錯誤訊息出現後又轉頭思考。
即使符合條件,思考表情仍要經過昨天的仲裁器。它有自己的冷卻時間,正在顯示同一張圖時拒絕重複啟動,短時間連問兩個慢問題也不會連播同一姿勢。
等待表情的來源優先權較低,不能蓋過安全警告、正式提醒或使用者直接指定的高優先反應。當回答真正開始,說話狀態接手;回答附有明確 thinking 內部標籤時,則由回答情緒路徑處理,而不是等待計時器猜測。
這樣「思考」終於回到一種情緒,而不是 API 呼叫的載入圖示。
我們把最容易重現的情境逐一寫進測試:早安不換圖、普通問題在正常時間不換圖、複雜問題延遲後才思考、普通問題超過長等待門檻可思考、同一表情受冷卻阻擋、API 失敗清理舊計時器、非 Realtime 轉錄不因狀態文字換圖、Realtime 開始說話取消等待並進入口型。
另外保留一條重要規則:如果 AI 回覆最後帶有合法的 thinking 情緒標籤,說完後仍可呈現思考,因為那是回答內容明確提出的情緒,不是等待狀態誤觸。
我也會從 Realtime 切回一般語音,再改用文字連續詢問,確認切換本身不會留下舊的等待世代。這正是過去最容易漏掉的地方:每條路單獨測都正常,前一條路的計時器卻在下一條路中突然醒來。
如果未來調整模型或網路層,只要仍透過這個共同等待規則,就不必再複製一套表情判斷。這也是移除舊觸發邏輯的意義:保留單一來源,讓下一次維護不會把 Bug 帶回來。
自動測試證明的是路徑與時間規則;我還會實際連續問候、問普通問題、故意問複雜規劃並模擬延遲,感受表情頻率是否像人。兩邊都過,才算真正修好。
這次 Bug 最值得記住的,不是某個計時器數字,而是:系統正在等待,不代表角色正在苦思。 UI 狀態與人物情緒看似相近,卻必須由不同來源負責。
明天 Day 16,我會把範圍再放大。即使每個動作單獨正確,呼吸、滑鼠視差、說話與表情同時作用,角色仍可能抽動;我們怎麼讓所有動作聽同一位指揮?
本篇規則已涵蓋文字、一般語音與 Realtime 的等待交接;實際 API 延遲仍受網路與服務環境影響。