メインコンテンツへスキップ

Claude API Message Threads(ベータ):エージェントを高速化

Claude Messages APIのmessage threads(ベータ)は会話をサーバー側に一時保持し、各ターンで新しいメッセージだけを送る仕組み。使い方、5分の有効期限、エラー対応、プロンプトキャッシュとの使い分けを解説。

Message threads(メッセージスレッド)は、2026年11月2日に発表されたClaude Messages APIのベータ機能です。スレッドは会話をサーバー側に短時間保持するため、最初のリクエスト以降は、新しいメッセージと直前のレスポンスの id だけを各ターンで送れば済みます。ドキュメントによれば、リクエストは小さくなり、会話が長くなっても最初のトークンが返るまでの時間(time to first token、TTFT)が低く安定したまま保たれます。

ベータ機能: スレッドのすべてのリクエストに message-threads-2026-08-12 ベータヘッダーが必要です(SDKのスレッドヘルパーは自動で付与します)。スレッドはZDR(ゼロデータ保持)の対象外です。

会話の再送がなぜ遅くなるのか

エージェントループでは、ツールの結果を返すたびに、履歴全体を含むリクエストをClaudeに送ります。ドキュメントによると、スレッドがない場合は毎ターン会話全体を再アップロードし、APIもそのすべてを改めて検証・トークン化します。スレッドを使えば、その作業の大半は新しいターンの分だけで済みます。

Anthropicによれば、大半のClaude Codeユーザーでmessage threadsがデフォルトで有効になっており、50万〜100万トークンのリクエストではTTFTの中央値が約35%下がっています。また、エージェントが抱えるコンテキストが多いほど、message threadsによるTTFTの短縮幅も大きくなるとしています。例として挙げられているのは、長時間動くコーディングエージェント、computer useエージェント、ドキュメントや画像を多用するワークフローです。

サーバーが保持するもの、しないもの

スレッドが保持するのは、APIがモデルに送る会話、createリクエストの system と tools、そして後続リクエストの検証に使う固定フィールドのフィンガープリントです。ファイルは参照として保持されるため、スレッドを使っている間はファイルを利用可能な状態にしておいてください。MCPサーバーのURL、MCPの認可トークン、コンテナの id は保存されないので、それらを使うリクエストには毎回 mcp_servers と container を付けます。

スレッドを一覧・取得・削除するAPIはなく、APIがそのターンを保存したかどうかをレスポンスから知る方法もありません。会話の正本(source of truth)はあくまでアプリケーション側です。自前で会話のコピーを持ち、リプレイ(会話全体の再送)の経路を最初から用意しておきましょう。(Claude Managed Agentsのsession threadsとは別の機能です。)

スレッドの開始と継続

Messages APIのリクエストに thread パラメーターを1つ追加するだけです。レスポンスは通常のメッセージです。

  1. Create: 会話全体、system、tools に "thread": {"type": "create"} を加えて送ります。
  2. Continue: 新しいメッセージだけに "thread": {"type": "continue", "previous_message_id": "<previous id>"} を加えて送り、system と tools は含めません。次のターンには新しいレスポンスの id を使います。
  3. Replay: continueリクエストが404エラーを返したら、新しいcreateリクエストで会話全体を送り直し、そのレスポンスの id から続けます。

SDKのスレッドヘルパーを使う

ヘルパーはMessagesリクエストと同じフィールドを受け取り、ベータヘッダーを付け、会話全体をメモリ上に保持します。以下はPythonとTypeScriptの例です(ドキュメントでは7言語を掲載)。

client = anthropic.Anthropic()

# Create the helper. This call sends no request.
thread = client.beta.messages.thread(
    model="claude-opus-5-5",
    max_tokens=1024,
    cache_control={"type": "ephemeral"},
    system="You are a support agent for Acme. Keep replies short.",
)

# Turn 1: the helper creates a thread and sends the full conversation
thread.send({"role": "user", "content": "Hi! I have a question about an order."})

# Turn 2: the helper continues the thread and sends only the new message
second = thread.send(
    {"role": "user", "content": "How long does standard shipping usually take?"}
)

for block in second.content:
    if block.type == "text":
        print(block.text)
const client = new Anthropic();

// Create the helper. This call sends no request.
const thread = client.beta.messages.thread({
  model: "claude-opus-5-5",
  max_tokens: 1024,
  cache_control: { type: "ephemeral" },
  system: "You are a support agent for Acme. Keep replies short."
});

// Turn 1: the helper creates a thread and sends the full conversation
await thread.send({ role: "user", content: "Hi! I have a question about an order." });

// Turn 2: the helper continues the thread and sends only the new message
const second = await thread.send({
  role: "user",
  content: "How long does standard shipping usually take?"
});

for (const block of second.content) {
  if (block.type === "text") {
    console.log(block.text);
  }
}

トップレベルの cache_control は任意です。SDKのベータ版ツールランナー(MCPヘルパー解説で使っている tool_runner() ループ)もデフォルトでスレッドを使います。無効にするには、作成時にPythonでは thread=False、TypeScriptでは thread: false を指定します。

thread フィールドを自分で送る

cURL、CLI、またはSDKの create メソッドを使う場合は、すべてのリクエストにベータヘッダーを付けます。

# Turn 1: send the full conversation and create a thread
curl -sS --fail-with-body https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2026-10-21" \
  -H "anthropic-beta: message-threads-2026-08-12" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-opus-5-5",
    "max_tokens": 1024,
    "cache_control": {"type": "ephemeral"},
    "system": "You are a support agent for Acme. Keep replies short.",
    "messages": [{"role": "user", "content": "Hi! I have a question about an order."}],
    "thread": {"type": "create"}
  }'

# Turn 2: send only the new message. Set message_id to the id of the turn 1 response.
# Leave out system and tools: the thread keeps them.
curl -sS --fail-with-body https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2026-10-21" \
  -H "anthropic-beta: message-threads-2026-08-12" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-opus-5-5",
    "max_tokens": 1024,
    "cache_control": {"type": "ephemeral"},
    "messages": [{"role": "user", "content": "How long does standard shipping usually take?"}],
    "thread": {"type": "continue", "previous_message_id": "'"$message_id"'"}
  }'

ターン2でも固定フィールドは繰り返し送っています。Pythonでは、同じ thread の値と betas=["message-threads-2026-08-12"] を client.beta.messages.create(...) に渡します。

リクエスト間で変えてよいもの

区分フィールドルール
createのみsystem、toolscreateリクエストでのみ送ります。continueリクエストでどちらかを送ると、null でも400エラーになります。
固定model、tool_choice、thinking、mcp_servers(各サーバーの認可トークンを除く)、context_management、output_config、container 内の skills、トップレベルの cache_control、anthropic-beta の値の組み合わせすべてのリクエストで同じ値を送ります。値が異なると400エラー thread_fingerprint_mismatch が返り、異なるフィールドが示されます。
自由max_tokens、stop_sequences、stream、metadata、service_tier、およびドキュメントに記載のないフィールドターンごとに変更できます。

createのみ・固定のフィールドを変えたいときは、新しいスレッドを始めます。server-side fallbackを使う場合、fallbacks はスレッドのすべてのリクエストで送るか、まったく送らないかのどちらかです。Claude Fable 5.1、Mythos 5.1、Opus 5.5、Sonnet 5.5、Haiku 5.5では、system や tools を変えると会話内の既存の thinking と redacted_thinking ブロックが無効になり、createリクエストが400エラーを返すことがあります。これらのブロックを除いて送れば回避でき、モデルはそれ以前の推論なしで回答します。

メッセージについてのルール:

  • 新しいメッセージだけを送る。 APIは保存済みの内容と照合しないため、再送したメッセージが二重に入ったり、エラーになったりします。
  • 通常は user メッセージから始める: 次のユーザーターン、または tool_use に答える tool_result ブロックです。
  • pause_turn は "messages": [] で再開する: そのレスポンスの id からcontinueリクエストを送ります。一時停止中に新しい user メッセージを送ると拒否されます。
  • 追記のみ、継続は1回だけ。 常に最新のレスポンス id から続けます。編集や分岐をしたいときは新しいスレッドを始めます。

コンパクションをしたい場合は、要約を自分のコードで作り、新しいcreateリクエストで system、tools とともに送ります。compaction on demandはスレッドでは使えません。Claude Codeが長いセッションをどう扱うかは、コンテキスト圧縮のチュートリアルを参照してください。

有効期限と復旧

スレッドの保持はベストエフォートです。最後のリクエストから5分で期限切れになり(APIがレスポンスを保存するたびに5分がリセットされます)、遅くとも最後の使用から1時間以内に削除されます。

APIがスレッドを継続できない場合、continueリクエストは error.details.error_code が thread_not_found の404を返しますが、理由は示されません。原因には、期限切れ、APIが応答したものの保存しなかったターン(max_tokens で切れたツール呼び出しで終わるレスポンスなど)、フォールバックモデルが書いた直前のレスポンス、別の組織・ワークスペース・ユーザー・サービスアカウントからのリクエスト、保存済みの会話が受け付けられない内容(画像のない会話に初めて画像を加える場合など)があります。

復旧するには、自前のコピーから会話全体を system と tools 付きで新しいcreateリクエストとして送り(それ以前のメッセージにある cache_control ブレークポイントは外します)、新しい id から続けます。リプレイの前に error_code を確認してください。存在しないモデルへのリクエストも404を返すためです。リプレイ直後にまた404が返る場合は、APIがその会話を保存できない可能性があるので、thread なしで送ります。

  • ストリーミング: id は message_start で届きますが、継続するのは message_stop を受け取ってからです。continueリクエストのストリームが途切れたら同じリクエストを再送し、thread_already_continued か thread_continue_in_flight が返ったらリプレイします。ドキュメントいわく、リプレイは常に安全です。
  • 拒否: stop_reason: "refusal" の後はスレッドを継続しません。拒否につながったターンを除くか言い換えて、新しいスレッドを始めます。
  • フォールバック: フォールバックモデルが書いたターンは保存されません。usage.iterations に fallback_message エントリがあれば、そのレスポンスも含めた会話全体を新しいcreateリクエストで送ります。

SDKのヘルパーは、thread_not_found、thread_already_continued、thread_continue_in_flight のときに1回だけ自動でリプレイし、メッセージなしで send() を呼ぶと pause_turn を再開し、拒否やフォールバックモデルのレスポンスの後は新しいスレッドで始め直します。途切れたストリームを自分から再試行することはなく、thread_fingerprint_mismatch と thread_unsupported_request のエラーはアプリケーションのコードに届きます。

エラー

以下のエラーはモデルの実行前に返り、トークンを消費せず、スレッドとその有効期限も変わりません。

ステータスerror_code意味対処
404thread_not_foundAPIがスレッドを継続できない。新しいcreateリクエストで会話全体を送る。
400thread_fingerprint_mismatch固定フィールドが異なる。メッセージに該当フィールドが示される。固定フィールドを揃えるか、新しいスレッドを始める。
400thread_already_continued各レスポンス id は1回しか継続できない。最新の id から続ける。そのレスポンスをクライアントが受け取っていなければリプレイする。
400thread_continue_in_flightこの id からの別のcontinueがまだ実行中。たいていは自分の以前の試行。完了を待ってその id から続けるか、リプレイする。
400thread_unsupported_requestスレッドが対応していない機能や組織設定を使っている。error.details.unsupported があればその名前が入る。その機能を外すか、thread なしで会話全体を送る。

error_code を持たない400エラーもあります。たとえば previous_message_id のないcontinueリクエストや、system や tools を含むcontinueリクエストです。

対応モデルとプラットフォーム

ドキュメントに記載されたすべてのモデルで、message threadsはベータとして利用できます:claude-fable-5-1、claude-mythos-5-1、claude-fable-5、claude-mythos-5、claude-mythos-preview、claude-opus-5-5、claude-opus-5、claude-sonnet-5-5、claude-sonnet-5、claude-haiku-5-5、claude-haiku-4-5-20251001、claude-opus-4-8、claude-opus-4-7、claude-opus-4-6、claude-sonnet-4-6、claude-opus-4-5-20251101、claude-sonnet-4-5-20250929。

対応プラットフォーム(すべてベータ)は、Claude API、Claude Platform on AWS、Claude Models on Google Cloud(Anthropic managed)、Microsoft Foundryです。Claude Platform on AWSでは、スレッドを作成したIAMロールまたはIAMユーザーの認証情報で、そのスレッドのすべてのリクエストに署名します。

データの扱い、料金、レート制限

Message threadsはZDRの対象外ですが、利用しても他のZDR対象機能の利用には影響しません。APIはスレッドをメモリ上に保持し、サーバー管理の鍵で暗号化し、永続ストレージには一切書き込まず、最後の使用から1時間以内に削除します。HIPAAの対象でもありません。

ドキュメントは、スレッドは料金もレート制限も変えないと明言しています。Anthropicの発表によれば、リクエストは小さくなっても、Claudeは毎ターン会話全体を読むため、トークン使用量は変わりません。

Message threadsとプロンプトキャッシュの違い

スレッドは料金を変えないので、コスト削減の手段は引き続きプロンプトキャッシュ(prompt caching)です。ドキュメントも、スレッドがプロンプトを代わりにキャッシュしてくれるわけではないと明記しています。スレッドでは次のようにします。

  • トップレベルの cache_control(固定フィールド)をすべてのリクエストで送ります。各ターンはそれ以前の会話をキャッシュから読み、新しいターンをキャッシュに書き込みます。
  • thread 付きのリクエストに置ける cache_control ブレークポイントは最大4つです。トップレベルの1つも数に入り、createリクエストの system と tools に置いたブレークポイントはcontinueリクエストのたびに改めて数えられ、保存済みの以前のメッセージ上のブレークポイントは数えません。1つでも超えると thread_unsupported_request が返ります。
Message threadsプロンプトキャッシュ
削減するものアップロード量とターンごとの検証・トークン化。TTFTが下がる処理時間とコスト。キャッシュ済みのプレフィックスから再開する
料金変わらないキャッシュ読み取りはベース入力料金の0.1倍以下(モデルによる)。書き込みは1.25倍(5分)または2倍(1時間)
有効期間最後のリクエストから5分で期限切れデフォルト5分、使うたびに更新。1時間のオプションは追加料金
ZDR対象外対象(Covered Modelsを除く)

長時間動き続けるエージェントループでは両方を併用します。スレッドのドキュメントの例もそうしています。Message Batches、ZDRが必要なトラフィック、ターン間隔が5分を超える場合はキャッシュだけを使いましょう。5分を超えるとスレッドは期限切れになりますが、1時間キャッシュならまだヒットしえます。

Message threadsを使うべきでない場面

次の場合は thread を付けないでください。

  • ターン間隔がたいてい5分を超える(人が各ステップを確認する場合など):continueのたびに404とリプレイになります。
  • Message Batchesやトークンカウントを使う:どちらも thread を受け付けません。
  • コンパクションやcontext editingに頼っている(keep: "all" の clear_thinking_20251015 を除く)。
  • 組織がこのトラフィックにZDRを必要としている、またはHIPAA readinessやInference hooksを有効にしている。
  • 履歴の書き換えや system・tools・model の切り替えが多い:変更のたびに新しいスレッドになります。
  • リクエストが単発:ドキュメントによれば、スレッドが最も役立つのは長いエージェントループです。

エージェント開発者向けチェックリスト

セッションが継続的でコンテキストが大きく育ち、4つのプラットフォームのいずれかを使っていて、上のどれにも当てはまらないなら、スレッドを採用しましょう。リリース前に確認すること:

  • アプリが会話全体を保持し、リプレイできる。
  • createのみ・固定のフィールドがスレッド内で変わらない。
  • 最新のレスポンス id からのみ継続し、ストリーミング時は message_stop の後に継続する。
  • HTTPステータスだけでなく error.details.error_code で分岐している。
  • 拒否やフォールバックモデルのレスポンスの後は新しいスレッドを始める。
  • どのリクエストも cache_control ブレークポイントが4つ以内(トップレベルを含む)。
  • 各スレッドで使うAPIキーとワークスペースは1組だけ(Claude Platform on AWSではIAMロールまたはユーザーも1つ)。

よくある質問

スレッドでトークン代は下がりますか?

下がりません。料金、レート制限、トークン使用量は変わらず、コストを下げるのはプロンプトキャッシュです。

以前のターンから分岐できますか?

スレッド内ではできません。新しいスレッドを始めます。たとえばヘルパーの thread.params を使い、messages を必要な位置まで切り詰めます。

Claude Codeはmessage threadsを使っていますか?

Anthropicによれば、大半のClaude Codeユーザーでデフォルトで有効です。今月のClaude Codeのその他の変更は、2026年11月のまとめをご覧ください。

出典