All posts
product2026/08/12

BibGenieがコンテキストを圧縮する方法

BibGenieがコンテキスト圧縮、構造化チェックポイント、ツリー型セッション永続化を組み合わせ、長期的な研究対話の一貫性・復元性・追跡可能性を維持する仕組みを解説します。

長期にわたる研究対話は、いずれ避けられない制約に直面します。モデルのコンテキストウィンドウには上限があるからです。

この制約はZotero上で特に顕著です。1つのセッションに、文献検索、PDFの読解、引用の抽出、ノートの整理、ツール呼び出し、繰り返しの訂正が含まれることがあります。履歴が増えるほど、その全体を毎回送るコストは高まり、最終的にはモデルの容量を超えます。しかし、古いメッセージを単純に削除することはできません。研究目的、重要な資料、ユーザーの制約、後続作業の前提となる判断は、会話の前半に記録されていることが多いためです。

BibGenieの Context Compaction は、過去のコンテキストを構造化された研究チェックポイントへ変換することで、この問題を解決します。会話履歴全体と直近メッセージの原文は維持されます。モデルには、これまでの進捗と次に行うべき作業を失わないまま、より小さく情報密度の高い作業コンテキストが渡されます。

本記事では、この設計を支える実装について解説します。

エージェントのリクエストが増え続ける理由

チャット画面ではメッセージを追加しているように見えますが、モデルが前回のリクエストを自動的に記憶するわけではありません。各リクエストには、必要なシステム指示、ツール、履歴、新しいユーザーメッセージを再び含める必要があります。ツール呼び出し、PDFの読み取り、Zotero検索が続くとコンテキストは増え、最終的にプロバイダーがコンテキストウィンドウ超過としてリクエストを拒否します。

その時点での選択肢は、履歴のない新しい会話を始めるか、既存のコンテキストを小さくても作業を継続できる表現へ変換することです。Compactは後者を行います。

コンテキスト管理は「古いメッセージの削除」ではない

最も単純な方法は、直近N件だけを残すか、上限に近づいた時点で先頭から削除することです。しかし、研究エージェントにとって、どちらも信頼できる方法ではありません。

第一に、メッセージ数とトークン数の間に一定の関係はありません。「続けて」という一言は数トークンですが、PDFの抽出結果やツール出力は数千から数万トークンになる場合があります。件数による切り捨てでは、モデルが実際に処理するコンテキスト量を判断できません。

第二に、古い情報が重要でないとは限りません。研究目標、採用基準、指定文献、引用形式、重要な意思決定は、セッションの序盤に現れることがよくあります。これらを削除すると、エージェントは直前の発言を覚えていても、そもそも何のために作業を始めたのかを見失います。

第三に、エージェントとの対話は単なるテキストの配列ではありません。研究プロセスには次のような要素も含まれます。

  • ツール呼び出しとその結果
  • Zoteroのitem key、添付ファイル、位置情報
  • 過去の結論に対するユーザーの訂正
  • 再試行すべきでない失敗済みの手順
  • 未完了のタスクと検証待ちの仮説
  • 画像などのマルチモーダルコンテンツ

したがって、Compactは単なる切り捨てでは不十分です。置き換え可能な過程の詳細を除きつつ、作業継続に必要な状態を保持するという、制御された情報再編成でなければなりません。

BibGenieではCompactを次のように定義しています。

過去のモデルコンテキストを構造化された研究チェックポイントへ変換しながら、セッション履歴全体と直近の会話原文を保持する。

重要なのは、圧縮されるのは次回モデルへ送るコンテキストであり、ユーザーの履歴ではないという点です。

完全な履歴から「Checkpoint + Recent Tail」へ

3ターンの会話があるとします。

U1 → A1 → U2 → A2 → U3 → A3

Compactを実行しても、BibGenieはこれらのノードを削除・書き換えしません。現在のセッション末尾に内部チェックポイント C1 を追加します。

U1 → A1 → U2 → A2 → U3 → A3 → C1

                    durable session leaf

C1 は過去のコンテキスト要約を保存します。また firstKeptMessageId は、原文のまま保持する最初のメッセージを指します。保持境界が U3 の場合、次のリクエストでモデルへ渡す内容は次のとおりです。

C1.summary → U3 → A3

ユーザーが次の質問を送ると、コンテキストは次のようになります。

C1.summary → U3 → A3 → U4

これにより、互いに矛盾しない2つのビューが成立します。

  • Durable history: データベースとUIには U1 → A1 → … → C1 → U4 の完全な履歴が残る。
  • Model projection: モデルには最新のチェックポイント、直近の原文、チェックポイント以降の新規メッセージだけを送る。
Loading diagram

これは単に文字列を短くする設計ではありません。監査可能な完全履歴と、モデル向けの高密度な作業記憶を分離する設計です。

Compactが実行されるタイミング

BibGenieには3つの実行経路があります。いずれも同じモデル解決、容量推定、しきい値判定を共有します。

1. 手動実行

研究の一区切りがつき、次の段階へ進む前にコンテキストを整理したい場合、ユーザーは Compact を選択できます。

手動Compactは自動しきい値に制限されません。「今、チェックポイントを作成する」という明示的な指示として扱われます。

  • 初回Compactでは、少なくとも2ターンあれば短いセッションでも実行できます。最初のターンを要約し、2番目を原文で保持します。
  • 既存チェックポイントの後に新しいメッセージがある場合、保持境界を動かす必要がなくても、previous summaryを基に更新済みチェックポイントを生成できます。境界が進む場合は、新たにRecent Tailから外れた履歴も要約へ統合します。
  • 圧縮できない1ターンしかない場合や、最新チェックポイントがすでにbranch leafである場合は、役に立たないエラーを表示せず、成功したno-opとして扱います。

これにより、処理対象がないことを失敗扱いせず、研究上の節目にチェックポイントを作成できます。

2. ターン完了後の自動チェック

アシスタントの最終回答が正常に永続化されると、BibGenieは現在のコンテキスト使用量を確認します。安全上限に近づいていれば、事前にCompactを開始します。

要約処理を次回送信時より前に移すことで、次の質問を送る際の待ち時間を減らせます。

自動チェックはセッションが安定している場合にのみ実行されます。ツール呼び出し、ツール結果、ユーザー承認が未完了であればCompactを見送り、途中状態のワークフローをチェックポイントとして固定しません。

3. 送信前Preflight

ターン後のチェックは待ち時間を改善しますが、正しさを保証する最後の境界は送信前Preflightです。

新しいユーザーメッセージがAI SDKの状態へ入る前に、BibGenieはそのメッセージを一時的にモデル投影へ加え、次のリクエスト全体を推定します。大量の文章を貼り付けた場合、画像を追加した場合、あるいはコンテキストウィンドウの小さいモデルへ切り替えた場合でも、providerを呼び出す前に危険を検出できます。

Loading diagram

Compact後も容量を超える場合、BibGenieは失敗が確実なリクエストをproviderへ送りません。入力内容を保持し、短くするよう案内します。

メッセージ数ではなくモデル容量で判断する

モデルごとにコンテキストウィンドウと最大出力長は異なるため、BibGenieは単一の固定しきい値を使いません。

基本的な関係は次のとおりです。

安全な入力上限 = Context Window - Reserved Tokens

Reserved Tokensは次のモデル出力のための余裕です。現在のモデルのコンテキストウィンドウに応じて算出されます。大容量モデルでは十分な出力余裕を確保でき、小容量モデルでは不適切なグローバル定数を適用せずにreserveを縮小します。

Recent Tailの予算もモデル容量に応じて変化します。そのためCompactは、トークン節約だけを目的に直近の会話をすべて平坦化することも、小さいモデルに収まらないRecent Tailを残すこともありません。

保持境界は必ず完全なユーザーターンの先頭に置き、アシスタント回答やツール結果の途中では分割しません。単一のassistant/tool turnだけで予算を超える場合は、その巨大なターンを残したまま過去へ遡るのではなく、その後にある最も近いuser boundaryを選びます。

providerの実測usageを優先する

すべてのproviderに対応する正確なtokenizerは大きな複雑性を招きます。また、コンテキストや課金の計算方法もprovider間で完全には統一されていません。そこでBibGenieは、実測usageを優先し、未計上の増分だけを推定します。

  1. 最新チェックポイント以降で、有効なusageを持つ最新のassistant messageを探す。
  2. providerが返したtoken usageを基準値にする。
  3. そのリクエスト以降に追加され、usageにまだ含まれていないメッセージを推定する。
  4. 信頼できるusageがなければ、現在のモデル投影全体を推定する。

ここで求めるのは、次回のproviderリクエストに含まれる可能性が高いコンテキスト量です。ユーザーが累積で消費したトークンではありません。課金向けの totalUsage をコンテキスト占有量として扱うことはありません。

テキストには保守的な文字数近似を使います。providerがreasoningを再送する可能性がある場合、それも推定に含めます。画像にはPreflight用の固定コストを設定し、マルチモーダルメッセージを単なるファイル名として過小評価しないようにします。現在のプラグインでユーザー側の file partとなるのは、主に貼り付け画像やZoteroのスクリーンショットです。

この推定は見せかけの精度を目指しません。次のリクエストが安全な範囲にあるかという運用上の問いに、安定して答えるためのものです。

要約ではなく、エージェント状態のスナップショット

一般的な会話要約は「何が起きたか」を説明します。一方、エージェントのチェックポイントには、作業を再開するための状態も必要です。

BibGenieは、次の固定構造で情報を保持します。

  • Research Goal: 現在の研究目標
  • User Requirements and Constraints: ユーザーの要件、好み、制約
  • Research Progress: 完了済み、進行中、ブロック中の作業
  • Findings and Evidence: 得られた知見と根拠
  • Key Zotero Resources: 重要なアイテム、添付ファイル、Zotero key
  • Decisions: すでに確定した判断
  • Next Steps: 次に行う具体的な作業
  • Critical Context: 正しく再開するために不可欠なその他の情報

Promptではさらに、ユーザーの発言、ツールが返した事実、モデルの推論を区別するよう求めます。これにより、モデルが一度推測した内容が、Compact後に確定事実として扱われる危険を減らします。

研究コンテキスト向けのシリアライズ

要約を生成する前に、BibGenieはUIMessageを研究向けの簡潔なテキスト表現へ変換します。

  • 通常のテキストは内容とrole labelを保持する
  • reasoningは長期チェックポイントへ含めない
  • ツール入力は保持し、長すぎる結果は切り詰める
  • ツールエラーや拒否状態は明示する
  • 画像と添付ファイルはファイル名とMIME typeを保持する
  • Zoteroデータは作業再開に必要なフィールドを保持する

保持する内容はZoteroリソースごとに異なります。

  • 文献アイテム:item key、タイトル、引用テキスト
  • PDFページ:添付ファイル名、現在のページ、総ページ数
  • EPUB:section index、href、CFI
  • 注釈:annotation key、テキスト、コメント、ページ、parent item key
  • CollectionとTag:安定した識別子と表示情報

これにより、大きな元オブジェクト全体を毎回の要約リクエストへ入れずに、後続のツール呼び出しに必要なZoteroの位置情報を保持できます。

連続Compactでチェックポイントを積み重ねない

長いセッションではCompactが複数回実行されます。BibGenieは過去のチェックポイントをすべてモデルへ送りません。投影されるのは常に最新の1つだけです。

2回目以降のCompactでは、次の情報を組み合わせます。

previous summary + 新たに古いコンテキストとなったメッセージ

そして新しいsummaryを生成します。

Summary 1 + New History → Summary 2
Summary 2 + New History → Summary 3

そのため、チェックポイント数に比例してコンテキストが増えることはありません。

保持境界も単調に進みます。新しい境界が前回のチェックポイント境界より過去へ戻ることはありません。すでにsummaryへ置き換えた履歴をRecent Tailへ再展開しないためです。

手動と自動のCompactは、ここで意図的に異なる動作をします。

  • 自動Compact: 保持境界が前進し、実際にコンテキストを解放できる場合だけ実行する。
  • 手動Compact: チェックポイント後に新しいメッセージがあれば、同じ境界を再利用し、previous summaryを基に更新版を生成できる。境界が前進した場合は、新たに除外された履歴も統合する。

この違いにより、バックグラウンド処理は容量改善に集中しつつ、ユーザーは研究段階を意図的に区切れます。

要約の出力予算はreserveから割り当て、モデル自身の最大出力長を上限とします。複雑な研究向けの安全上限であり、Promptでは引き続き簡潔な出力を要求します。

Compactがツリー型Sessionを理解すべき理由

BibGenieのセッションは単純な配列ではなく、分岐可能なメッセージツリーです。

ユーザーはRetry、最後のメッセージの編集、過去のassistant responseからのForkを行えます。複数のセッションが初期ノードを共有する場合があり、各セッションは独自のdurable leafによって現在のbranchを示します。

そのためCompactは、古いノードを書き換えたり、Recent Tailをチェックポイントの後へコピーしたりしてはいけません。そうすると次の問題が起こり得ます。

  • あるbranchの圧縮が別のbranchへ影響する
  • 共有ノードのparent関係が変わる
  • Retry後も無効なチェックポイントを継承する
  • 同じ直近メッセージが重複保存される
  • UI履歴とモデルが実際に見るコンテキストが一致しなくなる

BibGenieはappend-only checkpointを採用しています。

Loading diagram

C1.parentId = A3 は、ツリー上のどこでチェックポイントが追加されたかを表します。C1.firstKeptMessageId = U3 は、モデル投影で原文保持を再開する位置を表します。この2つは異なる次元の情報であり、互いに代替できません。

A2 から作成したForkは C1 を継承しません。C1 より後の安定したassistant messageからForkすれば、そのancestor chainにチェックポイントが自然に含まれます。共有ノードをコピーしたり変更したりする必要はありません。

チェックポイントを並行処理に安全な状態Commitとして扱う

要約生成には数秒かかることがあります。その間にbranchが編集、Retry、その他の操作で変わった場合、古い履歴を基にしたsummaryをcommitしてはいけません。

BibGenieはCompactを、バージョン条件付きの状態commitとして扱います。開始時に次の2つを記録します。

  • leafId:現在のdurable branch末端
  • branchRevision:durable contentが実際に変化した場合だけ増加するbranch version

要約生成後、専用トランザクションが両方の値を比較し、ツールワークフローが安定していること、保持境界が現在のbranchに属していることを確認します。条件を満たす場合にのみ、checkpointの追加、session leafの移動、revisionの増加を行います。1つでも一致しなければsummaryは古いため、commitを拒否します。

Loading diagram

要約中にbranchが変わった場合、BibGenieは古いチェックポイントを強制的に適用せず、データベース上の実際のbranchを再読み込みします。トランザクション完了前のキャンセルはrollbackされます。commit成功後はメモリ状態を同期し、データベースとUIが同じbranchへ収束するようにします。

Retry・Edit・Forkなど既存機能との整合性

信頼できるCompactは、要約を生成できるだけでは不十分です。既存のセッション操作が持つ意味を維持しなければなりません。

Retry

チェックポイントは内部メッセージです。Retryは最後の実際のassistant responseを対象にします。そのターンより後にチェックポイントがあれば、古いtailとともに無効になります。新しい回答は通常の容量チェックを再び通ります。

Edit

最後の実際のuser messageを編集すると、それに続くassistant responseとチェックポイントは現在のbranchから外れます。再送信時にはPreflightが再実行されます。

Fork

Forkの対象は安定した実際のassistant messageに限られ、内部チェックポイントは対象になりません。新しいbranchがチェックポイントを継承するかどうかは、対象ノードのancestor chainだけで決まります。

破損した履歴の保護

セッション読み込み時、BibGenieはparentの欠落、parent cycle、不正なdurable messageを検査します。トポロジーが破損している場合、UIは安全に読める範囲だけを表示し、セッションを読み取り専用にします。読み込みやCompactの過程で元のデータベースを暗黙に書き換えることはありません。

Compact実行中のユーザー体験

コンテキスト圧縮は基盤機能ですが、理由の分からないUI停止として見えるべきではありません。

手動または自動Compactが始まると、チャットには Compacting earlier context… と表示され、キャンセルできます。入力欄は編集可能なままなので、ユーザーは次の質問を準備できます。

ユーザーが明示的に送信した時点でのみ、入力内容が確定し、実行中のCompact完了を待ちます。完了後はBibGenieが自動的に送信を続けます。失敗またはキャンセルした場合、メッセージが勝手に送られることはなく、下書きも維持されます。

Compact中は、Retry、Edit、Fork、モデル切り替え、2回目のCompactを一時的に無効化します。これらはsummaryの基となるbranchを変更するためです。一方、入力欄の編集はdurable historyを変更しないため、早い段階で禁止する必要はありません。

ユーザーから見た効果は明確です。

  • コンテキスト増加によって長期研究が突然停止しない
  • 新しい会話を作って研究背景を説明し直す必要がない
  • 小さいコンテキストのモデルへ切り替えた場合、送信前に容量を再評価する
  • 重要文献、Zotero key、結論、未完了タスクを引き継げる
  • 直近の会話は原文のままで、局所的な参照や語調が保たれる
  • プラグイン再起動後もチェックポイントが正しいbranchに属する
  • Compact前の完全な履歴をいつでも確認できる

Compactにはコストがある:プロンプトキャッシュは再構築される

コンテキストが短くなっても、Compact直後の最初のリクエストが必ず安くなるとは限りません。Compactは入力の一部を要約に置き換えるため、以前のキャッシュされたプレフィックスはその位置以降で再利用できません。最初のリクエストは再計算され、その後に新しいプレフィックスを中心としたキャッシュが作られます。

目的は最短のプロンプトではなく、コンテキスト容量、必要な情報、キャッシュ再利用、レイテンシ、コストのバランスを取ることです。

設計上の選択:見せかけの精度より検証可能性

BibGenieの実装は、成熟したエージェントのcompactionパターンを参考にしながら、Zotero、マルチモーダル入力、ツリー型永続化へ適応しています。同時に、明確な価値のない複雑化を意図的に避けています。

  • すべてのproviderに対して正確だと装う統一tokenizerを使わない
  • Compact前のメッセージを物理的に削除・付け替えしない
  • Recent Tailを複製しない
  • provider overflow後に自動Compactして元リクエストを再試行しない
  • 通常のメッセージ永続化経路でチェックポイントを作成・変更しない
  • 課金用の累積tokenとコンテキスト占有量を混同しない

この選択により、重要な性質を検証しやすくなります。いつCompactが動くのか、どのbranchを要約したのか、モデルへ何を送るのか、データベースに何をcommitしたのか、失敗後にどの状態で停止するのかが明確です。

Compactは本質的に非可逆な圧縮です。すべてのtokenを逐語的に記憶させることではなく、有限のコンテキストウィンドウ内でタスクの連続性を最大限維持することが目的です。完全履歴は追跡可能性、チェックポイントは作業状態、Recent Tailは局所的な詳細を担います。

チャットボットから長期的な研究パートナーへ

一般的なチャットシステムが主に考えるのは、「このターンにどう答えるか」です。研究エージェントには、もう1つの問いが必要です。「次のターンへ、どの状態を持ち越すべきか」

BibGenieのContext Compactionは、単なる要約呼び出しではありません。モデル容量のPreflight、研究コンテキストのシリアライズ、構造化チェックポイント、ツリー型セッション投影、並行バージョン検証、トランザクションによる永続化、Retry・Edit・Forkとの一貫した連携を組み合わせた仕組みです。

研究が数十ターン、複数の文献、多数のツール呼び出しにまたがるとき、すべてのtokenを覚えることよりも、次の点を常に把握していることが重要です。

  • ユーザーが最終的に達成したいこと
  • どの主張にすでに根拠があるか
  • どの結論がまだ仮説にとどまるか
  • どの作業が完了しているか
  • 次に何をすべきか

CompactがBibGenieにもたらすのは、まさにこの能力です。有限のコンテキストウィンドウでありながら、長期的に前進し、確実に再開でき、研究の文脈を維持するエージェントセッションを実現します。