iT邦幫忙

2026 iThome 鐵人賽

DAY 28
0
AI Engineering

不是模型太慢,是你沒算過這筆帳:地端 LLM 工程實戰 30 天系列 第 28

Day 28 - RAG 明明撈到答案,小模型為什麼還會抓錯數字?

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20260908/201835509RqSSyj3OA.png

我問 Gemma 4 E4B:T1 五次量測的 pp 全距是多少?正解 47.9%,它答 5.5%

5.5% 確實在原文裡——但那是拿掉一筆冷卻不足的量測後、其餘四次的結果。兩個數字就在同一句話裡。

問的是五次,它選了四次。

昨天處理的是候選池裡有什麼。今天接著查:正解已經撈到了,為什麼還會答錯?

我用前 24 篇自己量出來的數字出了 40 題——40.83 tok/s284 GB/s47.9%——降低它靠既有知識矇對的機會。其中 38 題的正解有進到 top-5:只給正解那一段,E4B 答對 36 題;連同另外四段一起給,剩 27 題。

https://ithelp.ithome.com.tw/upload/images/20260908/201835501btBdXLcGC.png

圖 1:同一句原文裡,五次與四次的數字都在;它選了不符合題目條件的那個。

這不是特例。我本來以為會看到它憑空生一個數字——沒有。它答錯的那個數字,每一次都在餵進去的段落裡找得到。

「context 那麼長,什麼數字碰巧都在裡面吧」——我也這樣懷疑,所以做了對照:拿同一條件、同位數的別題答案當隨機猜,看它落在同一份 context 裡的比例,是 12.7%。而 E4B 那 38 個吐出錯數字的回合(十種餵法累計,棄答另計),38 次全中。

這些錯數字都能在輸入裡找到,但光憑這點還不能確定它怎麼得到它們——真數字配錯對象、錯條件,一樣是不受來源支持的回答。能做的是把數字拿回 context 搜一次,先分成「找得到」與「找不到」,再核對條件。

少塞幾段、換順序,哪一個有差

那 4 段干擾,害的是順序還是存在?Day 22 把兩件事都放在 L6 Assembly,診斷法是「正確 chunk 放在 context 頭、中、尾各跑一次」——今天跑頭與尾,分開測段落數與正解位置。

我一開始用「正解剛好排第 1 名的題」對「沒排第 1 的題」去看——77.8% 對 54.5%,看起來排序很關鍵。但那是兩群不同的題,問法與難度本來就可能不同。

所以改成受控的問法:同一批 5 段、同一個相對順序,只把正解在第 1 位與第 5 位之間搬一次。

https://ithelp.ithome.com.tw/upload/images/20260908/20183550traAeSsjDX.png
圖 2:三列的正解都一定在裡面,所以量到的是生成端不是檢索。

搬位置這次差了 10 個百分點,但配對是 8 比 4、p = 0.39,40 題還不足以確認這個效果。拿掉那 4 段干擾的落差則量得出來:75.0% 回到 95.0%,改善 8 題、退步 0 題,p = 0.0078。

一組量得到、一組量不到,不等於「兩者的差異」通過了檢定。能說的是前者證據比較明確。

再往上加呢?從 5 段到 20 段沒有觀察到進一步下降(2 比 2,p = 1.0)——這輪最明確的落差在「從只有正解變成正解加干擾」那一步。(40 題的正解全部落在 top-20 以內,沒有一題是 Day 22 L5 的候選池漏撈。)

換更大的模型呢?拿掉那 4 段干擾之後答對率回升多少,E4B 是 20.0、12B 是 10.0、26B-A4B 只剩 2.5 個百分點——這次測的三個版本,大的受干擾比較小。而「搬位置」那一格是 +10.0、−7.5、0.0,三個版本連方向都不一致。

⚠️ 那 20 個百分點是我事先知道正解、人工只留那一段量到的差距,不是自動清理上線後的收益——真實系統得自己判斷該丟哪四段,那個判斷也會錯。

reranker 常被當成這一格的藥,但它做的是 L5——把正解排前面,而且不保證第一。重排後只留幾段,本來就同時把干擾拿掉了:「重排有用」不等於「順序有用」,兩件事包在一個動作裡。

換成 Qwen,還會抓錯嗎

你可能會問:是不是我剛好挑到不適合這份繁中資料的模型?所以我保留同一批題與段落、同一個順序,換 Qwen 再跑一次——同樣的量化與 runtime。

https://ithelp.ithome.com.tw/upload/images/20260908/20183550txlAdXHVZO.png

圖 3:正解段落相同;五段條件另加四段干擾,正解固定排第 1。

五顆的答對題數都減少。 Qwen3.8 27B 只給正解時 40/40 全對,加上同一批 4 段干擾掉到 36/40;Qwen3.5 9B 與 Gemma 4 12B 各少答對 4 題。五顆在這五種條件——只留正解、正解第 1、正解第 5、原始 top-5、附引用——累計有 78 個回合輸出錯數字,那個數字一樣每一次都在段落裡

有一題特別值得看:問「T2 那筆 median TPOT 對應的兌現率」(80.3%),Gemma 4 12B 與 Qwen3.5 9B 都答 88.4%——那是另一張表上同一台機器、不同模型與引擎的數字。兩家模型被同一個格子騙走。

⚠️ 五顆方向一致,但逐模型單獨看只有 E4B 分得出來(p = 0.0078;其餘四顆 0.125 到 1.0)。兩顆 Qwen 同時差了尺寸與版本(官方沒有 Qwen3.8 的 9B),這一欄只能當「部署選項比較」,不是參數量的對照實驗。

所以我會先查一件事:是不是把一堆長得很像、卻回答不同條件的段落一起塞了進去。圖 1 那題更麻煩——它挑錯的那半句就在正解的同一段裡。

那把條件拆開會不會有用?我做了最小的機械版本:同一批 5 段、同一個順序,只在 —— 處斷行讓每個子句自成一行(純語法,不看題目也不看 gold,只插入換行)。答對題數 30/40 → 30/40,改善 1 題、退步 1 題。 連圖 1 那題都沒救回來——兩個數字已經分成兩行,它還是答 5.5%。

⚠️ 精確地說:這次依指定標點拆行,沒有觀察到答對題數的淨改善;替數字明確標上對象與量測條件,仍待另測。

那叫它附上引用呢

直覺的補救是要它交代出處:答案、段落編號,加上那一段裡逐字照抄的一句原文,用 format schema 限制格式而不是靠 prompt 拜託。

https://ithelp.ithome.com.tw/upload/images/20260908/20183550nT21EXZQLs.png

圖 4:格內是作答回合的次數;棄答未列入。

E4B 有 6 題落在紅色那一格,標的都不是正解那一段——它們引了別段的真句子,仍然答錯;圖 1 則是在同一段裡挑錯條件。原文找得到,不代表用得對。(12B 剩 3 題、26B-A4B 是 0。)

至於引文本身:32 個作答回合裡只有 3 個連子字串都不是(9.4%,去空白再比 6.2%)。那把逐字比對當過濾器呢?查得過的 29 個答對率 79.3%,對全體 78.1%——幾乎沒動,濾掉的三個裡還有兩個是對的。

外部研究也觀察到引文對不上原文:ResearchQA 量到 15.5% 到 30.0% 不是原文子字串(單篇論文內的檢索、每顆模型 100 題抽樣,任務與判定都不同)。來源存在,不代表它支持答案——FACTUM 在兩顆 Llama 上量到 18.7% 與 30.9% 的引用無法由所標文件支持。

Anthropic 這個 API 走的是另一條路:伺服器端先切句,模型只輸出位置索引,cited_text 由 API 抽原文。這擋掉「引文與原文對不上」,擋不掉「這句話撐不住那個答案」。

該說不知道的時候

我另外出了 14 題答案不在語料裡的題,例如「T2 那台的主機板型號」——語料提過「消費主機板」,從沒寫過型號。五顆幾乎全對,E4B 是 14/14。

看起來很漂亮。但那 14 題全是「語料連這個欄位都沒有」,跟本篇主題正好相反。所以我又出了 5 題鏡像題:資料很像、數字很多,就是缺你指定的那一格——「DGX Spark 的 pp512」(三機表只有 pp2048)、「Qwen2.5-Coder-7B Q4_K_M 的 tg32」(只量過 Q8_0)。

https://ithelp.ithome.com.tw/upload/images/20260908/20183550YbqyXdporv.png

圖 5:上層柱高是比例、柱上標示題數;三類分母是 14、5、38。

E4B 從 14/14 掉到 1/5。 那 5 題它編了 4 個答案,每個都是隔壁那一格:問 pp512 給 pp2048、問 Q4_K_M 給 Q8_0、問 DGX Spark 給 4070 Ti。只量前一型,會高估它處理無解題的能力。

代價寫在下面那列:答案就在 context 裡的題,E4B 有 7 題也回「查無資料」。只看棄答率,看不出系統好不好用。

各家榜單都處理過這個坑:Vectara 的排行榜要你先看同一列的 Answer Rate——Phi-4 幻覺率只有 3.7%,但它只回答了 80.7% 的文件。

今天的實驗需要什麼

一份 golden set,30 到 50 題起步(Day 22 那條規矩),再加一批答案不在語料裡的題。無解題要出兩型:「欄位根本不存在」很好出也很好過;有鑑別力的是「資料很像、就是缺你要的那一格」。生成模型隨便一顆跑得動的都行,我用 Ollama 上的 Gemma 4 與 Qwen。

不能省的有四件:

  • 優先用自己的實測結果出題。 公開常識會讓你分不出它是讀懂了還是背過。
  • 題目要把條件寫死。 我有一題問「M4 Max 的權重讀取等效頻寬」,語料裡有兩個都對的答案(Day 10 的 284、Day 13 三機表的 448,量的是不同模型)。這種題不管它答哪一個都不公平,也分不出是抓錯格還是我問得不清楚。
  • 無解題比有解題更容易出錯,因為你是在證明一件事不存在。我一共寫了 7 題鏡像題,其中 2 題其實答得出來(表格的列不重複模型名,我 grep 漏了),剔除後保留 5 題——看到模型答得斬釘截鐵才回頭查的。
  • 分母要分開。 生成端的答對率只算「答案已經進到 context」的題,有解卻棄答的仍然算沒答對(本篇 top-5 的 71.1% = 27/38 就是這個口徑);只有在分析「吐出的錯數字」與「引文對不對得上」時,才把棄答另外列出來。

跑完先看三個數:「只放正解」對 top-5 的落差、答錯時那個數字在不在 context 裡、鏡像型無解題的棄答率配上誤拒率。

不必先挑框架。下面四支加起來 776 行,一半是判分那支的註解與護欄。

python3 research/day28/prep.py     # 切塊、嵌入、指派 gold chunk、檢索(CPU,約 50 秒)
python3 research/day28/run.py      # 只負責生成與存檔,可中斷續跑
python3 research/day28/analyze.py  # 判分是純離線函式,改判準不必重跑生成
python3 research/day28/split_ctx.py  # 拆行對照組的轉換(自帶「只插入換行」的斷言)

綁 JSON,這批抽取題有退步嗎

同一組題再跑一次,這次固定輸出 answerunit 兩個欄位。答對率 68.4% 對自由文字的 71.1%,配對 2 比 1,這組抽取題沒有測到明顯退步;格式合規率 100%。

這跟〈Let Me Speak Freely?〉那個常被引用的結論不衝突,但範圍比一般轉述的窄。同一張表上換成 JSON,claude-3-haiku 是 86.51 對 86.99、gemini-1.5-flash 89.33 對 89.66 幾乎不動,LLaMA-3-8B 卻從 75.13 掉到 64.67;掉最兇的 23.44 是 claude 再把一份剛性 schema 塞進 prompt 那一格。「JSON 會讓模型變笨」,連那篇自己的表都沒有一致支持。

它測的是推理題,跟我這組抽取題不是同一種任務。這次沒測到退步,是不是因為任務比較單純,這組實驗回答不了——圖 1 那題就說明抽取一樣要先認出條件。

地端這條路上,llama.cpp 官方寫得更直白:schema 只約束輸出、不注入 prompt,模型根本看不到它(tool calling 走另一條路,不適用)。想讓它照著填,得自己在 prompt 裡再寫一次。

小結

四種現象,各自對應一個接著要查的地方:

  • 只給正解仍然答錯 → 先查題目是不是唯一有解、gold 與單位標對了沒。我這 40 題有一題(a02)語料裡有兩個都對的答案,事後才發現。確認完才輪到查提示與模型。
  • 只給正解答對、多段就答錯 → 挑出「數字長得很像、但對象或條件不同」的那幾題單獨對照。E4B 有 38 個回合輸出錯數字,每一次都在餵進去的段落裡;換到 Qwen 也一樣掉。
  • 引文逐字相符、答案還是錯 → 去看那句原文支不支持答案裡的對象、條件與數值。只採信引用查得過的回合,答對率只從 78.1% 動到 79.3%,還誤殺兩個。
  • 明顯無解會拒答、相似資料缺解卻亂答 → 評測要涵蓋兩型無解題,並同時看誤拒。E4B 在「欄位不存在」是 14/14,換成「資料很像、就是缺你要的那格」只剩 1/5,誤拒 7/38。

明天 Day 29〈LoRA 微調基礎:RAG 救不了的,什麼時候該動模型〉。這一週修的都是「餵什麼進去」,但有一類抱怨連正解那一段都接不住——口氣不對、專有名詞在這一行不是那個意思。那不是檢索問題。明天先把提示、輸出約束與資料整理能解的排除掉,再判斷什麼時候真的該動模型,並把 QLoRA 在 12GB 卡上的記憶體帳算給你看。

咱們明天見。

這篇的條件與來源

機器 T1(M4 Max 128GB),生成走 Metal,檢索與嵌入全程 CPU。所有數字只代表這份語料與這組設定。

語料 day01.mdday24.md / 451 段 / chunk 300 token、overlap 0 / BAAI/bge-m3 rev 5617a9f6
題目 40 題有解 + 19 題無解(14 題「語料連這個欄位都沒有」+ 5 題「資料很像、就是缺你要的那一格」),全部在 research/day28/golden.jsonlunanswerable.jsonl。其中 a02 事後判定問法不夠精確(語料裡有兩個都對的答案),已標記;拿掉它重算各條件動 ≤2 個百分點
生成 Ollama 0.33.3 /api/chatthink:falsetemperature 0seed 20260907num_ctx 16384num_predict 160(cite 條件放寬到 400)
prompt system prompt 明寫「只能用資料區塊裡的內容」「找不到就只回『查無資料』四個字」——圖 5 各項結果都是被要求之後的行為,換一句 prompt 數字就會變
模型 Gemma 側 gemma4:e4b(8.0B)/gemma4:12b(11.9B)/gemma4:26b(25.8B)各 419 次跑滿十種餵法,E4B 另補跑 pos1s 40 次、合計 459 次;Qwen 側 qwen3.5:9b-q4_K_Mqwen3.8:27b-q4_K_M 各 219 次,補跑跨家比較使用的五種條件+無解題。五顆全是 Q4_K_M、同一條 Ollama 路徑。⚠️ 是 Ollama 的量化檔,不是 Day 06 引的官方 QAT 那一份。⚠️ 官方沒有 Qwen3.8 的 9B(4B/9B 那兩格是 Qwen3.5),所以那兩顆同時差了尺寸與版本
跨家口徑 Qwen 只跑五種條件(只留正解/正解第 1/正解第 5/原始 top-5/附引用),所以那 78 個回合的統計裡,Gemma 三顆也只取這五種,與內文其他地方「十種餵法累計」的數字不同分母。⚠️ 先前那顆 qwen3.8:27b-mlx 是 nvfp4+MLX runner,量化與 runtime 都跟這五顆不同,那 51 筆留在 raw.jsonl不進任何統計
判分 抽出回答裡所有數字正規化後比對;棄答只看 answer 欄(unit 欄寫「未提供」是沒有單位,不是拒答);「只用中文數字作答」的筆數必須為 0(本輪是 0;中文數字與阿拉伯數字要一視同仁)
單位 ⚠️ 判分不換算單位:gold 2.12 GiB、它答 2.28 GB 也判錯。但「錯的形狀」那組統計會把這種筆數扣掉——容差取兩邊最後一位小數的半格,不是固定百分比,否則 6.48 GiB(tensor 欄)對 6.976 GB(磁碟檔)這種只差 0.26% 的兩本帳會被誤當成換算
引用的四格分類 逐字相符率只在有作答的回合上算(E4B 32/40),棄答另列、不併進來。⚠️ 若把 8 次棄答也算成「引文不相符」,就會錯算成 (3+8)/40 = 27.5%——不是分母大小的問題,是兩種事件混算
拆行對照 pos1s = 與 pos1 完全相同的 5 段與順序,只在 —— 處斷行讓每個子句自成一行。拆的時候不看題目也不看 gold,只插入換行——research/day28/split_ctx.py 有斷言擋住「數字集合變了」與「除換行外還動到字」。⚠️ 它獨立分析:不併入十種餵法那 38 個回合的統計,也不併入跨家五種條件那 78 個回合的統計
檢定 配對 exact sign test,只取兩個條件下正解都在 context 裡的題。「拿掉 4 段干擾」逐模型是 8:0(p = 0.0078)、4:0(0.125)、1:0(1.0)、5:1(0.2188)、4:0(0.125)——只有 E4B 單獨分得出來
圖 3 沒放的兩欄 實際 top-5 的答對題數 27/32/35/32/34(分母 38);有解卻棄答 7/1/2/2/3(分母 38,圖 5 有畫)

⚠️ 這組題天生偏向「找得到」的事實:題目看過語料才寫,全部是單一數字的抽取式單跳題,摘要、比較、多跳完全沒測。

⚠️ 鏡像題一共寫了 7 題,剔除 2 題、保留 5 題。 剔掉的是 u15「T2 四次 process 的 tg 全距」與 u18「4070 Ti 上 Gemma 4 12B 的 tg 實測」——day08.md:157 那一列的 57.72 [57.71–57.72] 兩題都答得了。是看模型的答案才回頭查到的。⚠️ 5 題夠揭露盲點,還不足以排出各模型的拒答能力

⚠️ 語料是數字密集的規格表與帳。 換成散文會不會一樣容易抓錯格,這輪沒測——而候選數字有多密,本來就決定了「碰巧命中」的基準線。

⚠️ 語料指紋是 e1cd341b…,與 Day 25/26/27 記的 5f3ff35a… 不同。 那三篇跑完之後 day22.md 的週導覽被改過(因為 D28 換了主題),三行字就換掉整份指紋。檔案清單、切法與 embedder 完全相同。

⚠️ gpt-oss:20b 本機那份載入失敗(tensor "blk.0.ffn_down_exps.weight" size overflow),本輪沒有它。

用在哪 出處
答對率、錯的形狀、引用四格分類、棄答與誤拒、JSON 對照、所有 sign test 一手實測,research/day28/raw.jsonl 存的是每一次生成的原文回答)
引用句有 15.5%–30.0% 不是原文子字串 ResearchQA,arXiv:2607.11074(2026-07)。⚠️ 資料集是 494 篇論文、6,211 組問答,但那張表是八顆模型各跑同一份 100 題等距抽樣;context 走的是單篇論文內的檢索流程,不是整篇直接餵。正規化子字串比對,ground truth 由 LLM 生成
引用標到的文件撐不住那句話:Llama-3.1-8B 18.7%、Llama-3.2-3B 30.9% FACTUM,arXiv:2601.05866(2026-01)。TREC NeuCLIR 2024、每題 15 份文件;粒度是來源文件不是 chunk,且不區分「標到不存在的來源」與「標到真來源但撐不住」;百分比由原文計數推算(107/572、93/301)
Citations 是伺服器端切句 + 模型只輸出索引,cited_text 直接抽原文 platform.claude.com 的 Citations 官方文件(2026-09-07)。⚠️ 它與 structured outputs 互斥,一起開回 400;自訂 content blocks 不會自動切句
⚠️ 「檢索沒撈到幻覺率跳 6.5 倍」要退掉:分母是「完全不給 context」不是「證據不足」 Google Research 部落格與其配圖。66.1 ÷ 10.2 = 6.48,但 sufficient 對 insufficient 只有 1.15–2.6 倍,且 GPT-4o 方向相反。論文全文查無這兩個數字,只在部落格
先看 Answer Rate 再看幻覺率 Vectara 幻覺排行榜(2026-05-11 更新,106 個模型,判官是自家 HHEM-2.3)
格式限制的影響隨模型、任務與提示方式而變 〈Let Me Speak Freely?〉EMNLP 2024 Industry Track,Table 1(GSM8K,Text/JSON/XML/YAML 四欄,含「+ schema constraint」列)與 §4.1 的 Last Letter 觀察
schema 只約束輸出、不注入 prompt llama.cpp grammars/README.md(master,2026-09-07)。tool calling 另有 template 注入,不適用

上一篇
Day 27 - 企業知識庫:更正只有 2 段,舊說法還有 12 段
下一篇
Day 29 - 32 層只掛到 8 層:微調前,先查你的 LoRA 掛在哪裡
系列文
不是模型太慢,是你沒算過這筆帳:地端 LLM 工程實戰 30 天30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言