在搭載本地 Qwen 3.8 27B 模型的 MacBook Pro 上測試九種程式碼代理框架

簡要總結

在單一 M4 MacBook Pro 上運行九種流行的程式碼代理框架,搭配本地部署的 Qwen 3.8 27B 模型,可清楚分出三類表現:(1) 輕量且穩定的框架(pi、mini‑swe‑agent、chad)每秒產生約 8 個 token,回合延遲低於一秒;(2) 重量級但有紀律的框架(dsh、cline、codex、goose)每秒產生 6–8 個 token,但首個 token 等待時間較長;(3) 啟動耗時的框架(crush、opencode)需耗時 3–4 分鐘才會輸出,且速率僅約 5–6 token / s。差異主要來自系統提示詞大小、工具架構數量與快取重用效率。


實驗設定

  • 硬體:Apple M4 MacBook Pro,24 GB RAM,macOS 26.6.2。
  • 模型:Qwen 3.8 27B,透過 unsloth/Qwen3.8-27B-GGUF 進行 3 位元量化,由 llama.cpp(版本 10470)提供服務。
  • 伺服器:所有框架共用單一 llama-server 實例;代理伺服器強制執行統一的採樣規則(temperature = 1.0,top_k = 20,top_p = 0.95,min_p = 0.05)。
  • 快取:32,768 token 的統一前綴快取,分為四個槽位。
  • 基準測試:八個 Exercism Python 練習題,每題以自動核准模式執行,使用相同的單句提示。資料由伺服器自身會計系統收集(除兩列 chad 使用內部追蹤外)。

指標定義

指標 含義
首個 token 前的等待時間 預填系統提示詞、工具架構與第一個使用者請求所需時間。
後續回合的等待時間 首回合後的中位數與第 90 百分位停頓時間(不包含側邊請求)。
快取重用率 後續回合中從前綴快取取得的 token 百分比。
實際每秒產生的 token 數 總產生 token 數除以實際時間,包含預填與工具開銷。
通過數(門檻) 在 1,200 秒超時內完成的 Exercism 任務數。

為何本地推理比雲端更困難

  1. 大型系統提示詞與工具架構 – 在筆電上讀取速度約 90 token/s、寫入速度約 10 token/s 的情況下,2,000 token 的提示詞需耗時約 22 秒才開始生成;而 Opencode 使用的 18,000 token 提示詞則需約 226 秒。雲端 GPU 的預填速度超過 10k token/s,將這些延遲壓縮至不到一秒。
  2. 縮小的上下文視窗 – 消耗完系統提示詞後,剩餘上下文通常低於 32 k token。Opencode 的 18k token 提示詞僅留下約 44 % 的視窗空間用於實際工作,而輕量的 pi 框架則保留約 94 %。
  3. 側邊請求開銷 – 重複發出輔助請求(例如程式碼摘要)的框架會導致本地模型排隊或重複預填,使 GPU 的實際使用率超過 100 % 的實際時間。

測試結果

框架 版本 工具數 提示詞(token) 首個 token 等待時間 後續回合等待時間(中位數·第90百分位) 快取重用率 每秒 token 數 通過數(共 24 題)
mini‑swe‑agent 2.4.6 1 1,171 12.2 s 3.6 s·21 s 96 % 8.0 11(14 次超時)
pi 0.80.3 4 2,008 21.6 s 1.3 s·22 s 99 % 8.1 19(7 次超時)
cline 3.0.60–61 26 5,876 64.1 s 9.9 s·52 s 94 % 7.3 17
codex 0.151.0 10 7,804 87.8 s 9.6 s·28 s 94 % 6.9 19(5 次超時)
dsh 0.1.1‑rc.2 25 8,052 94.4 s 2.2 s·34 s 99 % 7.2 18
goose 1.50.0 18 9,617 110.3 s 1.0 s·22 s 100 % 8.0 22(3 次超時)
crush 0.92.0 26 16,263 199.8 s 1.8 s·40 s 100 % 5.8 18(8 次超時)
opencode 1.17.12 10 18,046 225.7 s 4.6 s·44 s 99 % 5.7 15(13 次超時)
chad(llama.cpp) 2.0.3 5 2,563 25.6 s 0.8 s·19 s 99 % 7.9 24
chad(MLX,序列) * 2.0.3 5 2,566 4.7 s 1.0 s·19 s 99 % 12.4 21(3 次超時)
chad(MLX,dflash2) * 2.0.3 5 2,562 4.6 s 0.9 s·36 s 99 % 17.4 22(3 次超時)

數據解讀

  • 輕量框架(pi、mini‑swe‑agent、chad)將系統提示詞控制在 ~2k token 以下,快取重用率超過 99 %,每秒穩定在 ~8 token。chad 的 MLX 版本透過在程序內擁有快取,使吞吐量翻倍(最高達 17.4 token/s)。
  • 重量級但有紀律的框架 雖有較長的首個 token 等待時間(最高達 ~110 s),但因高快取重用率,穩態吞吐量仍可接受(約 7 token/s)。
  • 啟動耗時的框架(crush、opencode)需超過 3 分鐘才開始輸出,速率降至 ≤6 token/s,對筆電而言不切實際。
  • 通過率 與延遲高度相關:僅 chad(兩種變體)成功完成全部 24 題;其次為 goose(22/24)。mini‑swe‑agent 雖有不錯的 token 速度,但因頻繁超時導致通過數偏低。

面向本地模型框架的設計教訓

  1. 精簡系統提示詞 – 每多一個 token 就會在筆電上增加約 0.01 秒的預填延遲。目標應低於 2k token。
  2. 限制工具架構數量 – 每增加一個工具,提示詞大小與可用上下文視窗都會減少。
  3. 持續保留前綴快取 – 在回合間重用快取預填(≥95 % 重用率)可消除重複工作,大幅提高實際吞吐量。
  4. 將代理迴圈與模型共置 – chad 的在程序內 MLX 實作顯示,擁有快取可消除網路往返,帶來 2×–3× 的速度提升。
  5. 提供草稿模型 – DFlash2 草稿模型使 chad 的 token 速率從 12.4 → 17.4 token/s,展現輕量草稿模型在早期 token 生成上的價值。

社群反饋精選

"如果你需要在資源受限環境中使用的程式碼代理,請試試 hax —— 一個僅 0.7 MB 的原生二進位檔,搭配極簡提示詞與工具集。" – OleksandrC

"像這樣的基準測試變化極快;一個可重現的程式庫能讓任何人於自己的硬體上比較每回合 token 數、首個 token 延遲與通過率。" – humbleferret

"jcode 在記憶體使用上表現最佳,以極小的 Rust 二進位檔勝出,卻未被納入本研究。" – lrvick

"Reasonix 可能是個有趣的比較對象,因為他們高度專注於前綴快取重用。" – swiftcoder

這些評論強調了輕量提示詞、開源可重現性,以及存在未被原始矩陣涵蓋的其他超輕量代理的重要性。


如何重現此基準測試

整個實驗皆由 chad 倉儲中的腳本完成:

# 克隆倉儲
git clone https://github.com/nathansutton/chad.git
cd chad

# 安裝相依套件(推薦使用 uv)
uv run python benchmarks/matrix/run.py setup   # 安裝模型、建置 llama.cpp
uv run python benchmarks/matrix/run.py smoke   # 健康檢查
uv run python benchmarks/matrix/run.py llama   # 透過 llama.cpp 伺服器執行所有框架
uv run python benchmarks/matrix/run.py mlx     # 使用 MLX 後端執行 chad
uv run python benchmarks/matrix/run.py table   # 產生上列的 Markdown 表格

所有原始資料(grid.jsonturns.jsonl)皆與基準測試程式碼一同提交,確保從單一資料列到聚合數字的完整可追蹤性。


結論

當將雲端 LLM 替換為筆電上的本地模型時,主要影響因素是 提示詞大小所導致的預填延遲。原本設計用於近乎免費的雲端預填(大型系統提示詞、大量工具架構)的框架,在本地環境中變得無法使用。透過有紀律的極簡提示詞、持續的前綴快取,以及若可能的話,採用在程序內的模型迴圈,即可在消費級硬體上實現接近雲端的吞吐量。

Sources

相關