本番AI Agentのコンテキスト圧縮
メッセージ切り詰め、ツール結果の整理からHermes Agentの階層的Compactionまで
要約
AI Agentが検索、ファイル、端末、ブラウザ、データベースを繰り返し呼び出すと、コンテキストは増え続けます。問題は最終的に収まらなくなることだけではありません。各ターンの入力token、コスト、first-token遅延が増え、古いツール出力・重複ログ・解決済みの問題が有効情報を薄め、制約を忘れたり、同じツールを再実行したり、失敗済みの方法を試し直したりします。一方で履歴を乱暴に削除すれば、長いタスクの連続性が壊れます。
本番向けコンテキスト圧縮の目的は、できるだけ短い要約を作ることではありません。
Agentが正しく、安全に、検証可能な形で作業を続けるために必要な状態を、できるだけ少ないactive tokenで保持することです。
本稿は『深入理解 AI Agent:设计原理与工程实践』第2.7節を読解の軸とし、2026年7月までのOpenAI、Anthropic、LangChain v1、Google ADK、Hermes Agentの公式資料と現行ソースを再確認します。書籍の方法論、現行製品・フレームワーク、Hermes Agentのmainブランチの実挙動、本番へ直接適用できる工学的提案を区別します。
1. なぜコンテキスト圧縮が必要か
1.1 ハード制約:コンテキストウィンドウには限界がある
典型的なAgent loopは、ユーザー要求、モデルのツール呼び出し、ツール結果、分析、次のツール呼び出しを追加し続けます。ウィンドウを実際に圧迫するのは、ユーザーの発話よりも、数万tokenを返すWebページやPDF、大きなログ、多数のソースファイル、ブラウザのスナップショットとマルチモーダル添付、ファイル全文を含むツール引数、過去のreasoning・メタデータ・ベンダーのreplay fieldです。上限を超えればリクエストは失敗し得ます。上限未満でもセッションが健全とは限りません。
1.2 ソフト劣化:収まることと、うまく使えることは違う
LangChain v1は、履歴が収まっていても古く脱線した内容がモデルを妨げ、遅延とコストを増すと明記しています。Anthropicは、コンテキスト膨張で有効情報の利用率が下がる現象を context rot と呼びます。1 2
コンテキスト容量:まだ余裕がある
情報密度:継続的に低下する
モデルの注意:古いログ、重複結果、無関係な詳細に分散する
圧縮はcontext_length_exceeded回避だけでなく、各判断で見える情報密度を上げるためにも必要です。
1.3 長期Agentに必要なのは会話要約ではなくタスク引き継ぎ
「返金について話し、注文を調べ、助言した」という会話要約では作業を再開できません。必要なのはcheckpoint / handoffです。
active_goal: 返金APIの重複請求を修正する
constraints:
- データベースschemaを変更しない
- APIの後方互換性を保つ
completed:
- 並行リクエストで重複請求を再現した
- payment/idempotency.pyを特定した
- idempotency key検証を追加した
failed_attempts:
- Redis TTLだけではrace conditionが残る
verification:
unit_tests: "47/50 passed"
failing:
- test_concurrent_refund
- test_retry_after_timeout
- test_duplicate_webhook
modified_files:
- payment/idempotency.py
- tests/test_refund.py
remaining:
- 3件の並行テストを修正する
- 完全な回帰テストを実行する
これは「今どの状態にあり、次のAgentターンがどう続けるか」を答えるものであり、「過去に何を話したか」ではありません。
2. 混同してはいけない4概念
コンテキスト圧縮 / Compaction
次のモデルターンで実際に見えるactive contextを変えます。古い内容を削除、外部化、または要約に置換します。
Prompt Cache
キャッシュは必ずしもコンテキスト長を減らしません。80,000 tokenのリクエストでも、同一の60,000-token prefixはprefill計算を再利用できます。キャッシュは「再計算しない」ため、圧縮は「ずっと持ち続けない」ためのものです。
長期記憶
ユーザーの好み、業務上の事実、経験をセッションをまたいで残します。現在タスクの状態を置き換えたり、全履歴をsystem promptへ恒久的に詰め込んだりしてはいけません。
RAGとArtifact Retrieval
完全な原文はモデル外に保存し、active contextには要約、artifact_id、出所、再取得方法だけを置きます。圧縮の損失を抑える最も重要な基盤です。
3. 主なコンテキスト圧縮手法
本番システムは通常、安価なものから賢いものへ、複数手法を組み合わせます。
3.1 メッセージ切り詰めとsliding window
最近の一定メッセージ数またはtoken数だけを残し、system prompt、必要なら最初のタスク、最後の実ユーザー要求を保持します。tool_callと対応するtool_resultは分割しません。LangChain v1は、trim messages、永久削除、要約を短期記憶の基本パターンとして挙げます。1
追加LLM呼び出しが不要で高速・安価・決定的であり、要約幻覚もないため、overflowの最後の安全網になります。ただし早期の制約や決定が消え、重複呼び出しや失敗案の再試行を招きます。通常のチャット、独立性の高い単純ターン、または他方式のfallbackに向きます。
3.2 決定的フィルタリングとノイズ除去
コードで明確な低価値情報を削除します。重複ログ行、Webのナビゲーション・広告、空結果、処理済みstreaming delta、反復するstatus通知、再計算可能な統計、期限切れ進捗などです。
def should_drop(message) -> bool:
return (
message.is_empty
or message.is_duplicate
or message.kind in {"heartbeat", "stream_delta"}
or message.expired
)
LLMコストがなく、挙動が安定してテストしやすく、ほぼ全ての本番Agentで最初の層に置くべきです。規則で認識できるノイズだけを扱え、過剰削除の恐れがあり、履歴中間の書換えは以後のPrompt Cacheを壊します。
3.3 ツール結果の整理と降格
ツールを呼んだ記録は残し、巨大な結果本文だけを短い再取得可能な記録に置き換えます。
assistant:
read_file("server.log")
tool:
[read_file] server.log、50,000行;
DatabaseTimeoutを127回、PermissionDeniedを3回検出;
完全な内容:artifact://logs/run-103
AnthropicのContext EditingとTool-result Clearingはこの系統です。2 ツール集約型Agentで大きな効果があり、LLMなしでも意思決定の軌跡を保てます。ただし、ツールがなお利用可能で、同じ入力から同等の結果を得られ、再取得コストが許容でき、データ源が残る場合にのみ低損失です。リアルタイム価格、一回限りの認可、短命のWebページ、不可逆取引結果は回復できないことがあります。
3.4 大きな内容をArtifactへ外部化する
大きな対象を最初から主コンテキストに入れません。200 MBのログをファイル、object store、databaseに保存し、ID、型、サイズ、構造化統計、少量preview、利用可能なqueryだけを置きます。
artifact_id: "artifact://pytest/run-20260726-103"
type: "test_log"
lines: 58321
summary:
passed: 128
failed: 2
failures:
- test_refund_timeout
- test_duplicate_webhook
available_operations:
- grep
- read_lines
- download
OpenAIは、大きなresourceをcontainer filesystemまたはdatabaseに置き、Agentが必要に応じてファイルを開きqueryを実行する方式を推奨しています。3 コード、端末ログ、ブラウザページ、PDF、DB結果、大きなJSON、画像、スクリーンショットに適しますが、Artifact Store、アクセス制御、ライフサイクル管理、安定した参照が必要です。
3.5 ローリング構造化要約
安定したheadを原文のまま残し、古いmiddleの軌跡をcheckpointへ圧縮し、最近のraw tailを残します。
System Prompt
+ 初期タスク / 重要制約
+ Structured Checkpoint
+ 最近の原文メッセージ
LangChain v1のSummarizationMiddleware、Google ADKのContext Compaction、Hermesのdefault compressorはこの設計です。1 4 5 目標、決定、進捗、未完了作業を維持しながら大きく縮められますが、本質的に有損で、追加LLMを要し、数値・path・error・境界条件を落とし得ます。要約の再要約はdriftも招きます。
checkpointにはhistorical_task、goal、constraints、completed_actions、active_state、blocked、key_decisions、resolved_questions、relevant_files、critical_context、remaining_work、source_refsなどを推奨します。「少し変更し、問題が少し残る」という散文では不十分です。
3.6 タスク認識型圧縮
単に履歴を要約させるのではなく、現在のタスク、いま答えるべき問い、確認済み事実、未確定事項、改変禁止のfield、将来追跡すべきsourceを入力します。情報密度が上がり、既知・未知・衝突・次の行動を分けられるため、Deep Research、調査、debug、受入基準が明確なCoding Agent、長い業務処理に向きます。一方、短期目標に過剰適合し、タスク変更後に削除済み情報が再び重要になる危険があります。
3.7 引用付き・追跡可能な要約
重要な事実ごとにsource handleを残します。
facts:
- claim: "サービスは14:32以降timeoutを起こし始めた"
source_ids:
- "artifact://logs/prod-103#L820-L912"
confidence: high
verified: true
要約自体は有損でもsource indexは可能な限り無損です。企業RAG、法務、金融、研究、運用、データ分析など、citationとauditが必要な場面に向きます。stable Artifact ID、権限、保持が必要で、引用があることは要約の正しさを保証しません。
3.8 ベンダー提供のネイティブCompaction
OpenAI。 Responses APIはresponses.compactによるネイティブcompactionを提供し、Agents SDKのOpenAIResponsesCompactionSessionが利用します。type=compaction itemには不透明なencrypted_contentが入ることがあり、Codexは長時間coding taskの継続にこの機構を使います。3 6 7 モデル訓練と内部状態に適合し実装コストも低い一方、監査が難しくvendor lock-inがあります。低遅延用途では、stream終了を阻害し得る自動圧縮より、idle時またはturn間の手動圧縮が適することがあります。
Anthropic。 Anthropicは長い会話でserver-side Compactionを推奨し、再送可能なcompaction blockを生成します。Context Editingはツール結果など特定内容を細かく扱います。これらはbetaであり、現在の公式資料を確認すべきです。8 2 server側token計算、明示的message type、要約指示のカスタマイズを得られますが、有損でありAPI変更の可能性があります。default promptを完全に置き換えるなら、開発者が完全な保持規則を用意しなければなりません。
単一vendorに深く結び付き迅速に導入したいならnative compactionを先に評価します。監査、cross-vendor、厳密なfield制御が必要ならclient-side structured checkpointを使います。clientがcanonical stateを維持し、providerがmodel trajectoryを管理する併用も可能です。
3.9 TokenレベルPrompt Compression
LLMLingua、LongLLMLingua、LLMLingua-2は、新しい要約を書くのではなく、低情報量のtokenやphraseを削除・並べ替えます。
original: The system encountered a very serious database connection timeout.
compressed: system encountered serious database connection timeout
LLMLinguaは小型言語モデルでtoken重要度を評価し、LLMLingua-2はtoken classificationとして圧縮を扱います。9 10 自然言語のRAG背景、議事録、原文へ戻れる資料には使えますが、否定、限定、正確な数値を落とし、JSON、コード、SQL、tool parameterを壊す恐れがあります。2026年の大規模実測は、入力長、圧縮率、hardwareが一致するときだけend-to-end加速が得られ、他ではcompressorのoverheadが利得を相殺し得ると示しました。11
Tool Call JSON、Tool Resultの構造field、コードとSQL、UUID、hash、path、port、安全方針、hard business constraint、金額、日付、法的文言は、専用評価なしに圧縮してはいけません。
3.10 子Agentによるコンテキスト隔離
これは事後圧縮というより、ノイズを主コンテキストに入れない方法です。検索子Agentが多数のファイルを読みgrepを実行し、入口ファイル、重要関数、call site、test位置、confidenceだけを返します。主Agentは高密度の結論だけを扱えます。コード検索と複数sourceの調査に特に有効ですが、完全なtask説明、追加モデル呼び出し、reportの漏れ、より複雑なschedule・timeout・error処理を要します。
4. 比較
| 手法 | 損失 | 追加LLM | 圧縮力 | 主なリスク | 適する場面 |
|---|---|---|---|---|---|
| Sliding window | 高い | なし | 中 | 重要履歴を失う | 単純chat、最後のfallback |
| 決定的filter | 低い | なし | 低〜中 | ruleの誤削除 | 全Agentの第1層 |
| Tool-result cleanup | 条件付きで低損失 | なし | 高い | 再取得不能 | tool-heavy Agent |
| Artifact外部化 | 低い | なし | 非常に高い | 参照切れ | file、log、page、image |
| 構造化ローリング要約 | 中 | あり | 非常に高い | 漏れとdrift | 汎用長時間Agent |
| タスク認識要約 | 中〜高 | あり | 非常に高い | task切替で不足 | research、debug、coding |
| 引用付き要約 | 比較的低い | あり | 中〜高 | 基盤の複雑さ | enterprise、audit |
| Native compaction | 実装依存 | server側 | 非常に高い | 不透明性、lock-in | 単一vendorの長タスク |
| Token-level圧縮 | 中 | 小型model | 高い | 厳密構造を壊す | 自然言語RAG |
| 子Agent隔離 | 低い | あり | 非常に高い | report漏れ | coding、Deep Research |
5. 本番の最適解:一つを選ばず階層pipelineを設計する
完全な原始軌跡 / Artifact Store
│
▼
1. Admission Control:大きな内容を入口で外部化し、構造化previewを返す
▼
2. Deterministic Cleanup:重複除去、ノイズ削除、再取得可能なtool resultの整理
▼
3. Canonical State Projection:TODO、count、phase、verificationをコードで保持
▼
4. Structured Compaction:古いmiddleをtask checkpointへ
▼
5. Recent Raw Tail
▼
6. LLM
モデルのコンテキストを唯一の事実源にしてはいけません。PostgreSQL、LangGraph State、Redisなどに決定的で検証可能なcanonical stateを置き、完全なartifactを別に保存し、簡潔なactive projectionだけをモデルへ渡します。
順序はcheap-firstです。重複除去、明確なノイズ削除、大対象の外部化、tool resultの降格、state bar、LLM要約、全量Compaction。要約は結論を保つ一方、最新対話の微妙な語調、指示対象、暫定状態は苦手なので、最近のraw tailを常に残します。tool callとresultは完全なgroupで保持します。
50%、70%、80%を固定値として写してはいけません。安全なtriggerは、context window、予約output、想定tool burst、safety margin、system promptとtool schema、multimodal添付、vendor replay fieldを考慮します。hysteresis、圧縮後のtarget水位、minimum reclaim、cooldown、無効圧縮circuit breakerも設定します。
圧縮はatomicに行います。messageを複製し、複製上で圧縮し、checkpointとmessage構造を検証してから一度にcommitします。失敗したら原sessionを残し、alert、cooldown、summary model切替を行います。path、URL、UUID、commit hash、issue番号、DB primary key、金額、日付、port、完全なerror code、test名、versionなどの厳密identifierは、free-form要約に任せず、コードで抽出・構造化保存するか原文保持します。履歴要約には時刻とtask境界を付け、最新の実ユーザーmessageを最高権威にします。
6. Hermes Agent:階層圧縮の実例
6.1 差し替え可能なContext Engine
Hermesはコンテキスト管理をContextEngineとして抽象化します。defaultは有損のContextCompressorで、LCMなど別engineはpluginで明示的に選びます。モデルごとのwindowやcache特性、監査・保真性の要求、戦略の独立評価と置換を考えると、agent loopへ圧縮を固定で書くより合理的です。5
6.2 二層のtrigger
公式資料は、Agent処理前に約85%で働くGateway Session Hygieneの安全網と、Agent Loop内で実API tokenを使い、文書上のdefaultが50%のContextCompressorを説明します。しかし「default 50%」は全modelの実際の圧縮点ではありません。現行資料とsourceには、modelごとのoverride、512K未満windowでのraise-only 75% floor、特定Codex routeの自動調整、Codex app-serverのnative thread compactionがあります。5 12
6.3 現行sourceの決定的な事前圧縮
LLM要約の前に、現行mainはbyte完全一致のtool resultを重複除去し、古い巨大resultをtool固有の1行要約にし、terminal command、exit code、line数、file path、read offset、content size、search条件、hit数を保持します。巨大なTool Call parameterはJSONを有効に保って切り詰め、深刻なpressure下では保護tail内の完了済み巨大outputも降格し、古いimageをplaceholderへ置換し、trimされたSkillには決定的reload markerを挿入します。12
6.4 Head / Middle / Tailと境界付き要約入力
Hermesはsystem promptと初期anchorをheadとして原文保持し、古いtask軌跡のmiddleを要約し、token budgetと最小message数で最近tailを保護します。境界はtool callとresultのpairを保つようにします。現行mainは無制限のmiddle全体を要約modelへ送らず、各message本文とtool-call argumentをtruncateし、要約用全sequenceを約160,000文字に制限しつつ先頭・末尾を残して省略印を付けます。要約は圧縮内容の約20%を目標とし、output上限は旧12,000ではなく現在10,000 tokenです。12
6.5 Agent handoff、旧タスクの再起動防止、失敗処理
Historical Task SnapshotはGoal、Constraints & Preferences、Completed Actions、Active State、Blocked、Key Decisions、Resolved Questions、Relevant Files、Critical Context、Pruned Skillsを含み、具体的path、commandと結果、test通過・失敗数、error、技術判断、環境・process、Skill reload指示を重視します。12
要約はREFERENCE ONLYと印付けされます。最新の実ユーザーmessageだけが現在タスクの権威であり、過去に完了した要求を再実行してはいけません。新しいstop、undo、never mindは古いplanを止めます。task anchorは例や要約からでなく、実ユーザーmessageから決定的に抽出されます。
次回Compactionでは旧要約と新しい完了作業、error、verificationを合わせ、進行中を完了へ移し、古い状態を更新します。現行sourceには、圧縮境界のredaction、URL credentialとsecretの除去、inline thinking除去、空要約検出、認証・network等の失敗時abort、cooldown、fallback count、anti-thrashing、providerの実tokenによる事後検証、tool call/resultのorphan cleanupがあります。12
長所はcheap-first、対象を絞ったtool result降格、最近軌跡の原文保持、構造化handoff、cache考慮、model別threshold、交換可能compressor、失敗経路の厚さです。リスクは、構造化要約もなお有損でdriftすること、source更新が高水準文書より速いこと、弱い補助summary model、巨大な静的system/tool prefix、低すぎるthresholdによる頻繁な圧縮とcache失効です。
7. LangChain v1 / LangGraph v1での実装
7.1 単純な場合:SummarizationMiddleware
from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware
from langgraph.checkpoint.memory import InMemorySaver
agent = create_agent(
model="gpt-5.4",
tools=[],
middleware=[
SummarizationMiddleware(
model="gpt-5.4-mini",
trigger=("tokens", 40_000),
keep=("messages", 20),
)
],
checkpointer=InMemorySaver(),
)
これはprototypeと一般chatには適します。本番ではmemoryではなくPostgreSQLなど永続的checkpointerを使うべきです。1
7.2 Tool-heavy Agent:階層custom middleware
from typing import TypedDict
class AgentState(TypedDict):
messages: list
active_goal: str
constraints: list[str]
todo: list[dict]
tool_counts: dict[str, int]
modified_files: list[str]
verification: dict
artifact_refs: list[dict]
compaction_version: int
from copy import deepcopy
def compact_context(messages, state, policy):
original = messages
working = deepcopy(messages)
working = deduplicate_tool_results(working)
working = externalize_large_payloads(working)
working = demote_old_refetchable_tool_results(working)
working = strip_old_images(working)
if estimate_tokens(working) < policy.trigger_tokens:
return working
head, middle, tail = split_head_middle_tail(
working,
keep_recent_messages=policy.keep_recent_messages,
keep_recent_tokens=policy.keep_recent_tokens,
preserve_tool_pairs=True,
)
try:
checkpoint = summarize_middle(
middle=middle,
canonical_state=state,
required_exact_fields={
"paths", "ids", "hashes", "errors", "test_names", "amounts", "dates",
},
)
validate_checkpoint(checkpoint, state)
except Exception:
return original
compacted = sanitize_tool_pairs(head + [checkpoint.to_message()] + tail)
return compacted if estimate_tokens(compacted) < estimate_tokens(original) else original
stateと要約を分離します。tool_counts、verificationの件数、artifact sourceのような信頼できる事実はコードが更新し、要約modelはそれらを非構造化履歴とともに次のターン向けに整理するだけにします。
8. Trigger thresholdの選び方
割合をそのままコピーせず、次のbudgetを使います。
context window
- 最大想定output
- 次ターンで最大のtool result
- system promptとtool definition
- multimodal budget
- safety margin
= 最後に許されるinput水位
real/rough prompt token、static prefix、recent tail、summary、tool result、artifactized tokenを監視し、trigger_tokens、target_tokens_after_compaction、minimum_reclaim_tokens、cooldown_seconds、max_compactions_per_task、ineffective_compaction_limitを設定します。
9. 圧縮システムの評価
圧縮率だけを測ってはいけません。タスク完了率、次の行動の一致、元のユーザー目標・安全制約・業務制約・未完TODO・失敗案の保持、厳密ID/path/hashの忠実性、citationの追跡性、圧縮後の重複tool call、多回圧縮後のdriftを測ります。入力token、Compaction自身のcost、first-tokenとend-to-end遅延、Prompt Cache、Artifact再取得、100ターン当たりの圧縮回数、無効圧縮、失敗とfallback比も測ります。
summary model timeout、空のsummary、429/ quota不足、認証失敗、圧縮後も上限超過、tool call/resultの切断、最新ユーザーの「停止」と旧要約の実行中taskの衝突、summary中secret、繰返し要約によるcommit hash改変、削除済みresultの再取得不能、画像/Base64の反復流入を必ず試験します。
10. 選択ガイド
通常chat:最近messageのtrim + 軽量rolling summary + session database
Coding Agent:file/logのArtifact化 + tool result降格 + 構造化task checkpoint
+ path/hashのプログラム保存 + 検索子Agentの隔離
Deep Research:検索結果の外部化 + task-aware要約 + 各factのsource
+ retrieval子Agent隔離 + 必要に応じnative Compaction
高リスク業務:Canonical State database + Event Log + 監査可能な構造化要約
+ Tool Result参照 + コード層hard constraint
低遅延real time:決定的cleanup優先 + idle時Compaction + 小さいrecent tail
11. 以前の説明への修正
現行の証拠により、Hermesの50%は普遍的triggerではないこと、旧tool outputを汎用placeholderへ替えるだけではないこと、要約inputには境界がありoutput ceilingは12Kでなく10Kであること、失敗時にmiddleを黙って捨てるという表現は不正確なこと、Tool-result Clearingは天然に無損ではないこと、native Compactionの不透明性はvendorごとに異なること、研究上のPrompt Compression高速化は本番性能の約束ではないこと、Google ADKがtokenとevent-window両方を支援していることを明確にすべきです。
12. 最終提案
1. 原始データ全体をPromptの外に保存する。
2. 大きなtool resultを入口からArtifact化する。
3. 重複除去、ノイズ削除、Canonical Stateはコードで扱う。
4. 古く再取得可能なtool resultを降格する。
5. 測定済みthresholdで構造化task checkpointを作る。
6. 最近のraw tailを残す。
7. 要約にsource handleを付け、厳密identifierを守る。
8. 圧縮失敗時は元sessionを保持する。
9. hysteresis、cooldown、無効圧縮circuit breakerを使う。
10. 圧縮率でなくタスク成功率で評価する。
モデルに帳簿全体を背負わせないでください。信頼できる現在状態、再取得可能な証拠index、そして十分に完全な最近の現場を渡してください。
参考資料
確認日:2026-07-26。Agent API、model、frameworkは急速に変化するため、本番導入前にvendor公式資料と固定した依存versionのsourceを再確認してください。
LangChain v1, Short-term memory. ↩︎ ↩︎ ↩︎ ↩︎
Anthropic, Context engineering: memory, compaction, and tool clearing, 2026-03-20. ↩︎ ↩︎ ↩︎
OpenAI, From model to agent: Equipping the Responses API with a computer environment, 2026. ↩︎ ↩︎
Google Agent Development Kit, Context compression. ↩︎
Hermes Agent, Context Compression and Caching. ↩︎ ↩︎ ↩︎
OpenAI, Unrolling the Codex agent loop, 2026. ↩︎
OpenAI Agents SDK, Sessions and OpenAIResponsesCompactionSession. ↩︎
Anthropic, Compaction and Context editing. ↩︎
Jiang et al., LLMLingua: Compressing Prompts for Accelerated Inference of Large Language Models, EMNLP 2023. ↩︎
Pan et al., LLMLingua-2: Data Distillation for Efficient and Faithful Task-Agnostic Prompt Compression, 2024. ↩︎
Kummer et al., Prompt Compression in the Wild: Measuring Latency, Rate Adherence, and Quality for Faster LLM Inference, 2026. ↩︎
NousResearch,
agent/context_compressor.py, checked againstmainon 2026-07-26. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎