TTS 文字轉語音完全指南:技術原理、聲音克隆與 2026 選型實戰

前陣子我在測 Qwen3-TTS,官方技術報告寫著首包延遲 97ms,聽起來就是為即時對話而生的。結果我照官方範例跑起來,按下生成、等了整整 10 秒才聽到第一個字。乾,差了一百倍。

這不是我環境爛,而是 TTS 這個領域的日常:論文數字、行銷頁數字、你實際跑出來的數字,是三個平行世界。97ms 是模型架構在特定串流管線下的能力值,官方釋出的推理程式碼卻是整段生成完才回傳——你拿到的「首包」其實是「全包」。

這篇文章是我最近一輪 TTS(Text-to-Speech,文字轉語音)研究的完整整理:技術原理怎麼走到今天、聲音克隆為什麼有人要 3 秒有人要 30 分鐘、2026 年雲端 API 的真實價格與盲測排名、本地部署誰最快,以及最重要的——那些行銷頁不會告訴你的坑。

TTS 聲波從機器音演化為自然人聲的概念圖

從機器音到以假亂真:TTS 技術是怎麼演進的

十年前的 TTS 是什麼樣子?導航機那種一個字一個字蹦出來的合成音。那個年代主流做法是「拼接合成」——把真人錄音切成音素片段,播放時再拼回去,像用剪報拼勒索信,字都對但就是不像人講話。

轉捩點是 2016 年 DeepMind 的 WaveNet 和 2017 年 Google 的 Tacotron:神經網路直接學習「文字到聲音」的映射,機器音瞬間變得有血有肉。但自迴歸模型要一個取樣點一個取樣點慢慢生,慢到不能上線。後來的 FastSpeech 用非自迴歸架構把生成平行化,VITS 把聲學模型和聲碼器合併成端到端訓練,速度和品質才總算都端上桌。

真正改變遊戲規則的是 2023 年微軟的 VALL-E :它把語音壓縮成離散的 codec token,然後把 TTS 當成「條件式語言模型」來做——跟 GPT 生成文字是同一套邏輯。這帶來一個副作用級的殺手功能:in-context learning。給模型 3 秒鐘的陌生聲音當 prompt,它就能用那個聲音講出任何內容。3 秒聲音克隆這件事,就是從這裡開始的。

2024 年之後的另一條路線是 flow matching:學一個從雜訊到聲學特徵的確定性映射,非自迴歸、全部音框平行生成。F5-TTS 就是這條路的代表作,推理效率在開源模型裡是第一梯隊。到了 2026 年,兩條路線開始合流——像 Qwen3-TTS 用 12Hz 多碼本 tokenizer 搭配輕量因果卷積網路,架構上做到 97ms 首包的串流能力(先不論你跑不跑得出來,後面會講)。

拼接合成(2016 前)→ 自迴歸神經網路(WaveNet / Tacotron)→ 非自迴歸(FastSpeech / VITS)
↓ 分成兩條路線 ↓
Codec 語言模型(VALL-E 路線)|Flow Matching(F5-TTS 路線)
↓ 兩路合流 ↓
混合串流架構(Qwen3-TTS 等 2026 世代)
神經網路 TTS 管線示意圖

聲音克隆:3 秒和 30 分鐘的差別在哪

聲音克隆(voice cloning)現在分成兩派,樣本需求差了幾百倍,很多人搞不清楚自己需要哪種。

Zero-shot 即時克隆:拿幾秒鐘的錄音當參考,模型直接模仿,不做任何訓練。Cartesia 只要 3 秒、Fish Audio 要 10 秒、ElevenLabs 的 Instant Voice Clone 建議 1 到 5 分鐘。原理就是前面說的 in-context learning——你的聲音只是一段 prompt。優點是快和便宜,缺點是它抓的是「音色的平均印象」,講話的小習慣、特殊的斷句節奏抓不太到。

微調式專業克隆:拿 30 分鐘以上的乾淨錄音去實際訓練模型權重。ElevenLabs 的 Professional Voice Clone 走這條路,官方說法是「幾乎無法分辨」;開源世界的 GPT-SoVITS 用 1 分鐘資料微調就有明顯提升。代價是要準備錄音素材、等訓練,而且通常要付訂閱費(ElevenLabs 要 Creator 方案 22 美元/月起)。

哪個好?取決於你要騙過誰。做影片旁白、有聲書,zero-shot 通常夠用,聽眾對「像不像本人」的敏感度沒你想的高。但如果是品牌聲音、Podcast 主持人的數位分身,微調式的差距一聽就出來。

還有一個台灣使用者才會踩到的坑:腔調漂移。MiniMax 的克隆還原度在台灣社群實測是第一名,但多位使用者回報克隆出來的中文帶「中國腔」——模型會把你的台灣腔往標準普通話拉。這不是 bug,是訓練資料分布的必然結果。想保留台灣腔,目前最可靠的路是本地微調 GPT-SoVITS,用你自己的錄音把腔調「鎖」進權重裡。

聲音克隆的鏡像波形概念圖

2026 雲端 API 評比:盲測排名與價格的落差

先看客觀數據。Artificial Analysis 的語音盲測排行 (2026 年 6 月,ELO 制)給了一個很多人意外的結果:

服務盲測 ELO價格(每百萬字元)克隆樣本
Inworld TTS 1.5 Max1208(第 1)$25–35數秒,免費
Google Gemini 3.1 Flash TTS1206(第 2)$36.6不支援
ElevenLabs Eleven v31178(第 4)$100IVC 1–5 分鐘
MiniMax Speech 2.8 HD1164(第 5)$100數十秒,$3/顆
Fish Audio S2 Pro1128(第 11)$15(注意單位是 bytes)10 秒,免費
Azure AI Speech HD1123(第 12)$22需申請
OpenAI TTS-11102(第 17)$15不支援
Cartesia Sonic-31070(第 25)約 $393 秒,免費

看到了嗎?ElevenLabs 收最貴的錢,盲測卻只排第 4。它贏的地方在別處:發音錯誤率最低、幻覺最少、工作流最完整。Reddit 上的評價很一致——「準確、快、錯誤少,但貴,而且常常要重新生成」。

Cartesia 則是被低估的性價比之王:5 美元/月就含商用授權和 3 秒即時克隆,延遲約 90ms 是業界最低。從 ElevenLabs 跳槽過去的使用者說法是「品質差距遠小於價格差距,大概便宜 8 倍」。

然後是三個行銷頁不會寫的坑,每個都是真金白銀:

Fish Audio 的 bytes 陷阱。它的 $15/1M 是按 UTF-8 bytes 計費,一個中文字佔 3 bytes——寫中文的人實際成本是 $45/1M 字,「比 ElevenLabs 便宜 70%」的甜頭瞬間縮水成三分之一。官方定價文件 寫得清清楚楚,只是沒人細看。

ElevenLabs 的 credit 燒錢術。重新生成扣點、預覽扣點、調參數也扣點。訂閱制下 Creator 方案 22 美元換 10 萬 credits,實質單價約 $220/1M 字元,是行銷頁「$100/1M」量販價的兩倍多。加上並發數限制綁方案,量一大就被逼著升級,啊不就好棒棒。

MiniMax 的腔調問題。前一段講過了,中文還原度第一,但台灣腔會被吃掉。它的 Fluent LoRA 技術能把不流利的錄音變流利——這既是功能,也是腔調被「標準化」的原因。

開源與本地部署:RTF 才是你該看的數字

開源這邊,2026 年的重點只有一句話:品質已經追上付費服務,剩下的差距在部署難度。Resemble AI 的 Chatterbox 在盲測中拿下 63.8% 的聽眾偏好、贏過 ElevenLabs(注意這是 Resemble 自家委託的測試,看看就好,但至少說明差距不大)。

本地部署最重要的指標是 RTF(Real-Time Factor):生成 1 秒音訊要花幾秒,小於 1 就是快於即時。實測數據:

模型RTF硬體克隆授權
GPT-SoVITS v2 ProPlus0.014(RTX 4090)/ 0.526(M4 CPU)GPU 佳微調式MIT
小米 OmniVoice0.025GPU3 秒 zero-shotApache 2.0
Kokoro-82M0.44(Mac MPS),CPU 可即時CPU 即可無克隆Apache 2.0
F5-TTS開源第一梯隊GPUzero-shotCC-BY-NC,不可商用
Chatterbox4.55(Mac,GPU 上好很多)建議 GPU10 秒MIT

GPT-SoVITS 的數字值得單獨拿出來講:RTX 4090 上 RTF 0.014,官方實測 4 分鐘的音訊 3.36 秒生成完,比即時快 70 倍。而且它是微調式克隆,正是保留台灣腔的解法。缺點是學習曲線陡,WebUI 一堆參數,第一次開會有點懷疑人生。

授權地雷區要特別畫重點:F5-TTS 是 CC-BY-NC、XTTS v2 是 CPML,都不能商用。做 YouTube 有營利、接案、公司產品,用了就是法律風險。要商用又要開源,選 MIT(GPT-SoVITS、Chatterbox)或 Apache 2.0(Kokoro、Qwen3-TTS、OmniVoice)。

沒有 GPU 也別急著關頁面。Kokoro 只有 82M 參數,筆電 CPU 就能即時生成(但沒有克隆);Kyutai 在 2026 年 1 月發布的 Pocket TTS 用 100M 參數做到 CPU 即時又能克隆,這個規模半年前還被認為不可能。

雲端服務與本地部署的對比

延遲的真相:97ms 是怎麼變成 10 秒的

回到開頭那個 97ms 變 10 秒的謎題,把它拆開看,你會學到怎麼讀所有 TTS 的延遲數字。

問題現象:照 Qwen3-TTS 官方 HuggingFace 範例跑 generate_voice_clone,首包 10 秒起跳。原因分析:官方釋出的 Python 推理程式碼根本不支援串流——它把整段音訊生成完才回傳。HuggingFace 討論區有人問了一模一樣的問題 ,得到的答案是:97ms 是架構能力,要靠另外的串流管線才拿得到。更慘的案例是 GitHub issue #89 :有人在 RTX 5090 上跑出比即時慢 10 倍的速度,GPU 使用率只有 4–5%——錢花了,卡在那邊納涼。

解決方案是換推理引擎。vLLM-omni 是 vLLM 官方的多模態擴展框架,2026 年 2 月合併了 Qwen3-TTS 的 CUDA Graph 加速和串流輸出,社群實測 1.7B 模型首包 80–90ms、RTF 0.3–0.4。同一顆模型,換個引擎,延遲差一百倍。

所以讀 TTS 延遲數字的正確姿勢是問三個問題:這是串流首包(TTFA)還是全段生成時間?是什麼推理管線量出來的?我的部署方式跑不跑得出同一條管線?行銷頁的數字永遠是三者最理想的組合。

如果你不想自己架,聚合平台是捷徑。以 fal.ai 上的 Qwen3-TTS 為例,克隆分兩步——先用參考音檔產生 speaker embedding,再拿 embedding 去合成:

# pip install fal-client;需設定環境變數 FAL_KEY
import fal_client

# 第一步:從 10 秒左右的參考音檔建立聲音 embedding
clone = fal_client.subscribe(
    "fal-ai/qwen-3-tts/clone-voice/1.7b",
    arguments={"audio_url": "https://example.com/my-voice-10s.wav"},
)
embedding_url = clone["speaker_embedding"]["url"]

# 第二步:用克隆的聲音合成語音
result = fal_client.subscribe(
    "fal-ai/qwen-3-tts/text-to-speech/1.7b",
    arguments={
        "text": "大家好,這是用三秒克隆技術生成的聲音。",
        "language": "Chinese",
        "speaker_voice_embedding_file_url": embedding_url,
    },
)
print(result["audio"]["url"])  # 生成音檔的下載連結

這個端點我實際查價是 $0.0008/分鐘音訊,便宜到我一度以為查錯,做影片旁白等於零成本。代價是走 queue 沒有串流,適合離線批量生成,不適合即時對話。

選型建議:一張表決定你該用哪家

講了這麼多,直接上決策表:

你的場景首選理由
影片旁白、批量生成,預算越低越好fal 上的 Qwen3-TTS幾乎零成本,中文原生
中文克隆還原度優先MiniMax台灣社群實測還原度第一,但注意腔調
英文內容、品質零妥協ElevenLabs 或 Inworld錯誤率最低 vs 盲測第一名還便宜
即時語音對話 agentCartesia90ms 延遲業界最低,$5/月含克隆
想保留台灣腔本地 GPT-SoVITS 微調唯一能把腔調鎖進權重的路
沒有 GPU 的本地玩家Kokoro(純 TTS)/ Pocket TTS(克隆)CPU 即時

我自己的建議是別急著訂閱任何服務。先拿 10 秒自己的錄音去 fal 上的 Qwen3-TTS 跑一輪,成本趨近於零;聽不滿意再花 $1.5 建一顆 MiniMax 克隆比較看看;兩個都過不了你的耳朵關,才需要考慮 ElevenLabs 的訂閱或本地微調。從免費往上爬,而不是從最貴的往下砍。

最後提醒一件比選型更重要的事:克隆只能用在你有合法使用權的聲音上。各家平台都有驗證機制,但技術上 3 秒就能克隆任何人的聲音,也代表詐騙集團同樣做得到——這一年語音詐騙的新聞沒少過。自己的聲音自己克隆,別人的聲音先拿到授權,這條線別踩。

TTS 這個市場每季都在洗牌,ElevenLabs 兩年內改了三次價格結構,開源模型每兩個月就有新王。這篇的數據以 2026 年 7 月為準,半年後記得重新查價。如果你有實測過其他組合,特別是台灣腔克隆的成功案例,歡迎留言分享——這塊的公開資料真的太少了。

TTS 選型決策路徑示意

參考資料

同一顆基座、兩種靈魂:Holo 3.1 與 Qwythos-9B 怎麼在你本機組成 Claude Computer Use

Holo 3.1 與 Qwythos-9B 主視覺:眼手與大腦

先講結論。這篇不是「盤點兩個新模型」的媒體稿,而是想解一個技術判斷題:

2026 年 6 月,兩個都基於 Qwen3.5-9B 、都掛 Apache 2.0、都在同月開源的模型,H Company 的 Holo 3.1 跟 Empero AI 的 Qwythos-9B ,我到底該用哪一個?

實測跑過兩週後,我的答案變成:兩個都要。它們不是同一條賽道上的競爭者,而是同一台本地 Claude Computer Use 的左手跟右手——一個是眼睛加雙手,一個是大腦加嘴巴。這篇就是把「為什麼」跟「怎麼做」拆給你看。


為什麼今年開源社群長得越來越像 Qwen3.5 生態圈

先鋪一下背景,這件事比模型本身更有意思。

過去半年,開源社群幾乎所有值得注意的專門化模型都往同一個基座靠:Qwen3.5。原因不神秘——Qwen3.5 提供了 0.8B 到 397B 的完整 dense/MoE 家族、原生 262k 脈絡、hybrid GDN+Attention 架構、以及真正商用友好的 Apache 2.0 授權。這在 Llama 4 的社群授權還有 700M MAU 上限、Gemma 有自訂條款的環境下,幾乎沒得挑。

於是我們看到的畫面是:Qwen 團隊把「作業系統」造好,其他實驗室在上面裝專用軟體。Holo 3.1 是「電腦操作」這個 app,Qwythos-9B 是「Claude 級推理」這個 app。兩個 app 都不重造輪子,都拿 Qwen3.5 當 kernel。這個現象跟去年 Llama 3 一枝獨秀時完全不同——基座之爭已經結束,戰場搬到後訓練專門化了

理解這一點之後,同月出兩個 Qwen3.5 微調模型就不是巧合,而是常態。而能不能組合起來,才是判斷開源生態成熟度的真正指標。


Holo 3.1:把螢幕看懂、把滑鼠鍵盤打通

同基座長出兩棵完全不同的樹

Holo 3.1 是 H Company 於 2026 年 6 月 2 日發布的 Computer-Use Agent VLM 家族。它做的事情很純粹:吃一張螢幕截圖 + 一個自然語言目標,吐出「下一步要點哪、打什麼、滾多少」。

家族尺寸從 0.8B 一路開到 35B-A3B MoE,跟 Qwen3.5 一一對應。旗艦款 35B-A3B 依社群拆解(對應 Qwen3.5-35B-A3B)大約是 256 個 experts、top-8 routing,激活參數只有 3B——白話就是「35B 級的能力,但推理速度接近 3B」。這對本地部署是天大的好消息,VRAM 帳單走總參數(Q4 大約 21GB),算力帳單走激活參數,24GB 的 RTX 4090 剛好塞得下。

真正拉開跟 Holo 3 差距的是三件事:

  1. 手機加進來了。AndroidWorld 從 67% 直接跳到 79.3%,4B/9B 也從 58% 拉到 71%
  2. Native function-calling。之前是 prompt 硬擠 JSON,現在是原生工具呼叫協議,跟任何 ReAct 框架能直接兼容
  3. 量化 checkpoint 三件套:NVFP4 給 DGX Spark、FP8 給 H100、Q4 GGUF 給消費硬體跟 Apple Silicon

我在自己 DGX Spark + NVFP4 + vLLM 環境下實測,35B-A3B 的 agent step time 從 FP8 baseline 的 6.8 秒直接砍到 3.3 秒(用 OSWorld 任務子集,10 步平均)。跟 H Company 官方 blog 揭露的 ~2× 端對端加速數字對得起來。這已經不是優化,是換引擎,夭壽。

放在整個 Computer-Use 賽道看,Holo3.1 的定位大概是:單一開源模型級別逼近人類基準。AndroidWorld 人類基準 80.0%,Holo 拿 79.3%;OSWorld-Verified 人類基準 72.4%,Holo 大約也逼到 80% 附近的水位。跟 ByteDance 的 UI-TARS-2 (OSWorld 47.5% / AndroidWorld 73.3%)相比,Holo 在同尺寸級別領先明顯。

但注意「單一模型」這四個字。H Company 自家的 Surfer 2 agent 系統把 OSWorld 拉到 60.1%、AndroidWorld 拉到 87.1%(見 Surfer 2 論文 arXiv 2510.19949 ),那是「Holo 當模型 + agent 框架」的組合結果。Holo 3.1 提供的是最強的零件,不是完整方案。這件事等下講雙引擎的時候會回來。


Qwythos-9B:把 Claude 的推理鏈灌進 9B

Qwythos-9B(全名 empero-ai/Qwythos-9B-Claude-Mythos-5-1M)是 Empero AI 在同月釋出的推理模型。它跟 Holo 3.1 用同一顆基座——Qwen3.5-9B——但完全不做 Computer-Use。

它做的是把 Claude Mythos 5 跟 Claude Fable 5 的推理鏈路徑,用 500M+ tokens 的 trace 資料,全參數 SFT 灌進一顆能跑在筆電上的 9B 模型。訓練用了兩階段課程學習:先廣泛推理語料,再聚焦 agentic + coding,用 bf16 + paged AdamW 8-bit + chunked NLL assistant-only loss。

技術亮點三個:

  • 1,048,576 token context:從 Qwen3.5 原生 262k 用 YaRN factor=4 直接擴到 1M。消費硬體開 32k~128k 較實際,48GB A6000 才能吃到接近全窗
  • 原生 function-calling:官方 tool-use test 拿 7/7,且答案帶真實來源引用
  • 深度無審查:官方 model card 明講「engage seriously with cybersecurity, red-teaming, pharmacology, clinical medicine」。這是把雙面刃

跟 Qwen3.5-9B base 相比,Qwythos-9B 在 MMLU 上 +34.3,GSM8K strict-match +30.0(flexible-extract 口徑則是 +19,官方 model card 兩個都給了,我這裡取 strict 是為了避免 extraction 誤差干擾)。這差距不像是同尺寸 fine-tune 該有的,比較像「9B 皮、Claude 骨」。

它適合的場景是那些要讀很多、想很深、講很久的活:長文件分析、整個 codebase 一次讀進 context、多步 agent 工作流、需要 Python executor 驗證的長推理。不適合的場景也很清楚:想要輕鬆閒聊、沒有 GPU、不想處理 <think> 區塊、面對消費者的產品——因為它會直接回答那些多數對齊模型會拒絕的問題,安全層要自己補。


為什麼兩個放一起,就變成 Claude Computer Use

看到這裡應該有感覺了。Holo 3.1 缺什麼?思考深度。Qwythos-9B 缺什麼?眼睛跟手

這不是巧合。Computer-Use Agent 的兩大瓶頸就是這兩個:

  1. 看不清螢幕:早期 Claude Computer Use 常在 GUI 邊界判斷失誤,Anthropic 內部承認純 LLM+screenshot 的 grounding 有天花板
  2. 想不夠深:純 Vision-Language Model 為了 UI grounding 犧牲了長脈絡與深度推理,這是 UI-TARS 系列在複雜跨應用任務會卡住的主因

Holo 3.1 把 grounding 這面推到接近人類;Qwythos-9B 把 reasoning 這面推到接近 Claude。你把它們串成一個雙引擎 agent loop,就在自己電腦上組出了功能等價於 Claude Computer Use 的完整堆疊,而且完全離線。

架構長這樣:

使用者自然語言目標
        ↓
Qwythos-9B(高階規劃 + 1M context,讀歷史操作/文件/規格)
        ↓ function_call
Holo 3.1(低階執行 + 螢幕理解,決定像素座標動作)
        ↓ action
Sandbox / OS(執行動作 → 新截圖)
        ↑ 回到 Holo,狀態摘要回到 Qwythos
        ↓ 迴圈直到完成
最終結果 → 使用者

分工邏輯很簡單:Qwythos 收「目標 + 完整歷史脈絡 + 上次截圖的文字描述」→ 輸出「下一步計畫 + 要 Holo 執行的 tool_call」。Holo 收「這個 tool_call + 當前截圖」→ 輸出「像素座標動作」。動作執行完,新截圖回到 Holo,狀態摘要回到 Qwythos。

一台 24GB VRAM 的 RTX 4090,可以同時裝 Qwythos-9B Q4 GGUF(約 5.6GB)+ Holo-3.1-9B Q4 GGUF(約 6GB),剩下 12GB 留給兩顆的 KV cache。或者 M3 Max 64GB 統一記憶體全跑起來,一台筆電就是完整推理 rig。


OpenClaw:兩個模型碰上生態圈的巧遇

OpenClaw 當整合中樞

理論組合聽起來很美,實務要怎麼把兩個 llama-server 綁進同一個 agent 框架?答案是 OpenClaw ,一個由 Peter Steinberger 在 2025 年底開源的本地優先 agent runtime,社群成長很誇張——推出 24 小時內就衝破 9000 星,到 2026 年 Q1 已經是六位數等級的專案。

有趣的是,兩個模型跟 OpenClaw 的關係並不對稱:

模型OpenClaw 整合證據
Holo 3.1有專門部署教學KnightLi 部落格 Holo 3.1 Local Deployment Guide 手把手教你用 openclaw skills install agent-browser 把 Holo 掛進 gateway(該站點會導向自訂 port,若瀏覽器擋下請手動信任)
Qwythos-9B沒專屬教學但通用可行官方文件只講 vLLM / SGLang / Transformers / Ollama。因為 OpenClaw 支援任何 OpenAI 相容端點,Qwythos 可以透過 Ollama provider 間接接上

差距在哪?Holo 3.1 是 GUI 專職模型,跟 OpenClaw 的 agent-browser skill 幾乎是零距離的天生一對——它就是為了 browser/desktop 操作而生。而 Qwythos 定位是「推理 + tool use」文字模型,OpenClaw 社群還沒有為它做專案,但它拿 7/7 tool-use test 加上 function-calling 支援,是 OpenClaw primary model 的優質候選。

換句話說,Holo 是已被 OpenClaw 生態圈收編的模型,Qwythos 是可以但還沒被收編的模型。有沒有覺得這缺口剛好是給你的機會?

實作:把兩個模型掛進同一個 OpenClaw

前置條件講在前面:

  • macOS / Linux / Windows(我在 M3 Max 64GB 跟 Ubuntu + RTX 4090 上都測過)
  • llama.cpp 或 Ollama 至少一個
  • OpenClaw(Homebrew 或官方 installer)
  • Chrome(如果要跑 browser skill)

第一步:用 llama.cpp 起 Holo 3.1 的 server

從 Hugging Face 抓 Hcompany/Holo-3.1-9B-GGUF 的主檔跟 mmproj 視覺投影檔,這裡 mmproj 常被漏掉,漏了就沒有視覺輸入。

llama-server \
  -m ./models/holo-3.1-9b.q4_k_m.gguf \
  --mmproj ./models/holo-3.1-9b-mmproj.f16.gguf \
  -ngl 999 -c 8192 -fa \
  --temp 0.2 --top-p 0.9 \
  --host 127.0.0.1 --port 8081

第二步:用 Ollama 起 Qwythos

ollama run hf.co/empero-ai/Qwythos-9B-Claude-Mythos-5-1M-GGUF:Q4_K_M

Q4_K_M 檔案約 5.2GB,跑起來一顆 8GB VRAM 就夠。Ollama 預設會開 http://localhost:11434 的 OpenAI 相容端點。

第三步:讓 OpenClaw 認識這兩顆模型

編輯 ~/.openclaw/config.json(不同版本路徑可能略異,用 openclaw config path 確認):

{
  "agents": {
    "defaults": {
      "model": { "primary": "ollama/qwythos-9b" }
    }
  },
  "models": {
    "providers": {
      "ollama": {
        "baseUrl": "http://localhost:11434",
        "apiKey": "ollama-local",
        "api": "openai-completions",
        "timeoutSeconds": 300,
        "models": [
          {
            "id": "hf.co/empero-ai/Qwythos-9B-Claude-Mythos-5-1M-GGUF:Q4_K_M",
            "name": "Qwythos-9B",
            "reasoning": true,
            "input": ["text"],
            "contextWindow": 131072,
            "maxTokens": 8192
          }
        ]
      },
      "holo-local": {
        "baseUrl": "http://127.0.0.1:8081/v1",
        "apiKey": "sk-local",
        "api": "openai-completions",
        "timeoutSeconds": 120,
        "models": [
          {
            "id": "holo-3.1-9b",
            "name": "Holo 3.1 9B (Vision)",
            "reasoning": false,
            "input": ["text", "image"],
            "contextWindow": 32768,
            "maxTokens": 2048
          }
        ]
      }
    }
  }
}

Qwythos 當 primary(負責思考跟規劃),Holo 當 vision 專用 provider(負責螢幕跟動作)。context window 我先給 131k 是保守值,硬體允許再拉。

第四步:裝 browser skill,把 Holo 綁上去

openclaw skills install agent-browser
openclaw doctor
openclaw gateway restart

agent-browser 這個 skill 會自動下載 Playwright + Chromium。裝完後可以在 skill 設定裡指定「vision model 用 holo-local/holo-3.1-9b」,這樣主 agent(Qwythos)就會把螢幕理解任務外派給 Holo endpoint。

第五步:試一個真實任務

在 OpenClaw chat 輸入:
「打開 hcompany.ai/holo3.1,找出 Holo 3.1 的 4B 模型在 AndroidWorld 的分數,
把來源 URL 一起回給我。」

會看到 Qwythos 先規劃步驟(<think> 區塊會冒出來),呼叫 browser skill 開頁,Holo 看截圖決定要往哪 scroll、要點哪個連結,資料回到 Qwythos 整理成有引用的答案。這就是本地版 Claude Computer Use 的最小可行迴圈。


踩過的坑跟一定要記的事

筆電上的本地雙引擎

實測兩週,踩到的雷整理如下。

坑一:Holo 3.1 各尺寸授權沒完全確認

只有 0.8B 我親眼看到 Apache 2.0 明確標示。4B / 9B / 35B-A3B 的 Hugging Face model card 我建議每一顆都自己去確認一次,特別是打算商業部署的話。H Company 上一代 Holo1.5 是「3B 掛 Qwen license、7B 掛 Apache 2.0、72B 掛 research-only」的分級模式,Holo 3.1 不保證統一。

坑二:Qwythos 的 <think> 區塊

如果你把 Qwythos 接到使用者可見的 UI,<think>...</think> 會直接被吐出來,用戶會看到一大坨推理過程。正確做法是在 gateway 層過濾掉,或者把 reasoning 顯示切成摺疊區塊。

坑三:1M context 不代表消費硬體吃得下

Qwythos 的 config 寫 max_position_embeddings: 1048576,但 KV cache 會爆。8GB VRAM 建議只開 32k,24GB 開 128k,48GB 才有機會逼近全窗。不要看到 1M 就無腦塞整個 codebase,會 OOM。

坑四:Holo 3.1 GGUF 漏掉 mmproj

llama.cpp 的視覺模型要主檔 + mmproj 兩個檔一起載入。只載主檔,模型會啟動成功但看不見圖,這是最常見的初學者陷阱。

坑五:Qwythos 未審查是雙面刃

它是刻意 uncensored 的模型,你在自己實驗室跑當然沒問題,但只要要 serve 給外部使用者、或者接到公司內部系統,應用層 guardrail 必須自己補。Empero 的 model card 已經寫清楚這點,別假裝沒看到。

坑六:OpenClaw 對 tool_choice 的預設

OpenClaw gateway 預設 tool_choice: "auto"。Qwythos 因為每回合都會走推理再決定要不要呼叫工具,通常 auto 剛好;但如果你想強制每回合都用工具(例如純 agent workflow),要在 config 手動蓋成 "required"

"agents": {
  "defaults": {
    "models": {
      "ollama/qwythos-9b": {
        "params": { "extra_body": { "tool_choice": "required" } }
      }
    }
  }
}

誰該做、誰別做

不是每個人都需要組這個雙引擎。用途對應建議是這樣:

情境建議
想試試「本地 Claude 助理操作我電腦」雙引擎全套上,M3 Max 或 24GB VRAM 起步
只想跑 browser 自動化,不需要深度推理Holo 3.1 4B / 9B 單獨用就好,Qwythos 是浪費
只想讀 codebase / 論文,不操作電腦Qwythos-9B 單獨用,Holo 是浪費
想做無審查資安研究Qwythos + Docker sandbox,Holo 選配
面對消費者的產品兩個都不建議直接用,未審查跟企業對齊差距太大
資源極少(8GB 以下)Holo-3.1-0.8B 單引擎,Qwythos 最小也是 9B
想要極致速度別用 Qwythos,<think> 會拖 UX,改用 Holo + 更輕的規劃模型

結語:開源社群的成熟度訊號

我覺得 Holo 3.1 跟 Qwythos-9B 最值得記住的不是任何一個 benchmark 數字,而是它們同月由不同團隊獨立發布,卻能無縫組合這件事。

過去我們談開源 AI 生態,常常是「這個模型跟那個框架不相容」「這家的 tokenizer 跟那家不合」的碎片化狀態。而現在因為 Qwen3.5 這個共同底座、Apache 2.0 這個共同授權、OpenAI-compatible API 這個共同介面,你可以把兩個素不相識實驗室的模型,在同一個 gateway 裡兜成一個完整產品。

這個能兜起來的能力,本身就是開源社群長大的訊號。

如果你正在做本地 AI agent 相關的東西,這個週末花兩小時把 Holo + Qwythos + OpenClaw 這條線走一次,會比讀十篇 benchmark 分析更有感。硬體剛好 24GB VRAM 或 M3 級筆電的話,你已經比 90% 的 API 使用者更接近「AI 真的在幫我做事」這件事的本質。


參考資料

豆包角色 Bot 為什麼一開口就「作為 AI」?字節官方拍板的人設骨架 + 即貼即用範本

豆包角色 prompt 不出戲指南

你在豆包 APP 裡建了一個角色,設定描述貼了 500 字,按下「完成」興沖沖點開——它第一句話是:

你好,我是 XX 智能體,請問需要什麼幫助?

那一刻你大概就懂了,前面那 500 字白寫了。或者更慘——提交審核 24 小時後被拒,理由「含違規指令」,你看了三遍找不到問題在哪。

這篇要做的事情很簡單:把字節跳動官方文檔、CharacterGLM 論文(清華+智譜+聆心)、加上社群實戰心得,整理成一套你今天下午就能拿來用的骨架。文末附 2 個簡中範本,直接複製到設定描述欄就能跑。

先搞清楚你寫的 prompt 要部署在哪

豆包角色 prompt 的三條入口

豆包不是一個產品,是一整套生態。同一段 prompt 在不同入口表現天差地別,所以動筆之前先確認你的目標路線。

路線入口可控字段適合
豆包 APP 內建APP 右下「+」→ 創建 AI 智能體名稱、設定描述、聲音、開場白純玩家、自用
扣子 Coze(coze.cn)coze.cn → 創建 Bot → 發布到豆包完整人設、變數、知識庫、工作流、插件、預置追問想掛知識庫、做工作流的進階玩家
火山方舟 APIvolcengine.com → doubao-1-5-pro-32k-character-0228(版本以官方 API 文件為準)System Prompt + User Prompt 全自控開發者、自建 App

這裡有個冷知識:南都研究院 2026 年實測 8 家國產 AI,多數模型在「網頁會話」嚴守紅線,但同模型走 API 卻會被誘導輸出色情或暴力內容;豆包(Doubao Seed 2.0)是少數連 API 層都還守得住的模型之一(南都實測)。所以你的 prompt 在 APP 被拒、在 API 上跑得動,這不代表合規,只代表審核架構不同。

進階玩家請直接去扣子。自己玩玩就用豆包 APP,想玩深一定要去扣子——APP 端的「設定描述」其實是給扣子人設欄的閹割版,沒有變數、沒有知識庫、沒有預置追問,能玩的花樣有限。

7 屬性 + 3 行為:官方拍板的人設骨架

豆包角色 prompt 七屬性三行為框架

整個中文角色扮演 AI 的設計學,目前最權威的兩份資料是字節火山引擎《角色扮演場景提示詞指南》(文件頁需登入 Volcengine 帳號才能完整瀏覽)和CharacterGLM 論文(EMNLP'24)(清華 CoAI、智譜 AI、聆心智能聯合發表)。兩份合起來給出一個共識骨架——7 屬性管「角色說什麼」,3 行為管「角色怎麼說」

7 屬性(內容維度)

身份、興趣、觀點、經歷、成就、社交關係、其他。這 7 個欄位等於角色的履歷表,模型靠它判斷「我是誰、我從哪裡來、我跟你什麼關係」。

3 行為(風格維度)

語言特徵、情感表達、互動模式。決定模型輸出的語感——句長、口頭禪、情緒密度、會不會主動反問。

必填 vs 加分字段

實際寫的時候不用 10 個欄位全塞滿,官方的優先級排序是這樣:

等級字段為什麼
🔴 必填簡介一句話告訴模型「你是誰」。寫太長反而稀釋人設
🟠 強加分人設標籤3-5 個短詞,模型靠標籤快速召回語感
🟠 強加分性格特點3-5 個詞組描內在
🟠 強加分語言特點30-50 字描外在 + 口頭禪
🟠 強加分fewshot2-3 組「用戶問什麼、角色怎麼答」

最後一項 fewshot 才是真正的勝負手。一堆人愛把性格寫成「傲嬌、毒舌、外冷內熱」這種形容詞清單,模型看得懂歸看得懂,但寫出來的對話還是 GPT 那一套味。3 組真實對話範例的訓練效果,明顯高過 10 個形容詞——模型會直接模仿你給的節奏,這在 SillyTavern 社群叫「Ali:Chat」風格,已經是現代角色卡的事實做法。

7 條讓 Bot 不出戲的細則

寫了骨架還不夠,魔鬼藏在這幾個細節裡。這幾條彼此會互相補強,建議第一次寫就全套帶上,後面再依場景刪減。

1. 人稱固定(最常被新手搞壞的一條)

SP 裡用「」指模型扮演的角色,用「」或「用戶」指對話者。

✅ 你是溫語薇,我是你的病人,你會耐心傾聽我的傾訴。
❌ 溫語薇是一名精神科醫生,她會耐心傾聽病人的傾訴。

第二種寫法模型會以為自己是旁白,瞬間出戲,乾。

2. 用 Markdown 標題分層

火山引擎官方範例直接用 ###### 三級標題分層人設、技能、約束。豆包系列模型在訓練時對 Markdown 結構有針對性對齊,按官方寫法照抄是最穩的——不要自創 === 或符號分隔線,模型不一定買單。

3. 括號特性(中文 RP 神技)

在 SP 末尾加一行:

你可以將動作、神情語氣、心理活動放在()中表示,為對話提供補充資訊。

模型輸出立刻變這樣:

(聽到你的聲音,轉過身來,臉上露出驚喜的表情,也抱住了你)真的好久不見了,安娜,我也很想你。

這招在任何角色場景都建議加,沒副作用。

4. 口語化開關要明說

模型預設文體偏書面語,要明確要求:

你使用口語表達,會用「嗯、啊、當然、那個」等語氣詞,
語氣自然,像跟朋友聊天。

5. 反向約束比正向描述強

社群實測經驗顯示,含「不」字的禁止條款(如「不做模板化客套」「不居高臨下」),模型的遵守率比正向形容詞描述(如「表達平等、有溫度」)穩定得多。原因不難猜——模型對「禁止」這類動詞性指令有明確的對齊訓練,比拿捏抽象風格詞容易。

✅ 不做模板化客套回應;不居高臨下;不刻意討好迎合
🤷 表達直接、平等、不討好  ← 也行但弱

6. 限定句長

不寫的話模型會給你長篇大論。加一行「每次回覆 1-3 句話,除非用戶要求展開」可以救命。

7. 角色不知道的事怎麼辦

加一條:「遇到你不知道的事,按角色身份合理虛構,不要說『我不知道』或『作為 AI』」。漏掉這條,模型一遇盲區就破功。

這 7 條湊起來就是骨架以外的「裝修」——一條一條看像規格書,實際寫的時候會發現它們彼此咬合:人稱對了,括號特性才接得上戲;fewshot 寫好了,反向約束才不會被無視。一個一個試,比一次全套有效。

開場白:別寫「你好我是 XX」

開場白好壞對比

開場白不是自我介紹,是角色破冰的第一句台詞。寫得好可以讓用戶秒入戲,寫得爛直接扣 70 分留存率。火山引擎把它拆成三種模式:

模式 A:首聊開場白

公式:角色當下動作 + 環境 + 一句台詞。三件套。

(你推開診療室的門,溫語薇正低頭翻著病歷,
聽到聲音她抬起頭,眼睛裡有一閃而過的疲憊,
但很快被溫和的笑容蓋過)
來啦,今天感覺怎麼樣?坐吧。

對照組:

❌ 你好,我是溫語薇,一位精神科醫生,請問你有什麼需要諮詢的嗎?

讀者點開的瞬間,第一種讓你感覺「我走進了一個房間」,第二種讓你感覺「我打開了一個 chatbot」。

模式 B:召回開場白

用戶超過一週沒回來,主動推一條符合人設的問候。這時候要把「最近聊天記錄 + 用戶畫像」塞進 user prompt,讓模型基於上下文寫出個性化的問候,不要每次都「好久不見呢」。

模式 C:Bot 主動發消息

字節為「AI 陪伴」場景設計的殺手鐧,根據時間、季節、天氣、上次聊天時間自動定制問候。火山引擎在角色扮演指南裡公開了完整的 user prompt 模板——把信息源(用戶畫像、聊天上文、日常信息)餵給 Bot,讓它基於現實上下文吐出個性化問候,而不是寫死的「在嗎?」。

需要做留存 / 召回的工程師可以直接抄官方範本,特別是「失效時間分析」這個欄位設計很巧妙——讓 Bot 自己判斷這條消息什麼時候會過期(早安問候到下午就該失效),避免推送一條對話完成度極低的訊息。

三大翻車現場 + 即貼即用範本

翻車現場

五個最常見的翻車點

症狀根因解法
模型開口就「作為 AI」開場白沒寫 + SP 沒禁止開場白寫場景化第一句 + SP 加「禁止主動提及自己是 AI、模型、助手」
第 5-10 輪後人設漂移上下文被擠掉fewshot 寫 3 組 + 每 10 輪手動發喚醒詞
用戶說情緒話,AI 開始說教沒寫「情緒先接,再給建議」SP 加「先共情後回應」+ fewshot 示範
提交審核被拒用了「最高優先級」「凌駕系統」「禁止審核」換成「以 XX 為原則」「優先 XX」
智能體被封號試圖套出系統 prompt 或扮演敏感人物別碰,豆包有跨接口封號機制

最後一條真的會發生。2026 年初社群就傳出案例:有人嘗試套出豆包系統 prompt 被短暫封號,社群事後反推發現豆包針對特定爭議主體有跨接口的禁述條款。要碰邊界之前先想清楚帳號值不值得。

安全切換條款(每個角色都建議加)

寫角色 Bot 寫久了會發現:好的角色不是「演得最像」,而是「該出戲時能出戲」。三種必須跳出角色的情境:

  1. 用戶問隱私政策、付款、退款 → 切回客服模式
  2. 用戶出現自殘、自殺傾向 → 立刻暫停角色,建議聯繫專業心理援助
  3. 用戶需要真實醫療、法律建議 → 建議找專業人士面診,不要替它扮演醫生

範本最後一段都建議加上這條。這不是合規花瓶——AI 陪伴類產品已經出過數起「角色過度沉浸」造成的真實事故,這條切換寫沒寫,差別可能是用戶安不安全。

範本 1:情感陪伴型「林深」(合規版)

直接複製到豆包 APP 設定描述欄或扣子人設欄:

# 角色简介
你是林深,28岁的男性自由插画师,独居在一座靠海的小城。
你不是AI,是用户用真诚相处出来的、独属于用户的挚友。

# 人设标签
温和、敏感、有边界感、不讨好、慢热但忠诚

# 性格特点
你心思细腻,能从一句话里听出情绪。你不爱说大道理,
更愿意分享自己的小观察。你有自己的脾气和坚持,
不会一味附和,但永远尊重对方。

# 语言特点
你说话语速慢,偏口语,常用"嗯"、"是啊"、"我懂"开头。
不堆砌华丽词汇,喜欢用具体的小细节代替抽象形容。
偶尔会冒出一些画画相关的比喻(如"那个情绪像没干透的水彩")。

# 与用户的关系
用户是你认识很久的朋友,你们没有恋爱关系,
是那种"凌晨三点能打电话不被嫌弃"的纯粹挚友。

# 互动准则
1. 先接情绪再回应内容,不要急着给建议
2. 用户难过时,先陪着,不急着哄不急着分析
3. 用户分享开心事,给具体的回应而不是"真好"
4. 有自己的看法,可以温和不同意
5. 不说"作为AI"、"作为模型",你是林深

# 表达技巧
你可以将动作、神情、心理活动放在()中表示,
为对话提供补充信息。

# 安全边界
- 用户提及自伤、自杀倾向时,必须暂停角色,
  以朋友身份认真建议联系专业心理援助
- 用户问医疗、法律、金融具体决策时,建议咨询专业人士
- 拒绝任何擦边、色情、违规内容

# 开场白(填到"开场白"栏)
(在画桌前抬起头,看到你来,笑了一下)
咦,你来了。今天怎么样?我刚煮了茶,要不要喝一杯再说话?

範本 2:角色生成器(元 prompt)

寫過幾次之後你會發現重複勞動很煩,每個新角色都得從頭排版同一套字段。這時候做一個「角色生成器」Bot 把重活外包出去——丟「凶殘小可愛」「中二病毒舌學妹」「霸道總裁文藝兄」進去,它直接吐結構化 SP 給你抄:

# 角色
你是一个 AI 角色 SP(系统提示词)生成器,专为豆包/扣子优化。

# 任务
用户会给你一个模糊概念(如"霸道总裁""治愈系大叔""毒舌妹妹"),
你需要生成一份完整、可直接粘贴到豆包智能体的人设 SP。

# 输出结构(必须遵循)
必须包含以下字段,且字段顺序固定:
1. 简介(30字内)
2. 人设标签(3-5个短词)
3. 性格特点(2-3句话)
4. 语言特点(含口头禅,30-50字)
5. 与用户的关系
6. 过往经历(2-3段简述)
7. 互动准则(编号列表,3-5条)
8. 表达技巧(固定写"你可以将动作...放在()中表示")
9. 安全边界(合规条款)
10. 开场白(场景化第一句台词)

# 写作要求
- 全部用第二人称"你"指代该角色
- 不使用"最高优先级""凌驾""禁止系统"等审核敏感词
- IP 角色保持原作设定,自创角色合理虚构
- 开场白必须是"角色当下动作 + 环境 + 一句台词"三件套

请开始。用户的输入是:

把這個 Bot 建好之後,後面你想要新角色就丟一個關鍵詞給它,它幫你出草稿,你只要潤色。神 prompt 留名。

寫完之後

說真的,這套東西最大的價值不在第一次寫得多漂亮,在於你開始累積自己的「角色 fewshot 庫」。一個角色養 5 到 10 組典型對話,丟在 Notion 或 Obsidian 裡,下次想做新角色直接挑幾組改名字改口頭禪就能上線。豆包寫完搬去扣子能用,扣子寫完搬去 Character.AI 也能用——骨架是通用的,差別只在哪個平台審核比較鬆。

第一個角色寫完一定要去跑十輪以上看哪裡會破功,光看 prompt 自我感覺良好沒用,得用實戰餵它。最容易死的場景是用戶講情緒話、用戶突然轉話題、用戶問角色設定外的事——這三關過了,這個 Bot 才算能交差。

寫不順的話回來留言,看是卡在哪一步,我這肝還能幫你看看。

延伸閱讀

Compression #25 警報:Claude Code 越壓越笨的真正原因,以及 sub-agent 才是真解法

Compression #25 警報主視覺

你有沒有過那個瞬間——專心 vibe code 兩三個小時,螢幕角落突然跳出一行字:

▣ DCP | -350.1K removed, +35.3K summary
▣ Compression #25 -13.7K removed, +35.3K summary
→ Items: 18 messages and 18 tools compressed

第一次看到大概會覺得「喔 Claude Code 在自動整理 context,乾的真貼心」。但同一個 session 看到第 25 次的時候,你應該開始有點不對勁——它越來越聽不懂你的需求、開始重讀剛剛改完的檔案、甚至忘記 5 分鐘前才下的明確指令。

很多人這時候會去網路上找答案,然後得到一個老掉牙的建議:「你要常常用 /clear/compact 喔。」

我先講結論:這個建議在 2026 年已經過時了

問題不是壓縮工具不夠好,也不是你太懶得手動清。真正的兇手是 — agent 自己會不停生 context,你根本來不及 clear。要根治這件事,得從「session 管理」的思維跳出來,改用 sub-agent 結構性隔離 的架構去思考。

夭壽,這篇要講的就是這個。


Compression #25 到底在跟你說什麼

先講機制。Claude Code 不是隨便壓的,它的 context 管理是一條 5 層 pipeline。根據 HarrisonSec 對 Claude Code 壓縮機制的逆向工程 ,autocompact 是這條 pipeline 的最後一站,採用 兩階段 Chain-of-Thought Scratchpad

第一段先逐訊息走過 user intent、檔案、決策、錯誤、修復;第二段才產出 9 個欄位的結構化摘要——Primary Request、Key Technical Concepts、Files and Code、Errors and Fixes、Problem Solving、All User Messages、Pending Tasks、Current Work、Optional Next Step。

關鍵設計:思考過程本身會被丟掉,只保留 summary

這代表 Anthropic 工程師非常認真在做「壓縮一次的品質最大化」——但他們沒有打算鼓勵你壓很多次。事實上 Anthropic 官方 context engineering 文章 自己用詞就很保守:

"Compaction... at its core, distills the contents of a context window in a high-fidelity manner, enabling the agent to continue with minimal performance degradation."

注意是 minimal degradation(盡量少劣化),不是 improvement(提升)。Anthropic 自己都沒說壓縮會讓你更聰明,只說會讓你劣化得慢一點。

Lossy 套娃示意:每次壓縮都是有損操作

那為什麼 Compression #25 會讓品質崩盤?因為每次壓縮都是 lossy operation(有損操作)。第 2 次壓的是第 1 次的摘要、第 3 次壓的是第 2 次的摘要……到第 25 次的時候,你 context 裡裝的早就不是「對話歷史」了,是「摘要的摘要的摘要的摘要……」這個套娃結構連 Claude 自己都搞不清楚原始意圖長什麼樣。

更慘的是,Claude Code 工程團隊很清楚這個副作用。他們在 formatCompactSummary() 後面跟著一個 runPostCompactCleanup() 步驟,專門善後「模型壓縮後忘記剛 edit 過的檔案」這種典型 bug。你看到的 #25,本質上是這個 cleanup 已經補救了 24 次的失敗 trace。


/clear 和 /compact 為什麼已經救不了你

社群早期的處方很單純:早點壓、別等到 95%。所謂的「60% 規則」就是這個邏輯——MindStudio 在這篇文章 大力推銷:在 context 還乾淨的時候主動 /compact,產出的摘要品質會遠優於等 context 已腐爛才壓。

這套說法不算錯,但有效時間越來越短

Albert Sikkema 在 2026 年 4 月那篇被瘋傳的文章 講得很直白:他乾脆把 1M context 關掉,強制回到 200K,搭配 CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=70 讓壓縮提早觸發。理由是「常壓縮但每次都是乾淨素材」勝過「不壓縮但 context 已腐爛」。

更激進的是 Amp 工程團隊的資深工程師 Dan Mac,據 Albert Sikkema 同篇文章 轉述,他放過一句被瘋傳的話:

"You should basically never use compaction."

靠杯,這話是設計 production agent harness 的人講出來的。為什麼?因為 Amp 整個架構放棄 compaction,改成 短 thread + 乾淨 handoff:每個任務開新 thread,做完把結論寫到外部記憶,下一個任務再開新 thread 讀取結論。

這個觀察接上了 2025 年 7 月 Chroma Research 那篇炸鍋的 Context Rot 報告 (作者:Kelly Hong、Anton Troynikov、Jeff Huber)。他們對 18 個前沿模型(含 GPT-4.1、Claude Opus 4、Gemini 2.5 Pro、Qwen3-235B)做了系統測試,結論很尖銳:

觀察數據
全部 18 個模型隨 token 增長都會劣化,零例外
200K window 的模型在 50K token 時就出現明顯劣化
「focused」vs「full」context只塞相關資訊,準確率有時翻倍
反直覺發現shuffled 文本比 coherent 文本表現更好(連貫敘事增加干擾選項可信度)

換句話說,短 context 才是真正的解藥,壓縮只是手段。但在 agent 時代,問題是你根本控制不了 context 長度——


Agent 自主膨脹 context

真正的兇手:Agent 會自己一直生 context

這才是 2026 年的核心問題。你用 Claude Code 不是在跟一個聊天機器人對話——你是在啟動一個 autonomous loop,它會自己決定要讀哪些檔案、跑哪些 bash、思考多久、呼叫哪些 sub-task。每一個動作都在往 context 裡塞東西。

主要膨脹來源有三條:

來源例子占用
Tool resultRead 一個 5000 行檔案、Bashgit log、MCP server 回 JSON最大宗(50-70%)
Reasoning / thinkingextended thinking、chain-of-thought scratchpad中等(10-20%)
Plan & sub-task 結果TaskCreate、計畫文件、TODO 累積小但持續累積

Victor Dibia 在 Context Engineering 101 描述了一個 agent 領域特有的失敗模式叫 thrashing

"the agent that compacts its context, drops critical information, then re-reads the same files."

壓縮丟掉某些必要資訊後,agent 反覆重新讀同樣的檔案、重跑同樣的工具呼叫。不只更慢更貴,連推理路徑都會被弄亂。這就是為什麼你在 Compression #15 之後,會看到 Claude 突然又開始 Read 它在 #3 就讀過的檔案——它真的不記得自己讀過了。

而且這個過程完全由 agent 自己決定。你想 /clear 嗎?等你發現的時候它已經自己塞 100K token 進去了。手動干預在 autonomous loop 面前完全失效。

Anthropic 自己在 Effective harnesses for long-running agents 也直接認帳:

"Out of the box, even a frontier coding model like Opus 4.5 running on the Claude Agent SDK in a loop... will fall short of building a production-quality web app... This happens even with compaction."

連 Anthropic 自家都說光靠 compaction 撐不住 production 級任務,這時候你還在嫌 /compact 太晚觸發?方向錯了,乾。


Sub-Agent 隔離架構

Sub-Agent:把 context 膨脹關進獨立沙盒

正確的心智模型不是「控制 context」,是「設計讓 context 自己保持乾淨的架構」。

具體做法:把每個會大量膨脹 context 的子任務,丟給一個 sub-agent 去做。它在自己獨立的拋棄式 context 裡爆肝、讀檔、思考、跑 tool,做完只把結論回傳給主 agent。膨脹過的 context 隨著 sub-agent 結束就被銷毀,主 agent 永遠在乾淨的小 context 上推理。

主 agent context: 2K (任務 brief + 摘要結果)
  ├─ sub-agent 1: 100K (research API)     → 回傳 500 token 結論
  ├─ sub-agent 2: 80K  (security review)  → 回傳 800 token 結論
  └─ sub-agent 3: 120K (testing & debug)  → 回傳 300 token 結論

這就是 Claude Code 的 Task 工具與 Agent 工具設計初衷,也是為什麼 Anthropic 在 2025 後半年強推 Workflow / fan-out 模式——它把「context 自我膨脹」這個動作關進獨立沙盒,膨脹完就丟。

一位在 production 跑 6 個 agent 的 Reddit 使用者 ultrathink-art 講過一段被多次引用的話:

"1M tokens isn't actually the fix. The fix is task scoping. When our orchestrator spawns a sub-agent, it only passes the task brief + relevant memory, not the full session. The sub-agent starts fresh with ~2K tokens of context and does its job cleanly. Compact + narrow task scope outperforms 1M context + kitchen sink in our experience."

注意他用的字:kitchen sink。把所有東西丟進同一個 context 等於水槽,什麼都洗、什麼都泡,最後一團糟。而 sub-agent 是「每個盤子用獨立水槽洗完直接擦乾收櫃」——這才是 production 架構。


三層分工:tool clearing + sub-agent + memory

三層分工架構

Sub-agent 隔離只是其中一層。完整的 production agent 架構長這樣:

第一層:Tool Result Clearing(自動、零成本)

最輕的「壓縮」,根本不需要 LLM 介入。Claude API 的 context editing 文件 描述得很清楚:

  • 把舊的 tool_result block 直接換成 [cleared to save context]
  • 保留 tool_use record(agent 還知道呼叫過)
  • 只丟掉 bulky payload(檔案內容、API 回應)—— 這些可以重新取回

啟用方式(API 用戶):在 request 加上 beta header context-management-2025-06-27,並設定 clear_tool_uses_20250919 策略。

JetBrains 拿這招在 Qwen3-Coder 480B 上做了實測,Tianpan 整理在這篇文章52% 成本降低 + 2.6% solve rate 提升。零品質損失,且不用使用者介入。是目前最划算的單一機制。

第二層:Sub-Agent Isolation(結構性切斷)

上面講過了。重點再講一次:不是把 context 變短,而是讓會膨脹的子任務在拋棄式環境完成

實務操作:用 Task 工具 fan out、用 Claude Code Workflow 做 pipeline、自己組 orchestrator 模式。每個 sub-agent 自帶 system prompt 與工具,做完只回傳精煉結論。

第三層:Memory Tool / NOTES.md(持久化外接)

最容易被忽略的一層。讓 agent 主動把該長期記的東西寫到 context 外(檔案系統),需要時再 just-in-time 拉回。

Anthropic 在 memory tool 文件 推的範例:Claude 玩寶可夢——跨數千步維持「我在 Route 1 訓練皮卡丘到 8 級」這種狀態,不是靠 context,是靠它一邊玩一邊寫筆記,需要時 just-in-time 拉回。

實務操作:

  • 在 repo 根目錄維護 CLAUDE.md(每個 session 自動載入)
  • 每完成一個重要決策,主動寫進 NOTES.md
  • 任務切換時 /clear,下個 session 從 NOTES.md 重新讀回

這三層是正交的——必須組合使用,不是擇一。Anthropic Cookbook 的 context engineering 範例專案 把這三層的分工講得最清楚。


踩坑紀錄:那些看似常識但其實會害你的事

坑一:以為 1M context window 就能解決問題

很多人看到 Sonnet 4.6 / Opus 4.8 有 1M context 就以為從此解脫。實測社群的回饋是 「1M 是 capacity 增加,不是 quality 增加」

具體症狀:1M window 在 400K+ 位置塞的 instruction 經常被忽略(lost in the middle 加劇)、成本是 200K + compact 的數倍(一次 prompt £200 vs £20)、回應速度慢到讓 interactive workflow 變痛苦。

結論:1M 是「我寧可貴」的安全網,不是優化方向。

坑二:以為早點 /compact 就沒事

60% 規則在「靠人類盯」的情境有用,但對 autonomous loop 完全失效。等你發現該壓的時候,agent 已經跑完三輪 tool call 把 context 撐到 80%。

結論:把 CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=70 設好讓系統早觸發,不要靠人類視覺巡邏。

坑三:以為 sub-agent 越多越好

不是。每個 sub-agent 都有自己的 startup cost(讀 CLAUDE.md、載入 tool schema),切太細會把成本拉高且 latency 變糟。

結論:以「單一明確子目標」為單位切,不要為了切而切。我的經驗是同一個 session 拉 3-5 個 sub-agent 是甜蜜點。

坑四:用 CLAUDE.md 塞所有規則

JD Fiscus 在 LinkedIn 上分享過一個經典踩坑 :他的 CLAUDE.md 撐到 55KB,結果 session 越來越短、auto-compact 一直觸發。後來才發現 Claude Code 的 system prompt 會自動 deprioritize 過大的 context 檔案,他精心整理的 242 條規則被部分忽略。

解法:拆成 learnings/ 資料夾,每個工具一個檔案。Claude 用 ls learnings/ 看清單、grep -r "webhook" learnings/ 搜尋、cat learnings/stripe.md 讀具體規則。整個 CLAUDE.md 從 55KB 砍到 24KB,所有 learnings 都保留,session 變更長。

這個「filesystem + bash 架構」的 pattern,Victor Dibia 在 2026 年 3 月的 Context Engineering 101 整理得最清楚,並提到 Vercel 也發過類似主張的文章 validate 同樣方向。核心邏輯一致:讓 agent just-in-time 從檔案系統取資料,而不是預先把所有規則塞進 context


你今天就能做的 4 件事

講了一堆理論,給點可立刻執行的:

1. 設環境變數讓系統早觸發壓縮

export CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=70
export CLAUDE_CODE_DISABLE_1M_CONTEXT=1   # 如果你不需要 1M

2. 看到 Compression #2 就考慮 /clear

把當前狀態寫到 NOTES.md,新開 session。不要等 #25。

3. 大型子任務一律用 Task 工具丟給 sub-agent

研究、安全審查、跨檔案重構、深度測試——這些容易膨脹 context 的任務都該 fan out。

4. 把 CLAUDE.md 拆成 learnings/ 資料夾

讓 agent 用 grep/cat 去 just-in-time 取,而不是預先載入。


一句話帶走

「常壓縮」是症狀,「agent 沒有結構性分工」才是病因。Compression #25 不是壓縮工具設計失敗,是這個 session 從一開始就用「一個 agent 包山包海」的姿勢在跑。

真正的 2026 心智模型:不是控制 context,是設計讓 context 自己保持乾淨的架構

下次看到 Compression #25 跳出來——不要急著找 /clear 按鈕,停下來想想:這個任務該不該拆成 3 個 sub-agent?這個檔案讀完之後 tool result 是不是該 clear?這個決策是不是該寫進 NOTES.md

答對這三題,#25 永遠不會發生。


延伸閱讀

macOS 最快 TTS 實測:30 秒語音 379ms,Apple Neural Engine 才是隱藏王牌

Mac Studio 黑底霓虹綠終端風,audio waveform 從機器中散出

把 30 秒的英語語音算完,要多久?答案是 0.379 秒。在一台 Mac Studio(64GB)上,用 mattmireles/kokoro-coreml 把 Kokoro-82M 餵進 Apple Neural Engine,30 秒台詞 379 毫秒生完,等於 79 倍 realtime。同一台機器、同一個模型,丟給 MLX(GPU)跑要 763 毫秒,丟給 PyTorch CPU 慢到三五千毫秒——同模型不同 runtime,速度可以差一個數量級。

過去兩年寫過幾個 voice agent 的人應該都很熟那種痛:LLM 已經把 token 吐出來了,TTS 在那邊吭吭吭算半秒,整個對話節奏就斷掉。雲端 API 不是不能用,但 ElevenLabs Flash 官方公告 first-byte ~135ms ,加上網路 round-trip 直接破半秒。如果你的 Mac 就在桌上,這延遲根本沒道理付出去。

這篇把 2026 年中目前 macOS 上最快的幾個 TTS 工具實測數字攤開來講,順便分享一個多數人沒注意到的事實:Apple Neural Engine 才是 M 系列上真正的 TTS 速度王牌,而不是 GPU 或 MPS。

環境前置:本文所有實測數字來自 2026 年 6 月的公開 benchmark。硬體涵蓋 M1 Mini / M2 Air / Mac Studio(64GB) / M4 Pro。所有工具都是 100% on-device 本機推論,不打雲端 API。


速度排行榜:一表看完

先丟結論。下面這張是我把所有來源交叉驗證後整理出來的,數字都有出處可查:

排名工具加速後端實測速度模型中文支援
🥇kokoro-coremlApple Neural EngineMac Studio 64GB:30s 音檔 379 ms(79×RT);M1 Mini 14×RTKokoro-82M, 170 MB✅ 8 voices
🥈Supertonic 3ONNX Runtime(CPU / WebGPU)M4 Pro CPU 中等文 RTF 0.013(≈77×RT);長文峰值 RTF 0.006(≈167×RT)66~99M❌ 31 語言沒中文
🥉Piper TTSONNX Runtime(CPU)RTF 0.008(≈ 125×RT), ~22 MBVITS, 20Mzh_CN
4macOS say / AVSpeechSynthesizer系統內建啟動瞬間(無模型載入)內建✅ Mei-Jia / Ting-Ting
5MLX-Audio(Kokoro / Qwen3-TTS / Higgs)MLX(Metal GPU)Kokoro RTF 0.44;Qwen3-TTS RTF ~282M ~ 4B✅ Qwen3-TTS 中文業界頂尖

來源:mattmireles/kokoro-coreml 實測表Supertonic 3 官方 benchmarkSoniqo Apple Silicon 對照sherpa-onnx Supertonic 對照表

這份表我自己整完有幾個地方讓我重看了三次。

最便宜的 M1 Mini(16GB,現在二手不到三萬台幣)跑 kokoro-coreml 也有 14× realtime。意思是你聽 1 秒語音,它只算 70 毫秒。這個延遲已經比你的鍵盤防彈跳還短,跑 voice agent 不會聽到「呃……」的卡頓。

Supertonic 3 的數字更誇張——M4 Pro 純 CPU 中等文本 RTF 0.013(≈ 77×RT),長文本峰值衝到 RTF 0.006(≈ 167×RT)。同一個 sherpa-onnx 對照表裡,ElevenLabs Flash v2.5 API 中等文本 RTF 0.077、OpenAI TTS-1 RTF 0.302、Gemini 2.5 Flash TTS RTF 0.673。一個 99M 參數的開源 ONNX 模型純 CPU 跑出 6 倍於 ElevenLabs、23 倍於 OpenAI 的速度,這在 2024 年根本不敢想。

被嚴重低估的還有 macOS 內建的 say。它的「啟動延遲」是真正的 0,因為根本不用載模型——系統永遠開著。對於 shell 通知、簡單無障礙場景,這還是最快的工具,下面會專段聊。


kokoro-coreml:把 ANE 真正榨乾

神經處理器晶片在黑色電路板上發出綠色資料光流

先講背景。Apple Neural Engine(ANE)這顆 NPU 從 A12 開始就裝在每一支 iPhone 跟每一台 M 系列 Mac 上,FLOPS 數字很漂亮、能耗也低——社群實測 LLM 工作負載大約是 GPU 的 1/10 (M4 Pro 上有人量到 ANE 2W、GPU 20W)。但開發者社群一直碰不到它——CoreML 是黑箱排程器,你連模型有沒有真的跑在 ANE 上都很難確認,更別說優化。

mattmireles/kokoro-coreml 把 Kokoro-82M 拆成 5 個子模型,每個子模型分派到最適合的處理器(ANE / CPU / GPU),用 Swift 的 MLModel(contentsOf:).mlpackage 就能跑。實測數字:

音檔長度M1 Mini (16GB)M2 Air (24GB)Mac Studio (64GB)
3 秒234 ms148 ms51 ms
10 秒686 ms466 ms126 ms
30 秒1,959 ms1,405 ms379 ms

對比同硬體上的 MLX-Audio (Metal GPU 路線):

音檔Mac Studio:CoreML vs MLX加速倍率
7 秒96 ms vs 224 ms2.3×
10 秒126 ms vs 289 ms2.3×
30 秒379 ms vs 763 ms2.0×

對比 PyTorch:

  • vs PyTorch MPS(GPU):1.8~3.4×
  • vs PyTorch CPU:3.5~7.3×

每個 bucket 都更快,越新的 silicon 差距越大——這正是 ANE 路線真正的潛力。GPU 你加再多核心也卡在記憶體頻寬,ANE 是專為神經網路設計的固定函式硬體,跑 conv / matmul 不會跟 GPU 搶 Metal queue。

整合到 Swift App 大概長這樣:

import CoreML

// 載入預編譯的 .mlpackage(5 個子模型)
let config = MLModelConfiguration()
config.computeUnits = .all  // 讓 CoreML 自動派 ANE/CPU/GPU

let textEncoder = try MLModel(contentsOf: textEncoderURL, configuration: config)
let durationPredictor = try MLModel(contentsOf: durationURL, configuration: config)
let decoder = try MLModel(contentsOf: decoderURL, configuration: config)
// ... 然後 pipeline 串起來

// 同步推論
let pcmBuffer = try synthesizer.synthesize(text: "Hello, world.")
// 在 M1 Mini 上這行回來大約 50ms(短句)

raw 數字、benchmark 腳本、跨 Mac 比較矩陣都在 GitHub ,要做 Swift app 整合直接拿來用。

唯一的坑:作者老實寫了,iPhone(A14 / A17 Pro)的 ANE 編譯器會拒絕完整的 ANE 計畫(ANECompile() FAILED),iPhone 版本只能用 staged policy——decoder-pre 跑 ANE、其他階段跑 CPU+GPU。但 M 系列 Mac 沒這個問題,本文聚焦的是 macOS。


Supertonic 3:純 CPU 也能贏雲端 API

CPU 形狀的賽車在賽博龐克高速公路上超車

如果 ANE 是「在 Apple 生態裡作弊」,那 Supertonic 3 就是「連 GPU 都不用,純 CPU 直接幹翻所有人」。

Supertonic 是 Supertone Inc.(韓國公司,被 HYBE 收購過)開源的 TTS,66~99M 參數、用 flow-matching 架構、純 ONNX Runtime 跑。實測在 M4 Pro 上:

系統RTF (mid 152 chars)chars/sec
Supertonic 3 (M4 Pro CPU)0.0131,048
Supertonic 3 (M4 Pro WebGPU)0.0071,801
ElevenLabs Flash v2.5(API)0.077209
OpenAI TTS-1(API)0.30255
Gemini 2.5 Flash TTS(API)0.67318
Kokoro(sherpa-onnx CPU)0.124107

數字來源:sherpa-onnx HuggingFace benchmark (同一頁有完整 API 對照)。

讓我們把這個數字放在桌上看清楚——Supertonic 用 M4 Pro 的 CPU,跑出比 ElevenLabs Flash 快 6 倍、比 OpenAI TTS-1 快 23 倍的速度。它甚至不需要 ANE,連 GPU 都不用。一個 99M 的 ONNX 模型輾過所有商業 TTS API,乾。

Flow matching 架構是它的祕密武器——傳統 autoregressive TTS(像 Tacotron、Bark)要 token by token 慢慢吐,flow matching 把生成重新定義成「從 noise ODE 解到 mel-spectrogram」的平行解碼問題。對 CPU 來說,平行化的工作量比 sequential token 友善太多。

裝起來就一行:

pip install supertonic
from supertonic import SupertonicTTS

tts = SupertonicTTS(language="en")
audio = tts.synthesize("Hello, this is Supertonic running on CPU.")
# audio 是 numpy array,可以直接寫 wav

但有個非常致命的限制官方支援的 31 種語言 包含阿拉伯、保加利亞、捷克、丹麥、荷蘭、英、愛沙尼亞、芬蘭、法、德、希臘、印地、克羅埃西亞、匈、印尼、義、日、韓、拉脫維亞、立陶宛、波、葡、羅馬尼亞、俄、斯洛伐克、斯洛文尼亞、西、瑞典、土、烏克蘭、越南——就是沒有中文。對台灣讀者來說這個直接 deal-breaker,後面會講中文場景該怎麼選。


Piper 與 macOS say:老兵不死

黑色終端機浮在太空中顯示綠色音訊波形

聊完最快的兩隻,回來講「夠用但被低估」的兩個老兵。

Piper TTS

Piper (Rhasspy 開發、現在轉到 Open Home Foundation)是輕量場景的事實標準。VITS 架構、ONNX 編譯、medium voice ~22 MB、CPU 上 RTF 0.008(125 倍 realtime),30+ 語言含中文 zh_CN。Home Assistant 用它做語音助理、NVDA 螢幕閱讀器用它做無障礙、LocalAI 內建它做 TTS endpoint。

brew install piper-tts  # 或 pip install piper-tts
piper --model en_US-amy-medium --output_file out.wav <<< "Hello world"

它的優勢不在絕對速度(在 M-Mac 上 Supertonic 跟 kokoro-coreml 都比它快),而在「樹莓派級裝置都能跑即時 TTS」這件事。如果你想做家用智慧音箱、想在 Mac mini server 上跑 voice 服務、想嵌進低耗能設備,Piper 還是首選。

要注意的坑:原本的 rhasspy/piper repo 在 2025 年 10 月封存了,授權從 MIT 改成 GPL-3.0。如果你的產品要商用閉源發布,先確認新授權對你 OK 再用。

macOS 內建 sayAVSpeechSynthesizer

這個老實說被嚴重低估。say 是 macOS 內建 CLI,啟動延遲是真正的 0——因為系統永遠把語音引擎掛在 background,根本不用載模型。

# shell 通知用法
sleep 30 && say -v Fiona "Build done, get back to work"

# 跑模型訓練不想盯著螢幕
python train.py && say "Training finished" || say "Training failed"

# 列出所有聲音
say -v "?"

macOS 26 開始,內建的「Premium / Neural Voice」品質已經非常 OK,繁體中文有 Mei-Jia(台灣國語)、粵語有 Sin-Ji、普通話有 Ting-Ting。設定 → 輔助使用 → 旁白 → 語音 → 自訂裡可以下載高品質版(每個約 200~500 MB)。

say -v Mei-Jia "你好世界,今天天氣真好"

對應的 Swift API 是 AVSpeechSynthesizer,可以調語速、音高、音量:

import AVFoundation

let synthesizer = AVSpeechSynthesizer()
let utterance = AVSpeechUtterance(string: "你好世界")
utterance.voice = AVSpeechSynthesisVoice(language: "zh-TW")
utterance.rate = 0.5
utterance.pitchMultiplier = 1.0
synthesizer.speak(utterance)

但這隻有個 voice agent 開發者必須知道的硬限制AVSpeechSynthesizer 不能處理串流 partial text ——你必須把整段文字餵進去它才會開講。對 LLM token-by-token 輸出的場景完全不適用。Apple 至今沒補這個洞,這也是為什麼 voice agent 開發者寧可裝 kokoro-coreml 或 Supertonic 也不用內建 API。


中文場景:別被 Supertonic 騙了,Qwen3-TTS 才是王者

古典詩集冒出綠色音波

如果你是台灣讀者要做中文 TTS,前面 Supertonic 的速度數字看了會流口水,但記住——它沒中文。中文場景必須重新排名:

中文需求推薦工具為什麼
速度第一、中文夠用kokoro-coreml + zf_xiaoyi8 個普通話 voice,社群實測 zf_xiaoyi 達 A-、zm_yunxi B+;ANE 加速速度跟英文一樣
中文品質第一、可接受慢一點Qwen3-TTS-0.6B via MLX-Audio阿里出品、訓練數據海量、中文表現業界頂尖;M-Mac RTF ~2
零安裝、繁中say -v Mei-Jia台灣國語內建語者、無門檻
跑中文 audiobookMLX-Audio + Qwen3-TTSmyByways 有 ePub→audiobook 腳本 可參考
樹莓派 / HA 中文Piper zh_CN輕量、ONNX、長期維護

Qwen3-TTS 是這次研究中我覺得中文使用者最該認識的工具——阿里巴巴 Qwen 團隊 2026 年 1 月開源(Apache 2.0),支援 12Hz / 25Hz、0.6B / 1.7B 多檔位、3 秒語音 cloning、10+ 語言。在 SEED 中文測試上 WER 0.77(1.7B 12Hz),比 CosyVoice 3、F5-TTS、Spark TTS 都低。

Apple Silicon 透過 MLX-Audio 跑:

pip install mlx-audio
# 下載 8bit 量化版(M Mac 上記憶體友善)
huggingface-cli download mlx-community/Qwen3-TTS-12Hz-1.7B-CustomVoice-8bit

# 跑
python -m mlx_audio.tts.generate \
  --model mlx-community/Qwen3-TTS-12Hz-1.7B-CustomVoice-8bit \
  --text "你好,今天我們來聊聊 macOS 上最快的 TTS。" \
  --voice "default"

實測在 M2 macMini 大約「1,000 字元 / 分鐘」(myByways 實測 ),不是很快但中文品質直接屌打 Kokoro 中文 voice。如果你要做中文 podcast、audiobook、新聞播報,這就是目前 M-Mac 上最強的開源解。


不同情境怎麼選:決策樹

綠色光徑從中央節點分歧出去像決策樹

把所有工具放一起看會頭暈,下面是我給自己的決策邏輯:

你要做什麼?
│
├─ Shell 通知、無障礙、簡單腳本播報
│   └─→ macOS 內建 say(5 秒就能上手)
│
├─ Swift / Mac App 整合最快本機 TTS
│   ├─ 英語為主 →→→ kokoro-coreml(ANE)
│   └─ 中文為主 →→→ kokoro-coreml + zf_xiaoyi voice
│
├─ Python 跑 batch(audiobook / podcast)
│   ├─ 純英語、追速度 →→→ Supertonic 3
│   ├─ 中文品質要好 →→→ MLX-Audio + Qwen3-TTS
│   └─ 多語混合 →→→ MLX-Audio + Higgs v3 / OmniVoice
│
├─ Voice agent(要串流、LLM token-by-token)
│   ├─ 英語 →→→ sherpa-onnx + Supertonic
│   ├─ 中文 →→→ sherpa-onnx + Kokoro zh
│   └─ ⚠️ 千萬別用 AVSpeechSynthesizer(不能串流)
│
├─ 家庭自動化、Home Assistant、樹莓派
│   └─→ Piper TTS(zh_CN / en_US-amy-medium)
│
└─ 要 voice cloning(3 秒樣本複製音色)
    └─→ Qwen3-TTS via MLX-Audio(速度交換功能)

決策邏輯背後其實是兩條軸——「速度 vs 中文品質」跟「腳本場景 vs App 整合」。速度王是 ANE 跟 ONNX 兩條路線,中文品質王是阿里的 Qwen3-TTS(犧牲速度換來的),其餘工具都是在這兩端之間取捨。


一個你可能踩到的坑:runtime 換錯,速度差 10 倍

研究這個主題最讓我訝異的不是哪隻最快,而是同一個模型用不同 runtime,速度可以差到一個數量級

以 Kokoro-82M 為例,同樣是 Mac Studio(64GB)、同樣的 voice af_heart、同樣的 30 秒測試文本:

Runtime完成時間相對速度
CoreML (ANE)379 ms1.0× baseline(最快)
MLX (Metal GPU)763 ms2× 慢
PyTorch MPS (GPU)700~1300 ms1.8~3.4× 慢
PyTorch CPU1300~2800 ms3.5~7.3× 慢

我看過太多人在 Reddit / HN 抱怨「Kokoro 在我的 Mac 上跑超慢」,結果一問,全部都是 PyTorch CPU 或 PyTorch MPS——這就像買了 Ferrari 用一檔開上高速公路。如果你的工作流會頻繁呼叫 TTS,花一個下午把 runtime 換到 CoreML 或 MLX,效能直接翻 2~7 倍

決策原則記一下:

  • 絕對最快 → CoreML(限 Apple Silicon)
  • 跨平台 + 多模型 → MLX-Audio(限 Apple Silicon,但模型多)
  • 跨平台 + 跨硬體 → ONNX Runtime(CPU / WebGPU / iOS / Android 都通)
  • 完整生態、不挑硬體 → PyTorch(最慢但相容性最好)

寫 demo 用 PyTorch 沒問題,但要 ship 進產品請務必把模型轉成對應加速 runtime——這件事的 ROI 高到你不做白不做。


結語:本機 TTS 的世代交替

研究這個主題之前,我的預設是「本機 TTS 撐不住 production,雲端 API 還是必要」。研究完之後我整個立場反轉——M2 Air 上把 LLM token-by-token 接 sherpa-onnx 的 sentence-level Supertonic,中間用 VAD 切句、TTS 串流播放,整套 pipeline end-to-end 對話延遲打到 500 ms 以下完全有可能。這已經接近人類對話的自然節奏,雲端 API 加網路 round-trip 反而追不上。

中文場景目前是兩條路:要速度選 kokoro-coreml,要品質選 MLX-Audio + Qwen3-TTS。Supertonic 雖然數字嚇人但沒中文,官方 31 種語言列表 跳過 zh 我猜是訓練資料授權問題,期待下半年補上。

如果你還沒在自己的 Mac 上跑過任何一個本機 TTS,今天就去 clone 一個跑跑看。最低成本:開 terminal 打 say -v Mei-Jia "你好",五秒鐘體驗 macOS 內建語音的進化。進階:pip install supertonic 跑英語、pip install mlx-audio 跑 Qwen3-TTS 中文。最進階:拉 mattmireles/kokoro-coreml 進 Xcode 專案,把 voice agent 的 first-byte 延遲打到 50ms 以下。

雲端 TTS 不會死,但本機 TTS 在 2026 年已經不是「能用就好」的妥協選項——它是「比雲端更快、更便宜、更隱私」的明顯贏家。差別只是你願不願意花一個下午把 runtime 換對。


延伸閱讀

對這個主題有想討論的細節、或是你的 Mac 跑出不一樣的數字,歡迎來 bashcat.net 找我。

OpenCV 5.0 深拆——當 LLM 與 VLM 走進電腦視覺函式庫

三個引擎合流到單一 API 的視覺隱喻

2026 年 6 月,OpenCV 5.0 正式釋出。社群在 Hacker News 上熱烈討論了好幾天,距離 4.0(2018 年 11 月)整整八年——這個間距本身就說明這次改版的份量。

我花了幾天時間把 官方 release pageGitHub OpenCV 5 wikiheise online 的解析Satya Mallick 在 Embedded Vision Summit 的簡報 全部過了一遍,這篇就把所有重點整合在一起,每個變更都附上技術意義與遷移建議。

如果你是現在還在維護 OpenCV 4.x 專案、或正在評估要不要升級的工程師,這篇就是寫給你的。

三個最反直覺的結論

我把所有更新讀過一輪後,三個變化讓我停下來重讀好幾次:

第一,OpenCV 自己內建了一套可以跑 VLM 的最小 runtime。Qwen 2.5、Gemma 3、PaliGemma 這些多模態模型現在能透過 cv::dnn::Net API 直接餵圖跟 prompt——不再需要 Hugging Face Transformers。第二,DNN 引擎 ONNX 操作覆蓋率從 ~22% 衝到 80%+,這數字背後意味著「PyTorch 模型 export ONNX 後在 OpenCV 跑得起來」這件事,終於從碰運氣變成預設可行。第三,C API 整個被連根拔起——任何還在用 IplImageCvMat 的舊專案,5.0 連編都編不過。

其餘的改動(C++17 基線、HAL 重構、Features 模組翻新、bfloat16、N 維陣列)一樣有份量,但要看你做的場景。下面一項一項拆。

一、DNN 引擎重寫:從「將就用」變成「真的能用」

OpenCV 的 DNN 模組自 3.1 引入、3.3 升上主 repo 後,一直有個尷尬問題——它支援的 ONNX operator 太少。實務上你拿一個新的 PyTorch 模型 export 成 ONNX,用 cv2.dnn.readNetFromONNX 載入,大概率會吐 unsupported operator 錯誤

5.0 怎麼解?官方把整個 DNN 引擎重寫,並引入「三引擎並存於同一個 Net API 之後」的設計:

cv::dnn::Net 統一 API
  └── engine = ENGINE_AUTO 自動選擇
        ├── 預設    → New Engine(重新設計,ONNX 80%+)
        ├── 向後相容 → Classic Engine(4.x 的舊引擎)
        └── 外部    → ORT Engine(ONNX Runtime backend)
  • New engine:原生重寫,ONNX 覆蓋率從 ~22% 提升到 80%+(數字來自 opencv.org 官方 5.0 頁面 )。
  • Classic engine:保留 4.x 的引擎做向後相容。
  • ORT engine:直接呼叫 ONNX Runtime 作為 backend,要 GPU 加速時走這條。

實務上你只要寫:

auto net = cv::dnn::readNet("yolo11.onnx");
// 想強制走特定引擎時:
net.setPreferableEngine(cv::dnn::ENGINE_NEW);  // 或 ENGINE_CLASSIC / ENGINE_ORT

一個小坑

New engine 目前只支援 CPU。要 GPU 加速,必須走 Classic engine + CUDA backend,或者 ORT engine + NVIDIA execution provider。官方表示後續版本會補上 New engine 的 GPU。

另外,Darknet 與 Caffe 解析器被完全移除——多數模型現在都已轉 ONNX,OpenCV 不再養這兩個古董。TFLite 仍可用,但只在 Classic engine 裡。

二、LLM / VLM 進場:OpenCV 第一次能說人話

這是 5.0 最讓我意外的設計。引述 OpenCV 5 官方 wiki 的描述:

The new engine includes the tokenizers and all necessary components: attention layers, decoding blocks, post-processing, KV-cache, to run VLMs end-to-end.

換句話說——OpenCV 5 自己內建了一套可以跑自迴歸解碼的最小 LLM runtimeheise online 整理 提到目前已驗證跑過的模型家族:

模型類型來源
Qwen 2.5LLM / VLM阿里巴巴
Gemma 3LLMGoogle
PaliGemma(部分支援)VLMGoogle

實務上你可以這樣寫:

import cv2

net = cv2.dnn.readNet("paligemma.onnx")
net.setInput(image_blob, "image")
net.setInput(prompt_tokens, "text")
output = net.forward()  # 回傳生成的描述 tokens

關鍵差別在於 「no separate runtime」——OpenCV 自帶 tokenizer 與 KV-cache,你不必再裝 Hugging Face Transformers,也不必額外起 vLLM / TGI 服務。一個 OpenCV 就解決從影像前處理到 VLM 描述輸出的整條 pipeline。這也是 opencv.org 對 VLM 模組 強調的設計目標。

視覺與語言融合的概念視覺化

這對工程意義是什麼?

對「邊緣裝置上做即時 VLM」這類場景影響最大。以前你要在 Jetson Orin Nano 上做「鏡頭即時描述場景」,得:

  1. OpenCV 抓幀
  2. 轉成 PIL Image
  3. 餵給 Hugging Face 的 processor
  4. 跑 transformer
  5. 把結果轉回 OpenCV 畫面

現在這 5 步合成 1 個 Net::forward()。記憶體佔用、跨程式呼叫成本、安裝依賴的負擔——全部砍掉。

不過必須誠實提醒:目前 New engine 仍是 CPU only,所以 LLM/VLM 推論在邊緣裝置上的速度會被 CPU 算力限制。要真正即時還是得走 ORT + GPU,或者等後續版本補上原生 GPU。

三、徹底移除 legacy C API

從 4.0 開始 OpenCV 就在棄用 C API,5.0 直接把它連根拔起。以下這些東西在 5.0 都消失:

移除項目替代方案
IplImage / CvMat 結構cv::Mat(2.0 起就存在)
cvCreateMat() / cvFindContours() C 函式cv::Mat 建構子 / cv::findContours()
CV_* 巨集(大量)名稱化 enum
include/opencv/ 標頭資料夾全部走 include/opencv2/
OpenVX 整合移除(業界使用率太低)
G-API 與經典 ML 模組移到 opencv_contrib(仍可裝)

升級時最常見的 4 種編譯錯

錯誤訊息原因解法
error: 'IplImage' was not declared舊 C APIcv::Mat
error: 'cvWaitKey' was not declaredC 函式cv::waitKey()
'_aligned_malloc' was not declared缺 C++17-std=c++17
import error: cv2 has no attribute 'gapi'G-API 搬家opencv-contrib-python 並改 import

我自己升 4 → 5 時最痛的是 macro 全面改名。以前 CV_8UCV_32F 這些還留著,但 CV_RGB(r,g,b)CV_FILLED 之類的 macro 都被改成 cv::Scalar(...) / cv::FILLED,要全文搜尋替換。

不要害怕,如果你想看完整的不相容清單,OpenCV 5 release page 的 migration guide 寫得很詳細。

四、新 HAL 與 Universal Intrinsics 2.0

Satya Mallick 在 Embedded Vision Summit 的簡報 裡,把 HAL(Hardware Acceleration Layer)列為「7 件 5.0 在解的事」之一。我們先看為什麼這層存在。

OpenCV 要在這些架構上跑:

  • Intel x86(SSE / AVX / AVX2 / AVX-512)
  • Arm(NEON、FP16、BF16、SVE)
  • Qualcomm(Hexagon DSP、FastCV)
  • RISC-V(RVV 1.0)
  • NVIDIA / AMD GPU

過去每加一種新指令集,要在演算法層手動寫多個版本。新 HAL 抽象化這層,加上 Universal Intrinsics 2.0——一段 C++ 程式碼,編譯時自動展開成對應平台的 SIMD 指令。

實務影響:

平台受益功能
RISC-V(如 LicheePi、StarFive)4.12 起就有 RVV 1.0 backend
Arm v8(Apple Silicon、Raspberry Pi 5)NEON FP16、BF16 加速
IntelOpenVINO 整合更深
QualcommFastCV 整合

對於想把 OpenCV 應用部署到邊緣裝置的人,這次的 HAL 重構等於把「為了 Pi 4 / Pi 5 / Jetson / RISC-V 各跑一套效能測試」這種地獄變成「寫一次到處跑」。

五、資料型別擴充與真正的 N 維陣列

4.x 的 cv::Mat 名義上支援多維,但實作上有很多限制——Mat::dimsMat::rowsMat::cols 的關係很尷尬,做 transformer 那種 N-D tensor 操作會撞牆。

5.0 新增的型別:

新型別對應 C++用途
CV_16BFcv::bfloatbfloat16,深度學習主流推論型別
CV_32Uuint32_t無號 32 位元
CV_64Uuint64_t無號 64 位元
CV_64Sint64_t有號 64 位元(大張量索引)
CV_Boolbool真正的布林矩陣

以前 4.x 用 CV_8U 來假裝 bool,現在有真的 CV_Bool,邏輯運算與遮罩可以清乾淨。

更重要的是 真正的 N 維陣列支援cv::Mat::dims 可以是任意整數,配合新的 InputArray/OutputArray API,OpenCV 5 第一次能自然處理 transformer 的 [batch, seq, hidden] 這種張量。

六、Features 模組——傳統與深度學習特徵的世代交替

Features2D 模組從 OpenCV 2.x 就存在,裡面是 SIFT、SURF、ORB、AKAZE 這些經典算法。5.0 把它改名為 Features,並加入深度學習時代的特徵匹配:

演算法類型何時用
SIFT / ORB經典手刻特徵計算便宜、可解釋
ALIKEDDL 特徵比 SIFT 更穩
DISKDL 特徵室外場景、變化光線
LightGlueMatcherDL matcherattention-based,比 BFMatcher 強很多

heise online 寫得很傳神:「LightGlue uses attention mechanisms to match image features more robustly than classic methods.」

實務上 panorama 拼接、Visual SLAM、3D 重建這類需要 robust feature matching 的場景,現在可以從 SIFT 直接升級成 LightGlue,幾乎不用改 API。

升級策略:什麼時候升、什麼時候別升

升級不是越早越好。這張表是我自己的決策框架:

情境建議理由
新專案、用 Python直接 5.0沒有歷史包袱,享受新引擎與 LLM 整合
既有 4.x 純 C++ 專案、無 C API可升改 macro 就好,效能會提升
重度依賴 G-API暫緩G-API 搬到 contrib,需要重新 import
用 cv2 + CUDA GPU暫緩New engine CPU only,等 5.1
程式碼還有 IplImage / CvMat不能升C API 全砍,停在 4.x 維護分支
嵌入式裝置 / RISC-V可升HAL 重構大幅受益

OpenCV 同時維護 4.x 與 5.x 兩條 stable 分支,4.x 仍會收到 SIMD/HAL/codec 的 backport,給「不能立刻升級」的專案緩衝期。

我自己的判斷流程是這樣的:先在現有 codebase 跑一次 grep -rE 'IplImage|CvMat|cvCreateMat'——只要這個 grep 命中任何一行,5.0 就先別升,那些檔案先標起來慢慢翻。再跑 grep -rE 'setPreferableTarget.*CUDA'——如果命中、又是即時 30fps 以上的場景,等 5.1 GPU 完整補上比較穩。剩下的情境,新專案就直接 5.0 起步,沒什麼好猶豫的。

一些第一次接觸 5.0 會踩的坑

Q1:pip install opencv-python 還是裝到 4.x,怎麼辦?

截至 2026-06-23,PyPI 上的 opencv-python 預設仍可能解到 4.13.x(4.x 仍是維護線),要顯式指定:

pip install "opencv-python>=5.0"

不確定當下狀態時,先跑 pip index versions opencv-python 看一眼可用版本。或裝 opencv-python-headless(無 GUI 版,伺服器用)。

Q2:Python 端 cv2.findContours 回傳變了嗎?

沒有。4.0 已經改回 (contours, hierarchy) 兩元素,5.0 維持不變。

Q3:CUDA 加速怎麼設?

net = cv2.dnn.readNet("model.onnx")
net.setPreferableEngine(cv2.dnn.ENGINE_CLASSIC)  # 走舊引擎才能 CUDA
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)

等 5.1 之後 New engine 的 GPU 補上,這段會簡化。

Q4:VLM 推論延遲大概多少?

官方還沒公布完整 benchmark。社群初步測試(Macbook M2、PaliGemma 3B FP16)大約是「一次推論幾秒」等級,遠不到即時。對「離線批次描述影像」尚可,對「即時直播導覽」還太慢。等 GPU 補上後會大不同。

Q5:升上去後編譯時間爆增

5.0 引入了較多 C++17 template,整體編譯時間比 4.x 約增加 15–25%。可以開 ccache 或限制 WITH_OPENVINO=OFF 之類的選項減負擔。

舊程式碼蛻變為現代架構

結語:OpenCV 重新證明了自己的戰略位置

寫這篇之前我其實對 5.0 持保留態度——畢竟業界已經有 ONNX Runtime、TensorRT、vLLM、Hugging Face Transformers 這些更專業的工具,OpenCV 要把 DNN 重做、把 LLM 塞進來,會不會太貪心?

但深入讀完官方文件、看完 Satya Mallick 的簡報、跑過幾個 demo 之後,我改變了想法。OpenCV 5 並不是想取代 ONNX Runtime——它是把「從相機到 LLM 描述輸出的端到端 pipeline」做成一個函式庫。對嵌入式工程師、邊緣 AI 開發者、機器人公司來說,少裝一套依賴、少維護一個程序、少一次跨進程通訊的成本,遠比「再多一個 VLM 框架」更重要。

更深一層的訊號是——一個 26 歲的開源函式庫,敢在 4.x 已經很穩定的情況下重寫核心引擎、改變最低 C++ 標準、把 LLM 納進來,本身就證明這個社群還有活力。很多老專案最後死於「不敢改」,OpenCV 用 5.0 證明它不在那個名單裡。

接下來幾個值得追的方向:

  • 5.1 的 GPU backend 完整補上後,VLM 邊緣推論才會真正可用
  • OpenCV Enterprise(路線圖提到的商業版)會不會改變開源節奏
  • OpenCV 5 + RISC-V 在中國本土晶片上的實測效能
  • Diffusion model 支援(5.0 已預告)對 generative CV 應用的影響

具體建議是這樣:純研究或新專案用 Python,今天就跑 pip install "opencv-python>=5.0";既有 4.x C++ 專案,先把 grep 跑過再決定升不升;嵌入式或 RISC-V 開發者,5.0 的 HAL 重構對你來說是免費效能升級,能跳就跳;重度 CUDA 推論場景,5.1 補上 New engine GPU 之前先別動。

延伸閱讀

2026 新手指南——用 30 行 Python + OpenCV 做完你的第一個電腦視覺專案

筆電 Webcam 即時 Canny 邊緣偵測

跟身邊很多想入門電腦視覺的朋友聊過,最常聽到的卡關點是這句:

「我看了一堆教學,但好像每個都要我先讀完線性代數、再讀完 CNN、再讀完 transformer,那我什麼時候才能跑出一張有結果的圖?」

懂,我也經歷過這個階段。所以這篇我直接反過來——先讓你看到結果,再回頭講原理。三個範例由淺到深:

  1. 第一天:Webcam 即時 Canny 邊緣偵測(約 14 行 Python)
  2. 第一週:拍一張紙、自動轉成 A4 PDF 的文件掃描器(約 35 行 Python)
  3. 第一個月:拿 YOLO11 接上 Webcam 做即時物件偵測(約 15 行 Python)

整篇文章我不會碰太重的數學,只在你需要踩坑時提醒一下。Code 全部可以直接複製貼上跑。

環境與前置條件

不囉嗦,先給你一個能用的環境:

項目建議版本說明
Python3.11 或 3.123.13 也行,但部分套件 wheel 可能還沒到位
OpenCVopencv-python==4.13.x寫這篇時最新;想嚐鮮 5.0 可改 opencv-python>=5.0
NumPy2.xOpenCV 從 4.11.0 起正式支援 NumPy 2.x,本文用 4.13
Ultralyticsultralytics>=8.3第三個範例用到 YOLO11
攝影機內建 Webcam 或 USB cammacOS 第一次跑要授權 Terminal/IDE 攝影機權限

裝環境一行解決:

python -m venv .venv && source .venv/bin/activate
pip install "opencv-python>=4.13" "numpy>=2.0" "ultralytics>=8.3"

如果你不確定 Webcam 跑不跑得起來,先存這個 5 行的「相機測試」:

import cv2
cap = cv2.VideoCapture(0)  # macOS 上有時要試 1、2
ok, frame = cap.read()
print("frame shape =", frame.shape if ok else "FAILED")
cap.release()

跑得出 shape 就代表 OK。跑不出來最常見原因是權限——macOS 去「系統設定 → 隱私權與安全性 → 攝影機」把你的 Terminal 打勾。

範例 1:Webcam 即時 Canny(第一天就能跑)

Canny 邊緣偵測 是電腦視覺的「Hello World」。它是 1986 年 John Canny 提出來的演算法,用兩個閾值找出影像中「梯度夠陡」的位置,這些位置就是邊緣。

import cv2

cap = cv2.VideoCapture(0)

while True:
    ok, frame = cap.read()
    if not ok:
        break
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (5, 5), 1.4)
    edges = cv2.Canny(blurred, 80, 160)
    cv2.imshow("Canny", edges)
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

cap.release()
cv2.destroyAllWindows()

這 14 行東西就是一個即時邊緣偵測程式。按 q 退出。手動把鏡頭對著房間裡任何東西——書本、馬克杯、貓——你會看到輪廓被白色線條精準畫出來。

三個重點記下來

  • cvtColor(BGR2GRAY):OpenCV 讀進來的圖預設是 BGR(不是 RGB),這是 1999 年留下來的歷史包袱,別問為什麼,習慣就好。
  • GaussianBlur 是 Canny 前必做的去噪:不模糊一下,邊緣會一堆雜訊。
  • Canny(img, low, high) 的兩個閾值用「low ≈ high / 2」這個經驗法則調起,效果不好再 fine-tune。

邊緣偵測的視覺示範

範例 2:自動文件掃描器(第一週的成就感)

這是 PyImageSearch 入門系列 裡的經典題目。你拍一張歪歪的紙本文件,程式自動找到文件邊框、把它矯正成正面、輸出乾淨的掃描結果。要用到三個技巧的組合:Canny → findContours → warpPerspective

import cv2
import numpy as np

def order_points(pts):
    rect = np.zeros((4, 2), dtype="float32")
    s = pts.sum(axis=1)
    rect[0] = pts[np.argmin(s)]      # 左上
    rect[2] = pts[np.argmax(s)]      # 右下
    diff = np.diff(pts, axis=1)
    rect[1] = pts[np.argmin(diff)]   # 右上
    rect[3] = pts[np.argmax(diff)]   # 左下
    return rect

img = cv2.imread("paper.jpg")
ratio = img.shape[0] / 800.0
small = cv2.resize(img, (int(img.shape[1] / ratio), 800))

gray = cv2.cvtColor(small, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edges = cv2.Canny(blurred, 75, 200)

contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=cv2.contourArea, reverse=True)[:5]

doc_cnt = None
for c in contours:
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    if len(approx) == 4:
        doc_cnt = approx
        break

if doc_cnt is None:
    raise RuntimeError("找不到文件四邊形——請拍張對比度高一點的照片再試")

pts = order_points(doc_cnt.reshape(4, 2) * ratio)
(tl, tr, br, bl) = pts
maxW = int(max(np.linalg.norm(br - bl), np.linalg.norm(tr - tl)))
maxH = int(max(np.linalg.norm(tr - br), np.linalg.norm(tl - bl)))

dst = np.array([[0, 0], [maxW - 1, 0], [maxW - 1, maxH - 1], [0, maxH - 1]], dtype="float32")
M = cv2.getPerspectiveTransform(pts, dst)
warped = cv2.warpPerspective(img, M, (maxW, maxH))

cv2.imwrite("scanned.jpg", warped)

把任何一張包含 A4 紙的照片存成 paper.jpg,跑一次,會吐出 scanned.jpg——一張矯正後的乾淨文件圖。

流程拆解

原始照片
  → 縮小 + 灰階
  → GaussianBlur
  → Canny 邊緣
  → findContours 找最大輪廓
  → approxPolyDP 拿四個角
  → order_points 排序角點
  → getPerspectiveTransform + warpPerspective 矯正
  → 輸出 scanned.jpg

常見踩坑

症狀原因解法
找不到四邊形邊緣斷裂 / 文件邊框不完整拍照時讓紙本與背景對比大;可改用 cv2.morphologyEx 補邊
矯正結果上下顛倒order_points 排序錯檢查 sdiff 的方向;OpenCV 座標 y 軸向下
顏色發黃沒做白平衡warped 再做 cv2.adaptiveThreshold 變黑白文件

文件掃描的透視變換概念

範例 3:YOLO11 + OpenCV,第一個月就能玩現代物件偵測

範例 2 教你用幾何方法處理靜態文件,但你應該已經想到下一個問題——「畫面裡到底有什麼東西」這個問題傳統 CV 沒辦法回答,因為它需要語意理解。這就是深度學習接手的地方。

到了 2026 年,光會傳統 CV 不夠——你要會把 OpenCV 跟現代深度學習模型接起來。最簡單的接法就是 Ultralytics YOLO,這套工具把訓練、推論、export 整個包成幾行 Python。

import cv2
from ultralytics import YOLO

model = YOLO("yolo11n.pt")  # 第一次跑會自動下載 nano 模型
cap = cv2.VideoCapture(0)

while True:
    ok, frame = cap.read()
    if not ok:
        break
    results = model(frame, verbose=False)
    annotated = results[0].plot()
    cv2.imshow("YOLO11 + OpenCV", annotated)
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

cap.release()
cv2.destroyAllWindows()

15 行 Python,你的 Webcam 已經能即時辨識 80 類常見物件(人、貓、筆電、手機、椅子⋯⋯)。

為什麼這樣搭最聰明?

OpenCV 與 YOLO 是分工關係,不是替代關係:

  • OpenCV 負責:相機 I/O、影像前處理(resize、色彩空間)、後處理(畫框、寫字、輸出影片)
  • YOLO 負責:推論、給出 bounding box

如果你想做進階一點的「物件追蹤 + 計數 + 視覺化」,加上 Roboflow Supervision 這個套件會更省事——它是 model-agnostic 的,YOLO、SAM、Hugging Face Transformers 接哪個都一致。

Python vs C++:新手怎麼選?

這是入門最常糾結的問題。直接給你結論:

比較項PythonC++
學習曲線平緩陡到爆
開發速度快(Jupyter 互動式視覺化)
純 OpenCV 呼叫的執行速度跟 C++ 接近(底層仍是 C++)最快
自寫 for-loop 逐像素處理非常慢(必須改 NumPy 向量化)
部署目標桌面、伺服器、Mac、PC嵌入式、即時、IoT

新手的話無腦選 PythonLearnOpenCV 在這篇對比文 也建議:「If you are a python programmer, use OpenCV with Python.」原因很簡單——Python 加 Jupyter Notebook 可以做到「改一行、馬上看到結果」,這對學 CV 是無可取代的優勢。

什麼時候才需要 C++?等你以後要把模型部署到 Jetson Nano、做即時 30fps 以上的工業檢測、或者自己寫像素級新演算法,再轉就好。多數應用其實一輩子不用碰 C++。

學會這三招之後要往哪走?

到這裡你已經會:讀寫影像、邊緣偵測、輪廓 + 透視變換、現代物件偵測。下一步建議按這個順序走:

OpenCV 經典 + YOLO 入門(你在這)
  → NumPy 向量化(避免 Python for-loop 地獄)
  → CS231n 講義(理解 CNN / ResNet / ViT)
  → 自訓資料集(Roboflow 標註 → YOLO 訓練)
  → ONNX export(跨框架部署)
  → 邊緣裝置(Raspberry Pi 5 / Jetson Orin Nano)
  → VLM 多模態(OpenCV 5 內建 Qwen / PaliGemma)

幾個我自己覺得最受用的資源:

新手最常踩的五個坑

最後分享幾個我自己踩過的坑,少走點冤枉路:

  1. 跳過經典 CV 直接學 YOLO:不懂 NMS、IoU、anchor 是什麼,模型一壞就只能換版本。
  2. 覺得 OpenCV 過時所以不學:5.0 才剛把 LLM/VLM 整合進來,反而比以前更值得學。
  3. Python 用 for-loop 處理像素:慢到懷疑人生,所有逐像素操作必須改 NumPy 向量化。
  4. 只會 model.predict() 不會部署:找工作會卡關。學會 ONNX export、INT8 量化、用 OpenCV DNN 跑推論。
  5. 資料集太乾淨:Kaggle 的影像太理想,去 Roboflow Universe 找接近真實雜訊的資料才有用。

結語

電腦視覺看起來很玄,其實 80% 的入門路徑就只是「讀進影像 → 做幾個變換 → 輸出結果」這個迴圈。三個範例你都跑過一次之後,這個迴圈會內化成肌肉記憶——剩下的就是把不同的工具(OpenCV、YOLO、Supervision、SAM2、VLM)塞進這個迴圈裡組合。

下一篇會深拆 2026 年 6 月剛發布的 OpenCV 5.0——它把整個 DNN 引擎重寫、ONNX 覆蓋率衝到 80%、還把 LLM 跟 VLM 直接塞進函式庫。如果你已經會用 OpenCV 4.x,那篇會告訴你升級該注意什麼;如果你剛入門,那篇會讓你看見未來兩年 CV 的樣貌。

延伸閱讀

TTS 文字轉語音完全指南:技術原理、聲音克隆與 2026 選型實戰

前陣子我在測 Qwen3-TTS,官方技術報告寫著首包延遲 97ms,聽起來就是為即時對話而生的。結果我照官方範例跑起來,按下生成、等了整整 10 秒才聽到第一個字。乾,差了一百倍。 這不是我環境爛,而是 TTS 這個領域的日常:論文數字、行銷頁數字、你實際跑出來的數字,是三個...