LLMコンテキストエンジニアリング実践:Prompt組み立て、Token予算とRAGコンテキスト設計

AI与大数据

概要

  • Context Engineering(コンテキストエンジニアリング)は2026年のLLMアプリケーション本番展開の中核スキル。Prompt Engineeringより範囲が広く、実務に直結する
  • Token予算はハード制約:システムプロンプト、ツール定義、RAG検索、会話履歴を層別に配分しないと、ウィンドウ超過による切り捨てかコスト爆発のどちらかに陥る
  • Prompt組み立ては文字列連結ではなく、優先度付きのコンテキストパイプライン。各層に明確な予算と退避戦略がある
  • RAGコンテキスト注入の3大落とし穴:検索ノイズが重要情報を埋没、Chunk境界による意味切断、重複コンテンツによるToken浪費
  • 本記事では原理からPython実装までの完全ソリューションを提供。Token予算計算機と本番向けContext Managerを含む

目次


なぜPrompt Engineeringだけでは不十分か

2024年は「良いPromptの書き方」が話題でしたが、2026年に企業がLLMアプリを本番展開する際に本当のボトルネックとなるのは「一文の書き方」ではなく、コンテキスト全体の組織化です。

実際の本番障害事例

あるECカスタマーサポートAIがローンチ1週間でクレーム率が急増。調査の結果:

現象 根本原因 影響
AIの回答が注文と無関係 RAGが10件の過去チケットを取得し、現在の注文コンテキストを埋没 的外れな回答
マルチターン後に応答が遅延 会話履歴が無制限に蓄積、Token超過で切り捨て発生 ユーザー意図の喪失
月間API請求が予算の3倍 システムプロンプトを毎回送信、Prompt Caching未活用 コスト爆発

これらは**「Promptの文言を最適化」では解決できません**。すべてContext Engineeringの領域です。

Prompt Engineering vs Context Engineering

観点 Prompt Engineering Context Engineering
焦点 単一プロンプトの文言と形式 コンテキスト全体の組織、予算、ライフサイクル
適用範囲 簡単なQ&A、単発タスク マルチターン、RAG、Agent、ツール呼び出し
中核スキル ロール設定、Few-shot、CoT Token予算、コンテキスト層別化、圧縮退避
本番複雑度 高(キャッシュ、検索、状態管理)
2026年面接での重要度 基礎 高頻度アーキテクチャ問題

一言で言えば:**Prompt Engineeringは「何を言うか」、Context Engineeringは「モデルに何を見せるか」**を管理します。


Context Engineeringの中核概念

コンテキストの4層構造

LLMへの完全な入力を「情報サンドイッチ」と考えます:

┌─────────────────────────────────────────────┐
│  Layer 1: システム層 (System Context)        │
│  ロール定義、行動制約、出力形式、セキュリティ  │
├─────────────────────────────────────────────┤
│  Layer 2: ツール層 (Tool Context)            │
│  Function Calling定義、MCPツール、Schema      │
├─────────────────────────────────────────────┤
│  Layer 3: 知識層 (Knowledge Context)         │
│  RAG検索結果、ナレッジグラフ、業務ルール      │
├─────────────────────────────────────────────┤
│  Layer 4: 会話層 (Conversation Context)    │
│  マルチターン履歴、現在の入力、推論ステップ    │
└─────────────────────────────────────────────┘

各層に独立したToken予算があり、層間には優先順位があります。総Tokenがウィンドウ上限に近づくと、低優先度の層から退避します。

コンテキストのライフサイクル

  1. 組み立て(Assembly):優先度に基づき各層をマージ
  2. 検証(Validation):Token総量、形式準拠、機密情報フィルタ
  3. 送信(Dispatch):LLM API呼び出し、Prompt Cachingで重複Token削減
  4. 更新(Update):モデル応答を会話層に追加
  5. 圧縮(Compaction):会話が長くなったら要約または低価値履歴を退避

Token予算:コンテキストウィンドウの「財務計画」

なぜToken予算が必要か

128Kコンテキストウィンドウのモデルでも、本番環境では:

  • システムプロンプト + ツール定義:通常 2K-8K Token
  • RAGで10文書 × 500 Token = 5K Token
  • 50ターンの会話履歴 × 200 Token = 10K Token
  • 出力予約:4K Token

合計で既に 21K-27K Token。複雑なAgentや長文書RAGでは容易に50Kを超えます。予算管理なしでは危険です。

推奨予算配分表(128Kウィンドウ)

予算タイプ Token上限 退避戦略
システム層 固定 4K 退避しない、Prompt Caching活用
ツール層 固定 6K 使用頻度に応じて動的ロード
知識層 弾性 20K 関連性スコアで切り捨て
会話層 弾性 30K スライディングウィンドウ + 要約圧縮
出力予約 固定 8K
安全バッファ 固定 10K 見積もり誤差による超過防止

Tokenカウンターの3つの実装

方式1:tiktokenによる正確なカウント(推奨)

import tiktoken

def count_tokens(text: str, model: str = "gpt-4o") -> int:
    encoding = tiktoken.encoding_for_model(model)
    return len(encoding.encode(text))

def budget_check(layers: dict[str, str], max_tokens: int = 128000) -> dict:
    usage = {name: count_tokens(content) for name, content in layers.items()}
    total = sum(usage.values())
    return {
        "usage": usage,
        "total": total,
        "remaining": max_tokens - total,
        "overflow": total > max_tokens,
    }

方式2:文字数推定(高速プリチェック)

中国語は約1.5-2文字/Token、英語は約4文字/Token。組み立て前の高速チェック用。

方式3:APIレスポンスの実際の使用量

response.usageから実消費を取得し、監視と動的予算調整に使用。


Prompt組み立てパイプライン設計

パイプラインアーキテクチャ

ユーザー入力 ──→ [意図認識] ──→ [知識検索] ──→ [コンテキスト組み立て] ──→ [予算検証] ──→ LLM API
                    │                │                    │                    │
                    ▼                ▼                    ▼                    ▼
              ロードするツール決定   Top-K文書フィルタ    優先度でマージ        超過時は圧縮

退避優先順位ルール

Token予算が不足した場合、以下の順序で切り捨て:

  1. 会話層の最も古いメッセージ(直近Nターン + 最初のシステムやり取りを保持)
  2. 知識層の低スコア文書(Rerankスコアの低い順に削除)
  3. 未使用のツール定義(このターンで呼び出す可能性のあるツールのみ保持)
  4. 最後にシステム層(固定内容としてPrompt Cachingを活用)

本番向けアセンブラー実装

from dataclasses import dataclass, field
from typing import Optional

@dataclass
class ContextLayer:
    name: str
    content: str
    priority: int
    max_tokens: int
    cacheable: bool = False

@dataclass
class ContextBudget:
    total_limit: int = 128000
    output_reserve: int = 8000
    safety_buffer: int = 10000

    @property
    def available(self) -> int:
        return self.total_limit - self.output_reserve - self.safety_buffer

class ContextAssembler:
    def __init__(self, budget: ContextBudget):
        self.budget = budget
        self.layers: list[ContextLayer] = []

    def add_layer(self, layer: ContextLayer) -> None:
        self.layers.append(layer)
        self.layers.sort(key=lambda l: l.priority)

    def assemble(self) -> str:
        available = self.budget.available
        parts: list[str] = []

        for layer in self.layers:
            tokens = count_tokens(layer.content)
            if tokens <= layer.max_tokens and tokens <= available:
                parts.append(layer.content)
                available -= tokens
            elif tokens > layer.max_tokens:
                truncated = self._truncate(layer.content, layer.max_tokens)
                parts.append(truncated)
                available -= layer.max_tokens

        return "\n\n---\n\n".join(parts)

    def _truncate(self, text: str, max_tokens: int) -> str:
        encoding = tiktoken.encoding_for_model("gpt-4o")
        tokens = encoding.encode(text)
        if len(tokens) <= max_tokens:
            return text
        return encoding.decode(tokens[:max_tokens])

RAGコンテキスト注入のベストプラクティス

RAGはContext Engineeringで最も落とし穴が多い部分です。

文書注入の3つの形式

形式1:XMLタグでラップ(推奨)

<retrieved_documents>
  <document source="product_manual_v3.pdf" score="0.92">
    製品保証期間は購入日から12ヶ月、人的損傷は保証対象外...
  </document>
  <document source="faq_returns.md" score="0.87">
    7日間の無条件返品は商品の完好性が必要、送料は購入者負担...
  </document>
</retrieved_documents>

形式2:番号付き引用(トレーサビリティ向け)

[1] 製品保証期間は購入日から12ヶ月...(出典:product_manual_v3.pdf)
[2] 7日間の無条件返品...(出典:faq_returns.md)

上記の参考資料に基づいて回答し、引用番号を明記してください。

RAGコンテキストの5つの鉄則

ルール 説明 違反時の影響
関連性閾値フィルタ 0.7未満の文書は注入しない ノイズ増加、幻覚増加
重複排除 同一文書の異なるChunkをマージ Token浪費
メタデータ保持 出典、時間、バージョンを明記 トレーサビリティ欠如
位置優先 最も関連性の高い文書を先頭に Lost in the Middle
動的Top-K 残り予算に応じてK値を調整 予算超過時のハード切り捨て

Lost in the Middle問題

スタンフォード大学の研究(2023年)により、関連情報がコンテキスト中央にあるとモデルのリコール精度が大幅に低下することが判明。本番での対策:

  • 最も関連性の高い2文書を先頭に配置
  • 次に関連する文書を末尾に配置
  • 中央にはシステムプロンプトやツール定義などの固定コンテンツ

コンテキスト圧縮と退避戦略

戦略1:スライディングウィンドウ

直近Nターンを保持。N=10-20を推奨。

戦略2:要約圧縮

SUMMARIZE_PROMPT = """以下の会話履歴を要約に圧縮してください。以下を保持:
1. ユーザーの核心的な要求と制約条件
2. 確認済みの重要事実(注文番号、製品型番など)
3. 未解決の問題

会話履歴:
{history}

要約(200字以内):"""

戦略3:構造化状態抽出

Agentシナリオでは、完全な会話ではなく構造化されたセッション状態を維持:

{
  "user_intent": "注文物流の確認",
  "entities": {"order_id": "ORD-20260703-8842"},
  "resolved": ["注文の存在を確認", "配送業者は順豊"],
  "pending": ["配達予定日"]
}

TokenコストがO(ターン数)からO(1)に削減されます。


Python本番向けContext Manager実装

class ProductionContextManager:
    def __init__(
        self,
        model: str = "gpt-4o",
        budget: ContextBudget = ContextBudget(),
    ):
        self.model = model
        self.budget = budget
        self.assembler = ContextAssembler(budget)
        self.conversation_history: list[dict] = []

    def build_context(
        self,
        user_input: str,
        system_prompt: str,
        retrieved_docs: Optional[list[dict]] = None,
        tools: Optional[list[dict]] = None,
    ) -> str:
        self.assembler.layers.clear()

        self.assembler.add_layer(ContextLayer(
            name="system", content=system_prompt,
            priority=0, max_tokens=4000, cacheable=True,
        ))

        if tools:
            tools_text = self._format_tools(tools)
            self.assembler.add_layer(ContextLayer(
                name="tools", content=tools_text,
                priority=1, max_tokens=6000,
            ))

        if retrieved_docs:
            docs_text = self._format_rag_docs(retrieved_docs)
            self.assembler.add_layer(ContextLayer(
                name="knowledge", content=docs_text,
                priority=2, max_tokens=20000,
            ))

        history_text = self._format_history()
        self.assembler.add_layer(ContextLayer(
            name="conversation", content=history_text,
            priority=3, max_tokens=30000,
        ))

        user_layer = f"<user_query>\n{user_input}\n</user_query>"
        self.assembler.add_layer(ContextLayer(
            name="current_input", content=user_layer,
            priority=4, max_tokens=4000,
        ))

        return self.assembler.assemble()

    def _format_rag_docs(self, docs: list[dict]) -> str:
        filtered = [d for d in docs if d.get("score", 0) >= 0.7]
        filtered.sort(key=lambda d: d["score"], reverse=True)
        parts = ["<retrieved_documents>"]
        for doc in filtered:
            parts.append(
                f'  <document source="{doc["source"]}" score="{doc["score"]:.2f}">\n'
                f'    {doc["content"]}\n'
                f'  </document>'
            )
        parts.append("</retrieved_documents>")
        return "\n".join(parts)

    def update_history(self, role: str, content: str) -> None:
        self.conversation_history.append({"role": role, "content": content})
        if len(self.conversation_history) > 40:
            self._compact_history()

    def _compact_history(self) -> None:
        old = self.conversation_history[:20]
        self.conversation_history = self.conversation_history[20:]
        summary = f"[Earlier conversation summary: {len(old)} messages condensed]"
        self.conversation_history.insert(0, {"role": "system", "content": summary})

面接頻出ポイントと落とし穴ガイド

よく聞かれる5つの質問

Q1:Context EngineeringとPrompt Engineeringの違いは?

Context Engineeringは入力コンテキスト全体の組織、予算、ライフサイクル管理を扱うシステムレベルの設計。Prompt Engineeringは単一プロンプトの文言最適化というテクニックレベルの最適化。本番では前者がシステムの稼働可否とコストを決定し、後者が回答品質を決定する。

Q2:128Kコンテキストなら圧縮不要?

いいえ。128Kは理論上限。実際にはコスト(Token課金)、レイテンシ(コンテキストが長いほど推論が遅い)、注意力減衰(Lost in the Middle)、マルチユーザー並行時のリソース競合を考慮する必要がある。本番では必ず予算管理が必要。

Q3:RAGで10文書すべて注入すべき?

いいえ。関連性フィルタ、重複排除、Rerank、予算に応じた動的Top-Kが必須。ノイズ文書は幻覚率を大幅に増加させる。

Q4:Prompt CachingとContext Engineeringの関係は?

Prompt Cachingはコスト最適化手段。Context Engineeringが何をキャッシュすべきかを決定する。システムプロンプトやツール定義はcacheable、会話層とRAG結果はキャッシュ不適。

Q5:マルチAgentシステムでのコンテキスト管理は?

各Agentが独立したContext Managerを維持。Agent間は完全な会話履歴ではなく構造化状態を渡す。Agent Aの完全なコンテキストをAgent Bに渡すとTokenが指数的に膨張する。

本番落とし穴チェックリスト

落とし穴 症状 対策
会話履歴の無制限蓄積 マルチターン後に遅延、超過切り捨て スライディングウィンドウ + 要約
RAGノイズ注入 回答がユーザーの質問から逸脱 関連性閾値 + Rerank
システムプロンプトの重複課金 APIコスト高騰 Prompt Caching
ツール定義の全量ロード 8K+ Tokenが未使用ツールに浪費 意図に応じた動的ロード
Token監視の欠如 コスト超過に後から気づく 呼び出しごとにusageメトリクス記録

マルチモデルコンテキストの差別化管理

TokenCounter インターフェースを抽象化。GPT の tiktoken で Claude の使用量を推定しない。

Prompt Caching 本番実践

システムプロンプトとツール定義をキャッシュ可能としてマーク。90% キャッシュヒット率で API コスト約 80% 削減。

企業カスタマーサービス改造事例

平均入力 Token 45K→12K、月額 API コスト ¥28万→¥9万、誤回答率 23%→6%。

Context Engineering vs ファインチューニング

80% の「モデル性能不足」はコンテキスト組織の問題。まず Context Engineering を最適化。

2026年トレンド

コンテキスト認識 Reranker、適応型 Token 予算、クロスセッション記憶、マルチモーダル管理、コンテキストセキュリティ。


まとめと関連記事

Context Engineeringは2026年のLLMアプリケーションがデモから本番へ移行する分岐点。中核は3つ:層別コンテキスト管理、厳格なToken予算、インテリジェントな圧縮退避

設計要点の振り返り

  1. コンテキストは4層:システム、ツール、知識、会話 — 各層に独立予算
  2. Token予算はハード制約、128Kウィンドウ≠無制限使用
  3. RAG注入はフィルタ、重複排除、ソート必須、Lost in the Middle回避
  4. 会話圧縮3戦略:スライディングウィンドウ、要約圧縮、構造化状態抽出
  5. Prompt Caching + Context Pipelineがコスト最適化のコンボ

関連記事

参考資料

ブラウザローカルツールを無料で試す →

#Context Engineering#LLM上下文工程#Prompt设计#RAG上下文#长上下文优化#2026