<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
  <title>Knas 的文章</title>
  <link>https://www.imaknas.com/#writing</link>
  <atom:link href="https://www.imaknas.com/writing/feed.xml" rel="self" type="application/rss+xml"/>
  <description>Knas 的文章</description>
  <language>zh-Hant</language>
  <item>
    <title>壓縮之後，還剩下什麼？</title>
    <link>https://www.imaknas.com/writing/what-survives-compaction/?lang=zh</link>
    <guid isPermaLink="false">https://www.imaknas.com/writing/what-survives-compaction/#zh</guid>
    <pubDate>Mon, 28 Sep 2026 12:00:00 +0000</pubDate>
    <description>長對話被摘要壓縮之後，哪些細節會留下來，其他的又為什麼消失。在 The Crucible 裡做的小規模實驗。</description>
    <content:encoded><![CDATA[<p><em>一段很長的 LLM 對話為了塞進 context window 而被摘要時，哪些細節會留下來？其他的又為什麼消失？我在很長的合成對話裡埋進事實，用不同方式壓縮，再測量模型還能召回多少。</em><em>簡單說：摘要會丟掉它無從得知日後會重要的東西，解法是讓原文一直拿得到。</em></p>
<h3>重點摘要</h3>
<ul><li><strong>摘要無法預知下一個問題會是什麼。</strong>改變計畫之後，OpenAI 和 Anthropic 的摘要只保留了新目標所需 32 個事實中的 4–13 個。事先宣告下一個目標，能救回 32 個中的 30 個；提到它的次數一樣多、但不說它是下一個目標，只救回 6 個。少了這項資訊，寫摘要當下唯一的解法就是不再壓縮。</li><li><strong>所以，永遠別讓摘要成為唯一的副本。</strong>保留原始訊息，等問題確定之後再讓小模型挑選要取回哪些，就能找回 32 個中的 28–32 個。最便宜的模型挑得跟最強的一樣好。</li><li><strong>開啟召回後，最便宜的摘要模型就夠用。</strong>單獨使用時，它的摘要保留的內容不到最周全那個模型的一半；加上召回之後就追平了，而每份摘要的成本大約只有 1/25。</li><li><strong>損失發生在摘要裡，而且會累積。</strong>摘要一旦丟掉某個事實，模型就答不出來。用便宜的摘要模型時，只經過一次摘要的事實全都留了下來；經過四次之後，一個都不剩。</li><li><strong>要求摘要模型保留什麼，跟用哪個模型一樣重要。</strong>只改一條指示，就讓一個便宜模型從 31/72 個事實提升到 70/72。而且好的摘要可能勝過原始歷史：它會把已被取代的舊值整理掉，否則小模型常會選到那些舊值。</li><li><strong>輔助機制必須持續證明自己值得存在。</strong>對話和模型之間的每一個機制，都要重新跟「完全不用它」比較。第一次稽核抓到召回誤導了一個較弱的模型；換了摘要模型之後，第二次稽核發現召回不可或缺。</li><li><strong>留意帳單。</strong>推理 token 是最大的成本，我早期的估算差了 2x，而 prompt 開頭的一個時間戳記，悄悄讓 prompt caching 失效了。</li></ul>
<h3>問題</h3>
<p>每個長時間運作的 LLM 應用，遲早都會碰到 context window 的上限。常見的解法是壓縮：把較早的歷史摘要起來，接著從摘要繼續。Claude Code 這樣做，Codex CLI 也這樣做，我維護的開源多模型聊天應用 The Crucible 也是。</p>
<p>我的問題很簡單：模型會不會在某個點突然忘記？如果細節真的遺失了，原因是什麼？是摘要、模型的注意力，還是反覆壓縮這件事本身？</p>
<p>我找不到有對照的答案，所以自己在應用裡做了一套。以下所有實驗都跑在這個應用真正的 LangGraph 流程上，程式碼和原始結果都已公開。</p>
<h3>我怎麼測量</h3>
<p><strong>埋進去的事實。</strong>每段合成對話有 140 輪往返，大約 23k tokens，其中 24 個虛構的事實藏在訊息中段：預算上限、審查者、金鑰標籤、埠號、日期、客戶原話的引述、供應商選擇，以及「我們說好不用 X」。因為數值是虛構的，模型無法靠既有知識作答。</p>
<p><strong>讓細節互相競爭。</strong>我的第一次小規模試驗在所有條件下都拿到 100%，因為在一般性的填充內容裡，這些事實是唯一具體的內容。所以現在每一輪都帶有形式相同的具體資訊（延遲、工單數、負責人），而事實分成三種變體：</p>
<ul><li><strong>單純：</strong>只講一次。</li><li><strong>干擾：</strong>附近有一個被否決的提案，數值不同。</li><li><strong>更新：</strong>先出現舊值，後來才被更改。回答舊值或被否決的值都算錯。</li></ul>
<p><strong>照應用的方式壓縮。</strong>對話會一輪一輪地重播，經過應用本身的摘要步驟，所以長對話在變長的過程中會被摘要好幾次。接著用問題逐一探測每個事實，例如「CDN purge job 監聽哪個埠？只回答數值。」</p>
<p><strong>把摘要和模型分開。</strong>我用一個 oracle（只看資訊在不在 context 裡的假模型）：若且唯若數值還在給它的 context 裡，它就答對。它的召回率反映的是摘要保留了什麼。真實模型的分數如果低於它，代表資訊明明在，卻被漏掉了。更嚴格的 oracle 還要求數值仍然跟它所屬的對象連在一起。</p>
<p><strong>成對比較。</strong>每個事實在每種條件下都探測一次，條件之間用成對比例檢定和 10 個百分點的等價界限來比較。這部分我用的是自己寫的 <a href="https://github.com/imaknas/ordal">Ordal</a> 函式庫。</p>
<p><strong>限制花費。</strong>在一次昂貴的意外之後（見下文），每次執行都會先對每個模型做一次校準呼叫，免費空跑整個實驗設計來計算 token 數，如果估計值超過硬性預算就拒絕開始。</p>
<h3>發現 1：好的摘要可能勝過原始歷史</h3>
<p>完全不壓縮時，在一段 23k tokens 的對話裡，三個小模型漏掉了 12–19% 的事實。漏掉的大多是更新過的事實：18 個更新過的事實中，gemini-3.5-flash-lite 有 10 個給出了已被取代的舊值。</p>
<p>用強的摘要模型壓縮就解決了這個問題。摘要保留了所有事實，並把每次更新都整理成最新的值，過時的答案因此降到零。</p>
<figure><img src="https://www.imaknas.com/writing/what-survives-compaction/images/table-01.png" width="600" height="168" class="keep-legible" alt="好的摘要勝過原始歷史：三個小模型讀 gemini-3.5-flash 的摘要時，得分都高於讀完整的 23k tokens 對話。"><figcaption>好的摘要勝過原始歷史：三個小模型讀 gemini-3.5-flash 的摘要時，得分都高於讀完整的 23k tokens 對話。</figcaption></figure>
<p>摘要不只是比較短的逐字稿。它是整合過的狀態，而對模型來說，這可能比原始歷史更好用。</p>
<h3>發現 2：每多摘要一次，損失就多累積一次</h3>
<p>用便宜的摘要模型時，一個事實經過幾次摘要，就能預測它會不會留下來。經過四次之後，什麼都不剩。</p>
<figure><img src="https://www.imaknas.com/writing/what-survives-compaction/images/chart-decay.png" width="660" height="380" class="keep-legible" alt="長條圖：經過 1、2、3、4 次摘要後仍留在 context 中的事實：100%、89%、65%、0%。"><figcaption>每次摘要後保留下來的事實（gemini-3.5-flash-lite 的摘要；n = 10、18、20、24 個事實）。</figcaption></figure>
<p><strong>是摘要次數的問題，還是空間不夠？</strong>有兩種解釋都符合這條曲線。一是每次摘要都會丟掉一點上一次保留的東西；二是固定大小的摘要會把最舊的事實擠出去。因為較舊的事實一定經過比較多次摘要，這兩個因素彼此混淆，分不開。</p>
<p>所以我用同一個模型，以兩種方式摘要同樣的對話：隨著對話變長逐步摘要，或是在最後一次摘要完。</p>
<figure><img src="https://www.imaknas.com/writing/what-survives-compaction/images/table-02.png" width="548" height="133" class="keep-legible" alt="一次摘要完，24 個早期事實中有 19 個仍跟所屬對象連在一起；逐步摘要只剩 8 個。"><figcaption>一次摘要完，24 個早期事實中有 19 個仍跟所屬對象連在一起；逐步摘要只剩 8 個。</figcaption></figure>
<p>單次摘要保留了大部分逐步摘要弄丟的早期事實。這指向的是反覆摘要，而不是舊事實沒有空間；不過整體的成對檢定並不是決定性的（+12.5 個百分點，95% 信賴區間 −3.5 到 +27.7）。</p>
<p>不過，一次大摘要也有自己的代價。它把 92% 的數值保留在某個地方，但只有 75% 還跟正確的對象連在一起。它弄丟的是一個數值屬於誰。</p>
<p><strong>重複能保護一個事實。</strong>我在對話稍後把每個事實再講一次，其他什麼都沒改。召回從 23/72 上升到 41/72，增加 25 個百分點（95% 信賴區間 +12 到 +37）。這項提升有一部分是因為重述比較新，所以經過的摘要次數比較少。</p>
<h3>發現 3：指示跟模型一樣重要</h3>
<p>應用原本的摘要 prompt 要求「一份精簡而詳盡的技術簡報」，並保留誰主張了什麼。我拿它跟 Codex CLI 的交接 prompt，以及一個我從基本原理出發寫的「狀態與索引」（state and index）prompt 比較。這個 prompt 要求列出每個決定、議定的數值和待辦事項，並註明是誰提出的；任何被改過的東西只留最新的值；再加上一行主題索引。</p>
<p>這些對話裡，有一半的事實是助理說的，而不是使用者。</p>
<figure><img src="https://www.imaknas.com/writing/what-survives-compaction/images/table-03.png" width="699" height="273" class="keep-legible" alt="指示跟模型一樣重要：狀態與索引讓 gemini-3.5-flash-lite 從 72 個事實中的 31 個提升到 70 個。"><figcaption>指示跟模型一樣重要：狀態與索引讓 gemini-3.5-flash-lite 從 72 個事實中的 31 個提升到 70 個。</figcaption></figure>
<p>告訴便宜模型必須留下的是<em>哪一類</em>東西，就讓它從 31 個事實提升到 70 個。代價是它寫出來的長度多了一倍。能力夠的模型即使在 Codex 大約 1,300 tokens 的交接摘要裡，也幾乎全部保留，所以限制在於摘要模型選擇保留什麼，而不是它有多少空間。</p>
<p><strong>一份摘要要花多少錢。</strong>應用原本的預設摘要模型 gemini-3.5-flash，每份摘要會花 10–20k 個推理 token，輸出 token 每百萬 $9：每份摘要大約 $0.21。gemini-3.8-flash 保留了同樣的事實（在 10 個百分點內等價），只要大約 $0.03，所以應用改用它，直到下文的發現 7 為止。把 3.5-flash 的思考程度降到「medium」，表現跟預設設定相當；「minimal」的成本只有四分之一，但少了 18 個百分點。</p>
<p>過程中還冒出一個 bug。應用把摘要本身算成新內容，所以摘要一旦長到超過門檻，每隔幾則訊息就會重新摘要一次：本來大約 20 份就夠，結果產生了 132 份。修正方式是要求累積到半個門檻量的真正新文字，才再次摘要。</p>
<h3>Codex CLI 和 Claude Code 怎麼做</h3>
<p>Codex CLI 是開源的，所以我讀了它的<a href="https://github.com/openai/codex/blob/9db8162d65/codex-rs/core/src/compact.rs">壓縮程式碼</a>。Claude Code 不是開源的，所以我依據的是它的<a href="https://code.claude.com/docs/en/how-claude-code-works.md">官方文件</a>。</p>
<figure><img src="https://www.imaknas.com/writing/what-survives-compaction/images/table-04.png" width="928" height="346" class="keep-legible" alt="Codex CLI 和 Claude Code 的壓縮方式，與這項研究之前的 The Crucible 並列比較。"><figcaption>Codex CLI 和 Claude Code 的壓縮方式，與這項研究之前的 The Crucible 並列比較。</figcaption></figure>
<p>Codex 甚至會在壓縮後警告：「長對話和多次壓縮可能讓模型的準確度下降」（long threads and multiple compactions can cause the model to be less accurate）。這就是發現 2，只是由它的作者親口說出來。</p>
<p>我把 Codex 的規則加進實驗。原文保留使用者訊息，救回的恰好就是使用者說出的事實：用便宜的摘要模型時，這類事實從 17/36 提升到 36/36，而助理說出的事實完全沒變。代價是之後每次呼叫都要多用 2.3 倍的 context。</p>
<h3>原則：永遠別讓摘要成為唯一的副本</h3>
<p>很容易就會下結論說，程式碼代理和對話型應用本來就需要不同的壓縮方式。我認為真正的差別更深一層。每一段 context 都有三個屬性：</p>
<ul><li><strong>權威性：</strong>是誰說的。使用者說的是需求；助理說的是主張；工具給的是觀察結果。</li><li><strong>可復原性：</strong>能不能再取回一次？檔案可以重新讀取；只在聊天裡說過的細節不行。</li><li><strong>時效性：</strong>之後還會用到嗎？目前的數值、決定和待辦事項會用到；已被取代的數值和走不通的路不會。</li></ul>
<p>這樣看，Codex 的設計就說得通了。使用者訊息具有權威性又無法復原，所以原文保留。工具輸出可以從 repository 重新取得，所以可以丟掉。摘要只需要承載仍然有效的狀態，這就是為什麼簡短的交接摘要就夠了。Claude Code 的 CLAUDE.md 做的是同一件事：把權威性的規則移出對話，放到壓縮碰不到的地方。</p>
<p>我測到的每一次損失，都是唯一副本只存在於摘要裡的資訊。The Crucible 從不刪除歷史；每則訊息都保存在它的 checkpoint store 裡。只是修剪之後，模型看不到它們而已。所以解法不是更好的摘要，而是讓原文重新拿得到。</p>
<h3>發現 4：把原文找回來，能救回有損的摘要</h3>
<p>我加了一個召回步驟。每次呼叫之前，它會在隱藏的歷史中搜尋跟最新請求最相符的四則訊息，把它們引用回 context 裡。搜尋方式是單純的關鍵字比對，依字詞的稀有程度加權。</p>
<figure><img src="https://www.imaknas.com/writing/what-survives-compaction/images/table-05.png" width="779" height="168" class="keep-legible" alt="召回救回了有損的摘要：72 個事實中，31 → 67，以及 9 → 66。"><figcaption>召回救回了有損的摘要：72 個事實中，31 → 67，以及 9 → 66。</figcaption></figure>
<p>召回讓兩個有損的配置分別提升了 50 和 79 個百分點，而在摘要本來就保留了一切的配置上沒有任何改變。能保留幾乎所有細節的最便宜設定，是最便宜的摘要模型寫 1k tokens 的交接摘要，再加上召回：66/72，之後每次呼叫讀 2.8k tokens。</p>
<p>一旦原文拿得到，摘要就不必是完整的紀錄，只要好到足以接續下去就行。</p>
<h3>發現 5：召回把「什麼才相關」的判斷交給了檢索器</h3>
<p>召回之所以效果這麼好，只是因為我的問題直接點名了主題。所以我把每個問題都改寫成描述主題，而不直接說出來：問「防火牆應該為那個在邊緣清除快取檔案的任務開放哪個網路埠？」，而不是「CDN purge job 監聽哪個埠？」。這些問題裡都沒有出現任何主題詞。</p>
<figure><img src="https://www.imaknas.com/writing/what-survives-compaction/images/table-06.png" width="710" height="273" class="keep-legible" alt="改用間接問題後，關鍵字召回從 72 個中的 66 個掉到 28 個；讓模型選擇搜尋詞，則救回到 54 個。"><figcaption>改用間接問題後，關鍵字召回從 72 個中的 66 個掉到 28 個；讓模型選擇搜尋詞，則救回到 54 個。</figcaption></figure>
<p>事實就在眼前時，措辭不重要：模型幾乎每次都能把「在邊緣清除快取檔案的任務」對應到 CDN purge job。召回把這個判斷交給檢索器，而關鍵字或小型 embedding 檢索器在這方面遠不如模型。讓便宜的模型讀摘要、選擇搜尋詞，能救回大部分的損失，但不是全部。</p>
<p>所以兩種設計都會因為能力不足而失敗，只是失敗在不同的地方。摘要失敗在摘要模型，而且每多摘要一次就多累積一次。召回失敗在檢索器。不管由誰來決定相關性，它對問題的理解都得跟模型差不多好。</p>
<h3>一個落空的預測</h3>
<p>我原本預期，說出口時聽起來不重要的事實，會更常被丟掉，即使是強的摘要模型也一樣。所以我把每個事實都改寫成隨口一提的話（「順帶一提，可能無關：staging 資料庫監聽 6543 埠」），其他什麼都沒改。</p>
<p>結果正好相反。便宜的摘要模型反而保留了更多這種順帶一提的話：用 Codex 式的交接摘要時是 18/72，而不是 1/72。強的摘要模型和召回則不論哪種寫法都全部保留。在每句話形式都一樣的填充內容裡，帶保留語氣的句子反而更突出，而不是被淹沒。聽起來不重要，不等於對模型來說不重要；而更難的問題，也就是事實被說出時沒有人能預見的相關性，仍然沒有答案。</p>
<h3>發現 6：摘要會丟掉任務暫時還不需要的東西</h3>
<p>於是我改把相關性綁在任務上，而不是措辭上。每段對話都追求一個明確的目標（「這週唯一的優先事項是 log shipper」）。有八個事實跟這個目標有關。另外八個是關於另一個目前還沒有人在處理的子系統，只是順口平鋪直敘地帶過，形式跟其他內容完全相同，而且其他地方都沒有再提到。最後一輪切換目標：「改變計畫：現在優先處理 warehouse loader。」接著探測每一個事實。</p>
<p>在這之前，我測過的摘要模型全都是 Gemini，所以我從每個供應商家族各挑兩個，在四段對話上測試：</p>
<figure><img src="https://www.imaknas.com/writing/what-survives-compaction/images/table-07.png" width="669" height="273" class="keep-legible" alt="改變計畫之後，OpenAI 和 Anthropic 的摘要只保留了 32 個目標外事實中的 4–13 個；只有 gemini-3.8-flash 保留了大部分（26/32）。"><figcaption>改變計畫之後，OpenAI 和 Anthropic 的摘要只保留了 32 個目標外事實中的 4–13 個；只有 gemini-3.8-flash 保留了大部分（26/32）。</figcaption></figure>
<p>OpenAI 和 Anthropic 的四個摘要模型，四個全都會丟掉目標外的事實，而 OpenAI 的兩個幾乎一個都沒留。我一直以來在測的 Gemini 家族，丟得最少。</p>
<p>我最初根據兩段 Gemini 對話得出的解讀是：越強的摘要模型丟得越多。但這在不同家族之間並不成立：在 OpenAI 家族裡，較強的模型篩選得比較嚴；在 Anthropic 家族裡，較強的模型反而篩選得比較鬆。家族的摘要風格比模型強弱更重要。真正站得住的是機制：以任務為中心的摘要，會省略任務暫時還不需要的東西，而沒有任何摘要模型能知道計畫即將改變。</p>
<p><strong>召回把它們全部找回來。</strong>召回是在目標切換之後才去看歷史，所以照理說不該受到改變計畫的影響。我用兩個最會依目標篩選的摘要模型來測試：</p>
<figure><img src="https://www.imaknas.com/writing/what-survives-compaction/images/table-08.png" width="799" height="133" class="keep-legible" alt="對兩個依目標篩選的摘要模型，召回都找回了全部 32 個目標外事實。"><figcaption>對兩個依目標篩選的摘要模型，召回都找回了全部 32 個目標外事實。</figcaption></figure>
<p>在讀取時才決定，恰好能找回在寫入時就決定所損失的東西。這是整個研究中，我唯一預期在新模型出來後仍會成立的結果：摘要是為當下的目標而寫，沒有摘要模型能預料到計畫改變，只有讓原文保持可取得的設計不受影響。有一個但書延續自發現 5：這些問題都點名了主題，所以關鍵字召回就夠了。同樣的問題改成間接問法時，關鍵字召回只找回 32 個中的 16–17 個，embedding 召回也沒有比較好；而模型引導的召回（由小模型讀取仍然看得到的內容，包括改變目標的那一輪，再選擇要取回什麼）則找回了 28–30 個。這裡的兩個摘要模型是兩次重複驗證，不是一組比較：它們的家族和等級都不同。</p>
<p><strong>選擇要取回什麼，不需要強模型。</strong>在那之前，負責選搜尋詞的模型一直是應用裡最便宜的 gpt-6-luna。所以我固定一個摘要模型（最會依目標篩選的 gpt-6-sol），只寫一次摘要，再重播給六個不同的模型，讓它們選擇要取回什麼，每個家族各一個便宜的、一個強的。同樣的間接問題，四段對話：</p>
<figure><img src="https://www.imaknas.com/writing/what-survives-compaction/images/table-09.png" width="622" height="308" class="keep-legible" alt="每個負責選擇取回內容的模型都勝過關鍵字召回；最便宜的 gpt-6-luna（30/32）追平了最強的模型。"><figcaption>每個負責選擇取回內容的模型都勝過關鍵字召回；最便宜的 gpt-6-luna（30/32）追平了最強的模型。</figcaption></figure>
<p>每個模型都勝過關鍵字召回。Luna 和 sol 在統計上等價，強模型也都跟 luna 等價；只有最小的 Gemini 稍微落後。最便宜的模型判斷得跟 gemini-3.8-flash 一樣好，而後者做同樣的呼叫要花 24 倍的錢（$0.59 對 $0.024）。這符合「決定的時機」這個解釋：問題確定之前，沒有摘要模型能可靠地判斷相關性；問題一旦確定，連小模型都做得到。哪個便宜模型夠用，每次新版本推出都會變；但「晚點決定會讓決定變簡單」這件事應該不會變。</p>
<p><strong>摘要為什麼會丟掉它們。</strong>「沒有摘要模型能預料到計畫改變」是一個主張，所以我測試了它。我重跑同樣的對話，只改一個地方：每次提醒目標時，都多加一句「完成之後，下一個優先事項會是 X」。事實、填充內容和位置都完全一樣。另外，我也試了一個對接下來會發生什麼一無所知的通用保險措施：在平常的指示之外再加上「優先順序可能改變；每個主題的具體數值都要保留，不只是目前的目標。」</p>
<figure><img src="https://www.imaknas.com/writing/what-survives-compaction/images/table-10.png" width="711" height="203" class="keep-legible" alt="宣告下一個目標，讓 gpt-6-sol 從 32 個中的 4 個提升到 30 個；通用保險措施只有在摘要長了 9× 時才有效。"><figcaption>宣告下一個目標，讓 gpt-6-sol 從 32 個中的 4 個提升到 30 個；通用保險措施只有在摘要長了 9× 時才有效。</figcaption></figure>
<p>對 gpt-6-sol 來說，知道下一個目標就是全部的關鍵：32 個中從 4 個提升到 30 個，代價是摘要長了 30%。通用保險措施也保留了所有事實，但靠的是幾乎不壓縮：摘要有 5.5k tokens，而門檻是 8k，重寫的頻率也多了一倍。不知道未來的話，在寫入時保留目標外事實的唯一方法，就是放棄壓縮。Claude Haiku 則顯示出第二種、另一回事的損失：即使告訴它未來、也加了保險措施，它仍然只保留 32 個中的 20 個，而且連目標內的事實也丟了。這看起來是保真度的問題，而不是篩選的問題。讀取時的召回兩者都能避開，因為原文還在。會不會只是因為那個主題的名稱一直被提到？宣告下一個目標會提到它十幾次，所以我做了一個對照組：提到它的次數一樣多，但說它是這一季不處理的範圍，改變計畫則仍然出乎意料。gpt-6-sol 保留了 32 個中的 6 個：救回的 26 個事實裡，大約 2 個來自名稱變得醒目，其餘 24 個來自知道它是下一個目標。</p>
<h3>發現 7：原文拿得到時，最便宜的摘要模型就夠用</h3>
<p>召回改變了摘要模型的用途，所以我重新挑選應用的預設摘要模型，這次開啟召回，跟應用實際運作時一樣。執行之前，我先寫下規則：留下在兩種情境下在統計上都不比最好的差的候選，再依 2027 年 1 月起適用的價格，選出每份摘要最便宜的那個（gemini-3.8-flash 的優惠價到 12 月結束）。四個摘要模型、細節密集的情境和改變計畫的情境，各四段對話，用嚴格的 oracle：</p>
<figure><img src="https://www.imaknas.com/writing/what-survives-compaction/images/table-11.png" width="928" height="221" class="keep-legible" alt="開啟召回時，gpt-6-luna 的摘要以大約 1/25 的成本追平了最好的；單獨使用時保留的內容少得多。"><figcaption>開啟召回時，gpt-6-luna 的摘要以大約 1/25 的成本追平了最好的；單獨使用時保留的內容少得多。</figcaption></figure>
<p>只有 gpt-6-luna 通過了這條規則：在細節密集的情境上跟最好的在統計上等價，在改變計畫之後本身就是最好的，而且每份摘要的成本大約只有 gemini-3.8-flash 的 1/25（成本以細節密集的情境、2027 年的價格計算）。單獨使用時，它的摘要保留的內容不到一半。一旦原文可以取回，摘要的工作就從「作為紀錄」縮小成「作為指標」，而指標可以很便宜。這個選擇只在召回開啟時成立：沒有召回，排名就會反過來。</p>
<p>有一個結果我目前還無法解釋：召回讓其他每個摘要模型都多保住了 16 到 29 個事實，但在改變計畫之後，對 gemini-3.8-flash 卻毫無幫助（兩種情況都是 56），而之後的一次稽核也重現了這個落差。</p>
<h3>讓輔助機制保持誠實</h3>
<p>這篇文章裡的每一個機制，從摘要本身到原文保留視窗和召回，之所以存在，都是因為它在我測試的模型上勝過了基準線。較新的模型可能自己就把這個差距補上了，而不再有幫助的輔助機制可能反而礙事。所以應用預設路徑上的每個機制，現在都會宣告自己的基準線和主張；每當模型清單改變，稽核就會在目前的模型上重新測量這一組比較，並記錄為保留、淘汰、有害或無定論。</p>
<p>前兩次稽核就已經改變了整個局面。兩次都用兩個便宜的作答模型，跑細節密集的情境：</p>
<figure><img src="https://www.imaknas.com/writing/what-survives-compaction/images/table-12.png" width="573" height="133" class="keep-legible" alt="召回從好壞參半（第一次稽核，周全的摘要）變成不可或缺（第二次稽核，便宜的摘要）。"><figcaption>召回從好壞參半（第一次稽核，周全的摘要）變成不可或缺（第二次稽核，便宜的摘要）。</figcaption></figure>
<p>摘要很周全時，召回的片段對較弱的模型反而是干擾：它會拿錯對象的數值，對不同的問題給出同一個答案。摘要很單薄時，這些片段就是主要來源，召回對兩個模型都變得不可或缺。第二次稽核也用真實的作答模型檢查了摘要模型的選擇：兩個較貴的摘要模型，對哪一個讀者都沒有表現得更好。</p>
<p>不是每個判定都該照做。稽核把原文保留視窗（原樣保留最新幾則訊息）標為「淘汰」：開啟召回後，它對事實召回毫無幫助。但這些探測只問埋進去的事實，而這個視窗存在的目的是跟最近幾輪保持連貫，這一點探測並沒有測到。稽核的好壞，取決於它檢驗的主張。</p>
<h3>應用裡改了什麼</h3>
<ul><li>重新摘要的迴圈已經修好，prompt caching 在三家供應商上都能運作。</li><li>召回預設開啟：對話串一旦被摘要過，最便宜的可用模型就會挑出新請求相關的原始訊息，再把它們放回來給模型看。對話串壓縮之前完全不花錢，之後每輪多一次小呼叫。</li><li>預設摘要模型是上面選出的 gpt-6-luna，也可以在 Control Panel 裡改選其他模型。</li><li>模型更換時，預設路徑上的每個機制都會重新稽核。</li><li>狀態與索引摘要、關鍵字召回，以及原文保留使用者訊息，這篇都有測量，但都不是預設。</li></ul>
<h3>花了多少錢，又出了哪些錯</h3>
<p>整個研究的 API 呼叫大約花了 $80。其中約 $41 花在最初的四次執行，那時我還沒有預算防護。其餘大約二十個實驗在硬性上限下花了約 $36，其中包括一次什麼結果都沒產出的執行，以及幾塊錢花在後來被拒絕執行的實驗的校準上；另外還有約 $3 是成本估算誤花掉的。</p>
<p>犯的錯跟結果一樣有啟發性：</p>
<ul><li><strong>天花板效應。</strong>第一次小規模試驗在所有條件下都拿到 100%，因為埋進去的事實是對話中唯一具體的內容。</li><li><strong>計分 bug。</strong>模型常常先回答，再引用來源，例如「Litware。它說：『我們選了 Litware，而不是 Margie 和 Contoso』」。在整個回覆裡任意比對，會因為引文中出現被否決的供應商而判錯。現在計分只讀明確作答的第一行。</li><li><strong>重新摘要的迴圈</strong>，也就是發現 3 提到的那個，只是因為第一次昂貴的執行寫出了 132 份摘要才被發現。</li><li><strong>用猜的價格。</strong>我以為某個摘要模型每百萬輸出 token 要 $2.50，實際上是 $9。我還只憑名稱就選了「nano」模型當便宜的預設，但有個較新的模型只要一半的價錢。現在價格都放在一張表裡，每筆都附來源，實驗的預設值也從這張表挑選。</li><li><strong>太嚴格的嚴格 oracle。</strong>我最初的「數值緊鄰它的對象」檢查用的是 200 個字元的視窗。按主題分成長段落來組織的摘要會讓它失效，但每個模型其實都還答得對。</li><li><strong>雜訊很大的估算器。</strong>每個模型只做一次校準呼叫是不夠的。有一次執行的花費是估計值的 1.8 倍。真正限制花費的是硬性上限，而不是估算。</li></ul>
<p><strong>一次設了上限卻什麼都沒產出的執行。</strong>一次長程執行（每段對話大約 22 份摘要）花光了整整 $5 的上限，卻產出零筆結果。所有條件同時在重播，摘要每合併一次就變長，變長的速度比我用單次呼叫校準的預測還快，結果上限讓所有條件都在中途停下。現在一次只跑一個條件，從最便宜的開始，只有剩餘預算足夠時才放行，而且每個條件一跑完就立刻存檔。</p>
<p><strong>一次會花錢的估算。</strong>成本估算是用替身模型空跑，所以應該是免費的。但負責選擇取回內容的模型，在設定實驗時就被交給了真正的模型 client，而空跑從來沒有把它換掉。估算上面那個六模型的實驗時，發出了大約 384 次真實呼叫，約 $3，哪裡都沒有紀錄，還被計價為零。現在每個會呼叫模型的步驟都會說明它呼叫哪個模型，估算時則用替身來計量。</p>
<p><strong>從沒命中的快取。</strong>整個實驗期間的快取命中率大約只有 1%。應用的 system prompt 一開頭就是精確到秒的當下時間，所以任兩個請求都沒有共同的前綴。把時間移出 system prompt 還不夠，因為每家供應商的快取方式都不一樣：</p>
<figure><img src="https://www.imaknas.com/writing/what-survives-compaction/images/table-13.png" width="928" height="276" class="keep-legible" alt="依供應商整理：每次請求才有的 context 要放在哪裡，prompt caching 才會生效。"><figcaption>依供應商整理：每次請求才有的 context 要放在哪裡，prompt caching 才會生效。</figcaption></figure>
<p>通則是：任何每次請求都會變的東西（時間戳記、檢索到的片段），都應該放在下一個請求會重複的最後一個位置之後，而那個位置在哪裡，取決於供應商。</p>
<h3>相關研究</h3>
<p>這些結果跟一批越來越多的研究放在一起看，其中好幾篇指向同一個方向：</p>
<ul><li><a href="https://arxiv.org/abs/2508.21433">The Complexity Trap</a>（JetBrains Research，NeurIPS 2025 DL4Code workshop）：在程式碼代理中，單純遮蔽舊的工具輸出，就能以大約一半的成本達到跟 LLM 摘要相當的效果。</li><li><a href="https://factory.ai/news/evaluating-compression">Evaluating Context Compression</a>（Factory.ai）：在真實的代理 session 中，以探測的方式評估壓縮。它把效果歸功於將每份摘要合併進一個持續存在的狀態，而不是每次重新產生，這跟本文狀態與索引的結果一致。</li><li><a href="https://arxiv.org/abs/2609.26779">CliffCompaction</a>（Nguyen、Cho、Chen、Dettmers，2026）：從不對已經壓縮過的內容再次壓縮，以避免漂移。這正是發現 2 測到的每次摘要都會發生的損失。</li><li><a href="https://arxiv.org/abs/2608.06503">Toward Reliable Context Compression for Long-Horizon Agents</a>（2026）：反覆壓縮會讓代理的執行變得不穩定。</li><li><a href="https://arxiv.org/abs/2608.16370">What Does Context Compression Cost an Agent?</a>（2026）：完成率維持不變，但代理會重新取回被丟掉的狀態，所以成本藏在額外的呼叫裡。</li><li><a href="https://arxiv.org/abs/2601.00821">Fidelity Before Structure</a>（2026）：在對話記憶上，檢索原文片段勝過檢索萃取出來的產物。</li><li>背景資料：<a href="https://arxiv.org/abs/2308.15022">用遞迴摘要做對話記憶</a>、Letta/MemGPT 的<a href="https://vectorize.io/articles/mem0-vs-letta">分層記憶加可搜尋的召回</a>、Anthropic 的 <a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents">context engineering 指南</a>，以及 Chroma 的 <a href="https://www.trychroma.com/research/context-rot">Context Rot</a>。</li></ul>
<p>我在其他地方還沒看到的（不過也可能是我漏看了）：一組有對照的「一次摘要」與「逐步摘要」比較，用來區分每次摘要的損失和容量不足；一個能把「摘要丟掉了」跟「模型漏看了」分開的 oracle；一個針對重複的成對檢定；一個探究以任務為中心的摘要為什麼會丟掉事實的因果檢驗（宣告下一個目標，對比只提到它的名稱）；以及一套稽核，每當模型改變，就把每一個處理 context 的機制拿來跟「不用它」重新比較。</p>
<h3>限制與下一步</h3>
<p>這是一項小規模試驗，不是基準測試：</p>
<ul><li><strong>合成的對話。</strong>真實對話更雜亂，下一步是重播真實的對話串。</li><li><strong>樣本小。</strong>每一格是來自三到四段對話的 32 到 96 個成對探測，而且只用了小型和中型模型。</li><li><strong>只有一個門檻，也沒有做多重比較校正。</strong>單一比較請當作參考指標就好。</li><li><strong>任務相關性的結果還是初步的。</strong>發現 6 和 7 每個條件只有四段對話，由 oracle 計分。真實的作答模型只在稽核中檢查過細節密集的情境，沒有檢查改變計畫之後的情況。真實對話的測試還沒做。</li><li><strong>字串比對計分。</strong>它很嚴格，而且只讀回覆的第一行。</li></ul>
<p>接下來我想在真實的對話歷史上跑這套實驗，並加入更強的模型。目標是把它變成一個小型的開源 context 管理層，決定哪些要原文保留、哪些要摘要、哪些留著可供檢索。</p>
<p><strong>程式碼與資料。</strong>所有東西都在 <a href="https://github.com/imaknas/the-crucible">The Crucible</a> 裡執行（<code>crucible compaction-eval</code> 和 <code>crucible scaffold-audit</code>）。這裡的每個數字都記錄在<a href="https://github.com/imaknas/the-crucible/blob/main/backend/experiments/NOTES.md">實驗筆記</a>中，原始結果就放在旁邊。</p>
<p><strong>這篇是怎麼做出來的。</strong>我在這項研究中用 Claude Code 當作寫程式和分析的助手。很多實驗程式碼，以及這篇文章的初稿，都是它寫的。我負責提出問題、檢查結果，結論由我負責。</p>]]></content:encoded>
  </item>
  <item>
    <title>沒有人做決定，我們只是在描述</title>
    <link>https://www.imaknas.com/writing/nobody-made-a-decision/?lang=zh</link>
    <guid isPermaLink="false">https://www.imaknas.com/writing/nobody-made-a-decision/#zh</guid>
    <pubDate>Sun, 24 May 2026 12:00:00 +0000</pubDate>
    <description>一場不准用 AI 寫 spec 的團隊比賽，讓我發現大部分工程師沒有在做決定，只是在描述系統。</description>
    <content:encoded><![CDATA[<p><em>一場不用 AI 的 spec 挑戰，讓我看見工程師實際上是怎麼思考的。</em></p><figure><img alt="" src="https://www.imaknas.com/writing/nobody-made-a-decision/images/en-1.png" width="960" height="540"></figure><p>上週我在團隊裡辦了一場比賽。</p><p>規則很簡單：一個模糊的需求，30 分鐘內不准用 AI，寫出一份 spec。接著把 spec 交給 <strong>Claude Code</strong>，讓它去實作。最後每個人上台報告，由團隊投票選出最好的成果。</p><p>我原本以為，結果會告訴我誰比較會寫 spec。沒想到它透露的東西比這更多。</p><h2>比賽設計</h2><figure><img alt="" src="https://www.imaknas.com/writing/nobody-made-a-decision/images/en-2.jpeg" data-zoom="/writing/nobody-made-a-decision/images/en-2@2x.jpg" width="540" height="720"></figure><p>這個需求是我刻意寫得很模糊的，內容幾乎就是照著我們平常實際在做的工作設計：</p><blockquote>當資料擁有者上架一份資料集、買家完成購買時，系統必須從買家的錢包扣款、產生一筆交易紀錄、更新雙方的錢包狀態，並通知相關人員。請考慮冪等性與失敗補償。</blockquote><p>八位工程師，各自作業。寫 spec 的階段不能用 AI，之後只能用 <strong>Claude Code</strong>。</p><p>在這之前的兩堂課，我都在跟團隊講 <strong>Harness Engineering</strong>：你給 AI 的環境跟 prompt 一樣重要；spec 就是你打造這個環境的方式；瓶頸不在模型。</p><p>這場比賽就是驗收。</p><h2>我看到了什麼</h2><p>有些人完全不知道從哪裡開始。</p><p>有幾份 spec 幾乎是把需求原封不動抄一遍。步驟那一段寫的是：<em>扣款、產生交易紀錄、更新錢包狀態、通知相關人員</em>。跟需求一字不差。沒有拆解，沒有順序，也沒有邊界情況。</p><p>這不是偷懶，而是更根本的問題：底下沒有一個心智模型，能把需求轉成結構。平常幫你搭出結構的工具一拿掉，就沒東西可寫了。</p><h2>深厚的領域知識，幫助沒有我想像中大。</h2><p>團隊裡最資深的工程師之一，在支付系統領域做了好幾年，卻卡住了。這位工程師在練習過程中的口頭回饋是：需求定義得不夠清楚，需要更多背景資訊才能開始設計。</p><p>資深工程師以前就是這樣工作的。有人寫好 PRD，你照著它設計。PRD 不清楚，就退回去要求對方釐清。</p><p>但這次挑戰要的不是照著一份完整的需求去設計，而是要他們<em>自己把模糊的地方釐清</em>：把模糊的需求當成要去結構化的問題，而不是拿來抱怨的障礙。這是另一種能力，多年的領域知識不會自動轉移過來。</p><h2>贏家把主導權整個交給 AI，然後就走開了。</h2><p>有位工程師用 auto mode 開了 <strong>Claude Code</strong>，讓它自己跑，回來直接看結果。這份 spec 不是最精準的，但結構夠好，AI 做出來的東西看起來完整又有說服力。團隊投票選它為最佳成果。</p><p>把工作交給 AI 本身不是問題。問題是到最後、產出回來的時候才浮現的。</p><p>大部分人都說，AI 加了一些他們沒寫進 spec 的東西：saga pattern、retry 邏輯、補償事件。多數人也承認，在有限的時間裡，他們沒把握這些東西加得對不對。</p><p>這才是真正的落差。問題不在 spec 不完整，每份 spec 都不完整。問題在於，當 AI 替你做了決定，你得自己先有一個決定，才有東西可以拿來評估它。如果你從來沒決定過失敗補償該怎麼做，AI 提出 saga 的時候，你就沒有立足點。你可以接受，也可以拒絕，但不管選哪個，你都是在猜。</p><p>一份記下你各項決定的 spec，不會阻止 AI 加東西，但它讓你有能力判斷 AI 加的東西對不對。</p><h2>沒人告訴過我的模式</h2><figure><img alt="" src="https://www.imaknas.com/writing/nobody-made-a-decision/images/en-3.jpeg" data-zoom="/writing/nobody-made-a-decision/images/en-3@2x.jpg" width="960" height="720"></figure><p>spec 階段結束後，我請每個人分享一件事：<em>你在 spec 裡做的最重要的決定是什麼？</em></p><p>沒有人回答這個問題。一開始我以為他們在迴避，後來才發現，我從來沒給過他們用「決定」來思考的理由。我提供的 spec 範本有結構（觸發條件、步驟、邊界情況），卻沒有任何選擇點。我要他們描述一個系統，又期待他們已經對這個系統做了決定。這不公平。</p><h2>描述與決定</h2><p>一個決定聽起來會像這樣：<em>「我選擇把錢包扣款步驟的失敗，跟入帳步驟的失敗分開處理，因為扣款成功但入帳失敗時，rollback 的邏輯不一樣，我不希望 AI 把它們併成同一個失敗處理器。」</em></p><p>有一個人很接近了。這位同事口頭分享的內容包括：如果扣款成功但入帳失敗，就 retry 三次；retry 還是失敗，就發出補償事件並關閉這筆交易。這是一個真正的決定：對方考慮過幾種做法，然後有理由地選了其中一種。</p><p>其他人都在描述自己的 spec。描述有時候很準確，但那不是決定。</p><p>事後回想，我發現問題不在他們說不出自己的決定，而是<em>他們根本沒做任何決定。</em>對大多數人來說，寫 spec 就是把自己對系統該怎麼運作的第一直覺抄下來，而不是在幾個選項之間做取捨。</p><h2>為什麼這件事比以前更重要</h2><p>在舊的工作流程裡，沒有明確的決定還撐得過去。你寫程式，有人 review，決定會在 review 的過程中浮上檯面，你還有時間修正方向。</p><p>AI 輔助開發把這個逼你面對問題的機制拿掉了。</p><p>當 <strong>Claude Code</strong> 幾分鐘內就把你的 spec 執行完，每一個你沒講明的假設，都會變成 AI 替你做的決定。它會很有自信地把空白填滿，做出看起來很完整的東西。而你要到 debug 的時候，才會知道它填了哪些空白。</p><p>spec 不再只是一份規劃文件，而是你的決定存放的地方。如果你沒在裡面做決定，你就不是在指揮 AI，而是放任 AI 自己指揮自己，最後再在產出上簽名。</p><h2>下一堂課我要改什麼</h2><p>這次練習讓我看見一個以前不知道怎麼看見的落差：<em>描述一個系統</em>，和<em>對一個系統做決定</em>，是兩回事。</p><p>下次的 spec 範本會加入明確的選擇點。不只是問「你的步驟是什麼」，而是問「如果扣款成功但入帳失敗，你選哪一個：retry、rollback，還是補償事件？為什麼？」逼他們在具名的選項之間做選擇，是我所知道唯一能讓人從描述模式切換到決策模式的方法。</p><p>投票方式也會改。同儕針對整體成果投票，往往會偏好看起來完整的成果，而不是精準的成果。下次我會加上一套評分標準，對準真正重要的三件事：spec 的涵蓋度、spec 與產出的一致性，以及骨架是否清楚。</p><p>開始之前，我會先花十分鐘給大家看我的發現。不是要點名誰，而是因為這次練習裡最讓人豁然開朗的洞見，也正是最有用的那一個：</p><p><em>團隊裡大多數人並不知道自己沒在做決定。他們以為描述系統就等於做了決定。</em></p><p>這就是 AI 暴露出來的落差。不是能力，也不是努力，而是以為把第一直覺寫下來就是 spec。</p><figure><img alt="" src="https://www.imaknas.com/writing/nobody-made-a-decision/images/en-4.jpeg" data-zoom="/writing/nobody-made-a-decision/images/en-4@2x.jpg" width="960" height="720"></figure><p><em>我為正在經歷這波轉型的軟體團隊開設 AI 工程工作坊。如果你的團隊也正面對同樣的轉變，很歡迎來聊聊：cshiauknas@gmail.com</em></p>]]></content:encoded>
  </item>
  <item>
    <title>AI 讓不思考的代價變高了</title>
    <link>https://www.imaknas.com/writing/ai-raises-the-cost-of-not-thinking/?lang=zh</link>
    <guid isPermaLink="false">https://www.imaknas.com/writing/ai-raises-the-cost-of-not-thinking/#zh</guid>
    <pubDate>Wed, 13 May 2026 12:00:00 +0000</pubDate>
    <description>從一條自動運作的內容流水線抽出 adaptive-iteration 的經過，以及為什麼 AI 讓想不清楚的代價變高。</description>
    <content:encoded><![CDATA[<figure><img alt="" src="https://www.imaknas.com/writing/ai-raises-the-cost-of-not-thinking/images/en-1.jpg" data-zoom="/writing/ai-raises-the-cost-of-not-thinking/images/en-1@2x.jpg" width="1321" height="720"></figure><p>2026 年 3 月，Andrej Karpathy 發表了一個叫 <a href="https://github.com/karpathy/autoresearch">autoresearch</a> 的專案。概念是：給 AI agent 一套真實的 LLM 訓練環境，讓它整晚自己做實驗。它會修改程式碼、訓練五分鐘、檢查結果有沒有變好、決定保留或捨棄，然後重複。你早上醒來，就會拿到一份實驗紀錄和一個更好的模型。</p><p>他對人類角色的描述讓我印象很深：<em>「你不會像一般研究者那樣去動任何 Python 檔案。你是在為那個程式寫程式。」</em></p><p>這就是轉變所在。不是寫程式碼，而是為寫程式碼的系統寫程式。</p><p>這種生活的某個版本，我已經過了好幾週，只不過不是在 ML 研究，而是在內容創作。每天，一個跑在 <a href="https://openclaw.ai/">OpenClaw</a> 上的 AI agent 會產生腳本、製作影片、發布上線、抓取數據，再針對哪些內容有效做 A/B 實驗。這些執行環節我都不參與。我做的是定義系統應該優化什麼、抓出它哪裡出錯，並在它偏掉之前把它導回來。</p><p>某個時間點我發現，這一切底下的模式其實跟影片毫無關係。它就是 Karpathy 描述的那個迴圈，只是換了一個領域。所以我把它抽出來，做成一個開源框架：adaptive-iteration。</p><p>但比起我們做了什麼，更有意思的是做的過程揭露了什麼。</p><h2>這個框架不是設計出來的，而是自己長出來的。</h2><p>adaptive-iteration 描述的是一個四段式迴圈：產出某個東西、衡量它、針對要改什麼提出假設，然後定期質疑你到底有沒有在優化對的東西。然後重複。</p><p>奇妙的是：這個框架本身，就是透過這個過程做出來的。</p><p>它不是一開始就從第一原理設計好的。它來自一個真實運作中的系統（一條已經自我迭代了好幾週的內容產線），我在一堆領域特有的雜訊底下，認出一個反覆出現的結構。我把這個結構描述給一個跑在 OpenClaw 上的 AI agent，我們一起把抽象做出來。我定義它應該是什麼，agent 負責實作。我抓出哪裡不對：一個方向反了的依賴關係、不該出現在公開 repo 裡的實作細節、需要明確寫出來的架構決策。agent 再去修正。這個循環一再重複，直到做出一個夠乾淨、可以發布的東西。</p><p>這個工具，是由它所描述的過程做出來的。這不是巧合，而是一個訊號。最好的抽象不是設計出來的，而是把一個真實的東西跑得夠久，久到看清它真正的樣子。</p><p>Karpathy 的 autoresearch 是這個迴圈的一個具體實例，綁死在 ML 訓練上。adaptive-iteration 則是把同一個迴圈做成可以帶著走的版本：記錄發生了什麼的 Ledger、找出什麼有效的 Analyzer、推理下一步該試什麼的 HypothesisEngine，以及 DomainAdapter 介面，也就是唯一會碰到你實際系統的那一層。領域你自己帶，其餘交給框架。</p><h2>AI 沒有降低打造東西的成本，它提高的是想不清楚的代價。</h2><p>這正是「AI 讓一切民主化」這套說法搞錯的地方。</p><p>在過程初期，我叫 agent 把框架推上 GitHub，它照做了。但我去看實際推上去的內容時，發現其中一個 adapter 檔案不是乾淨的範例，而是真正的實作，裡面寫死了私人路徑，直接暴露出一個我原本沒打算公開的正式環境系統的內部細節。agent 完全照著指示做，問題出在指示本身沒有想清楚。</p><p>在過去，這類錯誤本身就帶有摩擦力。打造東西很慢，模糊的心智模型有時間在實作過程中被釐清：過程的成本逼著你思考。當回饋迴圈變成即時的，這個逼你思考的機制就消失了。agent 會全速執行你的心智模型，連同它的缺陷一起。</p><p>這是沒人講的事：AI 沒有讓打造東西變容易，而是讓你心智模型的品質影響更大，後果也來得更快。清楚的模型一個晚上就能交出好東西；模糊的模型一個晚上就能交出錯的東西，而且在你發現之前，它已經上了 PyPI。</p><p>瓶頸沒有消失，只是換了形式，而且比舊的更不留情面。</p><h2>治理的不對稱</h2><p>這就帶到了這場典範轉移裡，比較不好大聲說出口的部分。</p><p>「現在人人都能打造東西」，技術上沒錯。但大多數這類討論忽略了一點：打造東西，跟打造<em>對的</em>東西，是兩個不同的問題。前者是執行問題，後者是思考問題。AI 解決了前者，卻放大了後者。</p><p>新的瓶頸（辨識跨領域可通用的模式、對一個系統該是什麼樣子保有清楚的心智模型、知道哪些架構決策重要而哪些不重要）並沒有比寫程式的能力分布得更平均，只是不一樣而已。一個人如果能看出自己的內容優化迴圈和提案策略迴圈共享同一個底層結構，又能駕馭 AI agent 把這個抽象乾淨地抽出來，這樣的人從這些工具得到的回報會不斷複利放大。做不到的人，只會做得更快，也錯得更快。</p><p>真正被民主化的是天花板。一位在某個領域深耕多年、卻從沒學過寫程式的研究者，現在可以做出自己領域一直需要的分析工具。老師可以打造適性化的課程系統。創辦人可以親手做出那個自己一直跟開發者描述、卻始終沒被做對的產品。那些因為提出的人無法實作、只能停留在想法階段的點子，現在都能執行了。</p><p>但地板沒有動。治理，也就是定義該打造什麼、評估打造出來的東西、並抓出兩者之間落差的能力，依然是一種技能，依然需要培養。Karpathy 的 autoresearch 之所以行得通，是因為 Karpathy 就是 Karpathy。他寫來指揮 agent 的 program.md，承載了數十年的 ML 研究直覺。產出的品質，取決於治理的品質。</p><p>這才是我真正在意的典範轉移。不是執行變便宜了，而是治理如今成了核心能力，而且跟寫程式不同，目前還沒有人在教。</p><p>這篇文章裡，我刻意留下三個沒有答案的問題。</p><p>在「衡量」本身就是難題的領域，也就是回饋週期很長、雜訊很多，或本質上就充滿爭議的情況下，會發生什麼事？這個框架假設你能觀察到結果，但世界上很多價值最高的決策，並不會附上一個 loss function。</p><p>治理作為一種技能，實際上可以拆解成哪些部分？我稱它為一種核心能力，然後就停在那裡了。這樣不夠。直覺和可以教的框架之間的差別，就在於你能不能說出它由哪些部分組成。</p><p>還有一個讓我睡不著的問題：AI 已經在往治理層推進了，像是 LLM-as-a-Judge、會自我修正的 agentic workflow、會自己產生假設的系統。我描述的那條人類治理與 AI 執行之間的界線，已經在移動了。當你治理的對象本身也在治理別的東西，你治理的究竟是什麼？</p><p>我做了一個號稱不限領域的框架，但我不確定自己有沒有誠實地檢驗過這個說法。這三個問題，我都還在想。</p><h2>Repo</h2><p>adaptive-iteration 是一個不限領域的實驗框架。領域你自己帶，實驗 → 衡量 → 學習 → 質疑的迴圈交給框架處理。</p><p>→ <a href="https://github.com/imaknas/adaptive-iteration">github.com/imaknas/adaptive-iteration</a><br>→ <a href="https://pypi.org/project/adaptive-iteration">pypi.org/project/adaptive-iteration</a></p>]]></content:encoded>
  </item>
  <item>
    <title>你的團隊為什麼用錯了 AI：一堂課帶來的改變</title>
    <link>https://www.imaknas.com/writing/why-your-team-is-using-ai-wrong/?lang=zh</link>
    <guid isPermaLink="false">https://www.imaknas.com/writing/why-your-team-is-using-ai-wrong/#zh</guid>
    <pubDate>Sun, 10 May 2026 12:00:00 +0000</pubDate>
    <description>一場公司內部的 AI coding 分享：差距不在提示詞，而在 Harness Engineering。</description>
    <content:encoded><![CDATA[<figure><img alt="" src="https://www.imaknas.com/writing/why-your-team-is-using-ai-wrong/images/en-1.png" width="1371" height="720"></figure><p><em>缺的不是下 prompt 的技巧，而是 Harness Engineering。</em></p><p>上週我在公司帶了一堂 AI coding 課，讓團隊看看我平常實際上是怎麼用 Claude Code 的。</p><p>我的發現讓我很意外：有些人用 AI 拿到 10x 的生產力，有些人覺得 AI 被過度炒作，兩者之間的差距跟技術能力、聰明程度，甚至跟使用 AI 工具的經驗都無關，而是在於<strong>有沒有看過一個好的工作模式</strong>。</p><p>大多數人從來沒看過高效率的 AI 輔助開發長什麼樣子，所以也不知道自己錯過了什麼。</p><h2>核心概念：Harness Engineering</h2><p>業界對這件事漸漸有了共同的名稱：harness engineering。<a href="https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents">Anthropic</a> 和 <a href="https://openai.com/index/harness-engineering/">OpenAI</a> 的工程團隊都發表過相關的做法，核心概念是：為 agent 打造它運作的<em>環境</em>，跟你給它的 prompt 一樣重要。這個洞見簡單卻深刻：一個能力很強的模型，放在設計不良的環境裡，表現就是會一直不如預期。harness（初始化、限制條件、結構化的脈絡）決定了你的 agent 是能專注在任務上，還是會整個跑偏。大多數開發者完全跳過這一步，打開聊天視窗就開始下 prompt。</p><h2>我示範的工作流程有三個步驟。</h2><h2>步驟 1：/init，先把 harness 建好</h2><p>在寫任何一行程式碼之前，先在 Claude Code 裡跑 /init。這就是 harness 的初始化：agent 會讀取你的專案結構、技術限制和程式碼慣例，建立一份共享的脈絡，之後的每個 session 都會繼承它。有沒有這一步，差別就在於 agent 是真的理解<em>你的</em>程式碼庫，還是只能憑經驗猜。團隊裡每個工程師都用同一套初始化好的 harness，就能得到一致、了解程式碼庫的產出。跳過這一步，你做的就不是 AI 輔助開發，而是很昂貴的自動補全。</p><h2>步驟 2：ticket → spec，先釐清再執行</h2><p>Jira ticket 告訴你要做<em>什麼</em>，spec 則告訴 agent <em>怎樣才算做完</em>。在開始實作之前，先跟 agent 一起把 ticket 轉成一份像樣的 spec：驗收條件、邊界情況、整合點。在這個過程中，agent 會把需求裡的缺口挖出來，也就是那些你還沒完全想清楚的地方。這不是額外的工作，而是本來就該做的規劃，只是現在有個 agent 主動幫你找漏洞。Anthropic 的研究發現，把工作拆成範圍明確的單位，而不是一次把整個功能生出來，是讓 agent 表現穩定的最大槓桿之一。spec 就是你切出這些單位的方式。</p><h2>步驟 3：審核計畫，然後放手</h2><p>spec 確定之後，agent 會產生一份實作計畫。審核這份計畫，不看程式碼，只看方向。做法對嗎？有沒有顧到你在意的事？滿意了就讓它跑。人決定方向，agent 負責執行。這正好對應到 Anthropic 所說的「coding agent」模式：給 agent 明確的範圍，讓它一步步推進，做完再回來檢查。</p><h2>真正的洞見</h2><p>AI coding 工具表現不好，不是因為 AI 不夠強，而是因為我們丟給它模糊的輸入，卻期待精準的輸出。團隊裡原本就有紮實 spec 紀律的工程師，馬上就上手了。習慣「邊做邊想」的人則覺得比較難，原因不在 AI，而是它暴露出他們思考需求時有多不明確。這就是 AI 生產力讓人不太舒服的真相：它會放大你既有的工程習慣。好習慣會跟著規模化，模糊的習慣還是一樣模糊，只是變快了。</p><h2>如果你正在帶一個使用 AI coding 工具的團隊</h2><p>不要只是開權限給大家，然後祈禱一切順利。辦一堂課，讓他們看看一個正確初始化的 harness 長什麼樣子，讓他們親眼看到，把 ticket 直接丟給 Claude，跟先一起把 spec 寫好，差別在哪裡。瓶頸不在模型，而在你的團隊知不知道怎麼打造它運作的環境。</p>]]></content:encoded>
  </item>
  <item>
    <title>從前後端到光譜：為混亂的AI人才市場，繪製一張清晰的地圖</title>
    <link>https://www.imaknas.com/writing/ai-job-spectrum/?lang=zh</link>
    <guid isPermaLink="false">https://www.imaknas.com/writing/ai-job-spectrum/#zh</guid>
    <pubDate>Sat, 09 Aug 2025 12:00:00 +0000</pubDate>
    <description>借用前後端的比喻，把混亂的 AI 職稱畫成一條從模型研究到系統實作的光譜。</description>
    <content:encoded><![CDATA[<p>AI時代來臨，但市場上對於職位的定義似乎是一片迷霧。A公司的「機器學習工程師」，做的是B公司的「AI工程師」的工作，而C公司的「資料科學家」，可能根本不碰模型。我們缺乏一套共同的語言，來描述AI時代下的不同專業職能，這讓企業招聘困難，也讓人才定位模糊。</p><p>本文的目的，並非要創造更多新名詞，而是試圖提供一個清晰的分析框架，幫助個人和企業，更好地理解和定位在AI浪潮中的價值。需要特別說明的是，這套分類並非業界標準，而是基於我個人的觀察與經驗的歸納，旨在幫助讀者快速找到自身與團隊的位置。</p><h3>一個熟悉的比喻：用「前後端」理解AI職能</h3><p>為了簡化這個複雜的問題，我們可以借用軟體開發中最經典的模型，也就是前後端分離，來做一個類比。</p><ul><li><strong>AI前端 (The “Model Layer”):</strong> 核心工作是圍繞著「模型本身」。它的任務是研發、訓練和優化演算法，追求的是模型內在指標的提升。對應的角色是科學家和演算法專家。</li><li><strong>AI後端 (The “System Layer”):</strong> 核心工作是將模型作為一個組件，去建構一個穩定、可擴展且能解決實際商業問題的大型應用系統。它的任務是確保整個AI應用的可靠性與最終的商業價值。</li></ul><figure><img alt="AI 前端與 AI 後端：一個圍繞著模型本身，一個把模型當成組件" src="https://www.imaknas.com/writing/ai-job-spectrum/images/layers-zh.png" width="696" height="406" class="keep-legible"><figcaption>AI 前端與 AI 後端：一個圍繞著模型本身，一個把模型當成組件</figcaption></figure><p>這個簡單的二分法，幫助我們做出了第一次關鍵的區分，讓我們看到AI領域存在兩種截然不同的價值創造路徑。</p><h3>模型的極限：當「前後端」的界線開始模糊</h3><p>然而，這個簡潔的模型在面對真實世界的複雜任務時，便會暴露出它的局限性。例如，一個關鍵的、高價值的工作：<strong>模型微調 (Fine-tuning)</strong>，究竟該屬於前端還是後端？</p><ul><li>從<strong>商業目的</strong>和<strong>數據來源</strong>看，它服務於特定應用，屬於後端。</li><li>從<strong>所需技能</strong>和<strong>執行過程</strong>看，它需要深厚的模型知識，又屬於前端。</li></ul><p>Fine-tuning 在光譜上的位置相對特殊，它既涉及模型參數調整，又需考量實際應用場景，因此在我看來，它是「模型端」與「系統端」之間的關鍵橋樑角色。</p><figure><img alt="模型微調橫跨模型端與系統端" src="https://www.imaknas.com/writing/ai-job-spectrum/images/bridge-zh.png" width="696" height="261" class="keep-legible"><figcaption>模型微調橫跨模型端與系統端</figcaption></figure><h3>更精準的地圖：「AI職能光譜」模型</h3><p>一個更準確的視角，是將AI職能視為一個連續的<strong>光譜</strong>。它清晰地描繪了從純粹的科學研究，到最終的商業應用，中間每一步的價值創造過程。為了讓這些角色在同一個脈絡下被比較，我將它們放在一條從「模型研究」到「系統實現」的光譜上。</p><figure class="figure-wide"><img alt="AI 職能光譜表：從模型研究到系統實現，依序比較研究科學家、應用科學家、資料/機器學習科學家、機器學習工程師、AI 系統架構師、AI 工程師、AI 顧問/解決方案架構師的光譜位置、核心任務、價值衡量與 Tech Stack。" src="https://www.imaknas.com/writing/ai-job-spectrum/images/zh-1.png" width="1200" height="610" class="keep-legible"><figcaption>AI職能光譜</figcaption></figure><p>這個更精細的光譜，清晰地劃分了「應用科學家」和「資料科學家」的區別：前者是探索未知可能性的<strong>先鋒</strong>，後者則是利用成熟技術為企業創造穩定價值的<strong>工匠大師</strong>。</p><p>更重要的是，它解壓縮了從「模型」到「產品」之間，那個最關鍵的工程地帶。它不再是一個模糊的「中心點」，而是一個由三個關鍵角色組成的「工程三部曲」：</p><ol><li><strong>機器學習工程師(MLE)</strong> 將模型變成穩定、可被呼叫的服務。</li><li><strong>AI系統架構師(AI Systems Architect)</strong> 將這些服務與其他系統組件，設計成一張宏大的應用藍圖。</li><li><strong>AI工程師(AI Engineer)</strong> 根據這張藍圖，實現最終的產品功能。</li></ol><figure><img alt="工程三部曲：從模型到產品功能" src="https://www.imaknas.com/writing/ai-job-spectrum/images/trilogy-zh.png" width="696" height="207" class="keep-legible"><figcaption>工程三部曲：從模型到產品功能</figcaption></figure><p>一份典型的AI系統架構師的思維產出，並非只是一份技術規格文件，而更像是一份完整的商業與技術作戰藍圖。例如，它會清晰地定義出一個分階段的導入策略：</p><ul><li><strong>第一階段:</strong> 專注於建構穩定、安全、可觀測的私有化AI基礎設施（如生產級RAG系統）。</li><li><strong>第二階段:</strong> 在此基礎上，規劃能創造巨大商業回報的高價值應用（如個人化數據分析、企業級智慧搜尋）。</li><li><strong>第三階段:</strong> 最終透過更前沿的技術（如領域模型微調），建立起競爭對手難以超越的、深度的技術護城河。</li></ul><figure><img alt="AI 系統架構師的分階段導入策略" src="https://www.imaknas.com/writing/ai-job-spectrum/images/phases-zh.png" width="696" height="261" class="keep-legible"><figcaption>AI 系統架構師的分階段導入策略</figcaption></figure><h3>給後端工程師的福音：「90/10法則」</h3><p>這個光譜模型，特別是從中心點到右端的職能，對廣大的Web後端工程師來說是個好消息。因為一個生產級AI應用，「90%是我們熟悉的後端工程」。</p><p><strong>重疊的90%技能包括：</strong></p><ul><li>基礎設施 (Kubernetes, Docker, CI/CD)</li><li>數據工程 (資料庫, Kafka, Redis)</li><li>API與微服務開發 (REST, gRPC)</li><li>核心軟體工程實踐 (可觀測性、測試、設計模式)</li></ul><p><strong>關鍵的10%差異則在於：</strong></p><ul><li><strong>與「不確定性」共舞的能力：</strong> 設計系統來管理模型的機率性輸出與潛在的幻覺。</li><li><strong>AI/LLM的「系統直覺」：</strong> 深刻理解Embedding、Prompt Engineering、Context Window等概念，並將其應用於系統設計。</li><li><strong>以「數據為中心」的架構思維：</strong> 將數據品質與版本控制視為系統設計的一等公民。</li><li><strong>全新的「評估與監控」體系：</strong> 除了監控系統指標，更要監控模型表現、數據漂移與API成本。</li></ul><figure><img alt="90/10 法則：九成是熟悉的後端工程，關鍵差異在最後一成" src="https://www.imaknas.com/writing/ai-job-spectrum/images/ninety-zh.png" width="696" height="239" class="keep-legible"><figcaption>90/10 法則：九成是熟悉的後端工程，關鍵差異在最後一成</figcaption></figure><p>後端工程師距離成為市場最渴求的AI人才，只差那最後10%的關鍵認知。</p><h3>結論：在這張新地圖上，找到你的位置</h3><p>AI時代的職涯路徑，不再是單一的階梯。我們都需要成為一個懂得在地圖上定位、並規劃自己前進路線的「戰略家」。</p><ul><li><strong>對個人而言：</strong> 這張地圖，能幫助你進行自我評估。你現在在哪個位置？你未來的發展，是想往光譜的左端深化，追求技術的極致？還是往右端擴展，追求商業影響力的最大化？</li><li><strong>對企業而言：</strong> 企業應該用這張地圖，來審視自己的團隊配置。你是否只招聘了大量的「AI工程師」，卻缺乏能定義系統藍圖的「架構師」？清晰的定位，才能帶來精準的招聘。</li></ul><p>在AI這個全新的大陸上，我們需要的，不僅是勇敢的探險家，更是能繪製地圖、指引方向的領航員。無論你身處光譜的哪一端，清楚自身定位並理解其他角色的價值，才是應對這個快速演化市場的長久之道。</p>]]></content:encoded>
  </item>
</channel>
</rss>
