看板 Soft_Job ※ 圖文整理 回首頁

[情報] 拆開 Grok Bot 的 harness:新版同一個小任務少送 28.8% 資料,可能變貴的是壓縮、翻舊紀錄這幾條長路徑

作者:chinghanho
時間:2026-10-22(Asia/Taipei)
來源:How the Grok Bot harness works/@gabefletcher/GitHub Gist(chinghanho 發布,2026-10-22)/en
長條圖:同一個最小任務兩輪送出的資料,舊版 .47 是 340,310 bytes,新版 242,142 bytes
▲ 同一個最小任務跑兩輪,新版少送 28.8%,主要是一開始附的工具說明從 40 個降到 11 個。數字取自 gist 的隔離環境實測。
新版 Grok Bot 處理同一個最小任務,送出的資料反而比舊版少;會讓用量變多的,是壓縮對話、翻舊紀錄、瀏覽器重抓、分派工作這些特定路徑。

適合在做 agent harness 的工程師,還有用 Grok Bot 覺得「變快了,額度卻燒得比較兇」的人。

這份 gist 由 @gabefletcher 署名,拆的是 Grok Bot 打包後的 JavaScript:前半看 host 17e335e 和桌面版 .52 的架構,後半比較 .47 到 .57.1 的速度和用量。手上沒有原始 TypeScript 或 source map,每個說法都標了是程式看得到(S)、推論(I)、還沒解(U),實測另外標 R。〔gist:How the Grok Bot harness works〕

一、畫面顯示送出了,訊息不一定已經存進資料庫

你按下送出,gateway(收發請求的入口)先記下「已受理」、把訊息顯示在畫面上,這時候這一輪的工作還沒跑完。〔gist:User turn and model/tool loop〕

如果資料庫剛好被鎖住、寫入失敗,流程還是會受理這次送出,只在 log 留一筆「沒有持久保存」。所以 API 回成功、畫面上也看得到訊息,當機之後這則輸入不一定還在。〔gist:User turn and model/tool loop〕

「An HTTP success or a visible message therefore doesn't always mean the input will survive a crash.」
HTTP 回成功、或畫面上看得到訊息,不一定代表這則輸入撐得過一次當機。

收尾也拆成好幾步:先寫 agent 的 checkpoint(存對話和執行狀態的存檔點),再寫聊天紀錄。checkpoint 成功、聊天紀錄卻失敗時,程式會丟出專門的錯誤。作者看到程式有排先後,但沒看到這些寫入包在同一個 transaction 裡。〔gist:Context, memory, compaction and restart〕

在這套程式裡,訊息送達、一步跑完、模型跑完、事情真的辦好,是四種不同的狀態。〔gist:Component prompt contracts〕

二、聊天畫面、模型收到的對話、長期記憶,三份資料各存各的

畫面上的聊天紀錄、模型實際收到的對話、跨對話留下來的長期記憶,放在三個分開的地方,讀取路徑也不同。〔gist:Architecture and control flow〕

聊天畫面沒有完整的 prompt。隱藏訊息、工具訊息、系統訊息不一定會出現在畫面上,所以從聊天紀錄沒辦法完整還原模型看到了什麼。〔gist:Component prompt contracts〕

要從當機恢復,需要對話歷史、工具狀態和摘要訊息;只拿模型供應商那邊的對話 ID 救不回來。〔gist:Context, memory, compaction and restart〕

長期記憶和對話壓縮是兩件事。每個 turn 結束後,記憶那邊另外記錄這次的對話證據或抽出事實;壓縮則是在對話太長時,把送給模型的歷史縮成摘要。摘要會用「使用者」的角色塞回下一輪的 context。〔gist:Learned memory, shared scopes and privateMain〕 〔gist:Summary instructions, carriers and lifetime〕

三、system prompt 照固定順序組,而且刻意少改,好讓快取吃得到

system prompt 是一段一段接起來的,順序寫死在程式裡,沒內容的段落直接跳過。〔gist:Assembly and injection order〕

順序放什麼
1基本指令,加上視情況出現的 spotlight 和語音頻道說明
2bot 的名字和個人設定、使用者身分、團隊 bot 角色、多工說明
3互動規則:內部細節界線、多帳號連接器、表單、代擬對外訊息、時區
4記憶和工作階段;記憶依序是使用者、專案、agent 自己的事實
5排程、技能、Stripe 付款、外部頻道
6其他 bot 名單、群組聊天、MCP 說明和狀態、遠端 box、密鑰、電腦操作

每一段都會算 hash,有些段落會釘住不動,直到下一次壓縮才更新。開頭不變,模型供應商的 prompt 快取才吃得到。中途改了個人設定,系統會在新的 turn 用一則附註告訴模型,等壓縮時才寫回 system prompt。〔gist:Assembly and injection order〕

工具清單也是同一套做法。開了 stableDynamicToolCatalog 這個開關,新增的工具和 subagent 清單會附在下一則使用者訊息裡,開頭的清單保持原樣。〔gist:Assembly and injection order〕

代價是模型得自己認得「附註比釘住的那段新」。作者提醒,快取有命中,不代表模型拿到的是最新的工具清單。〔gist:Assembly and injection order〕

換到你身上
  • 把這幾種情境寫成測試:移除工具、turn 跑到一半改權限、壓縮後工具清單變動、開關打開和關掉各跑一次。

四、prompt 裡寫「私人」,資料不會因此被隔開

privateMain 這個設定只改 prompt 的措辭,把預設的「使用者」改成「擁有者」,再加上工具說明的快取。真正的儲存隔離,要另外檢查記憶的讀寫程式、讀取權限、共用記憶的存取和後端同步。〔gist:Learned memory, shared scopes and privateMain〕

「The word private in a prompt doesn't enforce access control.」
prompt 裡出現「私人」兩個字,不會幫你做存取控制。

記憶分三層:agent 自己的、使用者共用的、專案共用的。寫進專案層要先有這個專案,bot 也要是成員;沒指定層級時,先用這段對話的預設,再退回 agent 層。〔gist:Learned memory, shared scopes and privateMain〕

背景整理記憶時,模型被要求只提小幅修改、每條都附證據,把既有記憶和對話都當成不可信的資料,不收臆測,也不動使用者親手寫的條目。第二個模型步驟再審一次,最後由程式檢查格式和證據引用才套用。作者的判斷是,保護使用者條目和限制可寫範圍,最後還是要靠程式擋,光靠模型審查不夠。〔gist:Learned memory, shared scopes and privateMain〕

同樣的情況在別處也有:要模型別談內部架構的段落、bot 訊息標成優先,都只是寫在 prompt 裡的話,沒有權限效力。〔gist:Assembly and injection order〕 〔gist:Bots, subagents, peer delivery and scheduling〕

換到你身上
  • 要隔離的資料,在讀寫記憶的程式裡檢查權限,不要只靠 prompt 的措辭。

五、bot 之間互傳訊息的節流開關,在 box 上是關著的

bot 跟 bot 傳訊息時,prompt 有一個 conservativeReplies 選項,會跟模型說回覆要到之後的 turn 才會送到,沒必要就別回。這個值來自 reducePeerChatter,而 box 版 host 把它設成 false,所以這段節流說明在 box 上沒有啟用。光把那段 prompt 抄過去,也不會讓它生效。〔gist:Bots, subagents, peer delivery and scheduling〕

「give every agent a mailbox and eventually one of them replies-all.」
給每個 agent 一個信箱,總有一個會按「全部回覆」。(gist 裡的玩笑話)

收到別的 bot 的訊息時,prompt 會標明寄件者是另一個助理。優先訊息可以打斷背景工作,但不會因此蓋過使用者的權限。〔gist:Bots, subagents, peer delivery and scheduling〕

去重靠的是記憶體裡一組有上限的已收訊息 ID,佇列也在記憶體裡。重開機之後訊息還在不在,原始碼看不出保證。〔gist:Context, memory, compaction and restart〕

作者認為,要擋住 bot 之間一路互回,得在信箱和排程器裡做。就算這樣,兩次分開的模型呼叫,還是可能各送出一則意思重複的訊息。〔gist:Subagents and peer chatter〕

換到你身上
  • 在信箱和排程器加上去重、期限、轉傳次數和回覆次數上限;結果不確定時,把狀態顯示給人看。

六、按下停止,背後跑的程式不一定真的停了

取消要穿過好幾層:畫面上的 turn、送給模型供應商的請求、執行工具的 daemon,最後才是作業系統裡的程序。〔gist:Cancellation and execution boundary〕

原始碼看得到兩段清理。呼叫端斷線時,box 上的 window router 會把上游請求一起砍掉;桌面版 .52 的本機 daemon 在清理時,會取消子程序的執行環境。這兩段來自不同版本的擷取。〔gist:Cancellation and execution boundary〕

連線關了,不代表子程序結束。整棵程序樹有沒有停、停了之後還會不會有晚到的寫入,作者標成未解,要實際量過才知道。〔gist:Unresolved edges that affect an implementation〕

換到你身上
  • 測取消時,連子程序有沒有真的結束、之後有沒有晚到的寫入一起量。

七、新版處理同一個小任務,兩輪送出的資料少了 28.8%

有人反映新版 agent 感覺比較快,用量卻多很多。作者拿新舊 host 在隔離環境裡各送兩次「.」,gateway、runner、序列化、SendToUser、存檔都是真的程式在跑,後端換成固定回「ok」的假伺服器,沒有接真的模型或帳號。〔gist:Actual requests, not estimates〕

第一輪(冷啟動)舊版 .47新版
送給模型的請求(protobuf bytes)167,854118,769
一開始附上的工具 schema40 個11 個
system prompt(UTF-8 bytes)48,43751,180
user-info 開頭訊息(bytes)3786,849

新版的 system prompt 和開頭訊息都變大了,但先附的工具說明少很多,抵掉還有剩。兩輪加起來,新版送 242,142 bytes,舊版 340,310 bytes,少了約 28.8%。〔gist:Actual requests, not estimates〕

原因是 95b13b6 這版把「工具說明用到再查」的預設從關改成開。30 個工具並沒有被拿掉,只是不先列出來,要用時透過 GetDynamicTools 查、CallDynamicTool 呼叫。開頭訊息多出來的 6,471 bytes 是 subagent 和工具清單,跟你的個人資料無關。〔gist:Actual requests, not estimates〕

作者再用同一個執行檔只切這個開關:都先附全部工具時,新版比舊版多約 25%;都用到再查時,新版多約 9%。預設改成比較省的模式,把同模式下的成長蓋掉了。測試裡沒有觸發查工具,所以之後查詢的額外成本、整個任務的總成本都還沒量。〔gist:Actual requests, not estimates〕

「The default flip masks same-mode growth.」
預設值一翻,同模式下變大的部分就被蓋過去了。

八、可能讓用量變多的,是幾條特定的長路徑

每則訊息背後本來就有隱藏的模型呼叫。新舊版都一樣,兩次輸入打了四次模型:回答、抽記憶、回答、抽記憶。抽記憶發生在你看到回覆之後、這輪正式結束之前,這件事 .47 就有了。〔gist:Actual requests, not estimates〕

壓縮對話。從 e6e1fb3 起,xAI 的壓縮會把原本的 system prompt 和工具清單一起送去。作者拿 20 KB 的假 system prompt 加 10 個 schema 實跑,送出的 JSON 從 4,585 bytes 變成 27,398 bytes。這證明組法變了,不能直接當成帳單變六倍。〔gist:Concrete ways input or work can grow〕

翻舊紀錄。95b13b6 加入的 ReadTranscript 名義上限是 48,000 bytes,實際算的是 JavaScript 字串長度,第一行不算,也沒限制分幾段。實測一則多段訊息收下了 402,644 個字元,一個 Unicode 案例收下 132,725 UTF-8 bytes。只有呼叫這個工具時才會發生。〔gist:Concrete ways input or work can grow〕

瀏覽器重抓。新版抓網頁快照失敗時,退路可能把目標元素和深度一起拿掉再試,原本只要一小塊,結果變成整頁快照。〔gist:Concrete ways input or work can grow〕

分派和事件。新版的指令更明確地建議超過兩輪工具就分派出去,worker 多了可能比較快完成,但總花費也可能變多;雲端監看可以喚醒主 agent,存密鑰失敗會排一個隱藏 turn。這些實際用起來分派多少,還沒有數據。〔gist:Concrete ways input or work can grow〕

換到你身上
  • 翻舊紀錄設整包結果的 UTF-8 位元組上限,瀏覽器快照的退路也設上限。
  • 依用途分開記錄成本和時間:主對話、摘要、記憶、審查各算各的。
  • 動壓縮之前,先測相容性和摘要品質,再決定拿掉哪些 context 或 schema。

九、本機流程略快,拖慢的可能是規則載入和 Auto-review 改成要等

新版本機流程量起來快一點,但每格只跑一組冷熱啟動,在已經開著的 WSL 上量,沒有真的模型延遲,不能當成效能評測。〔gist:Follow the work after the answer〕

從送出開始(毫秒,冷/熱)舊版 .47新版
第一個模型請求292 / 147280 / 122
看到回覆318 / 190303 / 138
這輪正式結束512 / 262458 / 278

團隊規則的快取改成同步等。.47 手上有舊快照就直接用,五分鐘後在背景更新;新版就算有快照也要等載入完。成員和規則查詢各有 10 秒逾時,沒有一個整體的上限。實際拖慢多少還不知道。〔gist:Speed improvements and a possible slowdown〕

Auto-review 從 shadow 改成 enforce。預設設定的使用者在舊版就會被分類,只是不用等結果;新版要等分類結果出來才繼續,多的是等待時間,分類的呼叫次數沒有增加。〔gist:Speed improvements and a possible slowdown〕

輸出後卡住的自動恢復,新版預設打開,等待時間 90 秒,工具還在跑時暫停計時。重試次數上限沒變,但恢復可能觸發得比較頻繁。〔gist:Speed improvements and a possible slowdown〕

十、幾個直覺的解釋,作者實測後都排除了

這些是一開始看起來很合理、測完站不住的說法。〔gist:Explanations that did not survive〕

說法測到的
重試次數或預設推理強度調高了沒有。預設仍是 grok-4.5、high、fast、max mode,步數上限也沒變
快取的輸入被算了兩次沒有。輸入 500、輸出 20,算出來是 520,不是把 400 的快取讀取再加一次變 920
每次呼叫都附上一份超大的分類 prompt那段字串從 61,737 長到 73,581 bytes,但只有宣告、沒被送出;分類走的是後端 RPC
隱藏的模型呼叫都是新加的抽記憶本來就有;語音結束的新流程是取代舊的那次呼叫
所有輸出上限都放寬了shell 輸出格式和 MCP 溢出處理,五個版本逐位元組相同

作者的結論是,新版改的是流程編排、重播和有條件載入的 context,沒有讓每個請求都變大。至於某一位使用者的帳單為什麼變多,要拿到實際的線上版本和開關、同一段時間的真實工作量、每種用途的 ID、供應商回報的用量和畫面上的計量,才分得出來。〔gist:What still resolves the user's exact “why”〕

換到你身上
  • 要拆用量時,在隔離的設定檔裡一次只關一個因素,跑同一份工作量比較。

明天就能做的事

  1. 把移除工具、turn 中途改權限、壓縮後工具清單變動、開關兩種狀態,寫成 harness 測試。
  2. 在讀寫記憶的程式裡檢查權限,不要只靠 prompt 寫「私人」。
  3. 在信箱和排程器加上 bot 回覆的去重、期限、轉傳和回覆次數上限,結果不確定時顯示狀態。
  4. 測取消時,一起量子程序有沒有結束、之後有沒有晚到的寫入。
  5. 翻舊紀錄設整包 UTF-8 位元組上限,瀏覽器快照的退路也設上限。
  6. 依用途分開記錄成本和時間。
  7. 動壓縮前,先測相容性和摘要品質。
  8. 拆用量時,在隔離設定檔裡一次關一個因素,跑同一份工作量比較。

資料來源

  1. How the Grok Bot harness works|@gabefletcher(GitHub Gist,chinghanho 發布)|2026
  2. @gabefletcher|X|gist 署名作者

※ 本文整理自上面這份 gist,〔gist:…〕連結都指向同一份 gist,括號內是對應的英文小節標題。內容是作者分析打包後原始碼和在隔離環境實測的結果,沒有接真的模型或帳號;bytes 不等於 token,也不是帳單金額。各數字依作者原文,沒有另外查證。前半架構對應 host 17e335e 和桌面版 .52,兩者是否為同一組發行版本,作者標為未證實。本文為非官方整理,以原文為準。

推 鄉民A: 工具說明改成用到再查,第一輪省很多,但查工具那一來一回的成本還沒算進去。
→ 鄉民B: 「privateMain 只改措辭」這段很實用,做多人共用記憶的都該檢查一下自己家的。
→ OP: gist 目前沒有留言,以上為模擬討論、非正式留言;本文為非官方圖文整理。