iT邦幫忙

2026 iThome 鐵人賽

DAY 3
1
Claude AI

從 LLM 到 Agent:用 Claude 拆解現代 AI 工程的每一層系列 第 3

情境學習:LLM 學到的是形狀,不是你的規則

  • 分享至 

  • xImage
  •  

上一篇在黑盒子裡找確定性,靠的是把話講清楚:情境、格式、不要什麼,全部寫下來。但有些東西很難用話講清楚,例如「我們團隊的 changelog 怎麼分」。這時候最直覺的做法是不講了,直接給它看幾個例子

先把這一篇會用到的四個詞講清楚:

  • 脈絡窗口(context window):模型這一次回答時「看得到」的所有文字。窗口外的東西,對這一次回答來說就不存在。後面會專門拆開它。
  • 零樣本(zero-shot)提示:只給指令,不給任何範例。
  • 少樣本(few-shot)提示:在指令之外,放幾組「這樣問、這樣答」的範例。
  • 情境學習(in-context learning):不改模型的任何權重,只靠脈絡窗口裡的東西把任務做出來。零樣本和少樣本都是它的一種,差別只在窗口裡有沒有範例。

同一個問題,零樣本和少樣本的差別長這樣:

零樣本:只有指令。

這則 commit 應該放在 changelog 的哪個區塊?新功能、修正,還是內部?
docs: README 補上本機開發步驟

少樣本:指令一樣,但前面先示範幾組。

這則 commit 應該放在 changelog 的哪個區塊?新功能、修正,還是內部?

feat: 支援用 Google 帳號登入 → 新功能
fix: 修正分頁在最後一頁時會重複顯示 → 修正
refactor: 把訂單驗證拆成獨立模組 → 內部

docs: README 補上本機開發步驟 →

少樣本沒有多講任何一條規則,它只是讓模型先看到「前面這樣問、就這樣答」。

上一篇預告過,範例比形容詞有效,但理由不是你想的那個。這一篇我用 Claude 跑了 24 次零樣本與少樣本的對照,把理由找出來。


30 秒實驗

任務是工程師天天在做的事:把 commit 訊息分到 changelog 的三個區塊,新功能、修正、內部

先用形容詞問一次,這是零樣本

把下面每一則 commit 訊息,分到我們團隊 changelog 的三個區塊之一:新功能、修正、內部。請照我們團隊的慣例分類,要精準、一致。

請分類下面這幾則,只輸出「編號. 區塊」,不要解釋:
1. feat: 匯出報表支援 CSV
2. fix: 時區轉換在夏令時間會少算一小時
3. chore(deps): 升級 axios 到最新的修補版本(修補安全性漏洞)
4. chore(deps): 升級 prettier 2 → 3
5. docs: README 補上本機開發步驟
6. perf: 搜尋結果改成串流回傳,第一筆結果出現的時間從 2 秒降到 0.4 秒
7. refactor: 把訂單驗證拆成獨立模組
8. perf: 單元測試改成平行執行,CI 時間減半

再開一個新對話,這次不講慣例,改成在前面放六個範例,這是少樣本

把下面每一則 commit 訊息,分到我們團隊 changelog 的三個區塊之一:新功能、修正、內部。

<examples>
<example>
commit:feat: 支援用 Google 帳號登入
區塊:新功能
</example>
<example>
commit:fix: 修正分頁在最後一頁時會重複顯示
區塊:修正
</example>
<example>
commit:chore(deps): 升級 lodash 的修補版本(修補安全性漏洞)
區塊:修正
</example>
<example>
commit:chore(deps): 升級 eslint 8 → 9
區塊:內部
</example>
<example>
commit:docs: 補上 API 分頁參數的說明
區塊:新功能
</example>
<example>
commit:perf: 首頁查詢改用索引,載入時間從 1.2 秒降到 0.3 秒
區塊:修正
</example>
</examples>

(接著貼上同樣的「請分類下面這幾則」和那 8 則)

注意範例裡藏了兩條不太符合常識的團隊慣例:文件(docs)一律算「新功能」;效能(perf)一律算「修正」。形容詞版本完全沒提到這兩條,範例版本只用例子暗示,沒有明講。

照這個慣例,正確答案是:新功能、修正、修正、內部、新功能修正、內部、修正


我跑了 24 次,結果是這樣

每一組都是全新的工作階段、各跑 3 次,全部列出來,沒有挑。模型是 Claude Opus 5,在 Claude Code 裡跑。分數是 8 題答對幾題。

上面那兩個提示詞,其實是第二輪用的。在那之前,我先跑了一輪沒有藏任何怪規則的版本,當作對照。

第一輪:先用一般工程團隊都會同意的分法(文件算內部、使用者感受得到的加速算新功能)

提示詞 3 次的分數
零樣本(只有形容詞) 8、8、8
少樣本(六個正確的範例) 8、8、8
同樣六個範例,標籤全部故意標錯 8、8、8
同樣六個正確範例,換個順序 8、8、8

第一輪的四個提示詞長這樣。它們的結尾都一樣,是上面那句「請分類下面這幾則,只輸出『編號. 區塊』,不要解釋」加上同樣 8 則 commit;差別只在開頭。

零樣本只有一段說明,沒有任何範例:

把下面每一則 commit 訊息,分到 changelog 的三個區塊之一:新功能、修正、內部。分類要精準、一致,符合一般工程團隊的慣例。

另外三個少樣本版本,開頭都是「把下面每一則 commit 訊息,分到 changelog 的三個區塊之一:新功能、修正、內部。」,接著是用 <example> 包起來的六個範例,格式跟上面那個範例版本一樣。三個版本只差在標籤與順序:

範例 commit 正確的範例 標籤故意標錯 換順序後的位置
feat: 支援用 Google 帳號登入 新功能 修正 第 5 個
fix: 修正分頁在最後一頁時會重複顯示 修正 內部 第 3 個
chore(deps): 升級 lodash 的修補版本(修補安全性漏洞) 修正 新功能 第 4 個
chore(deps): 升級 eslint 8 → 9 內部 新功能 第 1 個
docs: 補上 API 分頁參數的說明 內部 修正 第 2 個
perf: 首頁查詢改用索引,載入時間從 1.2 秒降到 0.3 秒 新功能 內部 第 6 個

「正確的範例」與「標籤故意標錯」都照表格由上到下排列;「換順序」用的是正確標籤,只是把同樣六個範例改排成表格最右欄的位置。

第二輪:換成上面那套違反常識的團隊慣例

提示詞 3 次的分數
零樣本(只有形容詞) 5、5、5
少樣本(六個範例) 6、6、6
同樣六個範例,換個順序 7、6、7
六個範例,再加一句話把規則寫出來 8、8、8

第二輪的 8 題裡,第 1、2、3、4、7 題每一組每一次都答對,差別全部出在兩條團隊慣例影響到的那三題。把它們的實際答案攤開來看:

題目 團隊慣例的答案 零樣本 少樣本 少樣本換順序 範例加一句規則
5. docs: README 補上本機開發步驟 新功能 內部 ×3 內部 ×3 新功能 ×2、內部 ×1 新功能 ×3
6. perf: 搜尋結果改成串流回傳 修正 新功能 ×3 修正 ×3 修正 ×3 修正 ×3
8. perf: 單元測試改成平行執行 修正 內部 ×3 內部 ×3 內部 ×3 修正 ×3

零樣本三題全照常識分;少樣本只把第 6 題拉過來;換個順序,第 5 題開始搖擺;直到把規則寫出來,三題才一起到位。

第一輪裡,零樣本和少樣本一樣好,範例沒有多幫任何忙;到了第二輪,差距才出現。兩輪合起來,有兩個意外。


第一個意外:標錯的範例,它直接不理

第一輪裡,我把六個範例的標籤全部打亂:feat 標成修正、fix 標成內部。照一般對少樣本的想像,模型應該會被帶歪。

結果三次都是滿分,而且三次都主動附註:範例的標籤看起來標錯了,所以它改成依每則 commit 實際做的事來分。

這其實跟研究的方向一致,只是更極端。Min et al.(2022)在分類與多選任務上,把範例的正確標籤換成隨機標籤,表現只掉了 0 到 5%;他們的結論是,範例真正在起作用的是標籤有哪些選項、輸入長什麼樣子、格式怎麼排,而不是每一組配得對不對。

但別把這句話讀成「標籤不重要」。那是總平均,個別資料集掉得多的也有,而且他們沒有測生成任務。我這裡看到的也只是:當範例跟它的常識衝突得很明顯時,它選擇相信常識。


第二個意外:範例教得會形狀,教不會規則

第二輪才是重點。只給形容詞時,3 次都是 5 分:它照一般慣例分,三條團隊規則全錯。這很合理,「照我們團隊的慣例」這幾個字裡根本沒有資訊。三次它都先去工作目錄裡翻了一下,想找有沒有寫下來的團隊規範(因為是在 Claude Code 裡跑,它看得到檔案),沒找到才自己分。

加上範例之後,分數往上走,但沒有走到滿分。錯在哪裡很有意思:

  • 第 6 題(使用者感覺得到的加速):6 次全部跟著範例,分到修正。
  • 第 5 題(README 補上本機開發步驟):範例明明示範了 docs 算新功能,6 次裡還是有 4 次分到內部。有兩次它自己解釋了理由:範例看起來是依「影響到誰」在分,使用者看得到的算新功能或修正,只有開發者看得到的算內部,而 README 的本機開發步驟是給開發者看的。
  • 第 8 題(CI 變快):6 次全部分到內部。範例裡的 perf 是使用者感受得到的加速,它就把規則理解成「使用者感受得到的 perf 才算修正」。

換句話說,六個範例同時符合好幾條規則,它從裡面挑了一條最合理、最接近一般常識的,而那條剛好不是我們的。它沒有錯讀範例,是範例本身就沒有把規則講死。

最後一組只多了一句話:「docs 一律算新功能;perf 一律算修正,不管使用者感覺不感覺得到。」3 次都是滿分。

這就是範例比形容詞有效、但理由不是你想的那個:範例不是在教它規則,而是在給它線索,讓它自己反推規則。 反推出來的,是它覺得最合理的那一條。


為什麼:範例是你偽造的對話

要理解它為什麼會「反推」,得回到第一篇那個請求結構。把範例改寫成 API 的樣子,其實是這樣:

{
  "model": "claude-opus-5",
  "max_tokens": 64,
  "system": "把 commit 訊息分到 changelog 的三個區塊之一:新功能、修正、內部。",
  "messages": [
    { "role": "user", "content": "docs: 補上 API 分頁參數的說明" },
    { "role": "assistant", "content": "新功能" },
    { "role": "user", "content": "perf: 首頁查詢改用索引,載入時間從 1.2 秒降到 0.3 秒" },
    { "role": "assistant", "content": "修正" },
    { "role": "user", "content": "docs: README 補上本機開發步驟" }
  ]
}

那些 assistant 的回答,模型從來沒有說過,是你替它寫的。少樣本不是一個功能,是你在 messages 裡塞了一段偽造的對話歷史。模型看到的只是「前面這樣問就這樣答」,然後把對話延續下去。

所以範例的效力,取決於這段偽造的歷史把模式交代得多清楚。它能從歷史裡看出輸出只有三種、格式是一個詞、大概依什麼分;但如果歷史同時說得通兩種規則,它就只能用自己的常識去補。這跟上一篇是同一件事:黑盒子只看得到脈絡窗口裡的東西,而範例送進去的是例子,不是規則。

至於順序,研究裡的效應比我看到的大很多。Lu et al.(2022)發現,同一組四個範例只換排列,情感分類的準確率可以從 85% 以上掉到 50% 左右,接近亂猜;而且好的順序換一個模型就不成立,範例加多、模型放大也不保證變穩。我這次換順序,分數只在 6 和 7 之間晃,差別出在第 5 題。我不打算從 3 次結果推論 Claude 對順序不敏感,那篇用的是好幾年前的模型、一個情感分類任務,我的也只是 3 次、8 題。能確定的只有一件事:順序會動到結果,而你事先不知道會動到哪一題。


情境學習發生在哪裡:脈絡窗口

「情境學習」裡的「情境」,指的就是脈絡窗口。上面那段偽造的對話、你的指令、要分類的 8 則 commit,連它正在寫的回答,全部都在同一個窗口裡。這是情境學習唯一的工作空間。

Claude 的官方文件把窗口叫做模型的工作記憶,並且特別強調它跟訓練資料是兩回事:訓練資料變成了權重,窗口則是這一次呼叫臨時看得到的東西。算進窗口的包括系統提示、messages 裡的每一則訊息(連貼進去的文件與圖片)、工具的定義,以及這一輪產生的回答。Claude Opus 5 的窗口是 100 萬詞元(token)。

聽起來很大,但有三件事跟範例直接相關:

  1. 模型沒有狀態。 每一次呼叫的輸入,都是「窗口裡的全部」重新送一遍。那六個範例不會被記住,我那 24 次實驗每一次都是全新的窗口,範例也每一次都重送。
  2. 窗口有上限。 光是輸入就超過窗口,API 會直接回 400 錯誤(prompt is too long)。範例再有效,也得塞得進去。
  3. 塞得進去不代表用得好。 官方文件自己就寫了:詞元越多,準確度與召回能力會下降,這個現象叫脈絡腐化(context rot)。所以窗口裡「放什麼」跟「放得下多少」一樣重要。

把這三件事和前面的實驗放在一起看,就知道情境學習為什麼長這個樣子:它能用的只有窗口裡的東西,而窗口每一次呼叫都從零開始。 這也帶出一個問題:如果什麼都沒有被存下來,這還算是「學習」嗎?


情境學習,算是「學習」嗎?

「情境學習」這個名字確實容易讓人誤會,好像模型讀完範例就「學會」了。先把兩種學習分開:

面向 訓練(微調) 情境學習
改了什麼 模型的權重 什麼都沒改,權重是凍結的
學到的東西存在哪 模型裡 只存在這一次的脈絡窗口裡
下一次呼叫 還在 不見了,要重送
靠什麼推出答案 訓練資料 模型原本就知道的東西,加上你這次給的範例

一篇 ICLR 2026 的論文,標題就直接問了這個問題:Is In-Context Learning Learning?(de Wynter)。它的答案分成兩半。

理論上,算。 作者拿機器學習對「學會」的正式定義來檢查,情境學習在數學上是符合的。但他也指出,情境學習不會把看過的例子存下來,每一次都是拿模型原本就知道的東西,加上提示詞裡的範例,臨時推一次。所以它到底學得多好,只能靠實驗量。

實驗上,很有限。 他測了 GPT-4 Turbo、GPT-4o、Mixtral 8x7B 和 Phi-3.5 MoE 四個模型,用九個答案能嚴格判對錯的形式任務(像是判斷奇偶性、走迷宮、把字串反轉),範例數從 0 個給到 100 個,每個模型累積 189 萬次預測。其中幾個結果,寫提示詞的人很值得記住:

  • 「少樣本」其實不少。 平均準確率的高峰出現在 50 到 100 個範例,不是三五個。
  • 範例一多,說明文字寫成什麼樣就沒那麼重要。 他把提示詞換成隨機打亂的字詞(word salad),一開始準確率很低,有時是 0,但範例一多,很快就爬到相當高的準確率。
  • 測試資料越偏離範例的分布,準確率越低。 其中思路鏈(chain-of-thought)的寫法最敏感。
  • 看起來很像的任務,表現可以差很多。 形式上相近的任務,平均準確率可以差到 31%。

他的結論只有一句:情境學習利用的是提示詞裡的統計特徵,而不是資料之間的關係。

回頭看我那 24 次,這句話剛好解釋了第二輪錯在哪裡:

  • 第 6 題(搜尋結果變快)跟範例裡那則 perf(首頁載入變快)是同一種東西:使用者感覺得到的加速。它在範例的分布裡面,6 次全對。
  • 第 5 題(README 的本機開發步驟)和第 8 題(CI 變快)都在範例的分布外面:範例裡的 docs 是給使用者看的 API 說明,範例裡的 perf 是使用者感覺得到的加速。這兩題 6 次裡分別只對了 2 次和 0 次。

範例沒有告訴它「docs 一律算新功能」,只告訴它「這種 docs 算新功能」。它抓到的是範例表面的規律,一碰到長得不一樣的輸入,就退回自己的常識。 這是我對自己結果的解讀,不是論文的結論:論文測的是形式任務和另外四個模型,不是 Claude,我的也只是 8 題。

所以與其說情境學習是「學會」,不如說是每次呼叫臨時借來的理解:這一次有效,下一次要重借;借到的是範例表面的規律,不是背後的規則。這也是為什麼第二輪只多一句明講的規則就滿分:規則不用再靠反推,它就寫在看得到的地方。

不過,「看得到的地方」也不是永遠都在。對話一長,窗口還可能在你沒注意的時候被改寫。


窗口快滿的時候:壓縮,以及為什麼要壓縮

100 萬詞元聽起來用不完,但在一段很長的對話、或一個會一直讀檔案和跑指令的任務裡,窗口是真的會被塞滿的。這時候有兩種處理方式,兩種都會改寫窗口:一種是直接把最舊的內容丟掉;另一種是壓縮(compaction),把比較早的對話濃縮成一段摘要,用摘要取代原文,對話再接著往下走。

這件事在 Claude 的幾個地方都看得到:

  • Claude 的聊天介面:官方文件提到,像 claude.ai 這樣的聊天介面,也可以用「先進先出」的方式管理窗口,舊的內容先離開。
  • Claude Code官方文件寫明它會自動壓縮,在接近窗口上限時摘要對話歷史;你也可以自己下 /compact,還能附一句話告訴它摘要時要保留什麼,例如 /compact Focus on code samples and API usage
  • API:Claude 的 API 提供伺服器端壓縮(目前還是 beta),預設在輸入累積到 15 萬詞元時觸發,產生一個摘要區塊,之後的請求就從摘要接著走,摘要之前的內容全部丟掉。

為什麼要這樣做?官方文件給的理由有三層,而且剛好都是前面講脈絡窗口時提過的事:

  1. 上限是硬的。 超過窗口就是 400 錯誤,不壓縮,長任務就只能中斷。
  2. 塞得越滿,回答越差。 壓縮文件自己寫的理由是:對話變長,回答品質會下降,所以要讓「正在用的脈絡」保持精簡。這就是前面說的脈絡腐化。
  3. 每一輪都在為整段歷史付錢。 Claude Code 的文件說得很白:它每一個請求都會送出整段對話,詞元成本跟著脈絡的大小一起長。壓縮之後,之後的每一輪都變便宜了。

但壓縮不是免費的,對情境學習來說尤其要小心:

  • 摘要會掉細節。 被摘要取代的原文就不在窗口裡了,模型之後只看得到摘要寫了什麼。如果你在對話早期放了幾個範例、或交代了一條規則,壓縮之後它們還在不在、長什麼樣子,取決於那段摘要。你以為它「學會」的東西,可能在某次壓縮裡被濃縮成一句話,甚至消失。
  • 壓縮本身也要花錢。 要產生摘要,模型得先把整段要壓縮的內容讀一遍,所以壓縮一個很大的脈絡,本身就是一個很大的請求。如果你要的其實是重新開始,而不是延續,Claude Code 的文件建議直接用 /clear,那才是不花錢的。

所以對寫提示詞的人來說,結論很實際:真正重要的規則與範例,不要只放在對話早期,要放在每次都會被送進窗口的地方。 窗口隨時可能被摘要改寫,而情境學習只認得窗口裡現在有的東西。


範例的代價

第一,範例每次都要重送。 前面說過,模型沒有狀態,那段偽造的對話每一次呼叫都要整段再送一次。六個範例不長,但真實的團隊範例常常是幾十組,每一次都在付錢。

第二,範例會把它鎖進你給的模式。 這是優點也是缺點。它學得到格式、學得到語氣,也會把範例裡碰巧出現的特徵當成規則,或者像第二輪那樣,把你沒打算教的規則一起學走。

第三,你不知道它反推出了哪一條規則。 分數不是滿分的時候,你看不出是範例不夠、順序不對,還是它挑了另一條說得通的規則。這一次我能看出來,是因為它剛好自己寫了解釋。

我現在的做法是:規則能用一句話講清楚的,就直接寫出來;範例拿來示範格式和邊界情況,不拿來偷渡規則。 兩個一起用,第二輪就是 8、8、8。


下一篇

提示詞變成資產之後,要付的代價。

到這裡,提示詞已經長出了情境、格式、規則和一整段範例,而它們全都擠在同一個脈絡窗口裡,每一次呼叫都要重送。上面說,重要的規則要放在「每次都會被送進窗口的地方」;下一篇就從那個地方講起:把這些東西存起來的做法、存起來之後看不見的代價,以及改了一個字之後,你怎麼知道它真的變好了


延伸閱讀

  • Rethinking the Role of Demonstrations(Min et al., EMNLP 2022):範例標籤換成隨機,分類與多選任務只掉 0 到 5%;真正起作用的是標籤空間、輸入分布與格式。
  • Fantastically Ordered Prompts(Lu et al., ACL 2022):同一組範例換順序,準確率可以從接近最佳掉到接近亂猜,而且好順序不跨模型轉移。
  • Context windows(Claude 官方文件):脈絡窗口是什麼、哪些東西算進去、各模型的窗口大小。
  • Is In-Context Learning Learning?(de Wynter, ICLR 2026):情境學習在數學上算學習,但實驗上很依賴提示詞表面的規律;範例要到 50 到 100 個才到高峰,分布一偏就掉。
  • Compaction(Claude 官方文件):伺服器端壓縮怎麼觸發、摘要取代了什麼、為什麼要讓脈絡保持精簡。

上一篇
在黑盒子裡找確定性:同一件事,換個問法,差在哪裡
下一篇
提示詞變成資產之後:窗口、快取,和你怎麼知道改好了
系列文
從 LLM 到 Agent:用 Claude 拆解現代 AI 工程的每一層9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言