ロングコンテキストは「コンテキスト長を増やせば解決する」問題ではない。入力が数百万〜千万トークン級になると、注意機構の計算・メモリ負荷だけでなく、重要情報の希釈、誤った要約の伝搬、ツール実行の爆発といった運用上の破綻が先に到来する。

Recursive Language Models(RLM)は、LLMが自分自身を再帰的に呼び出すことで、巨大入力を段階的に“読み進める”ための推論フレームワークである。Alex L. ZhangらはarXiv:2512.24601(初版投稿: 2025-12-31 UTC、改訂: 2026-01-28 UTC)で、RLMがモデルのコンテキストウィンドウを二桁倍(two orders of magnitude)超える入力を扱えること、さらに小規模にポストトレーニングしたRLM-Qwen3-8BがベースのQwen3-8Bに対して平均28.3%向上することを報告した。

本稿は、RLMの実装設計を「再帰エージェント」として分解し、Google ADK(Agent Development Kit)上で再現するための統合パターンを提示する。あわせて、エンタープライズで必須となる予算制御・監査・安全弁を“設計要件”として明文化する。

RLMが解く「ロングコンテキスト」の設計課題

エンタープライズで扱う長文入力は、単一の文書に限られない。例えば次のような入力は「長い」だけではなく「構造が深い」。

  • リポジトリ全体(コード、設定、CIログ、過去のPR、監査結果)
  • 数年分のインシデント対応ログ(チケット、チャット、検知アラート、対策手順)
  • 契約書群と社内規程、監査証跡(変更履歴つき)

このとき失敗モードは大きく3類型に整理できる。

  • 情報希釈: 重要箇所が埋もれ、局所最適な推論に落ちる(いわゆるneedle-in-a-haystack)
  • 誤要約の伝搬: 途中で作った要約が誤っていると、その後の推論が汚染される
  • 計算予算の破綻: 入力長に比例して推論コストが増え、実用のレイテンシ/コスト制約を超える

RLMは、この三点を「推論のプログラム化」で扱う。具体的には、巨大入力を外部環境(REPL)に退避し、LLMが必要箇所だけを参照(peek)し、必要に応じて自分自身(またはサブLM)を呼び出す(recurse)。

Recursive Language Models(RLM)の中核: REPLと再帰呼び出し

RLMの実装は、次の3コンポーネントに分解すると設計しやすい。

  • Context Store: “10M+トークン”相当の原文を保持し、部分参照(バイトレンジ、行番号、段落IDなど)を提供する
  • RLM Orchestrator: どの範囲を参照するか、いつ再帰呼び出しするか、停止するかを決める制御ループ
  • Subcall Runtime: 再帰呼び出しの実行基盤(同一モデル/別モデル、並列化、キャッシュ、トレース)

擬似コードで表すと次のような形になる。

def rlm_solve(task, ctx_store, budget, depth=0):
    state = init_state(task)

    while True:
        view = ctx_store.peek(state.cursor, state.window)
        action = llm_decide(task, state, view, budget, depth)

        if action.type == "ANSWER":
            return action.answer

        if action.type == "PEEK":
            state = state.apply_peek(action.range)
            continue

        if action.type == "RECURSE":
            if depth >= budget.max_depth:
                state = state.record("depth_limit")
                continue
            sub_budget = budget.child()
            sub_answer = rlm_solve(action.subtask, ctx_store, sub_budget, depth+1)
            state = state.merge(sub_answer)
            continue

        if action.type == "STOP":
            return fallback_answer(state)

設計上のポイントは、再帰は“魔法の長文理解”ではなく、参照戦略と停止条件を持ったプログラムである点である。したがって、RLMを実装する際は「どの条件で深掘りし、どの条件で打ち切るか」を先に定義しておく必要がある。

10M+トークン処理の実装設計: 予算、停止条件、キャッシュ

論文のTable 1では、BrowseComp-Plus(1K documents)のタスク長が6M〜11Mトークンであると記され、さらに「RLMs can scale to the 10M+ token regime」と明示されている。この規模をプロダクションで扱うには、次の制御が必須である。

  • 再帰深度の上限: 最大深度(例: 3〜6)と、深掘りに値する条件(不確実性、矛盾検出、未カバー領域)
  • トークン/コスト予算: ルートと子呼び出しに予算を分配し、超過時は縮退モードに切り替える
  • 参照窓(peek window): 一度に読む範囲を固定値ではなく、構造(章/関数/ログ区間)に合わせて可変にする
  • キャッシュ: 「この範囲をこの目的で読んだ結果(要点、抽出、検証)」をメモ化し、同一再帰での再読を避ける

Context StoreはRAGのベクトルDBと同一視されがちだが、RLMでは“引用可能な原文スライス”を安定して返すことが肝である。実務では次の2層にすると堅い。

  • 構造インデックス: 目次、見出し、関数境界、ログのタイムレンジなど(決定的に切れる)
  • 意味インデックス: ベクトル検索/キーワード検索(候補を出す)

候補提示は意味インデックス、最終的な“読む”のは構造インデックスに基づくスライス、という責務分離が、幻覚とリークを抑える。

実験結果の読み方: 「二桁%向上」をどう設計に落とすか

RLMの価値は「単に長い入力を処理できる」ことではなく、長文タスクでの精度・コストのトレードオフを再設計できる点にある。論文のTable 1は、複数のベースライン(Summary agent、CodeAct+BM25など)と比較している。

  • BrowseComp-Plus(6M-11M tokens): GPT-5のRLMは91.33、Summary agentは70.47、CodeAct(+BM25)は51.00を報告している
  • OOLONG: GPT-5のBase Modelは44.00に対し、RLMは56.50を報告している
  • OOLONG-Pairs: GPT-5のBase Modelは0.04に対し、RLMは58.00を報告している(情報密度が高いタスクで差が出やすい)

これらは「長文処理=入力を全部食わせる」設計の限界を示唆する。RLMは参照と再帰を通じて、入力全体の“取り込み”ではなく、タスクに必要な箇所の“選別”を推論の一部に取り込む。したがって実装設計では、peekの粒度(どの構造単位で読むか)と、再帰の契機(いつ子呼び出しするか)を性能レバーとして扱うべきである。

エンタープライズ実装パターンとGoogle ADK統合

Google ADK(Agent Development Kit)は、エージェントを「ツール呼び出しを含む制御ループ」として実装・評価・デプロイするためのオープンソースフレームワークである。RLMのオーケストレータを載せる基盤として、次の写像で実装できる。

  • Root Agent: 問題分解、peek戦略、再帰呼び出しの判断を行う
  • Peek Tool: (range, granularity) を受け取り、原文スライスとメタデータ(開始/終了、構造ラベル)を返す
  • Recurse Tool: subtaskcursor を受け取り、子エージェント(同一ロジック)を起動して結果を返す
  • Session/Memory: 参照履歴、キャッシュ、再帰木(トレース)を保存する

擬似コードは次の通りである(概念の提示を目的とし、ADKの実APIはバージョンにより差分がある)。

# Conceptual sketch: implement an RLM-style control loop on top of an ADK Agent.

class PeekTool:
    def __init__(self, store):
        self.store = store

    def __call__(self, start: int, end: int):
        return self.store.slice(start, end)

class RecurseTool:
    def __init__(self, agent_factory, budgeter):
        self.agent_factory = agent_factory
        self.budgeter = budgeter

    def __call__(self, subtask: str, cursor: dict, depth: int):
        child_budget = self.budgeter.child(depth=depth+1)
        child_agent = self.agent_factory(depth=depth+1, budget=child_budget)
        return child_agent.run({"task": subtask, "cursor": cursor})

# Root agent decides to call PeekTool / RecurseTool until it can answer.

エンタープライズで重要なのは「再帰を許すこと」よりも、再帰を観測・制御・監査できることである。最低限、次を整備する。

  • トレース: どの範囲を読んだか、どの子呼び出しを起動したか、各ステップの入出力要約
  • 権限分離: peek可能なデータ範囲を、テナント/役割/案件で分割(データ境界を越える再帰を禁止)
  • 安全弁: 深度上限、予算上限、タイムアウト、失敗時の縮退モード(粗い要約 + 不確実性の明示)

RLMは、巨大入力を扱うための運用設計(予算・監査・安全弁)を推論ループの中核に据える点で、単純なロングコンテキスト拡張や要約戦略とは別物である。したがって、まずは自社の代表タスク(コードベースQA、監査ログ解析、契約差分抽出など)を選び、peek粒度と再帰契機を変数としてAB比較するところから導入するのが現実的である。

FAQ

RLMとRAGの違いは何か?

RAGは「必要な情報を検索して短いコンテキストに詰め直す」戦略である。一方RLMは、巨大な原文を外部環境として保持し、peekと再帰呼び出しで段階的に読む。RAGは候補提示、RLMは“読むための実行モデル”として捉えると整理しやすい。

10M+トークンを扱うとき、最初に決めるべき設計は?

再帰深度、トークン/時間の予算配分、停止条件(いつ打ち切るか)である。ここが曖昧だと、ツール呼び出しが爆発してコストが破綻する。

再帰が深くなるほど精度は上がるのか?

一般には上がり得るが、逓減する。深掘りが有効な条件(矛盾検出、未カバー領域、重要箇所の不確実性)をトリガとして設計し、無条件に深くしないことが重要である。

ADK統合での最大の落とし穴は?

観測不能な再帰である。参照範囲、子呼び出し、要約結果が追えないと、監査・デバッグ・セキュリティのいずれも成立しない。再帰木と参照スライスIDの保存は必須である。

どんなタスクには向かないか?

入力が短いタスク、探索よりも生成が支配的なタスク、あるいは参照元が不安定でスライスが再現できないタスク(頻繁に変わるログ/ドキュメントのみ)には過剰となる。まずRAGや要約で十分かを見極めるべきである。

参考文献