レッスン2: コンテキストの解剖: システムプロンプト、ツール、そして例
学習目標:
- 1 回の LLM リクエストのコンテキスト(システムプロンプト、ツール定義、例、メッセージ履歴)を分解し、4 つすべてが同じアテンションバジェットを使っている理由を説明する
- システムプロンプトの「高度」の問題を診断し——一方の端はハードコードされて脆く、もう一方の端は曖昧でシグナルがない——正しい高度に書き直す
- コンテキストコストのレンズでツール定義と例を監査する: 機能の重なるものを統合し、戻り値を削り、エッジケースの羅列を少数の定番の例に置き換える
前提: レッスン1 を終え、コンテキストが有限の資源であるという前提を受け入れていること | 前: レッスン1 << | 次: レッスン3 >>
ボンネットを開ける: 1 回のリクエストに実際に何が積まれているのか
レッスン1 では Anthropic の定義を借りました。コンテキストエンジニアリングとは "the set of strategies for curating and maintaining the optimal set of tokens (information) during LLM inference"1 です。まだ抽象的です——「最適な集合」は実際にどのトークンでできているのでしょうか。このレッスンがやることは 1 つ、ボンネットを開けて、リクエストが飛ぶたびにウィンドウへ積まれているものを見せることです。
「Agent Harness Fundamentals: Loops and Control」でハーネスのループを手で書いたので、リクエストの形は見慣れているはずです。何を抱えているかで分けると、1 回のリクエストのコンテキストはおおよそ次の 4 ブロックです:
重要なのはここです。この 4 つは密閉された 4 つのポケットではなく、1 つのウィンドウの中の隣人同士です。"LLMs have an "attention budget" that they draw on when parsing large volumes of context" であり、"Every new token introduced depletes this budget by some amount"1。システムプロンプトに 1 段落の水増しが増えれば、その分の注意はメッセージ履歴には回りません。誰も呼ばないツールが 10 個マニフェストに居座れば、例が受け取る取り分が薄まります。そしてレッスン1 で扱ったとおり、"as the number of tokens in the context window increases, the model's ability to accurately recall information from that context decreases"1——しかもこの劣化は急落ではなく傾斜として訪れます。"These factors create a performance gradient rather than a hard cliff"1 だからです。だからこそ、どのブロックの無駄も、エラーで自己申告することは決してありません。全体を静かに少しずつ鈍らせるだけで、気づいたときにはたいてい、原因の行を指させません。
4 つのブロックは増え方も違います。システムプロンプト、ツール定義、例は基本的に静的です——書いた長さのまま居続けます。代わりにメッセージ履歴がループの中で膨らみます。"An agent running in a loop generates more and more data that could be relevant for the next turn of inference"1 からです。「Agent Harness Fundamentals: Loops and Control」で組んだハーネスで、各ターンのツール結果を messages 配列に push しているあの行こそ、その膨張の実況中継です。履歴をどうするかはこのレッスンの仕事ではありません——レッスン4「コンパクションとノート: 長時間タスクのコンテキスト管理」がまるごとそのために用意されています。このレッスンは静的な 3 ブロックを手なずけます。そこは毎ターン必ず支払う固定費だからです。
"context, therefore, must be treated as a finite resource with diminishing marginal returns"1 を行動に移すというのは、各ブロックに同じ問いを投げることです。このトークンは、どれだけの振る舞いの改善を買ったのか。ブロックごとに見ていきましょう。
システムプロンプトの高度: 2 通りの失敗
Anthropic のエンジニアリング記事は、システムプロンプトが位置する抽象度を「高度(altitude)」と呼び、2 つの失敗の極を挙げています。一方の端は "engineers hardcoding complex, brittle logic in their prompts to elicit exact agentic behavior"1(正確なエージェントの振る舞いを引き出そうとして、複雑で脆いロジックをプロンプトにハードコードするエンジニア)。もう一方の端は "vague, high-level guidance that fails to give the LLM concrete signals for desired outputs"1(望ましい出力について LLM に具体的なシグナルを与えられない、曖昧で高レベルな指針)。同じ注文サポートエージェントについてシステムプロンプトを 3 バージョン書いて、2 つの罠と良い答えを並べてみましょう。
低く飛びすぎ——ロジックがハードコードされる場合:
どのルールも、書いてあるケースだけをカバーします。ユーザーが「壊れて」ではなく「箱がつぶれていた」と書いたらどうなるでしょうか。どのルールも捕まえられないので、ルール 20 に落ちてとぼけた返答をします。さらに悪いことに、ルール同士が衝突し始めるので、審判役としてルール 19 を足すことになります——その時点であなたは、自然言語で if-else インタプリタを書いています。追加のたびにプロンプトは長く、脆く、注意の面で高くつくようになる一方で、書き漏らしたケースの数は書いたケースの数を常に上回ります。
高く浮かびすぎ——スローガンだけの場合:
トークンは節約できましたが、モデルには具体的なシグナルが 1 つも届きません。返金の境界はどこでしょうか。いくらまでの補償を認めてよいのでしょうか。何を人間に上げるべきでしょうか。すべて当てずっぽうです。「ユーザーに満足してもらう」を極限まで押し進めれば、返金すべきでないものまで返金することになりえます——そしてそれは不服従ではなく、あなたが何も伝えなかったということです。
正しい高度——Anthropic の基準は "specific enough to guide behavior effectively, yet flexible enough to provide the model with strong heuristics"1(振る舞いを効果的に導けるだけ具体的でありながら、モデルに強いヒューリスティクスを与えられるだけ柔軟)なプロンプトです:
このバージョンの構造を見てください。原則が一般化を担い、レッドラインがコンプライアンスを担うのです。「箱がつぶれていた」はどのルールにも逐語的には書かれていませんが、「破損は当社の責任」の下に自然に着地します。本当に交渉の余地がないもの(補償の上限、法的紛争)は、ひと握りの厳守事項として釘付けにされています。20 ルール版の半分未満の長さで、カバー範囲は明確に広くなっています。
高度を判断するための近道の問いがあります。書き漏らしたケースに直面したとき、このプロンプトはモデルに、そこから推論を始める方向を与えるか? 低いバージョンは与えられません(落とし穴に落とすことしか知りません)。高いバージョンは空っぽの方向(「満足」)を与えます。正しい高度のバージョンは、転用の効く原則を与えます。
常時ロードされる層: CLAUDE.md の規律
システムプロンプトは、あなたが打ち込んだ文字列だけではありません。多くのハーネスはプロジェクトレベルの設定をシステム層に恒久的に置いており、Claude Code の CLAUDE.md はその代表例です。ドキュメントいわく "CLAUDE.md is a special file that Claude reads at the start of every conversation."2(CLAUDE.md は、Claude がすべての会話の冒頭で読む特別なファイル)。「毎回読まれる」とは、その 1 行 1 行が毎セッションでアテンションバジェットを使うということで、だからこそドキュメントが課す規律は厳しいのです。
規律その 1: 広く当てはまるものだけを置く——"CLAUDE.md is loaded every session, so only include things that apply broadly."2 1 つのサブディレクトリでしか要らないビルドコマンド、1 種類のタスクでしか要らない規約。どちらも、常時ロード層の座席を勝ち取ってはいません。
規律その 2: 1 行ずつ削除テストにかける。"Keep it concise. For each line, ask: "Would removing this cause Claude to make mistakes?" If not, cut it."2(簡潔に保つこと。各行について問う——これを消したら Claude はミスをするか? しないなら削る)。これは潔癖症ではありません。ドキュメントは率直にこう警告しています: "Bloated CLAUDE.md files cause Claude to ignore your actual instructions!"2(肥大した CLAUDE.md は、Claude にあなたの本当の指示を無視させる)。これはアテンションバジェットの具体化そのものです——なくても済む行を詰め込むたびに、本当に効く数行が薄まります。同じページはコンテキストウィンドウを "the most important resource to manage,"(管理すべき最も重要な資源)とまで呼び、"Claude's context window fills up fast, and performance degrades as it fills."2 と注意を促しています。
では、めったに要らないが、いざというとき不可欠な素材はどこに住むのでしょうか。Claude Code の答えはスキルです。オンデマンドでロードされます——"Claude loads them on demand without bloating every conversation."2(Claude はそれらを必要なときにロードするので、すべての会話を肥大させない)。この組み合わせ——常駐層は最小限にとどめ、残りは必要になったら取りに行く——こそレッスン3 の主題なので、ここでは予約しておくだけにします。
余談を 1 つ。自分のプロジェクトに AGENTS.md や system_prompt.txt のような、恒久的にコンテキストに座っているものがあるなら、同じ削除テストをかけてください。常時ロード層の肥大はいちばん厄介です——会話のどの 1 ターンにも姿を現さないのに、そのすべてのターンに課税するからです。
ツールもコンテキスト: 定義にもコストがあり、戻り値にもコストがある
ツールはコンテキストに 2 回現れます。定義はすべてのリクエストに同乗し、戻り値はメッセージ履歴に入ります。どちらの端でも予算を使います。
先行コース「エージェントツール呼び出し: エージェントに実際に行動させる」はツール設計の機能面——パラメータの定義方法、エラーの扱い方——を扱いました。このレッスンは別の角度から見ます。ツール定義はどれも、モデルが読んで理解しなければならないトークンの一続きです。Anthropic の基準は、"tools should be self-contained, robust to error, and extremely clear with respect to their intended use"1(ツールは自己完結し、エラーに強く、意図された用途について極めて明確であるべき)であり、"building tools that are well understood by LLMs and have minimal overlap in functionality"1(LLM によく理解され、機能の重なりが最小限のツールを作る)ことです。両方に落第する 2 つの例を挙げます(読みやすさのためスキーマは簡略化しています):
どちらのツールも注文を検索でき、どちらの説明も曖昧で、両者の境界は作者本人ですら決めきれていません。"minimal overlap in functionality"1 という要件の狙いはまさにそこです。境界のぼやけたツールを積み上げれば、「どっちを使えばいいのか?」という問いを毎ターン新品でモデルに手渡すことになります。1 つに統合して目的と振る舞いを明確に書けば、この問いは消えます:
この説明は「何をするか」以上のことを述べています——戻ってくるものの形と、返すものが何もないときに何が起きるかまで書いてあります。これは "robust to error"1 の文字どおりの実装です。モデルは空振りがどう見えるかを推測しなくてよいので、検索が空で返ってきたときに変な復旧手を編み出す可能性がぐっと下がります。
次は戻り値の側です。Anthropic はツールに "returning information that is token efficient and by encouraging efficient agent behaviors"1(トークン効率のよい情報を返し、効率的なエージェントの振る舞いを促すこと)を求めています。注文の 40 以上の内部フィールドと完全な監査ログを丸ごと返すツールは、呼ばれるたびに低価値なトークンをバケツで履歴に注ぎ込みます——そしてそのトークンは履歴に残り、以降のすべてのターンで再び課税されます。上の例のような「デフォルトは削る、必要なら detail=true」が、この修正の標準形です。
最後に、ツールのマニフェスト自体にも引き算が要ります。一度も呼ばれないままコンテキストにいる 10 個のツールも、その定義分は毎ターン満額請求されます。ツールリストの監査と CLAUDE.md の監査は同じ所作です——消したらミスが起きるか? 起きないなら削る。
例: 定番を選ぶ。リストを積み上げない
例(few-shot)は 3 つ目の静的コストです。よくある腐り方はこうです。本番のバッドケースが出るたびに対応する例をプロンプトに足し、半年後にはエッジケースの 30 件カタログを所有している。Anthropic はこの点について率直です——"stuff a laundry list of edge cases into a prompt"1(エッジケースの羅列をプロンプトに詰め込む)のではなく、"curate a set of diverse, canonical examples that effectively portray the expected behavior of the agent"1(エージェントに期待される振る舞いを効果的に描く、多様で定番の例を厳選する)べきだ、と。
「定番(canonical)」とは、1 つの例が特定の状況ではなく振る舞いのクラスを代表するということです。サポートエージェントに戻ると、3 つの例で振る舞いの空間全体を枠づけられます。
- 標準フロー: 注文を検索し、責任の所在を判断し、解決策を提示するまでの一通り。
- 先に責任を引き受ける: こちらが誤った商品を送っており、ユーザーが求める前に補償を提示する。
- エスカレーション: エージェントの権限を超えているので、丁寧に説明して人間に引き継ぐ。
「多様(diverse)」とは、この 3 つが同じ振る舞いの 3 つのバリエーションではなく、判断の異なる分岐をカバーしているということです。
では、エッジケースはどこへ行くのでしょうか。その大半は、システムプロンプトの原則の層へ昇格させるべきです。「ユーザーが罵倒してきたら」に 300 トークンの会話例まるごとは要りません。原則を 1 つ——「ユーザーが感情的なときは冷静さを保ち、問題の解決に焦点を戻す」——で用が足ります。例は期待される振る舞いがどう見えるかを教え、原則は新しいものが現れたときにどの方向へ推論すべきかを教えます。もう気づいたかもしれません。例のリストにエッジケースを足すことと、システムプロンプトに分岐を足すことは、同じコインの裏表です——どちらも低い高度でのパッチ当てであり、穴を実際に塞ぐのは原則の層へ上がることだけです。
ブロックごとのチェックリスト: 解剖を実務に落とす
このレッスンを実行可能な形に畳みます。コンテキストに何かを足す前に、対応する問いを走らせてください:
この表のほかに、もう 1 つこのレッスンから持ち帰る価値のある原則があります。エージェントシステムの構築について書く中で、Anthropic は程度の感覚を示しています: "you should consider adding complexity only when it demonstrably improves outcomes."3 元の文脈はシステムアーキテクチャですが、コンテキストのどのブロックにも同じくらいよく当てはまります——ツールを 1 つ、ルールを 1 つ、例を 1 つ足すことは、いずれも複雑さの追加です。乗せる前に、それが振る舞いの改善を買うことを証明させてください。
これで静的な 3 ブロックをひととおり見ました。ですが、さらに次の問いが待っています。そもそもウィンドウに前もってロードすべきでない情報がある——モデルが何を必要とするか当てにいくのではなく、実行時にエージェント自身に探しに行かせる。次のレッスンの主題はそれです。
まとめ
- 1 回のリクエストのコンテキストは 4 ブロック——システムプロンプト、ツール定義、例、メッセージ履歴。これらは 1 つのアテンションバジェットを共有し、新しいトークンはすべてそれをいくらか削ります1。
- コンテキストは限界収穫が逓減する有限の資源です1。ブロックごとに「このトークンは何を買ったのか」と問う方が、漠然と「プロンプトを調整する」よりはるかに実行可能です。
- システムプロンプトには 2 つの失敗の極があります——ハードコードされた脆い分岐と、シグナルを運ばない曖昧なスローガン。正しい高度は、振る舞いを導けるだけ具体的でありながら、モデルに強いヒューリスティクスを残せるだけ柔軟なところ1で、「原則+厳守事項」がそこに着地するための実務的な構造です。
- CLAUDE.md のような常時ロードされる内容は、すべての会話の冒頭で読まれます。広く当てはまるものだけを入れ、1 行ずつ削除テストにかけてください。肥大したファイルは、モデルにあなたの本当の指示を無視させるからです2。
- ツールは定義と戻り値の両端で予算を使います。意図された用途を極めて明確にし、重なりは最小限に、戻り値はトークン効率よく1。一度も呼ばれないツールも毎ターン満額請求されます。
- エッジケースの羅列を詰め込む代わりに、多様で定番の例を少数だけ厳選してください1。エッジケースの大半は原則の層に属します。
- コンテキストに複雑さを足す前に、Anthropic の程度の感覚を思い出してください。足すのは、それが結果を明確に改善すると示せるときだけです3。
>> レッスン3: ジャストインタイム取得: エージェント自身にコンテキストを取りに行かせる