
最近做 AI Agent 的任務後,回來看自己這台機器,感受特別具體,agent 不是聊天,它是一個會自己決定下一步、會呼叫工具、會把整個過程塞回上下文再問你一次的迴圈。這個迴圈對推論端點的壓力形狀跟聊天完全不同,而本系列到 Day 18 為止建好的環境,就是為了好好和他一起工作。
今天先做 AI Agent 的框架總覽並把系統架構的流量分析給你看,明後天內容還有 Harness 實戰,以及多代理指揮中心等議題。不過開場前要先補充一個測試,在繁體中文考驗中, gpt-oss-120b 是今天補上的。
Day 15 的候選表裡它是唯一「未考」的一款地端模型,用 llama-server 路線考,同一份考卷(github.com/ivanusto/llm-zhtw-agent-exam)、同一組取樣設定:
| gpt-oss-120b | Ornith BF16 | Ornith NVFP4 | Flash-Next | pplx 27B | 27B FP8 | |
|---|---|---|---|---|---|---|
| 繁中十題 | 19 / 20 | 20 / 20 | 20 / 20 | 20 / 20 | 20 / 20 | 20 / 20 |
| 簡體字洩漏 | 0 | 0 | 0 | 0 | 0 | 0 |
| 工具呼叫十輪 | 10 / 10 | 10 / 10 | 10 / 10 | 10 / 10 | 10 / 10 | 10 / 10 |
| 多步 agent 三題 | 3 / 3 | 3 / 3 | 3 / 3 | 3 / 3 | 3 / 3 | 3 / 3 |
| JSON 緊湊度(多行 / 50) | 0 / 50 | 24 / 50 | 40 / 50 | 24 / 50 | 0 / 50 | 0 / 50 |
| 平均輸出長度 | 51 字元 | 60 | 63 | 59 | 51 | 51 |
| decode(同一支 exam.py) | 53.2 t/s | 30.1 | 77.5 |
前四項跑四輪,四輪完全一致(19/19/19/19、洩漏 0/0/0/0、工具 10/10/10/10、agent 3/3/3/3)。JSON 列是 5×10 = 50 輪,每十輪散布 0–0。取樣設定與既有五欄相同,temp 0.7、top_p 0.80、top_k 20。
掉的那一分是用語問題。 第 5 題要求答案含「記憶體頻寬」,它四輪都寫
「量化能減少每次運算所需的位元數,讓資料在記憶體與處理器之間傳輸的頻寬需求下降」。
字都在,就是不連成那個詞,被逐字比對判失。如果同一把尺套在六款模型上的畫,這一分需要照扣才行。
gpt-oss 關不掉思考。
其他五款地端模型都是在思考關閉下考的,harmony 模板沒有這個開關:exam.py 寫死送出的 chat_template_kwargs:{"enable_thinking":false} 不會報錯,
它被靜默忽略。
而這件事會影響測試結果,預設思考檔位下實測六題有兩題撞到 exam.py 的 max_tokens=250 上限,
其中多步 agent 那一題吐了 1,028 字元的思考、content 完全是空的。
所以補考用 --reasoning-effort low 逼近其他五款的思考關閉狀態,並用--reasoning-format deepseek 把思考分離到 reasoning_content,讓它不會混進content 汙染「繁體用字」與「簡體洩漏」兩個判準。改設定後同樣六題只剩一題截斷,
而那一題是模型話多,不是思考吃掉配額,其他五款模型面對的是同一個 250 token 上限。
這是六欄之中唯一一欄的考試條件跟其他五欄不同,所以如果要參考這份資料,需要參考這一段說明才行。
它的禮儀是滿分等級,而且贏過掛著 agent 招牌的。
50 輪全部單行緊湊、50 輪欄位全對、平均 51 字元,跟兩款 27B 完全同等級,把 Ornith 的 24/50 與 40/50
甩在後面。Day 15 的結論在這裡再被推一次:agentic 能力與 agentic 禮儀是兩件事,
而唯一明確掛著 agent 招牌的那款模型,就沒有那麼好的成果。
** 53.2 t/ vs 77.5 t/s**
第一,用 exam.py 這同一支腳本量,它是 53.2 t/s(四輪 53.10 到 53.99)不是 60.6。
60.6 出自 Day 11,而 Day 11 自己的長版已經把那個數字修正成 55.64,
差的 5% 是伺服器開銷。第二,53.2 不是全場最快,同一支腳本測試到的
Ornith NVFP4 是 77.5 t/s。llama.cpp 在單請求 decode 上的優勢是 Day 11 的結論,
它成立的對象是同一款權重換引擎,不是換一款兩倍大的模型還要比別人快。
跨引擎比 t/s 另有一個保留:兩邊的 token 不是同一種 token,
gpt-oss 走 llama.cpp 的 GGUF tokenizer、Ornith 走 vLLM 的 HF tokenizer,
分母定義不同,這個比較只能當數量級參考。
補考完,三部曲的主力模型定案:Qwen3.8-27B。理由是它在繁中、工具、多步與 JSON
禮儀四項全滿,而且是本機唯一同時有 vLLM(FP8)與 llama.cpp(Q8_0)兩種格式的一款模型,
下一節的引擎對照才能只留引擎一個變因。gpt-oss-120b 沒有翻盤但也沒有落敗,
它把 Day 15 那張候選表的結論從「Ornith 是唯一為 agent 而生的」推成
「掛招牌的那款禮儀最差,禮儀最好的三款都沒掛代理專用模型的招牌」。

市面上叫 agent 的東西太多,先分層,分完你就知道接下來的系列文為什麼這樣排。
協定層:MCP。
Model Context Protocol 解決「工具怎麼讓模型看見」,一個 MCP server 把檔案系統、資料庫、網頁、你的系統包成標準介面,任何支援 MCP 的 harness 都能接。它不做決策,屬於工作人的角色。
執行層:harness。
真正跑迴圈的東西,決定下一步、呼叫工具、管理上下文、處理錯誤重試。這一層是三部曲的主戰場,選手有 opencode(開源終端機 coding agent,任何 OpenAI 相容端點都接)、Hermes Agent(開源 agent 要角)、以及明天的主角 DeepSeek Harness(8 月 13 日釋出、MIT 授權、兩天破九萬星的外掛式架構,模型無關)。Claude Code 與 Codex 這類商業產品也在這層,但它們綁自家模型,不是地端 AI 議題。
指揮層:多代理管理。
當你同時開三個 harness 跑三件事,誰在等你、誰卡住了、誰跑完了,需要一個看板。這是後天 herdr 的位置,一個 agent 感知的終端機多工器。
這是今天的正題。把 opencode 接上 Day 18 的閘道,指向 Qwen3.8-27B-FP8,跑一個真實任務:
閱讀這個專案的 README 與 src 底下的主要原始檔,找出沒有處理的錯誤路徑(網路失敗、API 金鑰失效、打包失敗),整理成一份 GitHub issue 草稿。

標的是我自己的 just-ad-blocker(54 個檔),複製一份到暫存區跑,不動原始碼。
量測方式是在閘道上掛一支記錄器,把每一輪的完整 payload 與 usage 落成 JSONL,
再離線用這款模型自己的 tokenizer 斷詞。
| 組成 | 首輪(第 2 輪,暫定) | 第 21 輪(暫定) | 每輪是否重送 |
|---|---|---|---|
| 模板骨架 | 52 | 52 | 是 |
| 系統提示(opencode 內建) | 2,255 | 2,255 | 是 |
| 工具 schema(10 個工具) | 5,286 | 5,286 | 是 |
| 累積對話歷史與工具回傳 | 0 | 12,144 | 是 |
| 模型自己的思考回放 | 0 | 18,236 | 是 |
| 本輪新增內容 | 45 | 2,639 | 首次 |
| 合計 | 7,638 | 40,612 |
第五段是模型自己的思考。
opencode 把模型上一輪吐出的 reasoning_content
原樣放回 assistant 訊息裡再送一次,於是模型每一輪都要重讀自己過去所有的思考。
到第 21 輪,這一段是 18,236 token,佔整個 40,612 token 輸入的 45%。
這段在任何只數訊息的帳裡都是隱形的,因為它不是一則訊息,它藏在 assistant 訊息內部。
閘道既有的 [anatomy] 那行只數字元、只分 system 與 convo 與 tools 三類,
也看不到它。
拆解方法是差分渲染模型自己的 chat template:
骨架 + 系統 + 歷史 + 思考回放 + 本輪新增 + 工具 = prompt_tokens
20 個已完成的請求,這個恆等式的最大絕對誤差是 0。
首輪輸入 7,638 減掉任務描述的 43 個 token 等於 7,595,模板差分法算出的骨架加系統加工具是 7,593,兩者差 2 個 token,就是 user 訊息的包裝。
每一輪都原樣重送 7,593 個 token(骨架 52 + 系統提示 2,255 + 工具 schema 5,286),
這就是 prefix cache 處理的部分。
任務跑了 20 個已完成請求(17 個 agent 輪 + 3 個 opencode 自己發的側呼叫),總輸入 561,582 token、總輸出 34,788 token。輸入是輸出的 16.1 倍。
這是 agent 負載跟聊天最根本的差別,它是 prefill 型工作,而且絕大多數 prefill 是重複的前綴。
於是 Day 11 那三個推論條件現形了,prefill 重、前綴重複率極高、真實平行處理時,實測 vLLM 的 prefix cache 命中率(Δhits / Δqueries,冷啟動計數器歸零起算)在這個任務裡是 77.3%,第一輪之後的 TTFT 從 27.64 秒降到中位數 3.10 秒(全距 0.50 到 11.54 秒)。
prefix cache 確實是 agent 場景的主角,但它挽救的是重複的那 7,593,處理不了長出來的那 33,000。
TTFT 沒有降到接近零而是停在三秒上下,正因為每一輪真正新增的內容(工具回傳、
上一輪的思考)都是快取沒見過的,而它們一路在長。命中率 77.3% 這個數字或許這樣看比較好,分子是那塊不動的前綴加上已經看過的歷史,分母是整個一路變長的輸入。
同一句任務、同一份工作區副本、同一個 harness,換成 Qwen3.8-27B 的 Q8_0 GGUF 上 llama-server。
兩邊都是 8 位元、29 GB 級的同一顆模型,變因只有引擎。

| 項目 | vLLM(FP8) | llama.cpp(Q8_0) |
|---|---|---|
| 冷啟動首輪 TTFT(重放同一份 payload) | 21.76 s | 10.38 s |
| 後續輪 TTFT 中位(每千個輸入 token) | 0.103 s | 0.161 s |
| 後續輪 TTFT 全距 | 0.50 – 16.12 s | 0.76 – 41.02 s |
| prefix cache 命中率 | 73.5% | 沒有這個指標 |
| decode | 7.8 t/s | 7.09 t/s |
| agent 輪數(模型自己決定) | 20 | 27 |
| 總輸入 / 總輸出 | 701,936 / 50,183 | 954,241 / 65,218 |
| 輸入是輸出的幾倍 | 14.0× | 14.6× |
| 牆鐘總耗時 | 116.5 min | 158.1 min |
llama.cpp 贏冷啟動的第一輪,vLLM 贏之後的每一輪。
第一輪它快 2.1 倍,這是 Day 11「單請求 prefill 是 llama.cpp 主場」的再一次驗證。
但把後續每一輪的 TTFT 正規化成每千個輸入 token 之後,vLLM 快 1.56 倍,
而且 llama.cpp 的最壞情況是 41 秒對上 vLLM 的 16 秒。
所以 Day 11 那句「一個人用,選 llama.cpp」在 agent 場景要加一句話。
它單次 prefill 確實更快,但 agent 迴圈的成本不在第一次,
在後面那二十幾次重複前綴,而那正是 prefix cache 的主場。
Day 11 說「llama.cpp 單代理可以、開分身就撞牆」,這次的測試比上次更嚴格,
連單代理都碰到瓶頸。
三個必須講清楚的限制:
一、總耗時那一列不能單獨引用。 agent 每一輪要呼叫哪個工具是模型當下決定的,
兩個引擎跑出來的輪數本來就不一樣(20 對 27),所以 116.5 對 158.1 分鐘是
「同一個任務」的比較,不是逐輪對齊的比較。逐輪對齊的只有第一列,
它是同一份錄下的 payload 重放給剛啟動的伺服器,逐 token 相同。
二、llama.cpp 沒有可讀的命中率,這件事本身就是結論之一。
它的前綴複用是 server slot 的 prompt cache,沒有 Prometheus 端點、沒有 counter。
不是「它命中率比較低」,是「你量不到」。要在 agent 場景調校快取,這個差別很實際。
三、decode 那一列跟 Day 11 的方向相反。 Day 11 在 gpt-oss 這款 MoE 上,
llama.cpp 的單請求 decode 大勝 vLLM。而這次測試呢,在一款密集 27B 上,vLLM 反而略快
(7.8 對 7.09)。同一個引擎在不同架構上不必然給同一個答案,Day 11 的結論的適用對象是那款 MoE,不是所有模型。
這顆 27B 在本篇第一節的考卷裡繁中 20/20、簡體洩漏 0。但在這個跑了近兩小時、輸入長到 49k 的真實 agent 任務裡,它交出的 issue 草稿寫著「单次瞬態失敗」「最危险的三处」「凭据过期」。
十道短題目、每題 250 token 的考卷,量不到一個長迴圈裡會發生什麼。這不推翻 Day 15 的成績,它是說那份成績的適用範圍比看起來窄,而 Day 15 那份考卷的下一版該加一題長輸出的繁體維持力。
寫這篇的時候,GitHub 上有一款新的推論引擎正在熱門上揚中,柏克萊 Ion Stoica 與 Matei Zaharia 那組人的 FreeToken,8.6k 星,Apache 2.0 授權。它的定位是「邊緣原生 MoE 服務引擎」,用 CPU 加 GPU 的頻寬自適應協同執行,在消費級顯卡上跑 290B 級的 MoE(支援清單裡有 DeepSeek V4 Flash、Qwen3.6-35B-A3B、GLM-5.2),MXFP4 到 BF16 都吃,OpenAI 與 Anthropic 雙相容 API。
它跟今天這篇的交集在一個功能:語意錨點快取,專門針對 agent 迴圈裡工具呼叫與思考區塊造成的上下文編輯,避免重算。這正是上面量到的那個「絕大多數 prefill 是重複前綴」的問題,vLLM 用 prefix cache 解,它用另一套方法解,兩者誰更適合 agent 負載,是個值得正面對決的題目。
而今天那個第五段讓這題變得更尖銳,如果 agent 每輪要重送的不只是固定前綴,還包括模型自己不斷累積、佔到四成輸入的思考,那麼「針對思考區塊造成的上下文編輯」這個賣點打的正是這個要害。
但有一個只有這台機器能回答的疑問。FreeToken 的協同執行是為「VRAM 不夠、host memory 來補」的分離式架構設計的,統一記憶體上沒有這道牆,Day 14 已經看過一次類似的情況,Flash-Next 的 n-gram 卸載在 Spark 上價值歸零。FreeToken 的核心武器會不會在這台機器上變成擺設 ? 而它的快取設計又能不能獨立發揮 ? 這兩題排進這幾天後面的文章,用今天同一個 agent 任務、同一套流量解剖法對決 vLLM。
框架分完層、流量解剖完、主力模型定案,明天讓執行層真正開工:DeepSeek Harness 實戰。把 dsh 接上地端閘道,看它的外掛式架構怎麼跟本地模型相處、跟 ds4-server 上的那款 DeepSeek V4 Flash 是不是天作之合,以及一個地端 harness 該有的治理邊界,剛好是我最近做完的題目,打鐵趁熱吧。
我們 Day 20 見囉。
Day 1|為什麼 2026 年是地端 AI 部署元年:系列規劃與硬體總覽
Day 2|DGX Spark GB10 深度解析:128GB 統一記憶體到底解決了什麼問題
Day 3|網路與儲存規劃:10GbE 骨幹、雙 Spark 直連與 NFS 集中模型庫
Day 4|開箱之後:DGX OS 初始環境建置與 CUDA、Docker 生態確認
Day 5|NFS 模型庫實戰:下載工具、權限設計與版本管理
Day 6|llama.cpp、vLLM、TensorRT-LLM 、Ollama、DS4 與 Unsloth 的定位與取捨
Day 7|第一個模型上線:gpt-oss-120b 從模型庫到 API 的完整流程
Day 8|llama.cpp 實測:先定量尺與 SOP
Day 9|vLLM 實測:官方容器、同時處理吞吐曲線,與剛出爐的新模型 Ornith 1.5
Day 10|TensorRT-LLM 實測:我花了一個下午,跟它的預設值搏感情
Day 11|地端 AI 三大推論引擎綜合評測,同場加映神秘嘉賓
Day 12|量化格式解析:「4-bit」兩個字,古今多少事 ? 都付笑談中
Day 13|Perplexity 把整套 Agent 搬上 DGX Spark:地端元年的官方背書
Day 14|Qwen3.8-27B 與 Flash-Next 加碼實測:地端模型世代對決與落地評估
Day 15|Ornith 1.5 實測:為 AI agent 而生的 35B-A3B
Day 16|模型選型方法論:五個問題幫你跳脫排行榜迷失,找到適合自己任務用的 AI 模型
Day 17|ds4 深度解析:Redis 之父只為一種模型造了一個引擎
Day 18|OpenAI 相容 API 層:地端 AI 多模型常駐好助手
Day 19|地端 agent 框架總覽:它們到底對你的端點做了什麼呢?
Day 20|DeepSeek Harness 實戰:21 萬顆星的外掛式 harness 接上地端