在搭載本地 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 任務數。 |
為何本地推理比雲端更困難
- 大型系統提示詞與工具架構 – 在筆電上讀取速度約 90 token/s、寫入速度約 10 token/s 的情況下,2,000 token 的提示詞需耗時約 22 秒才開始生成;而 Opencode 使用的 18,000 token 提示詞則需約 226 秒。雲端 GPU 的預填速度超過 10k token/s,將這些延遲壓縮至不到一秒。
- 縮小的上下文視窗 – 消耗完系統提示詞後,剩餘上下文通常低於 32 k token。Opencode 的 18k token 提示詞僅留下約 44 % 的視窗空間用於實際工作,而輕量的 pi 框架則保留約 94 %。
- 側邊請求開銷 – 重複發出輔助請求(例如程式碼摘要)的框架會導致本地模型排隊或重複預填,使 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 速度,但因頻繁超時導致通過數偏低。
面向本地模型框架的設計教訓
- 精簡系統提示詞 – 每多一個 token 就會在筆電上增加約 0.01 秒的預填延遲。目標應低於 2k token。
- 限制工具架構數量 – 每增加一個工具,提示詞大小與可用上下文視窗都會減少。
- 持續保留前綴快取 – 在回合間重用快取預填(≥95 % 重用率)可消除重複工作,大幅提高實際吞吐量。
- 將代理迴圈與模型共置 – chad 的在程序內 MLX 實作顯示,擁有快取可消除網路往返,帶來 2×–3× 的速度提升。
- 提供草稿模型 – 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.json、turns.jsonl)皆與基準測試程式碼一同提交,確保從單一資料列到聚合數字的完整可追蹤性。
結論
當將雲端 LLM 替換為筆電上的本地模型時,主要影響因素是 提示詞大小所導致的預填延遲。原本設計用於近乎免費的雲端預填(大型系統提示詞、大量工具架構)的框架,在本地環境中變得無法使用。透過有紀律的極簡提示詞、持續的前綴快取,以及若可能的話,採用在程序內的模型迴圈,即可在消費級硬體上實現接近雲端的吞吐量。
Sources
相關
- Dispatch
- Dispatch
- Dispatch
- Dispatch
- Dispatch