從 3 小時到 30 分鐘:我的中文字幕自動化 pipeline

我幫一位財經教育創作者做影片字幕。一支兩小時的影片,人工校正要 2-3 小時;現在同樣的工作,pipeline 自動跑完加上我抽查,15-30 分鐘。這篇講這條生產線怎麼搭起來,以及三個讓它從「能跑」變成「可靠」的關鍵教訓。

生產線長什麼樣

整條 pipeline 在 Claude Code 裡用一個 skill 觸發,依序跑六個階段:

下載(yt-dlp)
→ 畫面術語抽取(OCR / VLM caption,每 60 秒一幀)
→ ASR(Breeze ASR 25,Apple Silicon 本地推理)
→ 預處理(斷句清理、詞中逗號修復)
→ LLM 校正(分段派 subagent,注入術語表+畫面上下文)
→ 後處理(超長字幕切分、品質 gate、SRT 輸出)

全程本地跑 ASR,只有校正階段用雲端模型。財經內容的難點不是語音辨識本身,是專有名詞:股票代號、ETF、指標縮寫、講者的口頭禪。ASR 把「美光」聽成別的詞、把「MA30」拆成碎片,這類錯誤靠通用模型修不好,要靠領域知識。

術語表是活的

系統的核心不是任何單一模型,是一個會學習的術語迴圈

  1. 每支影片校正完,跑一次 term learning,把「ASR 錯法 → 正確詞」寫成機械替換規則
  2. 下一支影片的 ASR 輸出,先過這批規則再進 LLM 校正
  3. 畫面上的投影片文字(OCR 抽取)補充當集的新術語

量化過一次效果:連續處理 8 支影片,第一輪學習後新增 16 條替換規則,同一支影片的自動修正數從 0 跳到 58。第二輪之後,LLM 校正 subagent 回報的修正量明顯下降——因為便宜的錯誤已經在上游被機械規則吃掉了。

教訓一:驗證要看值,不是看有沒有錯誤

有一次,一個校正 subagent 把 300 條字幕「過度合併」成 110 條,出現 10-29 秒的超長字幕。當時的驗證只檢查「檔案存在+格式正確」,照樣放行。

修法是把驗證改成檢查數值

ratio = corrected_count / original_count
if ratio < 0.55:
fail() # 條數掉太多,必是過度合併
if ratio < 0.80 and longest_entry_sec > 15:
fail() # 條數比例配合時長症狀雙重確認

閾值不是拍腦袋,是拿 10 部歷史影片的 88 個分段校準出來的(誤報率 0)。單看條數比例不夠——講者講碎句的段落天然低 ratio,要配上「最長條目時長」這個症狀一起判。

教訓二:subagent 的輸出永遠要防禦性解析

LLM subagent 偶爾會把判斷過程寫進輸出(「[通順,不改]」),或洩漏工具呼叫的 XML 標籤。更麻煩的是,後處理的切分邏輯會把單點污染放大成多處擴散

防呆分三層:prompt 明列禁止輸出的模式、合併前先 strip、後處理完再 strip 一次。原則只有一句:清理必須在切片之前,不能信任 subagent 自律

教訓三:資源衝突要編排,不是祈禱

32GB 的 M1 Max 跑不動兩個大模型同時推理。20GB 的視覺模型跑完之後,框架還會把模型在記憶體裡保留幾分鐘——這段時間啟動 ASR 就直接 OOM。修法很土但有效:caption 一跑完就明確下 ollama stop,再啟動下一個階段。小模型(1.5GB 的 ASR + 5GB 的輔助 ASR)反而可以放心並行,頂多互搶 GPU 變慢,不會掛。

值得抄的三個設計

如果你要搭類似的東西,我覺得最值得抄的是:

  1. 保留所有中間產物。每個階段的輸出都留檔。品質 gate 的閾值校準、事故後的重建,靠的都是這批歷史資料。
  2. 機械規則吃便宜錯誤,LLM 吃難錯誤。分層之後,貴的模型只處理真正需要理解的部分。
  3. gate 用真實資料校準。防呆閾值拿歷史產出算出來,不是猜出來。

這條 pipeline 的 skill 已經開源,跟它的姊妹技能(把錄音整理成忠於原話的文章)都在我的 GitHub 上。