我把一份合成測試資料裡兩個人的名字整組對調,再算一次說話者分群的錯誤率。結果是 0。
不是 0.1,不是接近 0,是 0。名字全錯,指標說沒問題。
這不是指標壞掉。後來發現,它本來就不是拿來回答「這個人叫什麼」的。
第 10 天把整理後的文字帶回指定字幕片段和影音時間窗。找得到位置,不代表聽得對;聽得對,也不代表知道是誰說的。多人會議或訪談,永遠多這一題。
第 5 天碰過一次,那時只做到不把「說話者可能判錯」藏起來。今天要往前一步,實際檢查:一個像 speaker_0 這樣的匿名標記,要具備哪些證據,才有資格變成名字、具名引言、待辦負責人。
| 天數 | 已回答的問題 | 不在那一天處理的事 |
|---|---|---|
| Day 5 | 怎麼保留原始轉錄、說話者標記、不確定性與人工複核點 | 沒有建立身分綁定與下游放行規則 |
| Day 10 | 整理後文字能不能回到指定字幕片段與時間窗 | 沒有確認說話者姓名 |
| Day 11 | 匿名分群怎麼升級成綁定特定版本的身分,以及哪些具名輸出可以放行 | 不判斷訊號是否新鮮,也不替來源主張做外部查證 |
Day 5 守住的是不把未知藏掉。Day 11 要做的,是讓未知真的改變後面能輸出什麼。
全文只回答一個問題:
一個匿名說話者標記,要具備哪些證據、而且綁在哪一份轉錄產物上,才可以升級成姓名、具名引言或待辦負責人?
我把它拆成四個判定。前一層通過,只讓下一層開始檢查,不會連姓名、引言和責任一起放行。下面講。
一場會議錄音進來,系統做的第一件事是把聲音分桶:這段和那段聽起來像同一個人,丟同一桶。桶子上只有編號,cluster_0、cluster_1,沒有名字。
第二件事,是猜每個桶可能是誰:比對聲紋、看聲道、聽自我介紹。產生的是候選,不是答案。
第三件事,是有人真的確認:這桶就是某某人,而且要記下確認的是哪一版時間軸。錄音重切過,舊的確認不能直接沿用。
第四件事,才是決定可以拿這個名字做什麼。匿名時間軸、姓名標記、具名引言、待辦負責人,需要的證據不一樣。
| 判定層 | 回答什麼 | 最小輸出 | 不能順便證明 |
|---|---|---|---|
| 匿名分群 | 哪些時間段看起來屬於同一個聲音? | cluster_id 與時間段 |
這個人叫什麼名字 |
| 身分候選 | 這個群組可能對應哪個已知人物? | 候選、證據參照、匹配狀態 | 候選已經由人確認 |
| 身分綁定 | 誰核准哪個群組對到哪個人物?核准又綁在哪一版產物? | confirmed、對照摘要、來源摘要、核准紀錄 |
原話聽得正確或可以公開 |
| 下游放行 | 這份證據足以輸出匿名時間軸、姓名、具名引言,還是待辦負責人? | allow、needs-human 或 reject |
缺少的文字忠實、公開授權與責任證據 |
只存一個 confidence 不夠。每一層都要留自己的證據、狀態和失敗原因。不然下游看到一個 0.92,不知道它是在說聲音分對了、名字猜對了,還是有人確認過了。
這四層是我替這條產線畫的分法,不是任何供應商或標準組織的共同規格。但「不同任務要分開評」有先例:NIST 在 2007 年的會議辨識評測(RT-07)就把語音轉文字、回答「誰在何時說話」的說話者分段歸群,以及把兩者結合的具說話者歸屬文字,列成三個不同任務。時間段分群通過,還不能替文字內容和真實身分一起背書。
這條線在真實工具的文件裡也看得到。
第 5 天講過 ElevenLabs 的 logprob 是字詞的對數機率,不是說話者信心。這裡只補一句:字有沒有聽對、說話者有沒有分對、名字有沒有綁對,是三個問題,logprob 只回答第一個。
今天真正要看的是另外幾個選項。它們各管一件事,沒有一個是姓名證據:
▸ 多聲道模式會關掉說話者分群,直接用聲道編號產生 speaker_0、speaker_1,每個聲道各自轉錄。前提是一個聲道只有一個人,最多五個聲道。同一聲道混進兩個人,兩人會共用同一個標記。聲道給的是穩定的聲音來源位置,channel_0 仍然不是誰的身分證。
▸ use_speaker_library 預設是關的。開了分群之後,才會把偵測到的說話者拿去比對工作區登錄過的聲音。這給的是候選,仍要保留設定、來源版本和確認狀態。
▸ detect_speaker_roles 只是把標記換成客服與客戶這類角色,不能和多聲道一起用。
▸ diarization_threshold 調的是「一個人被拆成兩個」和「兩個人被合成一個」之間的取捨。它不是姓名可信度的門檻。
pyannoteAI 的文件把這條線畫得更直接:分群產生 SPEAKER_00 這種通用標記;身分辨識再拿已知聲紋去配對特定人物。官方明說聲紋只用來找人,不會讓分群變準。建立聲紋時要求音訊裡只有目標說話者,最長 30 秒。
所以身分這一層,至少多出兩個來源問題:聲紋從哪來?誰確認它綁到哪個人?
信心分數也是分開給的。pyannoteAI 提供取樣點層級的分群信心、發言段落層級的分群信心,以及聲紋對群組的身分辨識信心。文件特別提醒:身分辨識信心衡量的是聲紋有多相符,不是分群器對這段屬於哪個群組有多確定。
這些分數是 0 到 100 的刻度,文件沒有說它是校準後的機率。所以它適合拿來排順序:先複核哪一段。它不適合當真相的機率。2024 年 Chowdhury 等人的研究就在做這件事:把分段信心交給後續處理,優先挑出可能有問題的片段。這支持一個很窄的結論,信心可以決定先看哪裡;它不能單獨把候選名字升級成已確認。
回到開場那個結果。名字全錯,錯誤率為什麼還是 0?
先講 DER,說話者分段錯誤率。它把三種時間加起來:誤接(沒人說話卻標了)、漏接(有人說話沒標到)、混淆(標到別人)。再除以參考語音的總時間。
差別在算之前那一步。pyannote.metrics 會先用匈牙利演算法(一種標準的最佳配對算法),替參考標記和預測標記找最佳的一對一對應,然後才計算。
用改考卷來比喻:它會先看你的答案卡,幫你把每個選項對到最像的正解,再算你錯幾題。
所以 cluster_0 改叫 cluster_1,它不在意。person_alpha 和 person_beta 整組對調,它也會跟著把對應對調。時間分群沒變,DER 就是 0。
這是設計,不是 bug。DER 回答的是「時間怎麼切」,本來就不該被匿名標記叫什麼影響。
要看名字對不對,得換一把尺。說話者身分錯誤率 IER 的分子一樣有誤接、漏接和混淆,差別在混淆這一項直接比參考和預測的身分標記,不先重新配對。名字對調,每一秒都算混淆。
這把尺有個前提:參考答案本身要可信。合成資料有標準答案,所以算得出來。真實會議如果沒有獨立核實過的名字,公式算不出真相。
先交代輸入。這次沒有拿任何私人會議當測試資料。
測試資料只有四段時間:0 到 10 秒是 person_alpha,10 到 20 秒是 person_beta,接著兩人各再出現一次,總長 40 秒。系統側用 cluster_0 和 cluster_1 表示兩個匿名群組。
這份資料明示為合成:沒有音訊、沒有逐字稿、沒有真實姓名、沒有重疊語音、沒有漏接或誤接。它不是聲學實驗,不能拿來推論任何模型、語言、麥克風或真實會議的準確率。
稽核器只測兩件事:匿名標記換名字時,分群指標會不會改;姓名對照被換掉或沿用到新版產物時,控制層會不會停止具名輸出。
| 變異 | DER | IER | 控制結果 |
|---|---|---|---|
| 原始匿名分群 | 0 | 不適用 | 最佳映射找到兩組正確時間 |
| 匿名標記交換 | 0 | 不適用 | 指標不受標記字串影響 |
| 姓名交換 | 0 | 1 | 有標準答案時可看出身分全錯 |
| 核准後只交換姓名表 | 不適用 | 不適用 | reject:approved-binding-digest-mismatch |
| 來源產物換版後沿用舊核准 | 不適用 | 不適用 | stale:source-artifact-mismatch |
姓名交換那一列,兩把尺要並排讀:DER 是 0,IER 是 1。40,000 毫秒全部變成身分混淆。
本機程式依 pyannote.metrics 4.1 文件的公式實作受限版本:兩人、無重疊、完整覆蓋。我另外裝固定版 pyannote.metrics 3.2.1,在 collar=0、計入重疊的設定下獨立重算,結果一樣是 0、0、0、1(評分範圍用參考與預測的聯集近似,不是官方 UEM 檔)。這份資料本來就沒有重疊,所以設定不影響結果。
後兩列不是指標題,是控制題。核准之後只把姓名表換掉,判定是 reject;來源產物換了版本卻沿用舊核准,判定是 stale。
老實說,這五列擺在一起很像一張成績單。但它們不能合成一個總分。前兩列驗的是分群對標記字串不敏感;第三列需要可信的身分標準答案;後兩列只驗核准內容和來源版本是否仍然一致。
實驗做完,我把「身分綁定」需要的最小資料形狀整理出來。這是本文的提案,不是 ElevenLabs、pyannote、NIST 或任何 RFC 的官方格式,也不是我現行流程已經接上的東西。
{
"source_artifact_sha256": "…",
"cluster_id": "cluster_0",
"person_ref": "person_alpha",
"identity_status": "confirmed",
"evidence_refs": ["synthetic-reference-v1"],
"binding_sha256": "…",
"approval_record_ref": "…"
}
每個欄位有一個工作:
▸ source_artifact_sha256 鎖定這張姓名表適用哪一版說話者時間軸。
▸ cluster_id 保留供應商或分群器給的匿名標記,不覆蓋。
▸ person_ref 指向另外管理的人物參照,不直接塞真名。
▸ identity_status 不只放「通過」,還要能表示候選、未知、拒收、過期。
▸ binding_sha256 是姓名表的摘要,要存到另一個地方的核准收據裡:不同權限、不同人能改的系統。跟姓名表放在同一個目錄、改完自己重算一次,就不算核准過。
這次跑出來的關係長這樣:說話者時間軸摘要是 1748d313…c6c8,核准姓名表摘要是 2e81dde7…0e58。收據分開保存後,正式對照得到 approved-binding-current。只把兩個 person_ref 對調,姓名表摘要就變了,舊收據拒收。把時間軸改成第二版,姓名表完全不動,也會因為來源摘要不同被標成過期。
真正要保存的是這條鏈:
特定版本的匿名時間軸
→ 姓名對照內容
→ 獨立核准收據
→ 允許的下游輸出
有個細節容易漏。JSON 物件的鍵順序、空白不同,語意可能一樣,位元卻不同。同一張姓名表,只是換了鍵的順序,就會得到不同的摘要。
RFC 8785 定義的 JSON Canonicalization Scheme 就在解決這件事:固定基本型別的序列化、遞迴排序屬性、用 UTF-8 輸出。這次程式只對受限資料做遞迴鍵排序,沒有宣稱完整通過 JCS 所有邊界。
固定表示只讓摘要可以重算。它不能證明 person_ref 填的是對的人。
這裡算了兩個 SHA-256:一個辨認說話者時間軸的版本,一個辨認已核准的姓名表。核准後姓名表被換掉,或來源產物換版卻沿用舊核准,摘要都會不同。
但如果人一開始就認錯人,那張錯的姓名表也能得到一個完全合法的摘要。摘要只認位元有沒有變,不認內容對不對。它不是數位簽章,不是身分證明,不是人工判斷的正確性,也不是公開授權。
要抓「一開始就認錯」,需要獨立的身分證據,或再做一次人工核實。再算一次雜湊沒有用。
最後一層,決定這個名字可以拿去做什麼。
| 輸出 | 最小條件 | 本次結果 |
|---|---|---|
| 匿名時間軸 | 有可用分群結果 | allow |
| 具名說話者標記 | 身分綁定已核准,且來源版本仍相同 | allow |
| 具名引言 | 再加文字忠實確認與公開授權 | needs-human |
| 待辦負責人 | 再加明確的責任指派內容與人工批准 | needs-human |
「某人說了這句」不等於「這句每個字都聽對」,也不等於「某人接受了這個待辦」。
具名引言要再加文字忠實確認和公開授權。這次沒有人工聽校,也沒有授權紀錄,稽核器給的理由是 transcript-fidelity-unchecked 和 publication-permission-unknown,所以停在 needs-human。待辦負責人要再加明確的責任指派內容和人工批准,理由是 responsibility-evidence-missing 和 human-assignment-approval-missing。
摘要模型如果只看到姓名和句子,很容易把這三個判定壓成同一個肯定句:某某說他會處理。看起來很順,其實一次跨了三層。
放行條件是本文的設計。真實組織要依用途、授權和風險自己調。
小實驗最怕寫大。下面這張表,是今天最重要的誠實邊界。
| 問題 | 這次能否抓到 | 需要什麼 |
|---|---|---|
| 匿名標記只改名字 | 不視為錯誤 | DER 的最佳一對一映射 |
| 有可信標準答案時,兩個姓名交換 | 可以 | 直接比較身分標記,IER = 1 |
| 核准後姓名表遭修改 | 可以 | 不同信任邊界保存的核准摘要 |
| 舊姓名表套到新版時間軸 | 可以 | 目前來源摘要與核准來源摘要 |
| 人工一開始就認錯人 | 不行 | 獨立身分證據或再次人工核實 |
| 重疊語音、漏接、誤接與真實聲學誤差 | 沒有測 | 有標註的公開音訊、固定評分條件與正式指標實作 |
完整性檢查不能冒充身分真實性檢查。
之後真的要測語音模型,AMI Meeting Corpus 是一條可以公開重現的路:約 100 小時會議,有個別頭戴式麥克風、混音與遠場訊號,還有逐位說話者的人工逐字稿。可以固定官方資料切分、交界寬容區、是否計入重疊,同時報 DER 和 IER。今天沒有下載或跑 AMI,只留這條路線。它是英文語料,部分參與者非母語,公開模型也可能看過這些資料,不能直接外推到臺灣華語的私人會議。
1/ 不做 ElevenLabs、pyannote 或其他工具的準確率排行榜。
2/ 不提出適用所有錄音的通用分群或身分門檻。
3/ 不公開任何私人會議的音訊、逐字稿、人名、引言、聲紋或商業資訊。
4/ 不替自己聲明聲紋蒐集、保存、同意或法規做法。
5/ 不把「某人說了」擴張成「某人說的是真的」;外部主張補證留到 Day 13。
6/ 不把整條內容產線改寫成多代理編排;通用編排留到 Day 16。
身分還沒確認,工作流不必整條停掉。匿名時間軸可以繼續往下走;姓名、具名引言、責任欄位先停。
這樣會少一些具名產出。
Day 12 把同一個原則帶到每日情報:固定時間到了,卻沒有足夠新訊號時,系統能不能老實輸出「今天沒有題目」,而不是把日期不明或昨天的內容包裝成今天的新消息?