長時間の会話の途中で「ここから先はこの制約を守らせたい」と思ったとき、これまではトップレベルの system フィールドを書き換えるしかありませんでした。ところが system はプロンプトの最先頭にあるため、1 文足すだけでprompt cache のハッシュが変わり、それ以降のキャッシュが全部外れます。
Opus 4.8 で入った mid-conversation system messages は、この穴を塞ぐ機能です。messages 配列の末尾に role: "system" を追記することで、キャッシュ済みのプレフィックスはそのままに、新しい指示を「system(=アプリ運営者)」の重みで適用できます。移行先 Opus 4.8 の全体像は Claude Opus 4.8 発表 を参照してください。
対応範囲(まず前提)
- Opus 4.8 のみ。beta ヘッダ不要。
- Claude API と Claude Platform on AWS で利用可能。Amazon Bedrock / Vertex AI / Microsoft Foundry では利用不可。
旧モデル(Opus 4.7 以前)は messages 内の role: "system" を 400 エラーで拒否します。
なぜキャッシュが効くのか
prompt cache はリクエストのプレフィックスを tools → system → messages の順でハッシュします。キャッシュヒットには、ブレークポイントまでがバイト単位で一致している必要があります。
- トップレベル
systemはハッシュのほぼ先頭。ここに 1 文足すと別ハッシュになり、system 以降の全キャッシュがミス。 - mid-conversation system message は指示を
messagesの末尾に置きます。それより前は一切変わらないので既存キャッシュエントリが一致し、新しいメッセージだけが新規入力として処理されます。
どう書くか
messages 配列に {"role": "system"} を追加するだけです。content は user / assistant と同様、文字列でもコンテンツブロックでも構いません。
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
cache_control={"type": "ephemeral"}, # 自動キャッシュを有効化
system="You are a code review assistant. Be concise.",
messages=[
{"role": "user", "content": "Review process() in utils.py for performance issues."},
{"role": "assistant", "content": "For large inputs, consider a generator..."},
{"role": "user", "content": "Now review the calling code that invokes process()."},
# 途中で「型注釈を必須にする」ポリシーが決まった。
# ここに追記すれば前のターンはバイト一致のまま → キャッシュが効く。
{"role": "system", "content": "From now on, every suggestion must include explicit type annotations."},
],
)
指示が競合した場合の優先順位は、後の system が先の system に勝ち、mid-conversation system はそれ以降のターンでトップレベル system に勝ちます。会話全体に効かせたい指示は引き続きトップレベル system に置き、「途中から必要になる指示」だけを mid-conversation system に回すのが基本設計です。
system と user の違い:operator 権限
「同じ指示なら user メッセージで足してもいいのでは?」という疑問が当然出ます。違いは優先度です。
userメッセージ = エンドユーザーからの入力として扱われるsystemメッセージ = **アプリ運営者(あなた)**からの入力として扱われる
両者が競合したときは system が優先します。「エンドユーザーが何を言っても守らせたい運営者レベルの事実・制約」は system ロールで、しかもキャッシュミスのコストを払わずに足せる、というのが本機能の価値です。
何に使えるか
- セッション途中のポリシー/ペルソナ変更 — 数十ターン進んだ後に「ここから SQL は必ずパラメータ化クエリで書く」を足す。トップレベル
systemを書き換えると全履歴が再処理される - その時点で権威を持たせたい文脈 — フレッシュネス情報・セッション期限・ツール可用性の変化を system レベルで注入。頻繁に変わるのでキャッシュ済みプレフィックスには置きたくない
- アプリが観測した状態変化 — ディスク上のファイル変更、ユーザーが auto-approve を切り替えた、利用可能ツールが変わった、残トークン予算が閾値を下回った、といった「運営者レベルの事実」
- エージェントループを中断させたくないユーザー入力 — Claude がツール実行中にユーザーが追記したメッセージを、次の tool result の後に system として中継すると、ターンを再起動せずに進行中の作業へ織り込める
- standing permission を与えるモード切替 — セッションレベルのモードで、高コストな機能(例:マルチエージェント workflow の自動起動)への恒常的な同意を与え、数ターンごとに短く再掲し、モード解除時に終了を告げる
エージェントループでの配置
ツール実行ループでは、tool result を届ける user メッセージの直後に system メッセージを置きます。ここは、Claude が作業中にユーザーが打ったメッセージを中継する場所としても使えます。
[
{ "role": "user", "content": "Run the test suite and fix any failures." },
{ "role": "assistant",
"content": [{ "type": "tool_use", "id": "toolu_01", "name": "run_tests", "input": {} }] },
{ "role": "user",
"content": [{ "type": "tool_result", "tool_use_id": "toolu_01", "content": "12 passed, 0 failed" }] },
{ "role": "system",
"content": "The user sent the following message while you were working: also update the changelog before you finish." }
]
書き方のコツは、「ユーザーを上書きする命令」ではなく「文脈の提示」として書くことです。「new input arrived from the user: X」「the remaining token budget is now Y」のように事実を述べて Claude に判断させる。Claude はユーザーの意図に反する指示に抵抗するよう訓練されており、その保護は system ロールにも及ぶため、「ignore what the user said」のような言い回しはむしろ効きにくくなります。
このパターンは会話のエンドユーザー本人の入力を中継するためのものです。ツール出力・取得した文書・第三者コンテンツを system に入れてはいけません(後述の制約)。
配置ルール(ここを外すと 400)
mid-conversation system message は置ける位置が決まっています。
- 先頭には置けない —
messagesの最初のエントリにはできない。最初から効かせたい指示はトップレベルsystemへ - 直前は
userターン(tool_resultブロックを運ぶuserを含む)、またはサーバーツール使用で終わるassistantターンであること - 直後は
assistantターンであるか、配列の末尾であること tool_useブロックとそのtool_resultの間には置けない- 連続した system メッセージは不可 — 指示は 1 つにまとめるか、次の
userターンを待って追記する
これら以外の位置に置くと 400 エラーになります。
prompt caching との併用
本機能とキャッシュは併用前提で設計されています。
- キャッシュは明示的に有効化する —
cache_control(トップレベルの自動キャッシュ、またはブロックごとの明示ブレークポイント)が無ければ何もキャッシュされない。system メッセージ自体はキャッシュエントリを作らない - 安定プレフィックスを通常どおりキャッシュ — リクエスト間で変わらない最後のブロック(
system末尾・ツール定義末尾・履歴の安定点)にcache_controlを置く - ブレークポイントの後ろに system を追記 — プレフィックスのハッシュを変えないのでヒットが続く
- 追記した system は次ターンでキャッシュ対象になる — 一度会話に入れば安定履歴の一部。次のターンでブレークポイントをその先へ動かせばキャッシュから読まれる
注意点として、送信済みの mid-conversation system メッセージを編集・削除しないでください。過去メッセージへの変更と同じく、そこから先のキャッシュが無効になります。指示を更新したいときは古いものを書き換えず、新しい system メッセージを追記します。キャッシュが外れた原因の特定には cache diagnostics が使えます。
セキュリティ上の制約
system コンテンツは運営者の指示として扱われ、Claude はそれに従います。だからこそ、会話の外から来たテキスト(生のツール出力・取得文書・Web コンテンツ)を system に直接入れてはいけません。それをやると、その文章に運営者レベルの権限を与えることになり、プロンプトインジェクションの経路になります。そうしたデータは tool_result ブロックに留め、ジェイルブレイク/インジェクション対策の原則を守ってください。
まとめ
mid-conversation system messages は、**「会話の途中で運営者レベルの指示を、prompt cache を壊さずに足す」**ための Opus 4.8 専用機能です(Claude API / Claude Platform on AWS、beta ヘッダ不要)。トップレベル system の書き換えがキャッシュ全外しを招くのに対し、末尾追記なら既存キャッシュを温存できます。配置ルール(先頭不可・tool_use/tool_result の間不可・連続不可、違反は 400)と、untrusted コンテンツを system に入れないという 2 点さえ守れば、長時間エージェントのガードレールを動的に・安価に足していけます。
release notes タグで Anthropic / Claude API のリリース情報を継続フォローしています。