你把 Qwen3.8-27B 裝進本機、聊天也答得像模像樣,接上 Agent 後卻可能遇到另一個世界:reasoning_effort 看似送出了,實際套用哪一檔不清楚;第一輪工具呼叫成功,第二輪一重播歷史就壞掉。這也是 Qwen3.8-27B 本機 Agent 真正該先驗收的地方。
這篇不重寫下載與安裝教學,而是交付一套可反覆執行的相容性驗收協定:固定模型、Prompt、工具 schema 與評分規則,再由讀者分別跑 llama.cpp、vLLM/OpenAI-compatible endpoint,填回關閉思考、low、medium、xhigh 四種模式的結果。讀完後,你會知道如何產生「哪個組合真的能完成兩輪 Agent 迴圈」的驗收表,而不是把未跑過的組合寫成成績。
先說清楚驗證範圍:截至 2026 年 8 月 18 日,本次 AlphaLab 執行環境是 Apple M4、16 GiB 統一記憶體,沒有安裝或執行 llama.cpp、vLLM,也沒有載入 Qwen3.8-27B 權重。AlphaLab 實際跑過的只有「不載入權重、直接重播官方 chat template」的 JSON-string history 測試;下文的 24-run 矩陣與 16/24/48 GiB 配置都是給讀者重跑的 protocol/候選起點,不是 AlphaLab 的跨 runtime benchmark 結果。
如果你還在決定量化檔與顯存,先看 AlphaLab 的Qwen3.8-27B 模型解讀、本機 LLM 顯存指南與GGUF 量化指南;本文從「模型已經能啟動」的下一步開始。
先說結論
- 先驗協定,再測速度。能聊天不代表能正確輸出 tool call、保留 call ID、接回 tool result。
- off 不是第四種 reasoning_effort。Qwen 官方模型卡列出的 effort 是 low、medium、xhigh;關閉思考要另外設定
enable_thinking=false。 - 同一個「OpenAI-compatible」標籤不保證同一種行為。把原始 request、response、版本與模型 revision 一起存下來,runtime 更新後才有東西可以重播。
Qwen3.8-27B 本機 Agent 的一句話定位
先記住這個式子:
本機 Agent 可用性 = 模型答對 × Runtime 傳對 × Harness 接對
任何一項是 0,整個迴圈就是 0。
模型決定「要不要呼叫工具」;Runtime 把模型輸出轉成 API 的 tool_calls;Harness(負責保存訊息、執行工具、把結果送回模型的控制層)則完成下一輪。排行榜通常只量第一項,本文的相容性套件專門把後兩項照亮。想先理解這三層差異,可接著讀AI Agent Harness 是什麼與Harness 四模式實測。

為什麼先做相容性實驗,而不是先追 tokens/s?
Agent 的失敗常是「格式正確但語意錯」或「第一輪成功、第二輪才爆」。例如 server 回傳一個外觀看似正常的 function.arguments,client 卻把 JSON 字串當成物件;又或者 UI 顯示 xhigh,後端實際沒有把該值送進 chat template。這些錯不一定會變成 HTTP 500,速度曲線也看不出來。
因此正確順序是:protocol correctness → task correctness → latency/throughput。先要求每次執行都通過同一套斷言,再比較延遲與 token。這和把模型排行榜轉成私有 Eval的原則相同:總榜只幫你選候選者,固定任務才負責驗收。
步驟一:把版本與啟動參數釘死
痛點是「昨天能跑、今天不能跑」卻無法重現。解法叫做版本帳本:每一筆結果都綁定 runtime 版本、模型 revision/GGUF 檔案雜湊、量化、GPU、context、KV cache 類型與完整啟動參數。先執行:
llama-server --version
python -c "import vllm; print(vllm.__version__)"
shasum -a 256 /path/to/Qwen3.8-27B-*.gguf
以下以 32K context 建立第一條 baseline,並把目前預設已開啟的 --jinja明寫出來,避免未來版本或既有啟動腳本改變 template 路徑;先不要同時加入 MTP、超長 context 或激進 KV 量化,否則出錯時無法知道是哪個變因:
llama-server \
--jinja \
-hf ggml-org/Qwen3.8-27B-GGUF:Q4_K_M \
--no-mmproj \
--reasoning-format deepseek \
-c 32768 \
--host 127.0.0.1 \
--port 8001
llama.cpp server 文件(commit 169e4a7)把 Jinja 設為預設,--jinja在此用來固定實驗意圖;文件也建議從 /props檢查載入的 template 是否具備工具能力。換句話說,第一個健康檢查不是問模型「你好嗎」,而是先確認 server 真正載入哪個 template。
vLLM baseline 則依 Qwen 官方 repository指定 Qwen reasoning parser 與 tool parser。下面採官方 FP8 checkpoint、只載語言模型,並把 262K 範例縮到 32K;recipe 的 vram_minimum_gb: 38只是容量 heuristic,不是實測峰值,而且 FP8 還要符合支援的硬體與 kernel。16/24 GiB 路線先跑上一段文字版 llama.cpp/GGUF:
vllm serve Qwen/Qwen3.8-27B-FP8 \
--host 127.0.0.1 \
--port 8002 \
--tensor-parallel-size 1 \
--max-model-len 32768 \
--language-model-only \
--kv-cache-dtype fp8 \
--reasoning-parser qwen3 \
--enable-auto-tool-choice \
--tool-call-parser qwen3_coder
vLLM Qwen3.8-27B recipe(commit 62a146b)列出 min_vllm_version: 0.17.0並安裝 transformers>=5.8.0;0.17 是架構下限,不等於所有 Qwen3.8 功能都已在該 release 驗證,較舊版本也只是未驗證而非已證實不相容。請 pin 官方 qwen38 image/exact build 並記錄 digest。上面兩個 baseline 都綁在 127.0.0.1;要開放到其他機器時,先加入 API key、反向代理或等效存取控制。兩個 endpoint 再用同一個 GET /v1/models、同一個 system prompt、同一組 generation 參數。請把「server 能回 200」與「Agent 測試通過」分成兩欄;前者只是啟動成功。
步驟二:正確拆開 off、low、medium、xhigh
Qwen3.8-27B 官方模型卡目前列出的 reasoning_effort是 low、medium、xhigh,其中 xhigh 為預設;「off」要用獨立的 enable_thinking=false。因此不要把四個字串塞進同一欄,而要建立兩個維度:
- Thinking 開關:
false或true。 - Effort:只有 thinking 開啟時才測 low、medium、xhigh。
- Budget:若 runtime 另有硬上限,把它當第三個變因;不要拿 token budget 冒充 effort。
原始 HTTP payload 的最小差異可以保存成四個 patch。關閉思考:
{
"chat_template_kwargs": {
"enable_thinking": false
}
}
開啟思考並選 low/medium/xhigh:
{
"chat_template_kwargs": {
"enable_thinking": true,
"reasoning_effort": "low"
}
}
如果你用 OpenAI SDK,chat_template_kwargs通常要放進 extra_body;若直接送 HTTP,它就是 request body 的欄位。上面把 effort 放在 template kwargs,是為了讓 Qwen 的 xhigh 跨過 vLLM 0.17 的舊版頂層 enum;vLLM 0.27.1 已接受頂層 xhigh,但這要列成另一組 pinned-version transport test。llama.cpp 與 vLLM 的接受欄位不必然同步,所以 adapter 應把「測試模式」翻譯成各 runtime 的 payload,同時把實際送出的 JSON 落盤,不能只記 UI 顯示值。
llama.cpp 這條 baseline 保持預設的 --reasoning auto,再加跑一組 transport test:off 送頂層 "reasoning_effort":"none",其餘三格送 low/medium/xhigh。若你在 server 啟動時硬設 --reasoning on或 off,要把它列成另一個變因;截至 2026 年 8 月 18 日,啟動時保存的 enable_thinking與 request override 仍可能互相覆寫,不能把兩種啟動方式的結果混在一起。
每一格不能只留一個 PASS。至少分成五欄:client validation(SDK 是否接受欄位)、server acceptance(HTTP/schema 是否接受)、template applied(有效 rendered prompt 或 server trace 是否真的套用)、behavior(固定任務的成功率/延遲)、accounting(原始 usage 欄位)。HTTP 200、request 裡看得到欄位,或輸出變長,都不能單獨證明 effort 已套用;runtime 沒有暴露 rendered prompt/effective kwargs 時,template-applied 欄應寫「未驗證」,不能硬填 PASS。
在模型 revision 1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0(template SHA-256 c3cf9e34abf4f9e36c2d72165aa9c132d3e2a725b6c2586aaa3a8af9d7a81041)裡,xhigh 會加入較完整的推理指示,low 會加入簡短指示,medium 不額外加入指示;enable_thinking=false才是關閉思考。這是 chat-template prompt steering,不是 reasoning token 的硬配額。
要證明「template applied」,不要從回答長短猜。llama.cpp 用 /apply-template檢查 rendered prompt;vLLM 0.27.1 可用 /v1/chat/completions/render後接 /detokenize,其他 qwen38 build 要先確認是否暴露相同 route,不能從 0.17 架構下限推定。斷言 xhigh/low 的固定指示字串存在、medium 兩者皆無、off 產生空的 <think></think> prefill;在 pinned build 上若 high/minimal/max 沒被 Qwen template 拒絕,也應標成契約漂移。
Qwen 目前預設 preserve_thinking=true。它決定舊 reasoning trace 是否留在多輪歷史,會直接改變 context 成長;請在 24 格 baseline 固定為 true,再用同一段兩輪 fixture 加跑 true/false 的 render test,不要把這個變因混進 effort 成績。
最小矩陣是 2 個 runtime × 4 個模式 × 每格 3 次 = 24 次。每次記錄首 token 時間、總延遲、輸出 token、runtime 回傳的 reasoning usage 原始物件、總 context、tool-call 合格與否、第二輪合格與否、最終任務合格與否。不同 runtime 若沒有回傳同名 reasoning token 欄位,保留原始 response,該格標成不可直接比較,不要補猜一個數字。

步驟三:用一個固定 Tool Call 測完兩輪
痛點是測試太「聰明」:Prompt 每次不同、工具回傳也不同,最後無法判斷是模型退步還是資料變了。解法是封閉 fixture。工具只接受唯一城市,Prompt 也明確要求先呼叫工具:
{
"type": "function",
"function": {
"name": "lookup_weather",
"description": "讀取固定測試天氣",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "enum": ["台北"]}
},
"required": ["city"],
"additionalProperties": false
}
}
}
固定 user prompt 是「請查台北天氣。一定要先呼叫 lookup_weather,不可猜。」第一輪收到 response 後,不要急著執行工具,先做六個斷言:
- HTTP 200,且 response 能依 OpenAI chat completion 結構解析。
tool_calls只有一筆,名稱精確等於lookup_weather。function.arguments在 wire 上是字串,而且能通過json.loads()。- 解析後精確等於
{"city":"台北"},沒有額外欄位。 - 第一輪的
tool_calls[0].id是非空字串;下一輪 role 為 tool 的 message 再把同一個值填入tool_call_id。 - 第一輪 content 不夾帶未解析的
<tool_call>標記。
通過後再回傳固定結果 {"city":"台北","temperature_c":31,"condition":"午後雷陣雨"}。第二輪必須沿用第一輪 assistant message 與 call ID,再追加 role 為 tool 的結果。最終回答要同時包含「31」與「午後雷陣雨」,而且不能再呼叫一次工具。這一輪才證明 Harness 的歷史重播接得起來。
下面是一格測試的最小可執行骨架;它會把兩輪原始 request/response 印到 stdout。FIXTURE_RESULTS只回傳 allowlist 內的固定資料,不會把模型產生的 arguments 當成指令執行:
import json, os, requests
BASE_URL = os.getenv("BASE_URL", "http://127.0.0.1:8001/v1")
MODEL = os.environ["MODEL"]
MODE = os.getenv("MODE", "off")
RUNTIME = os.getenv("RUNTIME", "llama_cpp")
RUNTIME_MODE_PATCHES = {
"vllm": {
"off":{"chat_template_kwargs":{"enable_thinking":False}},
"low":{"chat_template_kwargs":{"enable_thinking":True,"reasoning_effort":"low"}},
"medium":{"chat_template_kwargs":{"enable_thinking":True,"reasoning_effort":"medium"}},
"xhigh":{"chat_template_kwargs":{"enable_thinking":True,"reasoning_effort":"xhigh"}},
},
"llama_cpp": {
"off":{"reasoning_effort":"none"},
"low":{"reasoning_effort":"low"},
"medium":{"reasoning_effort":"medium"},
"xhigh":{"reasoning_effort":"xhigh"},
},
}
assert RUNTIME in RUNTIME_MODE_PATCHES
assert MODE in RUNTIME_MODE_PATCHES[RUNTIME]
TOOL = {"type":"function","function":{
"name":"lookup_weather","description":"讀取固定測試天氣",
"strict":True,
"parameters":{"type":"object","properties":{
"city":{"type":"string","enum":["台北"]}},
"required":["city"],"additionalProperties":False}}}
FIXTURE_RESULTS = {"lookup_weather": {
"city":"台北","temperature_c":31,"condition":"午後雷陣雨"}}
headers = {"Content-Type":"application/json"}
def complete(messages, tool_choice):
body = {"model":MODEL,"messages":messages,"tools":[TOOL],
"tool_choice":tool_choice,"parallel_tool_calls":False,
"temperature":0,"max_tokens":512}
body.update(RUNTIME_MODE_PATCHES[RUNTIME][MODE])
print("RAW REQUEST", json.dumps(body, ensure_ascii=False))
r = requests.post(f"{BASE_URL}/chat/completions",
headers=headers, json=body, timeout=180)
print("RAW RESPONSE", r.text)
r.raise_for_status()
return r.json()
messages = [{"role":"user","content":
"請查台北天氣。一定要先呼叫 lookup_weather,不可猜。"}]
first = complete(messages, "required")
assistant = first["choices"][0]["message"]
assert first["choices"][0].get("finish_reason") == "tool_calls"
assert "<tool_call>" not in (assistant.get("content") or "")
calls = assistant.get("tool_calls") or []
assert len(calls) == 1
call = calls[0]
assert isinstance(call.get("id"), str) and call["id"]
assert call["function"]["name"] == "lookup_weather"
raw_args = call["function"]["arguments"]
assert isinstance(raw_args, str)
args = json.loads(raw_args)
assert args == {"city":"台北"}
result = FIXTURE_RESULTS[call["function"]["name"]]
tool_message = {"role":"tool","tool_call_id":call["id"],
"content":json.dumps(result, ensure_ascii=False)}
second = complete(messages + [assistant, tool_message], "none")
final = second["choices"][0]["message"]
assert not final.get("tool_calls")
assert "<tool_call>" not in (final.get("content") or "")
assert "31" in (final.get("content") or "")
assert "午後雷陣雨" in (final.get("content") or "")
print("PASS: two-round tool-call fixture")
把程式存成 fixture.py後,測 llama.cpp 時先執行 export BASE_URL=http://127.0.0.1:8001/v1,再執行 export MODEL="$(curl -s "$BASE_URL/models" | jq -r '.data[0].id')",最後以 RUNTIME=llama_cpp MODE=off python fixture.py跑一格。測 vLLM 時把 endpoint 改成 export BASE_URL=http://127.0.0.1:8002/v1、重新取得 MODEL,並用 RUNTIME=vllm MODE=off python fixture.py。把 mode 換成 low、medium、xhigh,並對每個 runtime 各重跑 3 次、保存 stdout。這一版第一輪用 required、第二輪用 none,專門隔離 transport/parser/history;通過後再另跑 auto + strict,才量模型是否自行選對工具。若 endpoint 需要 Bearer token,另在 headers 加入環境變數,不要把密鑰寫入 fixture。
JSON 字串為什麼會讓 tool history 壞掉?
OpenAI-compatible response 的 function.arguments通常是 JSON 字串;但 template 內部若直接對它做 key/value 迭代,就會把「wire 格式」與「template 需要的物件」混為一談。AlphaLab 在 2026 年 8 月 18 日對 Qwen3.8-27B revision 1d4bf0f 的 chat template做了不載入權重的最小重播:把 arguments 保持為 "{\"city\":\"Paris\"}",Jinja 在迭代 tool_call.arguments|items時拋出 TypeError。這與目前仍開啟的 Qwen issue #1894重現路徑一致。
修法不是永久改寫 OpenAI wire history,而是在「直接呼叫 chat template」的邊界建立副本,僅把已驗證的 arguments 解成物件:
from copy import deepcopy
import json
def template_safe_history(messages):
safe = deepcopy(messages)
for message in safe:
if message.get("role") != "assistant":
continue
for call in message.get("tool_calls", []):
args = call["function"]["arguments"]
if isinstance(args, str):
parsed = json.loads(args or "{}")
if not isinstance(parsed, dict):
raise TypeError("function.arguments must decode to an object")
call["function"]["arguments"] = parsed
return safe
這段只示範格式正規化;production 還要補 schema 驗證、長度上限、工具 allowlist、timeout、重試與 idempotency。若 runtime 已在 server 邊界修正,就不應在 client 再轉一次。例如 llama.cpp 2026 年 8 月 18 日的 master與 vLLM 0.27.1都已在 server 邊界解析完整、有效的 JSON-string arguments;這不等於容忍截斷或格式錯誤的 JSON。把原始 fixture 同時送進 direct-template 與 server 路徑,哪條通過就保留哪條。
步驟四:把六關寫成 regression assertions
一份結果不是回歸測試;能在更新後自動指出哪一關退步,才是。建議每筆 run 依序檢查:
- 載入關:模型、tokenizer、chat template 與 tool parser 都成功載入。
- 控制關:分開記錄 client validation、server acceptance、template applied、behavior 與 accounting;未知欄位或未暴露 effective kwargs 不能靜默當成通過。
- 第一輪協定關:工具名稱、arguments 字串、call ID 與 finish reason 符合預期。
- 工具執行關:arguments 經 JSON Schema 驗證後才送進 mock tool。
- 歷史關:完整 assistant tool call 與對應 tool result 能被第二輪接受。
- 任務關:最後答案使用工具結果,沒有重複呼叫,也沒有裸露 parser 標記。
CSV 至少保留 runtime_version、model_revision、quant、context、kv_type、mode、seed、latency_ms、usage_raw、三個 pass/fail 與原始 response 的 SHA-256。reasoning 文字欄也要做 adapter:目前 vLLM Chat 輸出 message.reasoning,llama.cpp 的 deepseek format 輸出 message.reasoning_content;保留兩個原始欄位,再映射成自己的統一欄,不能把缺欄當成沒有推理。若你已有 trace 系統,讓每次 tool call、tool result 與第二輪共用同一個 trace ID;做法可參考Agent Observability 實作。
回歸門檻可以非常直白:任何既有通過格變成失敗就擋住 runtime 升級;品質全數通過後,總延遲增加超過你自行設定的容忍值才警告。不要把「更快但 tool call 壞掉」算成性能提升。
本文主套件走 Chat Completions。若你的 Harness 只支援 Responses API,要另做一條完整歷史重播 smoke test,第二輪再次送入 assistant function call 與 tool output,並設 store:false;不要假設 previous_response_id可跨本機 runtime 使用。Responses 與 Chat 是兩份 protocol 契約,不能用一邊通過替另一邊背書。
16/24/48 GiB:先選 artifact,再實測能否載入
這不是顯存實測表。圖中的 16/24/48 GiB 指單一加速器的可用 VRAM 級距,不等於 macOS 統一記憶體或整機 system RAM;共同假設只有文字工具、batch 1、concurrency 1、不載入 vision mmproj、不啟用 MTP。因為 AlphaLab 沒有跑這三組硬體,GPU offload、KV cache 類型、峰值 VRAM/system RAM 與可用 context 都必須留成「待量測」,不能由檔案大小推算 PASS。

截至 2026 年 8 月 18 日,精確 artifact 快照是:Unsloth revision f1bfb127c64f7072bdd2cad55f258b9c8b2910fe 的 Qwen3.8-27B-Q3_K_M.gguf 為 12.87 GiB;ggml-org revision 0669b98607d47046c7c2b3f801011d54a08cfccf 的 Qwen3.8-27B-Q4_K_M.gguf 為 17.67 GiB、Qwen3.8-27B-Q8_0.gguf 為 26.63 GiB、BF16 GGUF 為 50.11 GiB;官方 FP8 revision 017b9c7af6b5689d5dd426a76e0bc077eb5ca20a 的 safetensors 合計約 28.75 GiB。這些都只是下載 artifact 的容量地板,不含 runtime overhead。
- 16 GiB 候選:Q3_K_M 12.87 GiB;把 16K context 當第一個待測目標,逐筆記錄 offload、KV 類型與峰值記憶體,未跑前不得標成可用。
- 24 GiB 候選:Q4_K_M 17.67 GiB;把 32K context 當待測目標,而不是「較適合」的已驗證 baseline。
- 48 GiB 候選:Q8_0 26.63 GiB 或官方 FP8 約 28.75 GiB;兩者是不同格式/runtime 路徑,不做跨 backend 速度推論。FP8 還要由硬體與 kernel 支援,recipe 的 38 GB heuristic 也不是峰值保證。BF16 GGUF 單一檔已達 50.11 GiB,未計 overhead,不能列為 48 GiB 全 GPU 起點。
硬體升級的決策也要回到 anchor primitive:量化讓模型裝得下,只改善「模型能不能載入」;工具協定與歷史重播是否正確,仍要重新驗收。
Qwen3.8-27B 本機 Agent 最常踩的 5 個坑
坑一:把 off 當成 reasoning_effort 值
修法:測試資料模型分成 enable_thinking與 reasoning_effort;off 寫成前者為 false,另外三格才填 effort。這會避免 UI 名稱把兩種控制混成一個下拉選單。
坑二:把 effort 與 reasoning budget 當同一件事
修法:effort 是當前 chat template 的 prompt steering;budget 則必須寫出 runtime 的具體欄位與官方語義。像 max_tokens/max_completion_tokens通常限制整段 completion,不能在沒有文件時稱為「只限制 reasoning 的 budget」。固定一個變因再測另一個,並把 server acceptance、template applied、behavior 與 usage 分欄記錄。
坑三:只測第一輪 tool call
修法:fixture 必須真的追加 tool result,再要求模型產生 final answer。第一輪驗 parser,第二輪才驗 history serializer 與 Harness。
坑四:SDK 幫你轉型,raw trace 卻沒留下
修法:測試 harness 同時保存 HTTP body 與 SDK 解析後物件。若兩者不同,你才能知道 JSON 字串是在 server、SDK 還是自己的 adapter 被轉成 mapping。
坑五:用極端 KV 量化追 context,卻沒重跑工具品質
修法:每次改 KV 類型或 context,都重跑相同 24 格。llama.cpp function-calling 文件(commit 169e4a7)明確提醒,極端 KV cache 量化可能傷害 tool calling;context 數字變大不等於 Agent 可用 context 變大。
2026 年 8 月 18 日的 Runtime 狀態怎麼讀?
這篇能直接確認的不是「某 runtime 永遠有 bug」,而是兩個可重跑的當前訊號。第一,官方 Qwen3.8-27B chat template 在 revision 1d4bf0f 對 JSON-string tool history 的 direct-template 最小重播會失敗,issue #1894 仍為 open;這不代表已做 server-boundary 正規化的 llama.cpp master 或 vLLM 0.27.1 也會失敗。第二,llama.cpp 的 PR #27221正在處理 server 啟動時 --reasoning on/off與 request-level override 的優先順序;截至 2026 年 8 月 18 日,它是 open、非 draft、尚未合併。
這兩項都可能很快改變,所以它們應該變成 regression fixture,而不是變成永久結論。每次更新 runtime 或 model template:先跑 fixture、保存 commit/revision、比較通過格,再決定是否移除 adapter。只看 issue 標籤或 PR 標題,不能取代自己的 endpoint 回傳。
同樣地,Simon Willison 的單機實測展示 xhigh 與關閉思考可能帶來很大的時間/輸出差距,但那是一個 prompt、特定機器與特定 build 的觀察。它很適合當「為何要測」的線索,不適合填進你自己的性能欄位。
怎麼選:llama.cpp 還是 vLLM?
- 選 llama.cpp 起步:你的主要限制是 16/24GB 消費級 GPU、需要 GGUF 量化,願意明確控制 Jinja template 與 KV cache。
- 選 vLLM 起步:你的 checkpoint 與硬體能容納服務層,且需求是並發、OpenAI-compatible server、reasoning parser 與自動 tool choice。
- 兩者都測:你準備把本機模型接進長期維護的 Agent 產品。相同 fixture 能把「模型本身」與「runtime 轉譯」分開。
最實用的決策不是先押一個勝者,而是選一個 primary、一個 canary:primary 接日常工作,canary 在 runtime 更新時跑 24 格。只要 canary 連續通過,再交換角色。這比看 release note 猜相容性可靠得多。
Qwen3.8-27B 本機 Agent FAQ
1. Qwen3.8-27B 能塞進 16GB 顯卡嗎?
不能只憑檔案大小下結論。Q3_K_M artifact 為 12.87 GiB,但 16 GiB 顯卡仍要容納 KV、buffer 與 context;本文未在該硬體實跑,短 context 只能列為待測候選,不要把社群的 73K 單機紀錄當保證。
2. off、low、medium、xhigh 是四個 reasoning_effort 嗎?
不是。low、medium、xhigh 是模型卡列出的 effort;off 是 enable_thinking=false。測試結果也應分欄保存。
3. reasoning_effort 越高,Agent 一定越好嗎?
不一定。高 effort 可能改善複雜決策,也會增加 context、延遲與超限風險;真正指標是完成固定任務所需的總時間、重試數與成功率。
4. OpenAI-compatible client 可以讓兩個 runtime 行為一致嗎?
不能靠名稱保證。API 外形可以相似,reasoning 欄位、parser、finish reason 與歷史序列化仍可能不同;這正是 raw HTTP fixture 要測的內容。
5. 為何一定要檢查 arguments 是字串?
因為 wire contract 與 template 內部型別不同。先確認 server 回傳,再在唯一邊界做解析;若任由每層偷偷轉型,第二輪錯誤很難定位。
6. 只跑一次 fixture 夠嗎?
不夠。每格至少重複三次並保存 seed;這不是統計學上的最終 benchmark,而是先抓出偶發 parser/generation 失敗。
7. 模型更新後只需要重測新 checkpoint 嗎?
不夠。chat template、runtime、tool parser、client SDK 與 Harness 都可能改變;版本帳本中的任何一項變動,都應觸發相同 fixture。
8. 這套測試可以直接進 production 嗎?
它是最小驗收,不是完整防線。上線前還要加入惡意 arguments、超長輸入、平行 tool calls、timeout、重試、權限、idempotency 與真實任務資料。
給新手的 5 個重點
- 先固定版本、模型檔、context 與 Prompt,再改一個變因。
- 把 thinking 開關、effort 與 token budget 分成三欄。
- 第一輪驗 tool call,第二輪驗 history 與最終答案。
- 保留原始 HTTP,不讓 SDK 的自動轉型蓋掉證據。
- 六關全過後才比較 tokens/s、延遲與顯存。
接著閱讀
左右滑動查看更多推薦
最後回到那個式子:模型答對 × Runtime 傳對 × Harness 接對。你可以先用固定天氣工具依本文 protocol 跑完 24 格,把每次 request、response 與版本存下來;等六關全綠,再調長 context、換 KV 量化、加 MTP 或追 tokens/s。這樣得到的才不是一張漂亮跑分,而是一個你敢交給 Agent 使用的本機模型入口。





