AI Prompt Engineering · レッスン

コンテキストの長さと関連性

包括的なコンテキストとトークン制限、関連性のバランスを取ります。

レッスン 4/413 ステップ

「コンテキストの長さと関連性」はCoddyKit上の無料AI Prompt Engineeringレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Prompt Engineering学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Prompt Engineeringコースには全4レッスンが含まれています。

コンテキストウィンドウの容量配分

すべてのモデルには最大コンテキストウィンドウがあります。これは、1回のAPI呼び出しで処理できるトークンの総数です。入力(プロンプト+履歴)と出力(モデルの応答)の両方が含まれます。

この容量を理解することは重要です。上限を超えると、プロンプトが切り詰められたり、出力が失われたりします。関係のないコンテキストに容量を使うと、重要な内容を推論する余地がモデルから失われます。

コンテキストウィンドウのサイズ

コンテキストの上限はモデルによって異なります。2025年時点では、次のとおりです。

  • GPT-4o:128,000トークン
  • Claude Opus 4.5:200,000トークン
  • Gemini 1.5 Pro:1,000,000トークン
  • GPT-3.5 Turbo:16,385トークン

ウィンドウが大きいほど多くのコンテキストを含められますが、1回の呼び出しにかかるコストも増えます。ほとんどのタスクでは8,000-16,000トークンで十分です。関係のない内容まで含めるのであれば、大きいほどよいとは限りません。

import tiktoken

def estimate_tokens(text, model='gpt-4o'):
    encoding = tiktoken.encoding_for_model(model)
    return len(encoding.encode(text))

# Quick token budget calculator
models = {
    'GPT-3.5 Turbo':  16385,
    'GPT-4o':        128000,
    'Claude Opus 4.5': 200000,
}

prompt = 'Explain the concept of technical debt in 500 words for a non-technical CEO.'
prompt_tokens = estimate_tokens(prompt)

for model_name, limit in models.items():
    reserved_for_output = 1024
    available = limit - prompt_tokens - reserved_for_output
    print(f'{model_name}: limit={limit:,} | prompt={prompt_tokens} | '
          f'context budget={available:,} tokens')

含める情報:関連性の評価

コンテキストの情報を含める前に、次のように問いかけてください。この情報は回答を変えるか。

各コンテキスト要素を評価するための、シンプルな考え方は次のとおりです。

  • 関連性が高い(含める):タスクに直接影響し、使用する語彙を決め、選択肢を制限する
  • 関連性が中程度(場合によって含める):有用な情報を加えるが、なくても出力に問題はない
  • 関連性が低い(除外する):事実ではあるが、回答にまったく影響しない
def score_context_element(element, task):
    '''
    Heuristic: does this context element directly constrain or shape the answer?
    Returns: HIGH / MEDIUM / LOW
    '''
    high_signals = ['stack', 'constraint', 'deadline', 'must', 'cannot', 'budget',
                    'audience', 'goal', 'version', 'scale', 'limit']
    low_signals  = ['founded', 'headquartered', 'fun fact', 'history', 'awards',
                    'team building', 'company culture', 'office location']

    el_lower = element.lower()
    if any(s in el_lower for s in high_signals):
        return 'HIGH'
    if any(s in el_lower for s in low_signals):
        return 'LOW'
    return 'MEDIUM'

context_elements = [
    'Our stack is Python FastAPI and PostgreSQL',
    'We cannot use any paid third-party APIs',
    'Our company was founded in Berlin in 2020',
    'We need the solution to handle 1000 requests/second',
    'We won a startup award last year',
]

for el in context_elements:
    score = score_context_element(el, task='optimize our API')
    print(f'[{score:6}] {el}')

中間が失われる問題

研究により、LLMは非常に長いプロンプトの中間に置かれた情報にあまり注意を払わないことが示されています。50,000トークンのプロンプトの中間に置かれた重要なコンテキストは、部分的に無視される可能性があります。

ベストプラクティスは、最も重要なコンテキストをプロンプトの冒頭または末尾に置くことです。モデルはこれらの位置に最も強く注意を向けます。

import anthropic

client = anthropic.Anthropic(api_key='sk-ant-your-key-here')

# Structure: critical constraint at the TOP, then the body, then the task
well_structured_prompt = (
    # Critical constraint FIRST
    'CRITICAL CONSTRAINT: Output must be under 50 words and contain no code.\n\n'
    # Background in the middle
    'Background: we are explaining our API rate limiting policy to non-technical support agents. '
    'They handle billing inquiries and need to explain errors to customers. '
    'Our rate limit is 100 requests per minute per API key.\n\n'
    # Task at the end
    'Task: Write the explanation.'
)

response = client.messages.create(
    model='claude-opus-4-5',
    max_tokens=128,
    messages=[{'role': 'user', 'content': well_structured_prompt}]
)
print(response.content[0].text)

長いドキュメントを分割する

トークン予算を超える長さのドキュメントを扱う必要がある場合、次の3つの方法があります。

  • まず要約する:モデルにドキュメントを圧縮させ、その後は要約を使って作業する
  • 分割して処理する:ドキュメントを分割し、それぞれを処理してから結果を組み合わせる
  • 抽出して組み込む:プロンプトに含める前に、関連するセクションだけを抽出する

コンテキストウィンドウを超えるドキュメントを無理に入れようとしてはいけません。暗黙に切り詰められてしまいます。

import anthropic

client = anthropic.Anthropic(api_key='sk-ant-your-key-here')

def chunk_and_summarize(long_text, chunk_size=2000):
    '''Split text into chunks, summarize each, combine summaries.'''
    words = long_text.split()
    chunks = []
    for i in range(0, len(words), chunk_size):
        chunk = ' '.join(words[i:i + chunk_size])
        chunks.append(chunk)

    summaries = []
    for idx, chunk in enumerate(chunks):
        response = client.messages.create(
            model='claude-opus-4-5',
            max_tokens=256,
            messages=[{
                'role': 'user',
                'content': f'Summarize this section in 3 bullet points:\n\n{chunk}'
            }]
        )
        summaries.append(f'Section {idx+1}:\n{response.content[0].text}')

    return '\n\n'.join(summaries)

# Example usage
long_doc = 'word ' * 5000  # placeholder for a real document
print('Chunks needed:', len(long_doc.split()) // 2000 + 1)

実践での関連性フィルタリング

関連性フィルタリングとは、大きなドキュメントをプロンプトに含める前に、関連する部分だけを抽出することです。これは特に次のような場合に重要です。

  • 1つのセクションだけが関連する長いレポート
  • 1つの関数だけをレビューするコードファイル
  • 最後の3通だけが重要なメールスレッド
  • 50個のテーブルのうち2個だけが関連するデータベーススキーマ
import openai

client = openai.OpenAI(api_key='sk-your-key-here')

# Step 1: Filter first, then ask
full_schema = (
    'Table: users (id, name, email, created_at, role)\n'
    'Table: products (id, name, price, stock, category_id)\n'
    'Table: orders (id, user_id, total, status, created_at)\n'
    'Table: order_items (id, order_id, product_id, quantity, unit_price)\n'
    'Table: categories (id, name, parent_id)\n'
    'Table: reviews (id, product_id, user_id, rating, body)\n'
    'Table: sessions (id, user_id, token, expires_at)'
)

# Only include relevant tables for the specific question
relevant_context = (
    'Relevant tables for this query:\n'
    'Table: orders (id, user_id, total, status, created_at)\n'
    'Table: order_items (id, order_id, product_id, quantity, unit_price)\n'
)

response = client.chat.completions.create(
    model='gpt-4o',
    messages=[{
        'role': 'user',
        'content': f'{relevant_context}\nWrite SQL to find the top 5 orders by total value this month.'
    }]
)
print(response.choices[0].message.content)

会話履歴を管理する

複数ターンの会話では、ターンごとに履歴が増えていきます。履歴を賢く管理すると、トークン予算を適切に保てます。

  • スライディングウィンドウ:直近のNターンだけを保持する
  • 要約の挿入:古いターンを定期的に1つのメッセージに要約する
  • 重要事実の抽出:重要な決定事項を箇条書きで追跡し、システムコンテキストとして挿入する
  • 話題が変わったらリセット:関係のない話題に移るときは新しいセッションを開始する
import openai

client = openai.OpenAI(api_key='sk-your-key-here')

def summarize_history(old_history):
    '''Compress old conversation turns into a brief summary.'''
    history_text = '\n'.join(
        f'{m["role"].upper()}: {m["content"]}' for m in old_history
    )
    response = client.chat.completions.create(
        model='gpt-4o',
        max_tokens=200,
        messages=[{
            'role': 'user',
            'content': (
                'Summarize this conversation history in 3 bullet points. '
                'Focus on decisions made and key information established.\n\n'
                + history_text
            )
        }]
    )
    return response.choices[0].message.content

# Example: compressing old history before continuing
old_turns = [
    {'role': 'user',      'content': 'We are building a Kanban app.'},
    {'role': 'assistant', 'content': 'Great, what is your stack?'},
    {'role': 'user',      'content': 'React + FastAPI + PostgreSQL.'},
    {'role': 'assistant', 'content': 'Good choice for a Kanban app.'}
]
summary = summarize_history(old_turns)
print('Summary of old history:', summary)

コンテキストを圧縮する技法

多くのコンテキストを含める必要がある一方で、トークン予算が厳しい場合は、圧縮の技法を使用してください。

  • 文章より箇条書き:箇条書きは文章より30-50%トークン効率が高い
  • 既知の用語を略す:最初に使った後は「PostgreSQL 15」→「PG15」とする
  • 冗長な表現を削除する:「注目すべき点として…」→事実だけを述べる
  • 構造化形式を使う:key:valueの組は文章より密度が高い
import tiktoken

def count_tokens(text):
    enc = tiktoken.encoding_for_model('gpt-4o')
    return len(enc.encode(text))

# Same information, different token counts
prose_context = (
    'Our company is a startup that was founded recently and we are building '
    'a data analytics platform. It is worth noting that we use Python for our backend. '
    'Additionally, we have chosen PostgreSQL as our primary database. '
    'Furthermore, we deploy on AWS using ECS containers.'
)

bullet_context = (
    'Company: data analytics startup\n'
    'Stack: Python backend, PostgreSQL, AWS ECS'
)

print('Prose context tokens: ', count_tokens(prose_context))
print('Bullet context tokens:', count_tokens(bullet_context))
print('Tokens saved:', count_tokens(prose_context) - count_tokens(bullet_context))
print('Same information? Yes — same facts, 60% fewer tokens')

動的なコンテキスト選択

本番環境のAIアプリケーションでは、現在のクエリに最も関連する情報に基づいて、コンテキストを動的に選択することがよくあります。これはRetrieval-Augmented Generation(RAG)と呼ばれます。

すべてのドキュメントを含めるのではなく、ユーザーの質問と意味的に最も近いものだけを取得してプロンプトに挿入します。これにより、コンテキストを簡潔で関連性の高いものに保てます。

# Simplified RAG pattern: retrieve relevant chunks, inject into prompt
import openai

client = openai.OpenAI(api_key='sk-your-key-here')

# Simulated knowledge base (in production: vector database)
knowledge_base = [
    {'id': 1, 'topic': 'billing',   'text': 'Refunds are processed within 5-7 business days.'},
    {'id': 2, 'topic': 'shipping',  'text': 'Standard shipping takes 3-5 days.'},
    {'id': 3, 'topic': 'returns',   'text': 'Returns accepted within 30 days with receipt.'},
    {'id': 4, 'topic': 'warranty',  'text': 'All products come with a 1-year warranty.'},
]

def get_relevant_docs(user_query, kb, top_k=2):
    '''Simplified relevance: keyword match. Production uses embeddings.'''
    scored = [(doc, sum(w in user_query.lower() for w in doc['topic'].split())) for doc in kb]
    scored.sort(key=lambda x: x[1], reverse=True)
    return [doc['text'] for doc, _ in scored[:top_k]]

query = 'Can I return this and get my money back?'
relevant = get_relevant_docs(query, knowledge_base)
context = '\n'.join(relevant)
print('Injected context:', context)
response = client.chat.completions.create(
    model='gpt-4o', max_tokens=80,
    messages=[{'role': 'user', 'content': f'Context:\n{context}\n\nQuestion: {query}'}]
)
print('Answer:', response.choices[0].message.content.strip())

コンテキスト予算の計画

本番環境のアプリケーションでは、構築前にコンテキスト予算を明確に計画してください。

  • 出力用にコンテキストウィンドウの25%を確保する
  • システムメッセージとペルソナ用に10%を割り当てる
  • 直近の会話履歴用に30%を割り当てる
  • 動的なコンテキスト(取得したドキュメントや挿入データ)用に35%を残す

用途の変化に応じて簡単に調整できるよう、これらの割り当てをコード内の定数として記録しておきましょう。

# Context budget planner
MODEL_LIMIT = 128000  # GPT-4o

BUDGET = {
    'output_reserve':  int(MODEL_LIMIT * 0.25),  # 32,000 tokens
    'system_message':  int(MODEL_LIMIT * 0.05),  # 6,400 tokens
    'recent_history':  int(MODEL_LIMIT * 0.30),  # 38,400 tokens
    'dynamic_context': int(MODEL_LIMIT * 0.35),  # 44,800 tokens
    'task_prompt':     int(MODEL_LIMIT * 0.05),  # 6,400 tokens
}

total_input = sum(v for k, v in BUDGET.items() if k != 'output_reserve')
print('Context budget plan:')
for key, tokens in BUDGET.items():
    pct = round(tokens / MODEL_LIMIT * 100)
    print(f'  {key:<20}: {tokens:>7,} tokens ({pct}%)')
print(f'  {"total input":<20}: {total_input:>7,} tokens')
print(f'  {"+ output reserve":<20}: {BUDGET["output_reserve"]:>7,} tokens')
print(f'  {"= model limit":<20}: {MODEL_LIMIT:>7,} tokens')

長さより関連性が重要な場合

関連性が非常に高い500トークンのコンテキストは、関連性が低い5,000トークンのコンテキストを上回ります。モデルが大量の情報をかき分ける必要がなければ、より良い出力を生成できます。

コンテキストが長すぎて焦点が絞られていないことを示す兆候は次のとおりです。

  • モデルが制約の一部を無視する
  • コンテキストが長いのに、出力が一般的な内容に感じられる
  • モデルが質問の間違った部分を扱う
  • レイテンシーとコストが予想より高い

このような兆候が見られたら、コンテキストを絞り込んで再実行してください。

import anthropic

client = anthropic.Anthropic(api_key='sk-ant-your-key-here')

# Demonstrating: lean context produces sharper output
lean_context = (
    'Task: write a 50-word product tagline.\n'
    'Product: CLI tool that auto-generates Git commit messages from your diff.\n'
    'Audience: senior developers who hate writing commit messages.\n'
    'Tone: dry, witty, technical.'
)

response = client.messages.create(
    model='claude-opus-4-5',
    max_tokens=100,
    messages=[{'role': 'user', 'content': lean_context}]
)
print('Lean context output:')
print(response.content[0].text.strip())

知識チェック

ある開発者が、20ターン分の会話履歴を持つチャットボットを構築しています。20ターン後、コンテキストウィンドウがいっぱいになりかけています。重要なコンテキストを失わずに会話を続けるための最善の方法は何ですか。

コンテキストの長さと関連性 — まとめ

コンテキストを効果的に管理することは、プロンプト作成の中核的なスキルであり、本番環境のアプリケーションでは特に重要になります。主な原則は次のとおりです。

  • すべてのコンテキスト要素を高・中・低の関連性で評価し、高いものだけを含める
  • 重要な制約は中間ではなく、冒頭または末尾に置く
  • 文章より箇条書き形式を使い、30-50%のトークンを節約する
  • 予算を超えるドキュメントは要約または分割する
  • 複数ターンの会話では、最初からやり直すのではなく古い履歴を圧縮する
  • コンテキスト予算をコード内の定数として明示的に計画する
無料で開始

AI チューターと学ぶ AI Prompt Engineering — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
53
レッスン
199

よくある質問

「コンテキストの長さと関連性」レッスンは無料ですか?

はい。「コンテキストの長さと関連性」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Prompt Engineeringコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Prompt Engineeringコースには全4レッスンが含まれています。

「コンテキストの長さと関連性」で何を学びますか?

包括的なコンテキストとトークン制限、関連性のバランスを取ります。 ブラウザで直接実行するハンズオンコードでAI Prompt Engineeringを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

AI Prompt Engineeringを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのAI Prompt Engineeringは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「コンテキストの長さと関連性」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このAI Prompt Engineeringレッスンでコードを書いて実行できますか?

はい。すべてのAI Prompt Engineeringレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. AI プロンプトにおけるコンテキストとは
  2. 背景情報を提供する
  3. 効果的に状況を設定する
  4. コンテキストの長さと関連性
← AI Prompt Engineeringに戻る