Claude Media
Fable 5.1のxhigh/maxでmax_tokensに達し出力が切れる問題と対処

Fable 5.1のxhigh/maxでmax_tokensに達し出力が切れる問題と対処

Claude Fable 5.1をxhigh・maxのeffortで使うと、モデルが思考内で下書きしてから本文を書き直すためmax_tokensに達し出力が切れることがあります。原因と対処法をまとめます。

Fable 5.1のxhigh/maxでmax_tokensに達する問題とは

Claude Fable 5.1をxhighまたはmaxのeffortで動かすと、レスポンスが完成する前に打ち切られることがあります。stop_reasonが"max_tokens"になり、本文が途中で切れているのが典型的な症状です。

原因はコードの不具合ではありません。モデルが思考の中で成果物の大半を下書きし、そのあと改めて本文として書き出す挙動にあります。Fable 5.1のプロンプトガイドが名指しする既知の失敗モードなので、原因が分かっていれば事前に対処を仕込めます。

プロンプトガイドによると、xhighと特にmaxのeffortでは、モデルが返信を書き始める前により長く思考します。文書全体の書き直しや大きな表、完全なコードファイルのような長い成果物を1リクエストで求めると、その大半を思考の中で下書きしてから返信として書き出すため、待ち時間と出力トークンが余分にかかります。

ガイドの表現は「下書きすることがある」です。毎回必ず起きるとは書かれていません。ガイドが挙げるのは、長い文書の全面書き直しのように、長い成果物を1リクエストで求める場合です。

なぜ二重下書きが起きるか — 思考と本文が同じ予算を共有する

Fable 5.1はアダプティブシンキングで思考の深さを自分で決めます。thinking.type: "adaptive"を使い、budget_tokensを手動指定せず、effortの値だけで思考量をモデル自身が調整する方式です。budget_tokensで予算を指定する旧来の拡張思考とは別物です。

手動の拡張思考では、budget_tokensはmax_tokens未満でなければなりません。例外はインターリーブ思考だけで、これは思考ブロックが1回の応答内で複数に分かれる場合です。アダプティブシンキングにはbudget_tokens自体がないので、この例外も関係しません。思考トークンと返信トークンの合計がmax_tokens以下に収まる必要があり、上限に達した時点で生成は止まります。

effortのドキュメントも、この上限の性質をはっきり書いています。high以上では大きなmax_tokensを設定すること。これは総出力(思考+返信)のハード上限だと説明されています。Opus 5・Opus 4.8・Opus 4.7には「64,000トークンから調整を始める」という目安が付いています。

Fable 5.1の項には、この数値の目安がありません。「high以上では大きなmax_tokensを設定すること」とだけ書かれています。他モデルの数値を流用せず、実際のリクエストで必要な思考量を測って決めることになります。

切り分け: thinking_tokensで思考と返信の内訳を見る

まずstop_reasonを見ます。APIリファレンスでは、"max_tokens"はリクエストしたmax_tokens、またはモデルの上限を超えたときの値です。この値が返ったら、モデルは書きたい内容を書き切る前に止められています。途中で終わった本文はそのまま使えません。

const response = await client.messages.create({
  model: "claude-fable-5-1",
  max_tokens: 64000,
  output_config: { effort: "xhigh" },
  messages: [{ role: "user", content: "長い設計ドキュメントを全面的に書き直してください。" }],
});
 
if (response.stop_reason === "max_tokens") {
  // 次の節の thinking_tokens で、思考と返信のどちらが重いかを見る
}

Fable 5.1はthinking.displayの既定が"omitted"です。思考ブロックは返りますが、thinkingの中身は空になります。下書きが本当に起きたかどうかは、本文を眺めても分かりません。

手がかりになるのがレスポンスのusage.output_tokens_details.thinking_tokensです。内部の推論として生成された出力トークン数を表します。リファレンスによれば、output_tokens - thinking_tokensが思考以外の出力の近似になります。返ってきたレスポンスをresponse.jsonに保存してあれば、次のコマンドで両方を並べて読めます。

jq '{stop_reason, output_tokens: .usage.output_tokens, thinking_tokens: .usage.output_tokens_details.thinking_tokens}' response.json

出力は次の形になります。数値は形を示す仮の値です。

{
  "stop_reason": "max_tokens",
  "output_tokens": 64000,
  "thinking_tokens": 52000
}
くらべる

thinking_tokensの内訳で、次の一手が分かれる

思考が重い

thinking_tokensがoutput_tokensの大半を占める

返信に回ったのはoutput_tokens - thinking_tokensの分だけです。思考の中で成果物を下書きし、本文でも書き直した状況に当たります。対処2の一文を足すか、highに戻して再計測します。

返信が重い

thinking_tokensは小さく、返信が長い

思考ではなく成果物そのものがmax_tokensに収まっていません。max_tokensを引き上げるか、成果物を章ごとに分けて依頼します。

max_tokensと紛らわしいstop_reasonもあります。pause_turnはサーバーツールのループが反復上限に達した合図で、アシスタントの内容をそのまま送り返せば続きを生成できます。打ち切りではないので、この記事の対処は不要です。

model_context_window_exceededは、レスポンスがモデルのコンテキストウィンドウを埋めたときの値です。出力上限とは別の問題で、入力サイズ不明でも最大出力を引き出す実装パターンが扱っています。refusalはClaudeが応答を断った場合の値で、理由はstop_detailsに入ります。

対処1: max_tokensに思考分の余白を足す

最初の対処はmax_tokensの値そのものです。想定する返信の長さだけでなく、思考に使われる分の余白を見込んで設定します。既存のリクエストでmax_tokens打ち切りが出ているなら、まず引き上げて症状が消えるかを見るのが手早い切り分けです。

上限はモデルごとに決まっています。Sonnet 5.5のeffortの項は、エージェント的なコーディングでは最大値の128,000を設定してストリーミングするよう案内しています。Fable 5.1の項に数値はないので、実測しながら上げていきます。

max_tokensを大きくするとSDKはストリーミングを要求します。HTTPタイムアウトを避けるためです。messages.create()のまま上げると失敗する場合は、ストリームで受けて最終メッセージを取り出す形に替えます。

const message = await client.messages
  .stream({
    model: "claude-fable-5-1",
    max_tokens: 128000,
    output_config: { effort: "xhigh" },
    messages: [{ role: "user", content: "長い設計ドキュメントを全面的に書き直してください。" }],
  })
  .finalMessage();

引き上げた分は、使い切れば料金になります。思考トークンも出力トークンとして課金され、max_tokensで打ち切られたリクエストでも、下書きに使った思考と書きかけの本文の両方が請求対象です。使える成果物は手に入りません。

数字

Fable 5.1の出力トークンの目安

  • 最大出力

    128,000

    トークン。max_tokensに設定できる上限の目安

  • 出力単価

    $50

    100万トークンあたり。入力は$10

  • max_tokens 64,000を使い切ったとき

    $3.20

    64,000 × $50 ÷ 100万。128,000なら$6.40

標準料金。入力トークンと別に課金されます。

effortをhighから上げる判断そのものは、Fable 5.1の仕様記事の「Fable 5と同じプロンプトで何が変わるか」の節が扱っています。この記事は、max_tokensに達して出力が切れたあとの対処に絞っています。

対処2: 二重下書きを防ぐ一文をユーザーメッセージに足す

max_tokensを上げるだけでは、思考に使われるトークンとコストは増えたままです。プロンプトガイドは、ユーザーメッセージの末尾に次の一文を足す対処も示しています。モデルへの指示として働く英文なので、翻訳せず原文のまま使います。[max_tokens]はリクエストの実際のmax_tokens値に置き換えます。ガイドの例は64,000です。

Everything produced in one reply, including any reasoning or drafting done before the reply, counts toward a single limit of about [max_tokens] tokens. If that limit is reached before the reply is finished, the person receives a cut-off response and has to start over. Composing an entire output or deliverable in full as reasoning and then again as a reply would double the length of the turn without improving the result, so don't do that.
 
Instead, when the person has asked for a long or effort-intensive deliverable such as a multi-section document, a large table or dataset, or a complete code file, spend extra effort on understanding the request, checking the inputs the answer depends on, settling the structure and other difficult decisions, and otherwise using the reasoning space to reason and the output space to write an output. Usually it is not needed to draft an output multiple times.

公式の説明では、この一文で「文章とコードのリクエストで思考がかなり短くなる」とされています。上の文面をguard-note.txtに保存しておけば、max_tokensの値と常に揃えて組み込めます。

import { readFileSync } from "node:fs";
import Anthropic from "@anthropic-ai/sdk";
 
const client = new Anthropic();
const maxTokens = 64000;
 
const guardNote = readFileSync("guard-note.txt", "utf8").replace(
  "[max_tokens]",
  String(maxTokens),
);
 
const message = await client.messages
  .stream({
    model: "claude-fable-5-1",
    max_tokens: maxTokens,
    output_config: { effort: "xhigh" },
    messages: [
      { role: "user", content: `長い設計ドキュメントを全面的に書き直してください。\n\n${guardNote}` },
    ],
  })
  .finalMessage();

切れた応答を続きから生成するとき

すでに打ち切られた応答の続きだけが欲しい場面もあります。Fable 5.1は、末尾がアシスタントのメッセージ(プリフィル)のリクエストを400エラーで拒否します。続きを書かせる目的でも、切れた本文をアシスタント側に置いて送ることはできません。

公式の継続パターンは、切れた本文をアシスタントのターンとして並べ、そのあとにユーザーのターンで「途中から続けてください」と頼む形です。会話の末尾がユーザーメッセージなので、プリフィルのエラーには当たりません。

  • 本文が途中で切れているだけなら、この継続で足りる場合があります
  • 切れた応答に不完全なtool_useブロックが含まれるときは、続きを頼むのではなく、max_tokensを上げて同じリクエストを再試行します

Claude Codeで使う場合 — max_tokensに当たる設定が別にある

Claude CodeではAPIのmax_tokensを直接は編集できません。

くらべる

同じ症状への手の打ち方が、使い方で変わる

API

APIを直接呼ぶ

max_tokensを引き上げ、effortはoutput_config.effortで指定します。対処2の一文はユーザーメッセージの末尾に足します。

Claude Code

Claude Codeで動かす

CLAUDE_CODE_MAX_OUTPUT_TOKENSを引き上げ、effortは/effortでhighへ戻します。モデルの上限を超える値は上限まで下げられます。

CLAUDE_CODE_MAX_OUTPUT_TOKENSを引き上げると、オートコンパクションが働くまでに使えるコンテキストウィンドウが狭くなります。Claude Codeが知らないモデルIDでは、既定が32,000、上限が128,000として扱われます。既定値と上限の詳細はCLAUDE_CODE_MAX_OUTPUT_TOKENSの環境変数ガイドにあります。

Fableモデルは思考をオフにできないため、xhighやmaxでは思考が必ず有効です。一文を足す対処2はユーザーメッセージを自分で組み立てるAPI向けの方法で、対話セッションでは依頼文のたびに自分で足すことになります。

よくあるつまずき

  • [max_tokens]を置き換え忘れる: プレースホルダーの文字列のまま送ると、モデルは実際の上限を把握できません。
  • 短い応答にも一文を足してしまう: ガイドが対象にしているのは長い成果物を求めるプロンプトです。分類や短い回答が中心なら、その用途はガイドの対象外です。
  • Claude CodeでMAX_THINKING_TOKENSを設定して解決しようとする: 正の値は、アダプティブ推論のモデルではClaude Codeに無視されます。Fableモデルは0にしても思考が止まりません。
  • Sonnet 5の同種の症状と混同する: Claude Sonnet 5でも同じstop_reason: "max_tokens"が起きますが、原因はアダプティブシンキングが既定でオンになったことです。Sonnet 5のプロンプトガイドには、思考内の下書きの説明はありません。

まとめ

max_tokensに達したら、まずthinking_tokensを見ます。思考が重ければ対処2の一文かhighへの切り替え、返信が重ければmax_tokensの引き上げを先に試します。

公式ガイドはhighを出発点としています。xhigh・maxは、計測で品質差が出た依頼にだけ使う選択肢です。判断材料はeffortの使い分けにあります。

この記事を共有:XはてブLinkedIn