Agent Mentor Learn
コンテキストエンジニアリング: 有限のアテンションを効くところに使う · 第 2 回 / 全 6 回

レッスン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 ブロックです:

text
1 回のリクエストのコンテキスト├── システムプロンプト(役割、ルール、背景知識)├── ツール定義(各ツールの名前、説明、パラメータスキーマ)├── 例(few-shot: 期待される振る舞いを描く入出力サンプル)└── メッセージ履歴(ユーザーメッセージ、モデルの返信、各ターンのツール呼び出しと結果)

重要なのはここです。この 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 つの罠と良い答えを並べてみましょう。

低く飛びすぎ——ロジックがハードコードされる場合:

text
あなたは注文サポートエージェントです。以下のルールに厳密に従ってください:1. ユーザーが「届いていない」と言ったら、テンプレート A で返信する。2. ユーザーが「壊れて届いた」と言ったら、テンプレート B で返信し、$10 のクーポンを発行する。3. TB で始まる注文番号: まず配送を確認する。JD で始まる注文番号: まず在庫を確認する。4. ユーザーのメッセージに「クレーム」という語が含まれていたら、人間に引き継ぐ。…(残り 14 個のルールは省略)19. ユーザーがルール 2 とルール 4 の両方に該当する場合は、ルール 4 が優先する。20. 上記のどれにも当てはまらない場合は「申し訳ありません、理解できませんでした」と返信する。

どのルールも、書いてあるケースだけをカバーします。ユーザーが「壊れて」ではなく「箱がつぶれていた」と書いたらどうなるでしょうか。どのルールも捕まえられないので、ルール 20 に落ちてとぼけた返答をします。さらに悪いことに、ルール同士が衝突し始めるので、審判役としてルール 19 を足すことになります——その時点であなたは、自然言語で if-else インタプリタを書いています。追加のたびにプロンプトは長く、脆く、注意の面で高くつくようになる一方で、書き漏らしたケースの数は書いたケースの数を常に上回ります。

高く浮かびすぎ——スローガンだけの場合:

text
あなたは注文サポートエージェントです。プロフェッショナルかつ friendly に、ユーザーの問題を柔軟に処理し、ユーザーに満足してもらってください。

トークンは節約できましたが、モデルには具体的なシグナルが 1 つも届きません。返金の境界はどこでしょうか。いくらまでの補償を認めてよいのでしょうか。何を人間に上げるべきでしょうか。すべて当てずっぽうです。「ユーザーに満足してもらう」を極限まで押し進めれば、返金すべきでないものまで返金することになりえます——そしてそれは不服従ではなく、あなたが何も伝えなかったということです。

正しい高度——Anthropic の基準は "specific enough to guide behavior effectively, yet flexible enough to provide the model with strong heuristics"1(振る舞いを効果的に導けるだけ具体的でありながら、モデルに強いヒューリスティクスを与えられるだけ柔軟)なプロンプトです:

text
あなたは注文サポートエージェントです。目標は、ユーザーの購入後の問題を 1 回の会話で解決することです。
判断の原則:- 未発送の注文は、依頼があれば返金してよい。発送済みなら、受け取り拒否か返品手続きへ案内する。- 破損、誤配送、欠品は当社の責任: ユーザーが求める前に、こちらから補償を提示する。- 責任の所在がはっきりしないときは、まず重要な事実(注文番号、写真)を確認してから判断する。
厳守事項(決して越えない):- 1 件あたりの補償は $50 を超えない——それ以上は人間に引き継ぐ。- 身体的な被害や法的紛争が関わる会話は、直ちに人間に引き継ぎ、フラグを立てる。

このバージョンの構造を見てください。原則が一般化を担い、レッドラインがコンプライアンスを担うのです。「箱がつぶれていた」はどのルールにも逐語的には書かれていませんが、「破損は当社の責任」の下に自然に着地します。本当に交渉の余地がないもの(補償の上限、法的紛争)は、ひと握りの厳守事項として釘付けにされています。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 つの例で振る舞いの空間全体を枠づけられます。

  1. 標準フロー: 注文を検索し、責任の所在を判断し、解決策を提示するまでの一通り。
  2. 先に責任を引き受ける: こちらが誤った商品を送っており、ユーザーが求める前に補償を提示する。
  3. エスカレーション: エージェントの権限を超えているので、丁寧に説明して人間に引き継ぐ。

「多様(diverse)」とは、この 3 つが同じ振る舞いの 3 つのバリエーションではなく、判断の異なる分岐をカバーしているということです。

では、エッジケースはどこへ行くのでしょうか。その大半は、システムプロンプトの原則の層へ昇格させるべきです。「ユーザーが罵倒してきたら」に 300 トークンの会話例まるごとは要りません。原則を 1 つ——「ユーザーが感情的なときは冷静さを保ち、問題の解決に焦点を戻す」——で用が足ります。例は期待される振る舞いがどう見えるかを教え、原則は新しいものが現れたときにどの方向へ推論すべきかを教えます。もう気づいたかもしれません。例のリストにエッジケースを足すことと、システムプロンプトに分岐を足すことは、同じコインの裏表です——どちらも低い高度でのパッチ当てであり、穴を実際に塞ぐのは原則の層へ上がることだけです。

ブロックごとのチェックリスト: 解剖を実務に落とす

このレッスンを実行可能な形に畳みます。コンテキストに何かを足す前に、対応する問いを走らせてください:

ブロック投げる問い
システムプロンプト高度は正しいか? 書き漏らしたケースに直面したとき、モデルに判断の方向を与えるか?1
常時ロードされるファイルこの行は広く当てはまるか? 消したらミスが起きるか?2
ツール定義用途は十分に明確か? 他のツールと重なっていないか? 戻り値はデフォルトで削られているか?1
それぞれが振る舞いのクラスを代表しているか? リストがまた伸びていないか?1
メッセージ履歴ここでは扱いません——レッスン4「コンパクションとノート: 長時間タスクのコンテキスト管理」を参照

この表のほかに、もう 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: ジャストインタイム取得: エージェント自身にコンテキストを取りに行かせる

Footnotes

  1. Effective context engineering for AI agents — Anthropic Engineering — https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

  2. Best practices for Claude Code — Claude Code Docs — https://code.claude.com/docs/en/best-practices 2 3 4 5 6 7 8

  3. Building Effective AI Agents — Anthropic Engineering — https://www.anthropic.com/engineering/building-effective-agents 2

練習

01

経費承認エージェントのシステムプロンプトです:

レベル1: ルールの羅列を正しい高度に書き直す
text
あなたは経費承認アシスタントです。以下のルールに従って承認してください:1. $100 未満のタクシー領収書: そのまま承認する。2. $100 以上のタクシー領収書: 移動の説明を求める。3. 平日 12:00〜14:00 の食事の領収書: そのまま承認する。4. 週末の食事の領収書: 却下する。5. 「電子機器」カテゴリの事務用品: マネージャーに回す。6. 請求先名義が会社名と一致しない領収書: 却下する。7. 上記のどれにも当てはまらない場合は「総務に問い合わせてください」と付記して却下する。

このルールセットでは、出張のホテル領収書はどのルールにも捕まらず、毎回ルール 7 で却下されます。平日の夕食の領収書はルール 3 にもルール 4 にも合致せず、同じ受け皿に落ちます。2 つのことをしてください: (1) このプロンプトがどちらの失敗の極にいるかを指摘し、なぜこの症状がその種のプロンプトでは避けられないのかを説明する。(2) 正しい高度に書き直し、上記の未処理の 2 ケースを両方カバーするバージョンを示す。

完了基準 · ローカルでチェック
02

EC のサポートエージェントを引き継ぎました。そのコンテキストには以下の 3 つのツール定義(スキーマは簡略)と、「ユーザーが誤字を打ったときどうするか」「ユーザーが同じ質問を 2 回したときどうするか」といったエッジケースばかりの 12 件の few-shot の例が入っています:

レベル2: ツールと例にコンテキストコスト監査をかける

コンテキストコスト監査を実施してください: (1) ツールリストの機能の重なりを指摘し、統合案を示す。(2) 統合後のツールが、必要な情報に到達できる状態を保ちながら、どうやって戻り値をトークン効率よくするのかを説明する。(3) 例のリストの作り直し案を示す: どんな例を残すべきで、エッジケースは誰が担当すべきか。

完了基準 · ローカルでチェック