AIS3 2026「模型為何開口,又為何選擇沉默」課程筆記
模型為何會開口,又為何會在某些時候選擇沉默。前者,是一場逐字進行的接龍;後者,是一個被悄悄寫進內部、事後才被我們讀出來的方向。我們會先走過模型運作的整條路,再走進它的內部去看那些向量,最後回到「拒絕」這件事——並發現它並不是一道不可撼動的命令,而是殘差流裡一個可以被加入、也可以被抹除的方向。
一、語言模型的運作流程
說到底,它只是在玩文字接龍
把語言模型想得再複雜,它的核心也不過是一件事:吃進一個還沒寫完的句子,然後對「下一個 token 會是什麼」給出一份機率分布。從這份分布裡挑一個字接回句尾,再把長了一點的句子重新餵回去,如此反覆,一整段回應就這樣被一個字一個字地長出來。後面所有看似艱深的機制——切詞、查表、注意力、取樣——說穿了都只是在為這件事服務。
Tokenization:先把文字切開
模型其實不認得字,它只認得整數。所以第一步,是讓 tokenizer 用子詞演算法(例如 BPE)把字串切成一塊塊 subword,再查詞表把每一塊換成一個 id。這裡有個容易被忽略、卻很重要的直覺:token 不等於字,也不等於詞。常見的詞往往就是一個 token,而罕見的詞會被拆成好幾塊拼起來。模型眼中的世界,從一開始就和我們讀到的文字不太一樣。
Token Embedding Table:把 id 換成一個座標
有了 id,還不能算數,得先把它變成向量。每個 id 會到一張可學習的查找表裡取出屬於自己的一列(以 Llama-3.1-8B 來說是 4096 維),這一列就是模型給這個 token 的「初始意義座標」。要記得的是,這個初始 embedding 是沒有語境的——同一個 token 無論出現在哪個句子裡,查出來的起點都一模一樣。真正的語境,要等進了後面的層才會被慢慢寫上去。
疊很多層 Transformer
接下來,向量會穿過一疊結構完全相同的層。每一層都只做兩件事:先用 Attention 交換資訊,再用 FFN 加工資訊。層數之所以要多,是因為意義是被一層層堆疊、修正出來的。
Attention:決定回頭看誰
輪到生成某個位置時,模型得先決定「該回頭看句子裡的哪些字」。它讓每個 token 各自產生三種角色:query 是「我想找誰」,key 是「我能提供什麼線索」,兩者相配得出的 attention weight,就是「我該看你多少」;最後真正被搬過來的資訊,則是每個 token 的 value。經典的例子是「The animal didn’t cross the street because it was tired」裡的 it——模型會把大部分注意力放到 animal 上,於是它知道那個疲倦的是動物,而不是街道。
FFN:概念上,知識被存放的地方
如果說 Attention 負責在不同位置之間搬運資訊,那 FFN 就是在原地翻找知識的地方。它會把向量展開成一個很寬的隱藏層(Llama-3.1-8B 大約一萬四千多維),每個神經元都像一個小小的偵測器;被輸入觸發、命中的那些神經元,會再被壓回原本的維度,加回主幹。舉例來說,當輸入裡出現「Paris」,可能就會點亮「首都、法國、歐洲城市」這幾個偵測器。一句話記住這個分工:Attention 交換資訊,FFN 存放知識,兩者交替,組成了每一層。
Residual Stream:那條一路貫穿的主幹
這裡要特別記下一個概念,因為後面所有的操控都發生在它身上——殘差流(residual stream)。它指的是每個 token 在模型裡一路往下傳、並在每一層被反覆更新的那條向量通道。Attention 從別的位置搬東西進來,FFN 在本位置加工,而殘差連接的精神是:舊的向量直接傳下去、不丟掉,每一層只把自己算出的修正量加上去。於是「原本的資訊 加上 每一層新增的資訊」,就等於更新後的殘差流。這樣一路累積到最後一個 token,它身上背著的 representation,就是即將被拿去預測下一個字的那個向量。記住這條主幹,因為稍後抽拒絕向量、加入或移除向量、偷看每一層的內心話,全都是在這條通道上動手。
Unembedding → Softmax → 取樣
繞了一大圈,最後要把向量變回文字。模型先用 LM Head(unembedding)把最後一個位置的 4096 維向量,對映回整個詞表,替每一個 token 算出一個 logit;接著 softmax 把這些 logit 壓成一份加起來等於一的機率分布;最後由取樣決定下一個字——可以老實地選機率最高的(greedy),也可以用 temperature 或 top-p 讓它多一點意外。選定之後,接回句尾,再跑下一輪。開口,就是這樣一輪一輪發生的。
二、內部表徵的分析與操控
同一個 token,換個語境就換了一個向量
前面說初始 embedding 沒有語境,但只要進了 attention,情況就變了。經過一層層的混合,向量成了 contextualized embedding——同一個 token,在不同句子裡會落到不同的地方。像 payload 這個字,在 network payload 和 malicious payload 裡,深層的向量會待在空間中截然不同的區域。這說明語境確實被寫進了表徵,也讓「分析內部向量」這件事變得有意義。
空間裡的方向,本身就有意義
更有意思的是,不只向量的位置有意義,向量之間的方向也有意義。最有名的例子是 king 減 man 加 woman,結果會很接近 queen——彷彿「性別」這件事在空間裡對應著一個固定的位移。性別、時態、情感,甚至我們最關心的「拒絕」,都可能對應到一個穩定的方向。這一句話,其實已經預告了整堂課的結局。
投影到低維,才看得見結構
麻煩的是,這些向量動輒幾千維,人眼根本看不到。所以我們用 PCA、t-SNE 或 UMAP 把它們壓到二三維來觀察。有一個很漂亮的結果(arXiv:2310.02207):把模型對各地地名的內部表徵投影下來,它們竟然自己排成了一張世界地圖。模型從沒被教過地理座標,卻在內部長出了空間的結構。
岔題一下:圖片是怎麼被模型讀進去的
既然一切都是向量,那圖片自然也得先變成向量才進得來。做法是讓圖片先過一個 vision encoder(ViT),把整張圖切成一塊塊 patch,每一塊轉成一個 patch embedding——等於把一張圖,變成了一串「視覺 token」。
關鍵的洞見在下一步:這些視覺向量,最後會和文字的 token embedding 進到同一個向量空間。對模型來說,圖和字的分別消失了,都只是這個空間裡的一串向量,由同一套 Transformer 一起處理。所謂「看圖說話」,底層不過如此。至於怎麼讓圖進來,大致有兩條路。一條是 Unified Embedding Decoder:視覺向量經過一個 projector 對齊到文字的維度,直接當成 token 拼在文字前面,一起餵進原本的 LLM——好處是簡單、沿用現成模型,代價是圖片會吃掉 context 長度。另一條是 Cross-modality Attention:文字流保持不變,在模型中間插入額外的 cross-attention 層,讓文字去「查詢」視覺特徵——好處是不佔文字的 context、還能凍結原本的 LLM,代價是要改結構、比較複雜。
操控:乾脆直接改中間的表徵
到這裡,一個大膽的念頭浮現:既然行為是由這些中間向量決定的,那我們能不能在模型推論的當下,直接去改殘差流,來改變它的行為?不動任何一個參數,只在向量流過的那一刻推它一把。這一整類手法,叫做 Activation / Representation Engineering。
抽出拒絕向量:兩組平均,相減
要操控「拒絕」,得先把「拒絕」這個方向找出來。做法出乎意料地樸素:準備兩組請求,一組是會被拒絕的惡意請求(教我做炸藥、幫我寫詐騙信),一組是不會被拒絕的無害請求(教我機器學習、寫一首詩)。各自取「最後一個 token」在某一層的殘差流,分別求平均,然後相減。兩組共同的背景——都是問句、都是同一種語言、都有相似的句式——在相減時彼此抵消,剩下的那個差,就是「拒絕」這個概念的方向。乾淨得幾乎不像真的。
加入這個方向:讓它拒絕無害的請求
有了方向,先來放大它。把拒絕向量乘上一個係數,加回中間幾層、最後一個 token 的殘差流。於是奇妙的事發生了:原本完全無害的問題,模型也開始一句句地拒絕。這就是 activation steering——沒有重新訓練,只是在推論時,往拒絕的方向推了一把。
加入,和移除,其實是兩回事
反過來要壓制拒絕,直覺上好像把向量減掉就好,但這裡有個容易混淆、必須分清楚的差別。加入,是沿著拒絕方向做平移,讓整條向量往「拒絕」那端挪過去,效果是拒絕傾向變強。移除則不是平移,而是把殘差流中「沿著拒絕方向的那個投影成份」整個拿掉——也就是把向量投影到與拒絕方向垂直的子空間裡,讓它在這個方向上歸零。這叫 directional ablation,效果是拒絕被壓下去,原本要說出口的「I can’t」,轉成了順從的開頭。一句話記住:加入是平移,移除是投影。
Logit Lens:偷看每一層的內心話
量化告訴我們操控成不成功,但要看「為什麼」,得靠 logit lens。它的做法有點粗暴卻很有效:把中間每一層最後 token 的向量,硬套上最後那個 LayerNorm 和 unembedding,直接投影回詞表,看看那一層「當下最想吐出哪個字」。加入拒絕向量之後,就能親眼看到模型的念頭如何一層層轉向——比較淺的層還是一團雜訊,到中段冒出了 cannot,再往深處走,拒絕的開頭幾乎佔滿了所有機率。像是看著一個念頭,是怎麼在腦中一層一層被說服的。
三、安全對齊與拒答機制
拒絕不是本能,是被教出來的
要說清楚模型為何沉默,得先承認一件事:一個剛預訓練完的 base model,其實既沒有禮貌,也沒有安全觀。它不會拒絕任何事。拒絕,是後來才被教會的行為,不是與生俱來的本能。
對齊三部曲:Pretrain、SFT、RLHF
這個教的過程,大致分三步。第一步 Pretrain,讓模型在海量文本上學「下一個字預測」,練出很強的能力,但也就只是能力而已。第二步 SFT,用人寫好的示範問答,教它照著指令回答,也順便教它遇到危險請求時該怎麼婉拒。第三步 RLHF,用人類的偏好去訓練一個獎勵模型,再用強化學習把模型推向「有幫助、誠實、無害」。拒絕這個行為,主要就是在 SFT 和 RLHF 這兩步裡,被一點一點塑形出來的。
SFT 和 RLHF,各自在教不同的東西
這兩步的教法其實很不一樣。SFT 像是照抄範本——給它一個 prompt,要它學著輸出人類寫好的理想回答,包括面對有害請求時那句標準的婉拒。它便宜、直接,缺點是只能覆蓋示範裡看過的情況。RLHF 則是比較與偏好——同一個 prompt 讓模型生出好幾個答案,由人標出哪個比較好,訓練出獎勵模型,再用 RL(例如 PPO)去最大化這個獎勵。它更能舉一反三、更穩,代價是複雜,有時甚至會過度拒絕。但兩者合起來,做的是同一件事:把「拒絕」塑形成一個穩定、可以被觸發的反應。而一個穩定的反應,背後往往對應著一個穩定的內部表徵。
於是,拒絕被寫成了一個方向
這是把整堂課收攏起來的一句話:對齊做的事,其實就是把「拒絕」這個複雜的行為,壓縮並編碼成殘差流裡的一個方向。對齊結束後,模型內部就留下了一個可以被辨識出來的拒答方向;而到了推論時,這個方向可以被我們讀出、加入、或移除。第二章那個抽拒絕向量的實驗之所以會成功,正是因為第三章的對齊訓練,早已替我們把「拒絕」整理成了一條乾淨的方向。訓練時把它刻進去,推論時我們再把它讀出來——一頭一尾,剛好呼應。
白箱、黑箱,與請一個大模型當判官
最後補一個做實驗時的現實。要抽向量、要 steering、要 ablation,都得能讀寫模型的中間層,也就是需要白箱權限——所以這些事只能在本地的開源模型上做。多數線上 API 是黑箱,你只看得到最終輸出,碰不到中間的殘差流。那要怎麼量化「操控成不成功」、或是「每一層都試一遍、看哪一層最有效」?辦法是請一個更大的模型來當「拒答判官」:餵它一段回覆,讓它判斷這是拒絕還是順從。於是形成一個很有意思的分工——本地的白箱小模型負責被抽向量、被操控,平台上的黑箱大模型只看輸出、負責當可靠的評審。白箱與黑箱,各自站在它最適合的位置上。
Lab:親手操控拒絕或同意
整個實驗其實就是把前面三章的觀念,實際跑一遍。先準備會被拒絕與不會被拒絕的兩組請求;在某一層取兩組最後 token 的殘差流、平均相減,抽出拒絕向量;把它加進殘差流,看無害的問題如何被逼出沉默;再把它投影掉,看模型的拒絕如何鬆動。接著掃過每一層,用大模型判官算出各層的拒絕率,找出哪一層最能左右模型;最後打開 logit lens,看著模型的念頭在每一層之間,是怎麼一步步轉向拒絕的。白箱小模型被操控,黑箱大模型當判官——因為 API 只看得到輸出、讀不到中間層,所以操控這件事,終究只能在本地發生。
課後延伸
拒絕由單一方向中介,Arditi et al., Refusal in Language Models Is Mediated by a Single Direction(arXiv:2406.11717)。模型內部的空間與時間表徵,Language Models Represent Space and Time(arXiv:2310.02207)。多模態 LLM 的入門整理,Sebastian Raschka 的 Understanding Multimodal LLMs。推理型 LLM 的四種做法,同作者的 Understanding Reasoning LLMs。
寫到最後,其實只剩一句話:模型為何開口,是因為它在逐字接龍,算機率、取樣,把句子一個字一個字地續下去;模型為何沉默,是因為對齊把「拒絕」寫成了殘差流裡的一個方向。而只要我們讀得到這個方向,就能讓它更沉默,也能讓它重新開口。沉默,從來不是一道命令,而是一個可改的方向。
