ローカルLLM Tool Adapterのトラブルシューティング分類
Posted:
ローカル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-compatibletool_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-context | context、VRAM、model server |
| adapter-tool-calling | parser、router、dedupe、suppression |
| proxy-cli | proxy、Responses、CLI JSONL、MCP 混同 |
| tool-output-web | warning、output relay、web tool、keyring |
| benchmark-harnesses | BFCL、Terminal-Bench、runner |