「牠」是誰?
你交給 AI 一句還沒寫完的話:「小貓跳上沙發,牠」。人一眼就知道「牠」是那隻小貓,模型看到的卻只是一串編號。跟著「牠」走進一棟三層樓的房子,看它怎麼找到小貓、模型怎麼接出下一個字,以及為什麼 AI 不必每寫一個字,就把整句話從頭重讀一遍。
故事裡會出現的東西
- 牠片段句子被切開後的一小段,依序走進房子的訪客。
- 記筆記本每個片段隨身帶著的一串數字,越往上走寫得越豐富。
- 條便條拿在手上,寫著「我現在想找什麼」。
- 牌名牌別在胸前,寫著「我能提供什麼線索」。
- 夾資料夾放在桌上,裝著「我真正能給的內容」。
- 冊規則手冊每層樓一本,訓練時寫好,使用時不會改。
此刻的「牠」,還不知道自己是誰
先弄清楚:為什麼模型需要「回頭看前文」
你有沒有注意過,AI 回答的時候常常會先頓一下,然後字才一小段一小段地冒出來?這不只是畫面特效。模型真的是一次只寫一小段,寫完一段,再根據「目前為止的全部內容」決定下一段。這個故事要講的,就是那一頓、和後面那一段一段之間,模型裡面發生了什麼事。
第一件事:模型看不懂字。系統會先用分詞器(tokenizer)把句子切成一段一段的片段,英文叫 token。片段不一定剛好是一個字或一個詞,怎麼切由分詞器決定;這裡為了好讀,把句子切成四段,標點先略過。每個片段會對到一個編號,系統再拿編號去一本「數字字典」查出一串數字。這串數字,才是模型真正拿來計算的東西。
點一個片段,看模型眼中的它長什麼樣子
請特別看「牠」。它那串數字是照編號查表查來的,系統只另外加了一點「我排在第 4 個」的位置資訊,好讓模型分得出順序。也就是說,不管前面寫的是小貓、小狗還是颱風,「牠」查到的數字幾乎一模一樣。此刻的「牠」,還不知道自己指的是誰。
這串數字可以想成每個片段隨身帶著的一本筆記本。剛進門時,筆記本上只有「我是哪個詞、我排第幾」。要接著往下寫,模型得先想辦法讓「牠」回頭看看前面出現過誰,把有用的資訊抄進自己的筆記本。
回到電腦裡
片段就是 token,編號叫 token ID,那本數字字典叫 embedding(嵌入表示),查出來的一串數字叫向量。編號本身沒有意義,只是用來查表的號碼。真實模型的向量通常有幾千個數字,這裡縮成 4 個;實際送進模型的內容還包含角色標記、系統指令和標點,這個故事只追蹤句子本身。
「牠」走進房間,回頭看了看前面的人
便條、名牌、資料夾,加上三層樓
想像一棟三層樓的房子,句子裡的片段依序走進去。先看一樓的房間。每個片段進房間之後,會照這層樓的規則手冊,用自己的筆記本做出三樣東西:
- 名牌 K別在胸前,寫著「我能提供什麼線索」,是給別人比對用的。
- 資料夾 V放在自己桌上,裝著「我真正能給的內容」。
- 便條 Q拿在手上,寫著「我現在想找什麼」。
接著輪到「牠」發問。它拿著便條,去和房間裡每個人的名牌比對,算出一個分數:便條和名牌越對得上,分數越高。分數再換算成「比重」,全部加起來剛好 100%。最後,它按照比重把大家資料夾裡的內容各抄一部分回來,混成一份,寫進自己的筆記本。
房間裡有一條規矩:每個片段只能看自己,和比自己早進場的人。「小貓」進場時房間裡只有它自己;「牠」最後進場,所以四個人都看得到。原因很實際:模型的工作是接著往下寫,寫到某個位置時,後面的內容根本還不存在。這條規矩到了故事後半段會變得非常重要。
一樓的房間:按三次按鈕,看「牠」怎麼回頭找人
一樓的結果是:「牠」把 46% 的注意力放在「小貓」、44% 放在自己,「跳上」和「沙發」加起來不到 10%。它按這個比重把資料夾的內容抄回來,筆記本裡從此帶著小貓的資訊。這個「回頭看、按比重抄」的動作,就叫注意力(attention)。你可以把發問的人換成「沙發」試試,會看到「牠」變成灰色:沙發進場時,牠還沒來。
為什麼名牌和資料夾要分成兩樣?因為「方便別人一眼判斷你是不是他要找的人」和「找到之後真正有用的內容」,是兩種不同的需求。模型讓它們各用一組係數去學,效果比共用一份好。
那三樣東西是怎麼做出來的?靠的是這層樓的規則手冊。手冊裡有三組固定的係數,分別把筆記本換算成便條、名牌和資料夾。這些係數是模型訓練時一點一點調出來的,訓練完就定下來;你使用模型的時候,它們不會因為你問了什麼而改變。四個片段用的是同一本手冊,只是各自的筆記本內容不同,所以做出來的東西不同。
回到電腦裡
便條、名牌、資料夾就是 Q(Query)、K(Key)、V(Value),三者都是一串數字。「比對」是把 Q 和 K 逐項相乘再加總(內積),再除以一個固定的數讓分數不要太極端;「換成比重」用的算法叫 softmax,先取指數再除以總和,所以結果一定不是負的、加起來剛好 100%。按比重混合 V 得到的那份內容,叫做注意力輸出。
規則手冊就是模型權重。請分清楚兩種「權重」:模型權重是訓練後固定的係數;剛才那些 46%、44% 是注意力比重,每次都依當下的輸入現算,兩者不是同一種東西。「只能看自己和前面」的規矩叫因果注意力(causal attention)。
一層樓裡還有幾件事
抄回來的內容是加進筆記本,不是把原本的蓋掉,這樣「牠」不會因為抄了小貓的資料就忘記自己是「牠」(這叫殘差連接)。加完之後,每個片段還會各自坐下來把筆記消化整理一次,這一步不再和別人交換資訊(叫前饋網路,FFN)。這兩個動作之前,都會先把數字的大小刻度整理一下,免得越算越極端(叫正規化)。
另外,真實模型的一層樓裡通常不只一組人在比對,而是好幾組同時進行,每組有自己的便條、名牌和資料夾,各從不同角度找資訊,最後再把結果合起來。一組就叫一個注意力頭(attention head)。這個故事只演一組。
然後上二樓、三樓
一樓忙完,四個片段帶著更新過的筆記本上二樓。二樓有自己的規則手冊,大家用「已經寫過一輪的筆記本」重新做一套二樓的便條、名牌、資料夾,再回頭看一次;三樓也一樣。一層一層往上,筆記本裡對前文的理解就越來越完整。
請記住誰會移動、誰不會:往上帶的只有筆記本。名牌和資料夾留在原本那層樓的房間裡,規則手冊也留在各層樓。到了三樓做完,模型只拿最後一個片段「牠」的筆記本,去換算出「下一段該接什麼」的候選名單。
讓整句話走進房子
三樓做完後,用「牠」的筆記本算出下一段的候選機率:
候選名單是一次算完所有樓層之後才產生的,不是每層樓各選一個字再拼起來。名單上每個候選都有機率,這個範例固定挑機率最高的「蜷」;真實的服務常常會照機率抽籤,所以同一句話每次接出來的內容不一定相同。順帶一提,這裡的機率也是用 softmax 算的,但用途和房間裡的比重不同:房間裡是在決定「向誰抄多少資料」,這裡是在決定「下一段寫什麼」。
回到電腦裡
一層樓就是一個 Transformer 層,真實模型常有幾十層。筆記本的正式名稱是隱藏表示(hidden state)。整段前文第一次走完所有層的階段叫 Prefill(前文處理)。最後把筆記本換算成候選分數的部分叫 LM Head(語言模型輸出層),換算出來的原始分數叫 logits。這個教學用小模型的輸出層係數,是為了讓它接出「蜷成一團」而特別校準過的。
每寫一段,整棟樓都要重跑一次嗎?
KV Cache 登場的理由
模型選出了「蜷」,但句子還沒寫完。要決定「蜷」後面接什麼,「蜷」自己也得走進房子:在每層樓做出自己的便條、名牌、資料夾,拿便條去比對前面所有人的名牌,抄資料,上樓,最後用它的筆記本選出下一段。
問題來了:它要比對的那些名牌,也就是小貓、跳上、沙發、牠在各層樓的名牌和資料夾,從哪裡來?有兩種做法,請你按按看差別。
同一句話,兩種做法同時進行
做法 A:每次清場,全部重來
每多寫一段,就請所有片段從一樓重新走一遍,名牌和資料夾全部重做。
做法 B:名牌和資料夾留在原地
做過的不收走。新片段進場時,只做自己的那一對,舊的直接拿來比對。
做法 B 就是 KV Cache:把每層樓、每個片段已經做好的名牌(K)和資料夾(V)留著,後面的片段直接用。Cache 的意思是「快取」,也就是把算過的東西暫時留下來,省得重算。
舊的名牌放了這麼久,不會過期嗎?不會,原因正是前面那條規矩。每個片段只看自己和比自己早進場的人,所以後來不管進來誰,都不會影響前面的人當初做出來的東西。「小貓」的名牌在第一輪就定了,「蜷」來不來,它都長一樣。做法 A 辛辛苦苦重做出來的,和留著的那一份一模一樣,所以才說是白費工夫。
那為什麼只留名牌和資料夾,不留便條,也不留抄回來的內容?因為後來的人用不到。便條只在「自己發問的那一刻」有用,問完就沒事了;抄回來的內容已經寫進各自的筆記本帶上樓,任務也結束了。新片段回頭看的時候,需要的只有舊片段的名牌(用來比對)和資料夾(用來抄)。
有兩個細節很容易誤會。第一,快取省掉的是重做舊片段,不是省掉比對。新片段還是要拿便條和每一張舊名牌比一次,前文越長,要比的名牌越多。第二,被選出來不等於已經進場。「蜷」剛顯示在畫面上時,各層樓仍然只有 4 對;它走過一樓變成 5、4、4,走過二樓變成 5、5、4,走完三樓才是 5、5、5。最後的結束標記被選出來之後就停了,不會再送進房子,也不會有自己的名牌。
句子一長,差距會大到什麼程度
計算的是「片段進場次數」:一個片段從一樓走到頂樓算一次。這是依公式算的次數,不是速度實測。
天下沒有白吃的午餐,KV Cache 是拿記憶體換時間。每個片段在每層樓都要留一對名牌和資料夾,對話越長,留的東西越多,而且要放在運算晶片旁邊最貴的那種記憶體裡。這也是為什麼超長的對話特別吃資源,服務商常常會限制長度、或對長文另外計價。
留著這些東西,要佔多少記憶體
示意設定:32 層、每層 8 組名牌與資料夾、每份 128 個數字、每個數字 2 bytes,算起來每個片段約佔 128 KB。不同模型差異很大,這只是讓你對數量級有感覺。
回到電腦裡
新片段一個一個進場、搭配快取往下寫的階段叫 Decode(逐步生成)。所以你看到的現象可以這樣對應:開頭那一頓主要是 Prefill,整段前文要一次走完所有層(實際上還會加上網路傳輸和排隊等候的時間);後面字一段一段冒出來是 Decode,每一段只處理一個新片段。
為了少佔記憶體,實際的模型會用一些技巧,例如讓好幾組便條共用同一組名牌和資料夾,或只保留最近一段範圍內的快取。這些做法各有取捨,這個故事沒有演。
使用者又問了一句:「牠睡著了嗎?」
快取還在不在,結果差很多
模型寫完「小貓跳上沙發,牠蜷成一團」,選出結束標記停了下來。現在房子裡每層樓各留著 7 對名牌和資料夾。接著使用者又問:「牠睡著了嗎?」這句話切成四個新片段。接下來會怎樣,要看那些留著的東西還在不在。請三種情況都按按看。
第二句話進場
這裡有三個常見的誤會。第一,聊天紀錄還在,不代表快取還在。紀錄是文字,快取是一大堆暫存在記憶體裡的數字,服務隨時可能為了騰出空間而清掉它。清掉了也不是不能回答,只是要把前文重新走一遍,開頭那一頓會比較久。
第二,快取不是模型的記憶,更不是學習。不管你跟它聊了多少,各層樓的規則手冊一個字都沒改。快取只是這一次對話的暫存品,對話結束或被清掉,就什麼都不剩。
第三,只有「從頭開始完全相同」的前文,快取才能接著用。一旦前面某個詞被改掉,從那個詞開始,後面所有片段留下的東西都不能信了,因為它們當初都回頭看過那個詞,筆記本裡混著它的內容。
最後,把三樣東西放回各自的位置
規則手冊
模型權重每層樓一本,訓練時寫好,使用時固定不變。二樓用二樓的手冊,不會去接手一樓的。筆記本
隱藏表示跟著片段一層一層往上帶。每層樓抄回來的內容都寫進這裡,它不會留在房間,也不會交給下一個片段。留在房間的名牌與資料夾
KV Cache按樓層分開保存,給之後才進場的片段回頭比對和抄寫。它是暫存品,不是記憶。| 故事裡的 | 真正的名稱 | 一句話說明 |
|---|---|---|
| 片段 | token | 模型處理文字的單位,不一定是一個字 |
| 數字字典 | embedding(嵌入表示) | 用編號查出起始的一串數字(向量) |
| 筆記本 | hidden state(隱藏表示) | 片段目前的數字表示,逐層更新、往上傳 |
| 規則手冊 | 模型權重(parameters) | 訓練學到的固定係數,每層各有一套 |
| 便條 | Q(Query) | 拿來和名牌比對的數字,只在自己發問時用 |
| 名牌 | K(Key) | 供別人比對的線索;它不是比對出來的分數 |
| 資料夾 | V(Value) | 按比重被抄走的內容;它不是「貢獻度」 |
| 比重 | 注意力權重(softmax 的結果) | 每次現算,加總 100%,和模型權重不同 |
| 抄回來的內容 | 注意力輸出 | 用來更新自己的筆記本,不放進快取 |
| 只能看自己和前面 | 因果注意力 | 也是舊快取永遠不必重算的原因 |
| 一層樓 | Transformer 層 | 注意力+各自消化(FFN),外加殘差與正規化 |
| 同層的好幾組人 | 注意力頭(attention head) | 同一層平行分工;和「多層接力」是兩回事 |
| 留在房間的名牌與資料夾 | KV Cache | 按層保存每個片段的 K、V,供後續片段重用 |
| 整句話第一次進場 | Prefill(前文處理) | 開頭那一頓的主要來源 |
| 之後一個一個進場 | Decode(逐步生成) | 字一段一段冒出來的階段 |
| 候選名單 | LM Head 與 logits | 用最後一個片段的筆記本算出下一段的機率 |
故事沒有說完的部分
這個故事把模型縮成 3 層、每層 1 組注意力、筆記本只有 4 個數字。係數是手工設定的教學用數字,所以一樓「牠看小貓」的比重有刻意安排,二樓、三樓的比重則沒有語意可以解讀,它們只用來示範「每層樓各算各的」。
真實模型在位置資訊的處理、注意力頭的數量、名牌和資料夾要不要共用、快取保留多久多長,都有各式各樣的設計;不同的服務對快取能不能跨次對話保留,做法也不一樣。這一頁講的是共通的概念流程,不是某個模型或某張晶片的逐步實作。
四個問題,確認真的看懂
選了之後會告訴你原因
延伸閱讀
- Hugging Face:Text generation(從 Prompt、token 到逐步生成與停止)
- Attention Is All You Need(Q/K/V、內積注意力與層內結構)
- Hugging Face:Tokenization algorithms(分詞器、token 與 token ID)
- Hugging Face:Chat templates(角色標記與聊天格式)
- Transformers:Llama 模型實作(各層權重、正規化、殘差、前饋與 LM Head)
- Dive into Deep Learning:Queries, Keys, and Values(比對線索與內容為何分工)
- Hugging Face:How caching works(分層快取、舊 K/V 重用與新 token 追加)
- Dive into Deep Learning:Attention Scoring Functions(縮放、softmax 與加權整合)
本頁的小模型採用先正規化、殘差連接與前饋網路的架構,單一注意力頭,Q/K/V 各 2 個數字,筆記本 4 個數字。所有向量、分數、比重與快取重用都在瀏覽器內即時計算,不呼叫任何模型 API,也不傳送資料。它不是訓練出來的中文語言模型。