先週の間、M5 Max 上でローカルエージェントのワークフローを最適化する際に、キャッシュミスを調査していました。
私の構成ではバックエンドに oMLX.ai を使い、エージェントとして OpenCode.ai や Pi.dev のようなものを用いていましたが、llama.cpp など別のバックエンドでも同じ挙動を再現しました。最初は、推論エンジンの問題か、キャッシュ実装のバグだと考えました。
ただ、繰り返し見ていたのは厄介な点でした:
- モデルが大量のコンテキストを読み込む
- ツールまたは関数呼び出しのチェーンを作る
- 私は単純なフォローアップ質問をする
- プロンプトの先頭(プレフィックス)を再利用する代わりに、会話の大きな塊が、はるか昔の履歴から再処理されてしまう
実際には、ツール中心のやり取りの後にフォローアップターンを挟むと、何の得もなく、何万トークンもの再計算が行われてしまうことがありました。
最初に、マルチモーダル/最初の画像への遷移に関する別の問題を見つけていて、それについては oMLX PR をすでに出しています。
しかし、より大きな「テキストのみ」の問題は、Qwen3.5 のチャットテンプレートだと分かりました。
プロンプトのフィンガープリントを追跡し、リクエスト間でレンダリングされたプロンプトを比較したところ、テンプレートが、推論コンテンツがない場合でも、過去のアシスタントターンに対して空の履歴 <think>...</think> ブロックを出力していることが分かりました。これにより、特にツール使用後などに、同等の会話履歴がリクエストごとに異なる形でシリアライズされてしまいました。
テンプレート自体が、不要なプロンプトドリフトを引き起こしていました。
これは重要です。プロンプトドリフトはプレフィックスキャッシュの再利用を損なうため、追加のトークン処理、より高いレイテンシ、そして無駄な計算につながるからです。
修正は本当にシンプルで、テンプレートの1行変更だけです:
from:
{%- if loop.index0 > ns.last_query_index %}
to:
{%- if loop.index0 > ns.last_query_index and reasoning_content %}
もし Qwen3.5 をローカルで提供していて、プレフィックスキャッシングに頼っているなら、静かにパフォーマンスを損ねている可能性があります。ツール使用の後に、長いフォローアップターンが意図せず再処理されているのに気づいたなら、その理由はこれかもしれません。
私はこれを、異なるエージェントやバックエンドでも再現しました。共通していた要因は、同梱されているテンプレートです。
Qwen3.5 でキャッシュミスをデバッグするなら、キャッシュ層の追加の回避策を入れる前に、まずチャットテンプレートを確認してください。
公式の Qwen3.5 モデルリポジトリに PR を作成しました。例えば:
https://huggingface.co/Qwen/Qwen3.5-122B-A10B/discussions/22
もし同様の挙動を見たことがあるなら、これが上流で修正されるように周知を手伝ってください。
TL;DR: Qwen 3.5 における大きなキャッシュ再利用の問題は、推論エンジンではなく同梱のチャットテンプレートに起因していることを突き止めました。このテンプレートは、推論コンテンツがない場合でも空の履歴 `<think>...</think>` ブロックを出力し、その結果プロンプトドリフトが発生します。これによりプレフィックスキャッシュの再利用が損なわれ、ツール使用後に大きなコンテキストが不要に再処理されます。修正はテンプレートの1行変更で、公式の Qwen 3.5 モデルリポジトリに PR を出しました。
[link] [comments]



