dsh-llm-pi-ai-image-offload:爲 pi-ai 路由恢復圖片 token 計量

前言

在 DeepSeek Harness(DSH)裏,工具返回帶圖片的結果時,dsh-spill-policy 會依據 LLM 適配器提供的 imageRequestPricing 估算圖片佔用的 token,再與 maxInlineTokens 比較,決定是否把過大的 base64 內聯內容移出請求。默認情況下 LlmAdapter.imageRequestPricing() 返回 undefined,只有 dsh-llm-deepseek 實現了該方法;走 @deepseek-ai/dsh-llm-pi-ai 的路由沒有實現,spill-policy 在取不到計算器時會拋錯並被外層捕獲,日誌裏出現「keeping the inline content」,整段大圖仍 inline 發給模型,容易撐爆上下文。dsh-token-meter 也會退回到固定結構啓發式,而不是按實際發送的字節計價。

下面介紹社區插件 dsh-llm-pi-ai-image-offload(維護者 ender-candle),它在適配器實例上補回 imageRequestPricing,讓 spill-policy 能按字節估算視覺 token 並 offload 超大圖片。

這是什麼

dsh-llm-pi-ai-image-offload 是 DSH 的 Cordis 插件包(npm 名 dsh-llm-pi-ai-image-offload,版本 0.1.0,MIT)。定位是:爲未聲明圖片計價的 pi-ai 適配器路由安裝 imageRequestPricing,並在每次 llm/adapters-updated 時重新應用。這裏的「pricing」指 token 覈算,不是計費。插件零運行時依賴,分類上屬於模型推理相關能力;在 SkillHub 插件目錄 可查到條目(社區站點,與 DeepSeek / 幻方無官方從屬關係)。

它修復的問題

當工具結果攜帶圖片時,spill-policy 會調用:

const calculator = ctx.get("llm")?.imageRequestPricing(provider, model);
if (calculator === undefined) throw new Error("the current model has no image token calculator");

pi-ai 路由沒有 override 該方法,上述邏輯失敗後被插件外層 try 喫掉,工具結果保持完全 inline,多兆字節的 base64 會原樣進入 provider 請求。裝上本插件後,無計價的適配器實例會得到基於傳輸字節的估算,spill-policy 才能與 maxInlineTokens 對齊並 shed 放不下的圖片。

核心行爲

  1. 對返回「無圖片計價」的適配器實例掛載 imageRequestPricing;已有真實實現的適配器不會被覆蓋(上游修復後本補丁會自動失效)。
  2. 若某適配器自己的實現會 throw,則不會被替換。
  3. Offload 不會從會話或工作區刪除文件;模型會收到 spill-policy 的說明和可再通過 read_image 讀取的路徑。

計價公式(路由未發佈 vision-token 賬時,按實際傳輸字節計):

transmitted = min(attachment.bytes, imageRequestTarget(...).maxBytes)
visualTokens = ceil(base64Length(transmitted) / charsPerToken)

其中 base64Length(b) = ceil(b / 3) * 4,與 harness 的字節換算一致。README 給出的失敗案例:2048×2048 JPEG 約 1,266,320 字節、請求預算 1 MiB 的路由上,截斷後 base64 約對應 349,526 tokens,高於默認 maxInlineTokens: 12500,因此應被 shed。

配置

字段均可選,通過 profile 裏該 bundle 的 config 傳入:

field default meaning
enabled true 關閉整個補丁
charsPerToken 4 每個 token 對應的 base64 字符密度
maxVisualTokens 400000 單次圖片 occurrence 的上限
providers (all) 允許的 provider route id 白名單
debug false 向 harness logger 記錄每條被 patch 的路由

示例(profile patch 片段):

- id: llm-pi-ai-image-offload
  name: dsh-llm-pi-ai-image-offload
  config:
    debug: true

安裝與啓用

先從 GitHub 安裝到指定 profile(推薦):

dsh plugin --profile <profile> add github:ender-candle/dsh-llm-pi-ai-image-offload

需要可復現安裝時可 pin commit:

dsh plugin --profile <profile> add github:ender-candle/dsh-llm-pi-ai-image-offload#<sha>

本地 checkout 路徑安裝:

dsh plugin --profile <profile> add /absolute/path/to/dsh-llm-pi-ai-image-offload

dsh plugin add 會更新 profile 的 package.json 與 pnpm-lock.yaml。接着在 profile 的 package.json 裏把 bundle 名加入 dsh.profile.bundles:

{
  "dsh": {
    "profile": {
      "bundles": ["...", "dsh-llm-pi-ai-image-offload"]
    }
  }
}

包內 cordis.patch.yml 會自動插入 host 行,一般無需手改 patch。重啓 harness 後 bundle 在啓動時加載。

如何確認已生效

Harness logger 使用內存 ring buffer,事後未必能看到 warn。README 建議:debug: true,再生成一張大圖觸發 spill,在 session log 中查找 image/offload 事件;未打補丁前該信號不會出現。

本地可跑單元測試(18 項,無額外依賴):

node test/offload.test.mjs

適用場景與注意

  • 適合:使用 @deepseek-ai/dsh-llm-pi-ai 路由、工具結果常帶大圖 base64,且已啓用 dsh-spill-policy 的 DSH profile。
  • 權限與安全:插件與當前 dsh 進程同權限運行;安裝前請閱讀 GitHub 倉庫 源碼與 MIT 許可證。
  • 風險(README 原文):LlmAdapter 實例字段不是文檔化的擴展點;registry 形狀變化時補丁可能靜默失效(行爲回到補丁前)。對上游按 vision 分詞的路由,估算可能偏多,這是保守策略,只會更早觸發 shed;provider 返回的 usage 仍是權威計量。

結尾

dsh-llm-pi-ai-image-offload 用很小的補丁把 pi-ai 路由缺失的 imageRequestPricing 補回來,讓 spill-policy 和 token 預算邏輯重新能處理超大 inline 圖片,避免上下文被 base64 佔滿。

  • 目錄頁:https://www.skillhub.cn/plugins/ender-candle/dsh-llm-pi-ai-image-offload
  • 源碼與中文 README:https://github.com/ender-candle/dsh-llm-pi-ai-image-offload
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜