ローカルLLM Tool Adapterのトラブルシューティング分類

ローカルLLM Tool Adapterのトラブルシューティング分類

ローカル LLM と tool calling adapter を組み合わせると、失敗原因が複数の層に分かれる。

最終応答だけを見ると「model が間違えた」に見えるが、実際には次のような層のどこかで起きていることが多い。

  • model context / VRAM
  • Hermes prompt / parser
  • tool pruning / router
  • OpenAI-compatible proxy
  • CLI の tool execution
  • shell sandbox
  • internal web tool
  • external research helper
  • benchmark harness

このメモでは、公開してもよい抽象度でトラブルの傾向を整理する。実 port、実 path、token 名、host 名、生ログは private runbook 側に残す。

全体の切り分け

flowchart TD
    Final[final answer] --> A{tool call eventは出たか}
    A -->|no| Router[adapter router / model tool selection]
    A -->|yes| B{tool executorは動いたか}
    B -->|no| Proxy[proxy / schema / unknown tool]
    B -->|yes| C{tool outputは正しいか}
    C -->|no| Sandbox[sandbox / command / environment warning]
    C -->|yes| D{finalが正しいか}
    D -->|no| Relay[output relay / model summarization]
    D -->|yes| Done[pass]

まず見るべきなのは final answer ではなく、tool call event と tool result 。

Runtime / Context / VRAM

代表症状:

  • request が context window を超える
  • model load は成功するが大きな request で落ちる
  • context を伸ばすと VRAM が足りない
  • metadata 上の training context と実起動 context が食い違う

確認するもの:

  • adapter / proxy が公開している model metadata
  • actual context window
  • GPU memory
  • model server log
  • request token 数

対策:

  • 実起動値を proxy / adapter の model metadata に反映する
  • context を無理に伸ばす前に VRAM 実測を取る
  • 長い過去会話や長い tool result は compression 対象にする
  • 最新 user instruction は圧縮しない

Adapter / Tool Calling

代表症状:

  • Hermes が <tool_call> を返すが OpenAI-compatible tool_calls にならない
  • JSON が崩れる
  • tool name が top-level ではなく arguments 側へ入る
  • 同じ final answer や tool call が二重に出る
  • command を実行してほしいのに Markdown の例で返す

対策:

  • Hermes 専用 prompt と parser を adapter に閉じ込める
  • malformed tool call の補正 fixture を持つ
  • duplicate final / duplicate tool call を dedupe する
  • 明示 read-only command は deterministic router で tool call にする
  • non-read-only command は upstream model に投げる前に suppress する

parser の regression は model を呼ばない JSONL fixture にすると速い。

Tool Pruning

代表症状:

  • tool が多すぎて model が選択を誤る
  • MCP resource listing と MCP tool call を混同する
  • 画像や sub-agent など低頻度 tool を通常 turn で選びかける

対策:

  • turn の intent に応じて tool schema を絞る
  • 通常 turn では shell 系の最小 tool だけを見せる
  • resource API は resource 一覧の明示要求時だけ見せる
  • 低頻度 tool は明示語がある時だけ出す

小型 model では「全部見せる」より「必要なものだけ見せる」方が安定する。

Proxy / CLI

代表症状:

  • adapter 直叩きでは tool call になるが、CLI 経由では実行されない
  • Responses API 変換後の event shape が期待と違う
  • final answer では「実行した」と言うが、tool execution event がない
  • proxy が adapter を通らず raw model server を見ている

確認するもの:

  • proxy backend が adapter を指しているか
  • model catalog の model name と context window
  • CLI JSONL の command_execution 相当 event
  • adapter log の request / response
  • tool result の stdout / stderr / exit code

対策:

  • adapter direct と CLI 経由の test を分ける
  • CLI JSONL harness で event を機械判定する
  • final answer だけを oracle にしない
  • timeout 時の stdout / stderr も保存する

Tool Output / Warning

代表症状:

  • command output の先頭に環境 warning が混じる
  • model が warning を実行結果と誤解する
  • 「出力だけ」と言っているのに model が要約して壊す

対策:

  • 既知 warning だけ allowlist 方式で分離する
  • 分離した warning は log / metadata に残す
  • output-only 指示は adapter が deterministic relay する
  • stdout / stderr / exit code を明示的に選べるようにする

warning を雑に消すと、本当に重要な失敗を隠す。消すのではなく「model へ渡す本文から分ける」と考える方が安全である。

Internal Web Tool

代表症状:

  • model が未知 tool call を返して CLI 側で実行できない
  • URL fetch が private address に向かう危険がある
  • web search の結果が毎回変わって regression が不安定になる
  • external research helper が desktop keyring や credential に依存する

対策:

  • fetch_url / search_web は adapter internal read-only tool として扱う
  • HTTP / HTTPS のみに限定する
  • localhost / private / link-local / metadata IP を拒否する
  • timeout と max bytes を必ず入れる
  • 通常 regression では mock fixture を使う
  • external research helper は専用 smoke に分離する

検索や外部調査は便利だが、adapter parser の評価とは別物である。通常 regression に混ぜない方がよい。

Benchmark Harness

代表症状:

  • host Python の version で benchmark package が壊れる
  • runner image に Docker CLI や Git が足りない
  • proxy catalog の model name と benchmark handler が合わない
  • official Terminal-Bench task が write 前提で read-only policy と衝突する

対策:

  • benchmark は専用 container / venv に隔離する
  • official score ではなく canary と失敗分類として扱う
  • BFCL は function calling の評価、Terminal-Bench は terminal integration の評価として分ける
  • write task は expected failure として扱う
  • read-only private task を用意する

記録の残し方

トラブルシューティングは、時系列だけで残すと後から探しにくい。原因層ごとに分ける方が再利用しやすい。

おすすめの分類:

ファイル内容
runtime-contextcontext、VRAM、model server
adapter-tool-callingparser、router、dedupe、suppression
proxy-cliproxy、Responses、CLI JSONL、MCP 混同
tool-output-webwarning、output relay、web tool、keyring
benchmark-harnessesBFCL、Terminal-Bench、runner