今天除了一個掛在心上的 bug,還有一個意外的發現——原來輸出任務太大,也會被腰斬。記下來。
環境
- 本地模型:Qwen3.6-35B(oMLX),用於翻譯 Agent
- 容器:Docker sandbox
- 工具呼叫:模型透過 structured output 機制發出 tool call,oMLX 作為 API server
問題
任務很單純:把一個 Markdown 檔案轉成 HTML。過程中觀察到的現象:
- 小範例 HTML → 正常產出
- MD 檔轉 HTML → 失效,工作被當成文字處理
- 同樣的 MD 檔單純輸出為 HTML 字串(非 tool call)→ 成功
一開始的猜測
工具被 sandbox 的 tool policy 擋住?檢查了 log,確認是正常的 profile 限制,與翻譯工作無關。
真正的原因
一開始完全不知道輸出會有多大——是後來用另一個模型成功產生 HTML 後,才發現輸出高達 48K。回頭檢查翻譯 Agent 的設定,才發現 maxTokens 上限只有 4,096。
4,096 tokens 的輸出容量,遇上 12,000+ tokens 的 HTML,任務在抵達上限時被強制截斷。截斷點剛好落在看起來像 tool call 的位置,因此觸發了「Assistant reply looks like a tool call, but no structured tool invocation was emitted; treating it as text.」這個錯誤。不是工具被阻擋,而是輸出還沒說完,就被截斷了。
為什麼要設定 maxTokens?
這是雲端 API 的標準做法:
- 成本控制:每個 token 都是錢,沒有上限的話一個失誤的 prompt 可以燒掉整個月的配額
- 延遲管理:輸出越長回應越慢,設定上限讓回應時間可以預期
- 防止模型失控:某些 prompt 會讓模型進入重複循環,設定上限可以截斷
但翻譯任務通常輸出的長度難以預估,尤其是要把一整篇文章轉成 HTML,長度可能是原始輸入的數倍。
對 local vs 雲端模型
local 模型沒有流量成本,但 maxTokens 仍有優點(防止模型在長輸出中卡死),也有缺點(長任務容易被腰斬)。
解法
把上限提高到 32,768,足以容納長 HTML 的輸出量。local 模型不需要極度保守的上限,稍微放寬對實際工作更有幫助。
結論
設定 maxTokens 不是錯,但數值要跟工作需求匹配。如果你的本地模型主要跑翻譯或長文任務,4,096 可能太低了。這次 debug 的順序是:先觀察到任務失敗 → 再用另一個模型確認輸出大小 → 才確定是 maxTokens 不足。也就是:先有大輸出,才發現上限不夠——不是先知道大小再想到可能是上限的問題。