🔧

Claude Code (Opus 4.8) でツール呼び出しが壊れる現象の原因と対策【Claude Code運用】

に公開

はじめに

Claude Code を Opus 4.8 で使っていると、突然こんな状態になることがある。

  • 「ファイルを読んでから編集します」と言ったのに何も起きない
  • ツール呼び出しをすると見るからにおかしいテキストが出て、次のリトライも同じように壊れる
  • /rewind しても数ターン後にまた再発する

これは Opus 4.8 固有のシリアライズ回帰バグ(GitHub issue #67307)が原因だ。本記事ではその根本原因・発生条件・回避策を解説する。

さらに、この問題を調査する過程で「対策ドキュメント自身が問題を悪化させる」という逆説的な罠に気づいた経緯と、Codex クロスレビューがその罠を指摘するまでの流れも合わせて記録する。

何が起きているか(根本原因)

正常時 vs 破壊時の違い

Claude Code のハーネスは、モデルの出力ストリームを解析してツール呼び出しのタグを検出し、実行する。正常時はこのタグが適切なプレフィックス付きで出力される。

破壊時は散文ブロックの末尾に 孤立した制御トークン が1行で出力され、直後のツール呼び出しタグがプレフィックスを失ってプレーンテキストとして出力される。ハーネスはタグを認識できないため、ツールは実行されない。

ハーネスが "could not be parsed. Please retry." を注入するが、リトライも同様に壊れる

なぜカスケード(連鎖)するか

ここが最も重要なポイントだ。

  1. 壊れたターンのテキストがそのままコンテキストに残る
  2. Opus 4.8 は自分の出力をパターンマッチして次の出力を生成する
  3. 壊れたパターンが「正しいフォーマット」として自己強化される
  4. 5回連続で同じ崩れを再生産する(stepcodex 実証)

単発の不運ではなく、一度発生すると自己増幅する構造になっている。

確定事実

  • Opus 4.8 限定(Opus 4.7 / Fable 5 / Sonnet 4.6 / Haiku 4.5 では発生しない)
  • 2026-06-01 以降に発生、特定の CLI バージョンとは無相関 → モデル側の回帰
  • Anthropic 側が修正待ちの状態(ユーザー側で根治は不可能)

発生条件(回避の鍵)

条件が判明しているため、振る舞いで回避できる。

高リスクな状況

  1. 長い散文ブロックの直後に単一のツール呼び出しを置く

    • 「〇〇を検討しました。△△を行います。…(300文字の説明)…ではファイルを読みます」→ Read
    • この「読みます」→ ツール というパターンが危険
  2. 長コンテキスト・auto-compaction 直後

    • コンテキストが圧縮された直後の最初のツール呼び出しは特に注意
  3. 単一のツール呼び出し(並列でない場合)

    • 複数ツールを並列発行するとほぼ発生しない

対策: 振る舞いで回避する

予防策3つ

1. 前置き散文を短くする
   ❌ 「ファイルの構造を確認してから編集します。まず Read で内容を把握し...」→ Read
   ✅ 「確認します。」→ Read(または前置きなしでいきなり Read)

2. 並列ツール呼び出しを活用する
   ❌ Read(file_a) → 次ターン → Read(file_b)
   ✅ Read(file_a) と Read(file_b) を1ターンで並列発行

3. ターンの早い位置でツールを出す
   長い判断プロセスを経た後のツールより、ターン冒頭でツールを出す方が安全

発生してしまったら

1. 何も言わずに、次ターン冒頭でツール呼び出しを再発行する
   (前置きテキストなし、いきなりツールから始める)

2. それでも連鎖するなら Esc → /rewind で壊れたターンをコンテキストから除去してから再発行

3. 長時間のパイプラインが何度も崩れるなら /model sonnet に一時退避する
   (Sonnet ではこの症状がゼロ)

逆説: 対策ドキュメント自身がカスケード源になった

ここからが本記事で最も伝えたい部分だ。

最初の対策ドキュメント

この問題を発見後、次のような対策ドキュメントを rules/ に書いた。

**Opus 4.8 ツール呼び出し破壊の予防**:
長い前置き散文の直後に単一ツールを置くと `call`/`count` 孤立トークン+antml prefix欠落で
未実行化しやすい。崩れたら壊れた行(`call`/`count` + 生 `<invoke>`)を絶対に復唱・引用しない。

一見正しそうに見えるが、これが 新たな問題を生んでいた

Codex クロスレビューが指摘した罠

このドキュメントを Codex(OpenAI の別ベンダーモデル)にクロスレビューさせたところ、以下の指摘が来た:

「壊れたパターンの具体的なトークン名(call/countantml prefix)をルールドキュメントに書くと、
このルールが読まれた瞬間にその崩れパターンがコンテキストへ入る。
Opus 4.8 のパターンマッチ自己強化の材料になりうる。」

要するに、「こういう壊れ方をする」と書いたルール自身が、その壊れ方のテンプレートをコンテキストに注入していた

修正後のアプローチ

修正前: 症状の逐語例(壊れたトークン名)をルールに書く
         → 常時ロードされるため毎セッションのコンテキストに入る

修正後: 症状の逐語例は遅延ロードの別ドキュメントに分離
         → 常時ロードのルールには「振る舞いの指針」のみ残す
            (「前置きを短く」「並列で出す」「復唱するな」)

この罠が成立する条件

これは Claude Code 特有の現象で、通常のソフトウェアドキュメントでは起きない:

  1. ルールファイルが毎セッション自動ロードされる(固定費として常時コンテキストに入る)
  2. モデルが自分の過去出力をパターンマッチして次の出力を生成する
  3. ドキュメントに書かれた「壊れたパターン」がそのまま参照パターンになりうる

まとめ

対策 変更規模 効果
前置き散文を短くする 書き方の習慣変更 発生率を大幅低下
並列ツール呼び出しを使う 実装パターン変更 並列発行時はほぼ発生しない
症状トークンをルールから除去 ドキュメント1行修正 カスケード自己強化を断つ
発生時はツールを冒頭で再発行 操作手順の習得 多くのケースで1ターンで回復

Opus 4.8 はコーディング性能が非常に高い一方、この回帰バグを抱えている。Anthropic 側の修正を待ちながら、振る舞いの工夫で回避できる。

また「AI に読ませるドキュメントの書き方」として、症状の逐語例は常時ロードのルールに書かず、遅延ロードの参照先に分離するという設計パターンは、他のルール整備にも応用できる。

参考

  • GitHub issue #67307(Anthropic/claude-code)
  • stepcodex による再現実証(カスケード自己強化の観察)
  • Codex CLI を使ったクロスレビューの実践については別記事で解説予定

Discussion