聽到 MoE(Mixture of Experts,混合專家模型)的運作方式,很多人第一反應是同一個疑問:
一句話被切開、丟給不同的「專家」分頭處理,那最後拼回來,怎麼還能讀起來通順?難道不會東一塊西一塊、語氣前後不接?
這個疑問非常合理——但它建立在一個誤會上。真相是:根本沒有「拼句子」這一步。
要講清楚這件事,得先把那個藏在背後的錯誤畫面拆掉。
先拆掉那個誤會
大多數人腦中的畫面大概是這樣:
句子被切成「今天」「天氣」「真好」,分給專家 A、專家 B、專家 C 各自寫一段,最後再黏起來——所以才擔心黏得通不通順。
實際上完全不是這樣。專家處理的不是文字片段,而是單一 token 在某一層的中間向量(hidden state)。
差別很大。專家的輸入是一串數字(向量),輸出也是一串同樣維度的數字,馬上被合併回主幹,繼續往下一層流。它從頭到尾沒碰過「字」,更沒有「我負責寫這半句」這種事。
所以「拼句子通不通順」這個煩惱,問錯了問題——因為句子不是被拼出來的。那字到底是怎麼出來的?
字是一個一個「猜」出來的
LLM 產生文字的方式,跟你手機輸入法的「自動選字」幾乎是同一回事。
你打「今天天氣」,手機在上面跳出建議:下一個字猜「真」。你點了,變成「今天天氣真」。然後它重新看一遍整句,再猜下一個字「好」。你又點,變成「今天天氣真好」。
LLM 就是這樣運作,只是它自己當那個點選的人:
看著:今天天氣 → 猜下一字:真
看著:今天天氣真 → 猜下一字:好
看著:今天天氣真好 → 猜下一字:,
看著:今天天氣真好,→ 猜下一字:適
... 一個接一個
這叫自回歸(autoregressive):永遠只做一件事——看著目前已有的全部文字,猜下一個字,然後把猜出來的字接回去,再猜下一個。它從來沒有「先生出一堆字、再排列組合」。
通順是怎麼來的?因為每猜一個字,它都重新讀過前面所有字。「好」這個字,是在「已經看過『今天天氣真』」的前提下選出來的——選「好」很自然,選「桌子」就很怪。它自然會挑通順的。
那專家在哪裡?
關鍵來了:專家不負責一段話,它是在「猜下一個字」的這一瞬間,幫忙做計算的小幫手。
把「猜下一個字」想成一道很大的計算題。這道題要經過很多步驟(很多層)才算得出來。在某些步驟,系統會找幾位顧問來幫忙算——這些顧問就是專家。
這張圖只在做一件事:反覆地「看全文 → 猜一個字 → 接回去」。三個地方值得對著看:
- 最外層那條虛線迴圈(橘色輸入 → 綠色選字接回 → 判斷有沒有結束),是字與字之間的接龍。猜出「好」、接回句子、才開始猜下一個字。
- 灰底大框由上往下(Attention → 路由 → 合併 → 下一層),是猜「一個字」時、一次前向傳播裡層與層之間的資料流,得一層一層往下走。
- 每一層的路由器各挑各的。第 1 層被選中的是專家 #3、#7(青色),到第 2 層重新路由、換成 #12、#20——同一個字在不同層走不同專家。旁邊灰色的其他專家,這個字、這一層完全不參與。
注意專家算出來的是「這一個字該是什麼」這道題的一部分,最後整個網路只吐出一個完整的字「好」。不是「顧問 A 寫了今天、顧問 B 寫了真好再拼起來」——沒有這回事。換了哪幾位顧問來幫忙,最後都只匯出那一個字。
路由器怎麼挑專家
那位決定「要找哪幾位顧問」的角色,圖裡叫路由器(router,又叫 gating network)。名字聽起來玄,本體其實就是一個線性層。
每個 token 的向量進來,路由器把它投影成「對每個專家的分數」,用 softmax 轉成機率,再只挑分數最高的幾個——這就是 top-k:
# 路由器本體就是一個線性層 W_g
logits = x @ W_g # token 向量 x → 每個專家一個分數
gates = softmax(logits) # 分數轉成機率
chosen = topk(gates, k=2) # 只取機率最高的 2 個專家
# 被選中的專家各自輸出,再用 gate 權重加權相加
y = sum(gates[i] * expert_i(x) for i in chosen)
k 要挑幾個是設計選擇。Google 的 Switch Transformer 走極端,k=1,一個 token 一層只進一個專家;Mixtral 用 k=2。k 越大,組合出來的表達力越強,但計算也越多。
這裡有個容易忽略的點:這套路由是學出來的,不是寫死的規則。 關鍵在 gate 權重可微分——被選中的專家透過它把梯度傳回路由器,路由器就慢慢學會「這種 token 該送去哪個專家」。(嚴格說,「挑哪 k 個」這個離散動作本身不可微,梯度是順著被選中那幾個的 gate 權重流回去的。)
專家的專長是自己長出來的
下一個自然的問題:那是誰決定「第 3 號專家管程式碼、第 7 號管數學」?
答案有點反直覺:沒有人決定。 MoE 的專家不是各自訓練好、再拼起來的模型。整個 MoE 層——路由器加上所有專家——是端到端一起訓練的。每個 token 走過被選中的那 k 個專家,算出 loss、反向傳播,只更新那幾個專家和路由器,沒被選到的這次完全不動。
一開始路由器是隨機的,誰擅長什麼純屬偶然。但訓練久了,分工會自己湧現出來。
只是湧現出來的分工,跟直覺差很多。實證分析(Mixtral、Switch 的論文都看得到)發現:專家不太是按主題分的——不會有一個專管哲學、一個專管醫學。它們更傾向按語法、token 層級的特徵分:縮排、特定標點、程式碼結構之類,而且相鄰的 token 常被送往同一個專家,這叫 temporal locality(時間區域性)。乾淨的領域分工大多沒出現。
想要可控的分工,得在架構上動手腳。DeepSeek-MoE 的做法是共享專家 + 路由專家:少數共享專家每次都啟動、扛通用知識,其餘路由專家做細粒度專精,減少大家重複學同一套東西。
順帶說,路由是學出來的,就帶來兩個訓練時的頭痛:
- 負載不均。 路由器很容易養出「贏者全拿」——少數幾個專家被大量選中、其他餓死。解法是另外加一個 load-balancing loss,懲罰分配不均,逼 token 平均分散。
- 容量上限。 為了在硬體上湊成固定形狀的 batch,每個專家設一個 capacity 上限,超過的 token 會被擠掉(直接走殘差跳過)或溢位到別處。
記住「負載不均」這四個字,等下講為什麼 MoE 不見得快時,它會原班人馬再出現一次。
循序還是並行
知道字是逐字接龍、每層又重新路由之後,很多人會問:那這一切到底是排隊一個一個來,還是同時進行?
要分三層看,答案不一樣:
| 哪個層次 | 循序 / 並行 | 為什麼 |
|---|---|---|
| 字與字之間 | 循序 | 自回歸:第 1 個字算完、接回去,才算第 2 個字 |
| 同一字、同一層的 top-k 專家 | 並行 | 被選中的 2 個專家同時開算,算完才加權合併 |
| 層與層之間 | 循序 | 第 1 層的向量算完,才能進第 2 層 |
一句話:字是循序接龍的,同一步被叫來的幾位專家是並行的,層跟層又是循序的。 「同一字內的專家並行」正是 MoE 省算力的前提——被挑中的少數平行算,沒挑中的完全不算。
順帶回答一個常被問的問題:你輸入 10 個字,會被不同專家處理嗎?幾乎一定會。 路由發生在 token 層級,10 個 token 各自獨立挑專家;再乘上每層重新路由(假設 32 層 MoE),一句話下來就是好幾百次獨立的路由決策。圖裡那個「第 1 層 #3/#7、第 2 層換成 #12/#20」的換手,就是這件事的縮影。
通順不靠專家,靠 attention
既然字是逐字接龍出來的,那真正讓句子前後連貫、語法正確的,是哪一塊?
是 self-attention(自注意力),不是 MoE。
Attention 讓每個位置都能看到前文所有 token,據此決定接下來該接什麼字。MoE 做的事很侷限:它只是把 Transformer 裡那塊 FFN(前饋網路)換成「稀疏、有好幾個版本的 FFN」,attention 完全沒被動到。
換句話說,兩者管的根本是不同層面的事:
- Attention 負責上下文、連貫、語意關係——通順來自這裡。
- MoE / FFN 負責對單個位置的特徵做非線性加工——換哪幾個專家,不影響句子接不接得起來。
所以「不同專家會不會害句子不通順」這個擔心,從一開始就是多慮的。專家動的是向量層級的加工,通順是 attention 加上逐字接龍保證的,兩者互不干擾。
(如果你想更往下挖一層、看 FFN 在 Dense / MoE / Hybrid 三種架構下結構上到底差在哪,可以接著讀《Dense、MoE、Hybrid:Transformer 的 FFN 有三種長法》。)
換成 Dense,長什麼樣
把同一張圖的「大框內部」換掉,就是傳統的 Dense(稠密)模型。
兩張圖刻意畫成一樣,方便對照:外層的逐字接龍迴圈一模一樣,差別只在灰底大框內部。
Dense 沒有路由器,也沒有專家選擇。每一層就是單獨一個 FFN,每個字經過時,把這一層的整個 FFN 從頭算到尾,全部參數都動用。MoE 則是每層擺了 N 個 FFN,路由器每次只開其中 k 個來算,其餘放著不動。
| Dense(稠密) | MoE(稀疏) | |
|---|---|---|
| 每層 FFN | 1 個 | N 個專家,每次挑 k 個 |
| 路由器 | 無 | 有,逐層重新挑 |
| 每個字的計算量 | 動用整層全部參數 | 只動用被選中的少數專家 |
| 總參數 vs 實際計算 | 總參數 = 計算參數 | 總參數很大,實際只算一小部分 |
這就是 MoE 的賣點:可以把總參數量堆得很大(知識容量大),但每個字實際的計算量只跟那 k 個專家有關,不會跟著總參數等比例暴增。
MoE 到底好在哪
繞了一圈,回到最實際的問題:搞這麼複雜,到底換到了什麼?
核心只有一句:在差不多的推理成本下,輸出品質更高。 因為總參數量大、記得住的東西多,但每個 token 實際只算一小撮專家,等於用「小模型的計算量」換到「接近大模型的知識廣度」。Mixtral 8×7B 每個 token 實際只算約 13B 參數,多項評測卻能逼近、甚至超過 70B 級的 dense 模型,靠的就是這個。
順著這點,還有兩個從輸出面看得到的好處:
- 冷門知識比較不會掰。 容量大,長尾的罕見事實記得住,問到小眾領域時,較不容易因為「記不下」而硬湊出幻覺。
- 任務之間比較不互相擠壓。 Dense 所有任務共用同一組 FFN,學了程式碼可能擠掉一點文學能力;MoE 不同專家能分攤不同類型的加工,減少這種互相干擾。
但有一句必須老實說:同樣的總參數量下,dense 通常品質更好。 MoE 是拿「參數利用效率」換「計算效率」——它賣的是「同計算量下贏 dense」,不是「同參數量下贏 dense」。順帶澄清一個常見誤會:Mixtral「8×7B」的總參數其實約 47B,不是直覺的 8×7=56B——那個名字只代表複製了 8 份 FFN 專家,attention 等其餘部分是共用的。真要拿同樣的總參數去堆一個全用滿的 dense,品質一般還是更紮實,只是 MoE 推理快得多、便宜得多。
固定什麼來比,答案會相反
「Dense 和 MoE 誰品質高」這題藏了個陷阱:不講清楚「固定什麼來比」,答案會完全相反。
| 比較前提 | 誰贏 | 為什麼 |
|---|---|---|
| 固定每個 token 的計算量(FLOPs) | MoE | 同計算量下能掛上大得多的總參數,知識容量輾壓 |
| 固定總參數量(例如都是 56B) | Dense | 參數每個 token 全用上,利用率高 |
所以在吵「誰比較強」之前,得先問一句:你固定的是計算量,還是參數量?
現實裡大家受限的是推理成本與速度,也就是「固定計算量」那一欄。這就是為什麼近年最先進的那批模型(DeepSeek-V3、Mixtral 等)幾乎都走 MoE——在「用得起的成本」這條線上,MoE 能把品質推得更高。
所以 MoE 比較快嗎?
順著上面的邏輯,很容易得出一句結論:「同樣的品質下,MoE 算得少,所以比較快。」
這句話被簡化過頭了。MoE 不見得快。
先補一個背景:現代大模型大到一張 GPU 裝不下,必須切到很多張卡上。Dense 的切法(張量平行 TP、管線平行 PP、資料平行 DP)通訊模式很規律,主力是 all-reduce——大家分頭算同一題,算完拼回來。MoE 多了一種 Dense 沒有的切法:專家平行(Expert Parallelism,EP),不同專家擺在不同卡上。痛點就從這裡長出來——token 被路由到哪個專家,就得把它的向量搬去持有那個專家的卡,算完再搬回來。這種動態搬運叫 all-to-all,比 all-reduce 不規律、也更難最佳化。
問題出在「算得少」指的是理論上的 FLOPs,但你真正感受到的速度是 wall-clock time(實際牆上時間)。這兩者之間,MoE 多了好幾筆 Dense 沒有的開銷:
- 路由計算:每層都要算 gating、做 top-k 選擇。這部分其實很小,通常不是主因。
- all-to-all 通訊(真正的痛點):專家分散在多顆 GPU 時,token 要被送去「持有對應專家的那顆卡」,算完再送回來。這個跨卡搬運往往比計算本身還耗時。
- 負載不均:熱門專家被塞爆、冷門專家閒置,整批得等最慢那顆卡,GPU 利用率被拖低。
省下來的 FLOPs,可能被通訊和等待吃回去。關鍵在於分清楚兩個常被混為一談的指標:
- 吞吐量(throughput):一小時能服務多少 token、多少使用者。同時服務大量請求時,通訊開銷被攤平,MoE 通常明顯贏——這對廠商的成本很友善,也是業界愛用 MoE 的原因。
- 單次延遲(latency):你按下送出,到第一個字冒出來。這種「就你一個人問一句」的場景,MoE 的通訊開銷沒得攤,優勢會縮水,有時還不如同等品質的 Dense 來得乾脆。
所以更精確的講法是:MoE 最佳化的目標,是在可接受的成本下塞進更大的模型;它的快主要兌現在高吞吐量,而不是單次低延遲。
從使用者的角度,這些其實都不重要
講了一堆 FLOPs、參數、通訊,但老實說,這些沒有一個是使用者會在意的。 你打一句話、等一個回覆,根本分不出背後是 Dense 還是 MoE。架構是工程選擇,不是使用者介面。
使用者真正感受得到的只有三件事:回得夠不夠快、答得夠不夠準、價格能不能接受。架構只是廠商為了同時把這三件事做好而選的手段——而且通常也輪不到使用者選,你用哪個產品,架構就是廠商定好的。
所以如果你讀到這裡是想挑一個模型來接自己的工作流,真正該比的不是架構標籤,而是拿你自己的真實任務實測:同樣幾題各跑幾輪,比延遲、比正確率、比成本。「它是 MoE」這個標籤,遠不如你自己場景跑出來的數字可靠。
結語
回到最開頭那個疑問——不同專家處理,怎麼還拼得出通順的句子?
現在答案很清楚:這個問題本身就站錯了地基。沒有人把句子切開分給專家,再黏回來。字是一個一個、看著全文接龍出來的;通順由 attention 保證;專家只是接龍途中某幾站的臨時幫手,動的是向量不是文字。
把整條線拉直來看:
看全文 → 猜一個字 → 接回去 → 再看全文 → 再猜一個字……而每一次「猜」的內部,MoE 只是讓少數專家出手、Dense 則讓整層 FFN 全員上陣。
下次再聽到「MoE 把工作分給不同專家」,你不會再想像一群人各寫半句話然後拼貼——你會知道,那只是一道計算題在每一層換了幾位顧問,而句子,始終是一個字一個字接出來的。