Claude Code 的翻譯 pipeline 加了一個流暢度關卡 — 參考 Andrew Ng 的 reflection pattern

外部審查在 zh-TW 翻譯裡抓到這個 Claude Code pipeline 的翻譯 QA 從來沒檢查過的缺陷;修法是新增一個有研究根據的 Section C 關卡。

白色卡片上的赭紅色 Claude 星形標誌與黑色字樣
本頁目錄

引言

一個外部的 AI 審查讀了這個部落格自己cloud-publish 那篇文章的 zh-TW 翻譯,抓到兩個真實的缺陷:開頭有一句把英文子句結構直接搬過來,還有同一個原文詞,一個翻在圖說裡、另一個翻在緊接著的下一段。這個部落格自己的翻譯審查關卡,本來就是為了在每次發布前抓出這種落差而存在。外部審查先抓到,就代表這個關卡有一個還沒被點名過的死角。這個死角比審查本身建議的解決方法,也就是每個語系各配專門 agent,要窄得多。兩個缺陷裡有一個,這個部落格自己的風格指南其實早就有規則寫著。真正的修法,是參考別的地方怎麼做 AI 翻譯 QA 的研究,做出一個範圍更窄的第二道審查關卡。這篇文章依序談審查抓到了什麼、現有關卡為什麼抓不到、修法背後的研究,以及現在接在 pipeline 上的這個關卡。寫這篇文章的當下,它還沒經過真實翻譯的驗證。

一行一行核對外部審查

這次審查來自另一個 AI session,任務是替一篇已經公開的 zh-TW 翻譯打分數。它抓到的大部分東西,拿去對照檔案本身都是真的:Introduction 第二段開頭的一句,密度高到把自己的重點都埋掉了;的前面堆了一串修飾語,跟英文的關係子句一樣的搭法;同一個英文詞「unattended」,圖說裡翻成無人看管,緊接著的下一段又翻成無人值守。有一個指控站不住腳。 審查說這篇文章還是沒有流程圖,但其實有:一個叫<Pipeline />的圖,從第一次發布就已經在文章裡了,把本機端跟雲端的分界、以及審查說「沒有」的合併判斷分支,都畫得清清楚楚。

這一個站不住腳的指控,值得留到後面提醒自己:外部審查是有用的證據,不是不用讀就能照做的判決。

為什麼現有的關卡兩個都沒抓到

這個部落格的發布 pipeline,本來就會在每個語系發布前跑一次翻譯檢查:審查關卡的 Section B。它檢查跟原文的正確性、完整性、固定的標題字串、標題有沒有重新組過、跟共用詞彙表的落差,還有有沒有漏翻。這些項目沒有一個是設計來抓「意思完全沒變,但讀起來就是英文語序」這種句子的,同一個詞被翻成兩種說法、而且兩種都沒錯、也都不在詞彙表裡的情況,這些項目也一個都抓不到。

第一個直覺反應,是在同一份檢查清單裡多加兩條。這個直覺撐著的時間,只到被人質疑為止:把主觀判斷硬塞進一份靠檢查清單推進的客觀審查裡,這個主觀判斷很容易被排在前面的項目一樣,用同樣走馬看花的方式打勾帶過。Section B 當時已經有九個項目,這兩條原本只會是第十跟第十一條。

別的地方實際上怎麼做

要把這件事想清楚,得真的去查別的地方怎麼做 AI 翻譯 QA,不能用猜的。Andrew Ng 的translation-agent專案對同一個模型依序下三個 prompt:先做初版翻譯,再用一個 reflection 的 pass,針對四個面向(正確性、流暢度、文體、用語)批評第一版,最後用這份批評重寫一次。它的重寫 prompt 點名用語問題的方式,是「用在這個語境裡不恰當、用法前後不一致」,措辭幾乎跟這個部落格 zh-TW 這次的狀況一模一樣。翻譯廠商那邊也收斂到同一種做法:Smartling 和 Lilt 都把品質審查做成架構上跟翻譯本身分開的一道獨立關卡。而 WMT 從 2021 年起拿來當人工評估標準的 Multidimensional Quality Metrics(MQM)框架,用的正好是 Ng 的 prompt 獨立收斂出來的同一組四個分類。

這些都不是在替一組專門 agent 團隊背書。Ng 的 reflection 迴圈是同一個模型、兩個 prompt、同一個 session,不是各自扮演不同角色的多個 agent。研究裡也查到了多 agent 的架構,像是一間模擬的翻譯公司,裡面有 CEO、好幾個編輯、還有校對。但這種架構驗證過的場景是超長篇的文學翻譯,不是一篇部落格文章。相較之下,DeepL 是靠訓練一個更強的單一模型來拿到流暢度,而不是多跑一道審查。這是一條只呼叫通用 API 的 pipeline 走不了的路。

這個判斷的證據有實際的極限,值得老實講清楚,不要跳過。Ng 自己的 README 說這個專案「還不是成熟的軟體」,而且查到的研究裡,沒有任何來源實測過子句堆疊或內部一致性的偵測率。這個設計的依據,是 prompt 的措辭剛好對得上這個部落格自己這次的狀況,不是一份實測數據。

早就寫在檔案裡的規則

有一件事,研究不需要出面證明:這個部落格自己的風格指南裡,子句堆疊這一半的問題早就有規則,是好幾個月前就為了這個理由寫下的。目標語言慣例那一節講得很白:*「原文一個句子裡如果有兩個以上的子句,要拆開,不要照樣保留。」*zh-TW 那篇文章帶著這條規則描述的那種句子上線的時候,這條規則早就已經存在了。真正在發布時執行的審查關卡,從來沒有針對翻譯後的文字把譯者導向這條規則。它一直待在譯者應該讀的風格指南裡,不在審查實際會走過的檢查清單裡。

這也是為什麼第一個直覺,也就是在已經很長的檢查清單裡多加兩行,光靠這樣是不夠的。規則早就以文字形式存在,卻還是沒人檢查。這說明需要的是一次不用跟別的東西搶注意力的專門通讀,而不是再加一行容易被跳過的項目。

一道更窄的第二關

修法最後落成審查關卡裡新的一節:Section C,緊接在 Section B 之後對同一個語系執行,把翻譯完的檔案當成母語讀者從頭讀到尾一次,而不是逐句拿去跟原文對照。

現在有三個步驟的翻譯審查關卡一張流程圖,依序是翻譯、Section B、Section C、發布四個方框,以箭頭相連。Section B 標示正確性、完整性、與詞彙表的落差;Section C 標示流暢度、內部一致性、語氣,並附有新增的標記。翻譯Section B正確性、完整性、與詞彙表的落差新增Section C流暢度、內部一致性、語氣發布
Section C 對同一個語系執行,緊接在 Section B 之後,在檔案發布之前。

它檢查三件舊檢查清單從來沒碰過的事:一個句子有沒有違反已經寫好的規則,把原文的子句結構直接搬過語言的邊界;同一個反覆出現的用語,不管詞彙表怎麼說,在整份文件裡是不是翻法一致;還有語氣從「引言」到「總結」是不是保持一致。把它套用在外部審查實際指出的地方,就能看出它到底是為了抓什麼而設計的。

外部審查抓到的兩個問題,用 Section C 的分類方式呈現兩列圖示。第一列標示流暢度,顯示同一句中文在修正前後的樣子:修正前是一長串修飾語堆疊在「的」前面的長句;修正後拆成兩個較短的句子,意思不變。第二列標示術語,顯示同一個英文原詞修正前被翻成兩種不同說法,修正後統一成一種說法。流暢度原封不動搬過來的英文語序修正前以一份完整、執行中沒有任何東西需要再問的規格出現修正後以一份完整的規格出現。執行到一半,不會有任何東西需要再問。術語同一個原文詞「unattended」,被翻成兩種不同的說法修正前無人看管無人值守兩種說法,一個在圖說、一個在下一段修正後無人值守統一成一種說法
外部審查找到的兩個問題,對照 Section C 執行的兩項檢查。

「unattended」的兩種翻法,各自單獨看都沒有錯,也都不在這個部落格的詞彙表裡,這正是為什麼 Section B 的用語檢查,設計來抓的是跟詞彙表之間的落差,卻沒有東西可以拿這兩種翻法互相比較。Section C 接在翻譯真正發布出去的兩個地方:本機的/blog publish指令,還有 routine 在無人值守發布一篇文章時讀的任務清單。就算是在沒有人盯著的情況下執行這個流程的 routine,也會跑跟人手動觸發發布時一樣的檢查。

總結

這個部落格的翻譯審查關卡,現在多了第三節:把翻譯完的檔案整份讀完,檢查流暢度、用語的內部一致性、還有語氣,疊加在原本就會跑的正確性和完整性檢查上面。當初引發這一切的兩個具體缺陷,一句子句堆疊的句子,還有一個英文詞的兩種翻法,正好就是 Section C 檢查清單點名的那兩個類別。這次的設計實際上能不能在真正的翻譯裡抓到這兩種缺陷的任何一種,現在還是個開放的問題。查到的研究裡,沒有任何來源實測過 reflection 這種做法對這兩種缺陷的偵測率;這個設計的依據,是這次事件跟它借來的那個已發表做法之間措辭對得上,不是一份實測數據。這個部落格下一篇真正走完整套 pipeline 翻譯的文章,也就是這篇文章自己,才是真正的考驗。 不是這篇寫理由的文字本身。

參考連結

分享這篇文章