階層的要約
章 → セクション → 文書要約という段階的な圧縮を行います。
「階層的要約」はCoddyKit上の無料AI Prompt Engineeringレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Prompt Engineering学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Prompt Engineeringコースには全4レッスンが含まれています。
階層的要約とは
階層的要約は、ドキュメント自体の構造を反映します。すべてのチャンクを同じように扱うのではなく、内容をレベルごとに圧縮します。
- ページ → セクションの要約
- セクション → 章の要約
- 章 → ドキュメントの要約
各レベルは、1つ下のレベルを圧縮して表現したものです。これは、人が本を要約する方法と同じです。章を読み、頭の中で要約を作り、それらを統合します。
階層的要約を使う場面
階層的要約は、次のような場合に適しています。
- 書籍:明確な章構成を持つ200ページ以上の書籍
- 研究論文:要旨、序論、手法、結果、考察
- 法的契約書:定義、義務、解除など、見出しが明確なセクションを持つ契約書
- 技術レポート:エグゼクティブサマリー → 調査結果 → 付録
短い記事には過剰な方法です。ドキュメントが自然なツリー構造を持つ場合に特に効果を発揮します。
ドキュメントのツリー構造
ドキュメントをツリーとしてモデル化します。
- ルート:最終要約
- レベル1のノード:章の要約
- レベル2のノード:セクションの要約
- リーフ:元のページまたはチャンクのテキスト
要約は下から上へ進めます。リーフ → レベル2 → レベル1 → ルートの順です。各ノードの要約は、その子ノードの要約だけを基に作成します。
from dataclasses import dataclass, field
from typing import List, Optional
@dataclass
class DocNode:
title: str
content: str = ''
summary: str = ''
children: List['DocNode'] = field(default_factory=list)
# Example: book with 3 chapters, each with 3 sections
book = DocNode(
title='My Book',
children=[
DocNode('Chapter 1', children=[
DocNode('Section 1.1', content='...raw text...'),
DocNode('Section 1.2', content='...raw text...'),
]),
DocNode('Chapter 2', children=[
DocNode('Section 2.1', content='...raw text...'),
])
]
)ボトムアップ要約
ツリーを下から上へたどります。リーフノードは元の内容から要約し、内部ノードは子ノードの要約から要約します。
import openai
client = openai.OpenAI(api_key='sk-...')
def summarize_text(text, role='section'):
resp = client.chat.completions.create(
model='gpt-4o',
messages=[
{'role': 'system',
'content': f'Summarize this {role} in 3-5 sentences.'},
{'role': 'user', 'content': text}
]
)
return resp.choices[0].message.content
def summarize_tree(node, depth=0):
role = ['document', 'chapter', 'section', 'page'][min(depth, 3)]
if not node.children:
node.summary = summarize_text(node.content, role)
else:
for child in node.children:
summarize_tree(child, depth + 1)
combined = '\n\n'.join(
f'{c.title}:\n{c.summary}' for c in node.children
)
node.summary = summarize_text(combined, role)
return node.summary段階的な圧縮
段階的な圧縮とは、レベルが上がるごとに情報密度を下げることです。目安は次のとおりです。
- ページ(2000トークン) → セクションの要約(200トークン) — 10倍の圧縮
- セクションの要約(200トークン) → 章の要約(100トークン) — 2倍の圧縮
- 章の要約(100トークン × 5) → ドキュメント(150トークン) — 3倍の圧縮
合計1万トークンのドキュメントを、主要な論点を保ったまま約150トークンに圧縮できます。各レベルで圧縮率を維持するようプロンプトを指定してください。
PAGE_PROMPT = 'Summarize this page in 2-3 sentences (under 80 words).'
SECTION_PROMPT = 'Given these page summaries, write a section summary in 3-4 sentences (under 120 words).'
CHAPTER_PROMPT = 'Given these section summaries, write a chapter summary in 4-5 sentences (under 150 words).'
DOC_PROMPT = 'Given these chapter summaries, write an executive summary of the entire document (under 200 words).'レベル間の一貫性の維持
階層的要約には、同じレベルの要約同士が矛盾したり、内容を繰り返したりするリスクがあります。そして、こうした誤りは上位レベルへ積み重なります。一貫性を維持するための方法は次のとおりです。
- モデルがコンテキストを把握できるよう、プロンプトに親セクションの見出しを含めます
- 前のセクションの要約ですでに述べた事実を繰り返さないようモデルに指示します
- 最終的なreduceステップで、矛盾があれば解消するようモデルに明示的に指示します
def summarize_sections_for_chapter(chapter_title, section_summaries):
content = '\n\n'.join(
f'Section: {s["title"]}\n{s["summary"]}'
for s in section_summaries
)
prompt = (
f'Chapter: {chapter_title}\n\n'
'Below are summaries of each section. '
'Write a unified chapter summary without repeating '
'the same facts from multiple sections.\n\n' + content
)
resp = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': prompt}]
)
return resp.choices[0].message.content研究論文の階層構造
研究論文には、要旨 → 序論 → 手法 → 結果 → 考察 → 結論という自然な階層があります。各セクションには異なる役割があるため、セクションごとに専用のプロンプトを使用します。
SECTION_PROMPTS = {
'abstract': 'Summarize the paper abstract: what problem, method, and result?',
'introduction': 'Summarize the introduction: what gap does the paper address?',
'methods': 'Summarize the methods: what approach was used?',
'results': 'Summarize the results: what were the key findings and metrics?',
'discussion': 'Summarize the discussion: what do the results mean?',
'conclusion': 'Summarize the conclusion and future work.'
}
def summarize_paper(sections_dict):
section_summaries = {}
for section, text in sections_dict.items():
prompt = SECTION_PROMPTS.get(section, 'Summarize this section.')
section_summaries[section] = call_llm(prompt, text)
return section_summaries法的契約書の階層構造
法的契約書は、定義 → 義務 → 救済措置 → 解除 → 準拠法という条項の階層に従います。階層的要約では、次の内容を保持する必要があります。
- 正確な数値(支払額、期限)
- 当事者名(顧客、ベンダー、ライセンサー)
- 条件を示す表現(~でない限り、~の場合を除き、~を条件として)
数値や条件を含む条項を要約する際は、その条項にフラグを付けるようモデルに指示してください。こうすることで、誤って内容が削除されるのを防げます。
LEGAL_PROMPT = '''Summarize this contract clause in plain English.
Preserve: all monetary amounts, dates, party names, and conditionals.
Flag any obligation with [OBLIGATION] and any amount with [AMOUNT].'''
def summarize_clause(clause_text):
resp = client.chat.completions.create(
model='gpt-4o',
messages=[
{'role': 'system', 'content': LEGAL_PROMPT},
{'role': 'user', 'content': clause_text}
]
)
return resp.choices[0].message.content階層的要約の保存
ルートの要約だけでなく、要約ツリー全体を保存してください。これにより、次のことが可能になります。
- ドリルダウン — まず章の要約を表示し、必要に応じてセクションの要約を表示します
- 検索 — ドキュメント全体だけでなく、セクションの要約に対してユーザーのクエリを照合します
- 更新 — 1つのセクションが変更された場合、そのツリーの分岐だけを再要約します
import json
def tree_to_dict(node):
return {
'title': node.title,
'summary': node.summary,
'children': [tree_to_dict(c) for c in node.children]
}
def save_tree(node, path):
with open(path, 'w') as f:
json.dump(tree_to_dict(node), f, indent=2)
print(f'Saved summary tree to {path}')増分更新
ドキュメントを更新したとき、階層構造があれば増分再要約が可能になります。変更されたノードとその祖先だけを再要約すればよく、すべての兄弟分岐はそのまま有効です。
10章の書籍で第3章を改訂した場合は、第3章のセクション、第3章、書籍全体の順に再要約します。すべてのノードではなく、3つのノードだけを再計算できます。
def update_node(node, updated_child_title):
# Re-summarize the changed child
for child in node.children:
if child.title == updated_child_title:
summarize_tree(child) # re-summarize from leaves
break
# Re-summarize current node from updated children
combined = '\n\n'.join(
f'{c.title}:\n{c.summary}' for c in node.children
)
node.summary = summarize_text(combined)
return node.summaryフラット方式と階層方式の比較
フラットなmap-reduceと階層的要約を比較します。
- フラット:単純で、ドキュメント構造を考慮しません。均一なドキュメント(ニュース記事など)に適しています
- 階層方式:構造を尊重し、ドリルダウンを可能にします。構造化されたドキュメントで、より高い一貫性を実現できます
実際には、両方を組み合わせるのが効果的です。各章内(多数のページ)ではフラットなmap-reduceを使い、章をまたぐ処理では階層方式を使います。これは、現実のドキュメントに対する最も堅牢なアプローチです。
理解度チェック
階層的要約では、ドキュメントのツリーをどの方向に進みながら要約しますか?
振り返り:階層的要約
階層的要約はドキュメントの構造を反映するため、より優れた結果を得られます。
- ドキュメントをツリーとしてモデル化します:ページ → セクション → 章 → ドキュメント
- ボトムアップで要約します:リーフから始め、最後にルートを要約します
- 各レベルで段階的な圧縮を行い、一貫性を維持します
- 明確な階層構造を持つ書籍、研究論文、法的契約書に適しています
- ツリー全体を保存して、ドリルダウン検索と増分更新を可能にします
次のレッスンでは、オーバーラップとローリング要約を使ってチャンク間のコンテキストを維持する方法を扱います。
よくある質問
「階層的要約」レッスンは無料ですか?
はい。「階層的要約」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Prompt Engineeringコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Prompt Engineeringコースには全4レッスンが含まれています。
「階層的要約」で何を学びますか?
章 → セクション → 文書要約という段階的な圧縮を行います。 ブラウザで直接実行するハンズオンコードでAI Prompt Engineeringを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
AI Prompt Engineeringを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAI Prompt Engineeringは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「階層的要約」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAI Prompt Engineeringレッスンでコードを書いて実行できますか?
はい。すべてのAI Prompt Engineeringレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。