mcpField
R
rlm

rlm

github.com/trampoline-aiエージェントワークフロー43661 回インストール今日更新
リポジトリ

rlm について

rlm は PredictRLM で呼び出し可能な事前設定済みエージェントを構築するスキルです。チャット応答ではなく、型付き入出力、サンドボックス実行、構造化結果を必要とする開発者向けです。

主な機能

  1. 01DSPy シグネチャでエージェントの契約を定義
  2. 02サンドボックスで Python を反復実行
  3. 03特定タスク向けのサブ LLM 予測
  4. 04スキルとホスト側ツールの利用
  5. 05出力を検証してトレースを返却

活用シーン

  1. 01大きなファイル入力を分析するエージェントの構築
  2. 02モデル推論と決定的なコードの組み合わせ
  3. 03ホスト側 API やデータベースへの接続
  4. 04アプリケーションコードへの構造化結果の返却

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/trampoline-ai/predict-rlm --skill rlm

インストール後、Claude Code で/rlmを入力して読み込まれたか確認します。

詳細

PredictRLM を作成する

スキルの更新を確認する

計画や構築を始める前に、インストール済みの rlm スキルに更新があるか確認してください。

npx skills update rlm

使用中のパッケージランナーに応じて、npx を pnpx、bunx、または同等のものに置き換えてください。 更新後は、続行する前にスキルを読み直してください。

RLM は、呼び出し可能な事前設定済みエージェントです。コンテキストを自律的に調査し、サンドボックス化された REPL でコードを記述・実行し、ツールを呼び出して結果を確認し、タスクが完了するまで反復します。チャットエージェントとは異なり、RLM は関数です。入力、出力、ツールを定義し、コードから呼び出します。チャットメッセージではなく、構造化データを返します。

基本的な考え方

呼び出し元は DSPy シグネチャを指定します。その入力フィールドと出力フィールドが関数の契約となり、docstring が実行手順となります。呼び出しのたびに、次の処理が行われます。

  1. PredictRLM は型付き入力を準備し、サンドボックス化された実行セッションを取得します。デフォルトのバックエンドは、Deno と Pyodide/WASM を介して動作するステートフルな Python REPL です。
  2. 外側の LM がシグネチャと戦略を読み取り、入力の調査、中間状態の保持、分岐、再試行、検証を行う Python コードを記述します。Python 変数は、その呼び出しの反復処理をまたいで保持されます。
  3. サンドボックス内のコードでは await predict(...) を使って、対象を絞ったサブ LMによる認識や抽出を実行できます。各 predict() 呼び出しには独自のコンテキストウィンドウがあり、型付き DSPy シグネチャ、Pydantic スキーマ、dspy.Image を使用できます。
  4. サンドボックス内のコードでは、Skill オブジェクトが提供するパッケージやモジュールも使用できます。また、WASM の外部の機能にはホスト側のツールを呼び出し、明示的に許可されたネットワークドメインにもアクセスできます。
  5. 作業が完了すると、外側の LM は SUBMIT(...) を呼び出します。PredictRLM は宣言された出力を検証し、ファイル出力をホストと同期して、出力フィールドと構造化された trace を含む dspy.Prediction を返します。

この分離には意図があります。外側の LM は計画とコード実行を担い、サブ LM は範囲を絞った理解タスクを担います。決定論的なライブラリやツールは、それぞれに適した処理を行います。大きなコンテキストは、1 つのプロンプトに蓄積するのではなく、ファイル、サンドボックス変数、対象を絞ったサブ呼び出しに保持されます。

application call
    -> DSPy signature: inputs + strategy + outputs
    -> outer LM <-> stateful sandbox REPL
                     |-> predict() -> sub-LM
                     |-> skill packages and modules
                     `-> host-side tools
    -> validated dspy.Prediction + trace

コア API

最小限の型付き RLM は、シグネチャ、設定済みの PredictRLM、通常の同期または非同期呼び出しで構成されます。

シグネチャクラスの docstring は、外側の LM に渡されるモデル指示プロンプトです。単なる開発者向けドキュメントではありません。RLM のワークフロー、判断ルール、検証手順、完了条件を記述してください。docstring を変更すると、モデルの実行時の動作が変わります。

import dspy
from pydantic import BaseModel, Field

from predict_rlm import CtxStr, File, PredictRLM
from predict_rlm.skills import pdf


class Analysis(BaseModel):
    summary: str = Field(description="Grounded summary of the documents")
    risks: list[str] = Field(description="Material risks supported by the documents")


class AnalyzeDocuments(dspy.Signature):
    """Inspect the documents, apply the criteria, and return a grounded analysis.

    Survey the files first. Extract only relevant evidence with focused
    predict() calls, verify important claims, then submit the typed result.
    """

    documents: list[File] = dspy.InputField(desc="Documents to inspect")
    criteria: CtxStr = dspy.InputField(desc="Criteria the outer LM must see in full")
    analysis: Analysis = dspy.OutputField(desc="Evidence-grounded analysis")


rlm = PredictRLM(
    AnalyzeDocuments,
    lm="openai/gpt-5.4",
    sub_lm="openai/gpt-5.1",
    skills=[pdf],
    max_iterations=30,
)

result = await rlm.acall(
    documents=[File(path="report.pdf")],
    criteria="Cover obligations, deadlines, and material risks.",
)
print(result.analysis.summary)

同期呼び出しには rlm(...) を、非同期呼び出しには await rlm.acall(...) を使用してください。どちらも dspy.Prediction を返し、宣言された各出力には result.analysis のような属性でアクセスできます。

主なコンストラクターの引数は次のとおりです。

  • signature — DSPy シグネチャクラス、または簡潔な文字列形式のシグネチャ。
  • lm — コードを記述する外側の LM。
  • sub_lm — 組み込みの predict() ツールが使用する LM。
  • skills — 再利用可能な指示、PyPI パッケージ、サンドボックスモジュール、ツール。
  • tools — サンドボックス内で公開する同期または非同期のホスト側呼び出し可能オブジェクト。
  • allowed_domains — サンドボックスで許可するネットワークの許可リスト。デフォルトでは空です。
  • max_iterations、max_llm_calls、max_output_chars — 実行予算。
  • output_dir — 宣言された File 出力をホスト側に収集するルートディレクトリ。
  • verbose と debug — 人が読める実行出力とライフサイクル診断情報。

大きなファイル入力や生成された成果物には、File または list[File] を使用してください。評価基準など、実行時の値全体を Python 変数として公開するだけでなく外側の LM のプロンプトにも追加する必要がある文字列入力には、CtxStr を使用してください。サンドボックスで再利用可能な指示、パッケージ、モジュール、または同梱ツールが必要な場合は、Skill を使用してください。認証済み API、データベース、ネイティブライブラリ、ホストのファイルシステムへのアクセスなど、特定のホスト側の処理には tools= を直接使用してください。

ランタイムカーネルと拡張モデル

ほとんどの RLM は、シグネチャ、File、CtxStr、Workspace、スキル、ホストツールだけを使用してください。ワークフローで新しい型付き境界、リソースのライフサイクル、実行基盤、または正確性が重要なイベントストリームが必要な場合に限り、カーネルを拡張してください。シグネチャで Pydantic モデルを使用するというだけの理由で、カスタムアダプターを選ばないでください。

構築時に、PredictRLM は直接指定されたオプションと RuntimeContribution モジュールファクトリーを解決し、指示、アダプター、ツール、パッケージ、唯一の実行バックエンド、イベントシンク、バリデーター、ツール操作を含む不変の RuntimeSpec にまとめます。モジュールファクトリーは構築時に一度だけ実行されます。その後、呼び出しごとに、新しい RunContext が作成され、可変状態、準備済み入力、バインディング、出力の予約、クリーンアップコールバック、エビデンスの状態を管理します。

カーネルのライフサイクルと所有権
construction
  direct options + RuntimeContribution modules
      -> immutable RuntimeSpec

invocation
  prepare typed inputs and output requirements
      -> compile path and artifact claims
      -> open adapter-owned resources
      -> validate requirements and acquire one ExecutionSession
      -> bind inputs and reserve outputs
      -> apply invocation-local prompt contributions
      -> run generated-code attempts
           -> after_execution durability hooks
      -> materialize submitted outputs while the session is active
      -> finalize input adapters in reverse order
      -> finalize and release the kernel-owned session
      -> run remaining LIFO RunContext cleanup

所有権の境界は厳格です。

  • アダプターは、セッションを取得する前に要件と保存先を宣言します。
  • ExecutionBackend が、呼び出しスコープの ExecutionSession を作成します。
  • アダプターは、サポートされているバックエンドやセッションの機能を使用できますが、セッションの取得、最終処理、解放は行いません。
  • 可変のプロバイダークライアント、リース、ベースライン、再試行状態は、共有アダプターではなく、呼び出しの PreparedInput または RunContext に保持します。
  • サンドボックスの保存先が重複している場合、生成コードの実行前にエラーになります。
  • アダプターのリソースは、成功時、失敗時、セットアップ失敗時、キャンセル時に最終処理されます。アダプターでエラーが発生しても、フレームワークが所有するセッションの最終処理は実行されます。
最小の拡張ポイントを選ぶ

要件を満たせる最初の境界を使用してください。

  1. シグネチャの docstring または CtxStr — 外側の LM が読む必要のあるタスク戦略や呼び出し固有の基準。
  2. Skill — 再利用可能な外側の LM 向け指示に加え、サンドボックスパッケージ、インポート可能な Python モジュール、または同梱のホストツールを提供します。
  3. tools= — 範囲を絞った同期または非同期のホスト呼び出し可能オブジェクト。ネイティブライブラリ、認証情報、API、データベース、ホストのファイルシステムへのアクセスには、これを使用してください。プレーンな JSON 形式のデータ、または Pydantic の値を返し、トランスポート境界で正規化できるようにします。
  4. File、Workspace、または既存のアダプター — 通常のコピー対象ファイル、生成ファイル、または可変ディレクトリには、これらを使用してください。新しい型を導入するより、これらの組み込み機能を優先してください。
  5. PreparedInput.path()、.paths()、または .glob() を備えた InputAdapter — カスタムの型付き入力を、まずホストパスとして実体化できます。保存先の正規化、重複チェック、コピーまたは明示的なマウント、バックエンド要件、モデルに表示されるサンドボックスパスは、カーネルが管理します。
  6. 完全な InputAdapter ライフサイクル — 外部リソースに、プロバイダーリース、ライブハンドル、試行ごとの同期、またはホストパスでは表現できないカスタムのセッション機能が必要な場合に使用します。
  7. OutputAdapter — カスタム出力に、セッションがアクティブな間に予約された保存先とプロバイダー固有の実体化が必要な場合に使用します。
  8. modules= を通じた RuntimeContribution — 複数のホスト側拡張をまとめて、再利用可能な構築時の単位として組み合わせる場合に使用します。
  9. events= を通じた EventSink — 実行中に順序どおりのライフサイクルイベントを必要とするコンシューマー向けです。完了した軌跡には prediction.trace を、完了した独立のライフサイクルログには prediction.evidence を使用します。
  10. execution= を通じた ExecutionBackend — 真に新しいサンドボックスまたは実行基盤が必要な場合に限って使用します。保守されているバックエンドには、sandbox_backend="jspi" または "sbx" を使用してください。

interpreter= は、従来の CodeInterpreter 形式の統合との互換性を保つための橋渡しであり、拡張の基本契約ではありません。新しいセッションネイティブな統合では、ExecutionBackend を実装し、execution= を使用してください。

入力アダプター

InputAdapter[T] は value_type を通じてシグネチャフィールドを選択し、呼び出し元の値をモデルから参照できるデータと実行時要件に変換します。アダプターのインスタンスは構築時に作成され、並行した呼び出しで使用される場合があるため、不変にするか、並行安全性を確保してください。

現在のライフサイクル名と役割を使用してください。

  • prepare(field, value, ctx) -> PreparedInput はバックエンドの取得前に実行されます。バックエンドもセッションも受け取りません。宣言的なパス、アーティファクト、サンドボックスルートの予約、メタデータ、要件、入力指示を返します。
  • open(field, prepared, ctx, backend) は、すべての入力が準備された後、セッションが存在する前に、アダプターが所有するクライアントまたはリースを取得できます。ハンドルはアダプターが所有するキーを使って ctx.state に保存してください。
  • bind(field, prepared, ctx, session) -> BoundInput は取得後に実行されます。デフォルトのアーティファクトマウントでは不十分な場合に限って使用してください。生成コードから参照できる最終的な値とバインディングを返します。
  • append_prompt(prompt, field, prepared, ctx) -> str は、バインド後に呼び出し単位のコンテキストを外側のアクションプロンプトと強制抽出プロンプトに追加できます。正規の PredictRLM.signature は変更しないでください。
  • after_execution(field, prepared, ctx, session, result, error) は、生成コードの各試行が完了した後に実行されます。その試行がエラーを起こす前に加えられた変更も含め、永続化や同期処理に使用してください。
  • finalize(field, prepared, ctx, session, error) は最後の保存を行い、アダプターが所有するリソースを解放します。開かれたアダプターは、開かれた順序の逆順で一度ずつファイナライズされます。取得に失敗した場合、session は None です。

一般的なパスのケースでは、prepare() のみを実装してください。

class S3FileAdapter(InputAdapter[S3File]):
    name = "s3-file"
    value_type = S3File

    async def prepare(self, field, value, ctx) -> PreparedInput:
        local_path = await materialize_s3(value.uri, ctx=ctx)
        return PreparedInput.path(
            local_path,
            instructions=(f"{field.name} is available at its sandbox path.",),
        )

一度限りのアダプターは PredictRLM(MySignature, adapters=[S3FileAdapter()]) に直接登録するか、ツール、パッケージ、イベント、実行バックエンドに関連する場合は、ランタイムモジュールから提供してください。

コピーは移植性の高いデフォルト動作です。必須のライブディレクトリビューが必要な場合に限り、mode="mount" を設定してください。未対応のバックエンドでは、黙ってコピーするのではなくエラーになります。.paths() は明示的なリストを公開し、.glob() はトラバーサルとシンボリックリンクによる逸脱をチェックしながら、ホスト側で決定的に選択します。

ID、URI、ホストパスで完全に記述できるリソースについては、PreparedInput.artifacts に Artifact を返し、デフォルトの bind() 呼び出しで session.mount(artifact) を実行させてください。プロバイダーが管理するライブハンドルの場合は、open() で取得して ctx.state に保持し、選択されたセッションが実装するケイパビリティプロトコルを bind() から使用してください。

削除されたライフサイクル名は使用しないでください。入力の prepare_session() は open() に、入力の mount() は bind() に、MountedInput は BoundInput に変更されました。prepare_session() は出力アダプターのメソッドとして引き続き使用されます。予約名の ctx_str アダプターは、CtxStrInputAdapter のサブクラスでのみ置き換えられます。

出力アダプター

OutputAdapter[T] は、カスタムの型付き出力境界を担います。

  • prepare_session() は取得前のポリシーと要件を提供します。
  • reserve() はセッション取得後、コードの実行前に出力先を確保します。
  • materialize() は、セッションがアクティブな間に、送信された値を呼び出し元向けの値に変換します。

出力アダプターには、入力アダプターのような finalize() フックはありません。部分的な失敗はその場でクリーンアップし、セッション終了後も存続する可能性があるプロバイダーのクリーンアップは ctx.add_cleanup() に登録してください。出力がサンドボックスパスを所有する場合は、予約アーティファクトの metadata["sandbox_path"] に設定してください。カーネルは実行前に、入力や他の出力との重複を拒否します。

ランタイムモジュール

関連するホスト側の機能をまとめるには、引数なしのモジュールファクトリーを使用してください。

from predict_rlm import CallableTool, RuntimeContribution


def document_runtime() -> RuntimeContribution:
    return RuntimeContribution(
        instructions=("Treat document IDs as opaque provider references.",),
        adapters=(DocumentReferenceAdapter(),),
        tools=(
            CallableTool(
                name="fetch_metadata",
                function=fetch_metadata,
                description="Fetch provider metadata for one document ID.",
                schema={
                    "type": "object",
                    "properties": {"document_id": {"type": "string"}},
                    "required": ["document_id"],
                },
            ),
        ),
        packages=("pure-python-package",),
        events=(DocumentAuditSink(),),
    )


rlm = PredictRLM(MySignature, modules=[document_runtime])

PredictRLM(modules=...) は、ホスト側のランタイム動作を組み合わせます。Skill.modules はこれとは異なり、生成コードがインポートできるよう、Python ファイルをサンドボックスにコピーします。機能を提供するパッケージは重複排除されます。同じアダプター名、ツール名、ツール操作名はエラーになります。また、解決された構成では実行バックエンドをちょうど1つ選択する必要があります。

実行、イベント、フック、ゲート
  • ExecutionBackend.start(spec, ctx) は、呼び出し単位の ExecutionSession を返す非同期コンテキストマネージャーです。セッションは、コードの実行、パッケージのインストール、成果物のマウントと収集、キャンセル、終了処理を実装します。オプションの機能プロトコルを追加すると、ホストディレクトリのマウントや変更可能なディレクトリの収集などの操作を利用できます。
  • EventSink は、非同期の emit、flush、close と strict フラグを実装します。失敗しても実行を失敗させてはならないモニタリングには strict=False を使用します。永続的で完全な証跡が正しさの一部となる場合に限り、strict=True を使用します。厳格なシンクが失敗すると、公開が成功しないことがあります。
  • DSPy コールバックは、RLM の反復処理の進行状況を高レベルで報告します。EventSink は、順序付けられたカーネルのライフサイクル証跡を報告します。両者は異なる問題を解決します。
  • prediction.trace と prediction.evidence は独立したオブジェクトです。それぞれを to_exportable_json() で個別にエクスポートしてください。呼び出しの作成後に失敗した場合、exception.evidence に証跡が格納されます。軌跡は exception.trace として利用できる場合もあります。trace.evidence を読み取ったり、実行時ログ用に予約されている evidence という名前の出力を宣言したりしないでください。
  • RuntimeHook(target=..., phases={"before", "after", "error"}) は、サンドボックス内のドット区切り関数を計測し、サニタイズされた RuntimeHookEvent 値を on_runtime_hook_event に送信します。PredictRLM v1 のランタイムフックには SBX バックエンドが必要です。ランタイムフックを前提とした、移植可能な拡張機能を設計しないでください。
  • submit_confirmation は、有効な SUBMIT の後に実行されるゲートです。RLM ループを続けるにはフィードバックを返し、送信を承認するには None または "" を返します。

カーネル拡張を実装する前に、パスベースの入力については docs/custom-path-inputs.md、ライフサイクルのパターンについては docs/custom-adapters.md、正確なメソッドシグネチャについては docs/api.md、イベントシンクの保証については docs/observability.md を読んでください。公開コントラクトは predict_rlm からインポートしてください。削除済みのシムモジュールである predict_rlm.adapters、predict_rlm.artifacts、predict_rlm.events、predict_rlm.execution、predict_rlm.kernel は使用しないでください。

拡張機能は、成功、生成コードの失敗、セットアップの失敗、キャンセル、並行呼び出しの各ケースでテストしてください。変更可能な外部状態を所有する場合は、LIFO 順でクリーンアップされること、および呼び出し間で状態が漏洩しないことを確認してください。

このスキルで構築するもの

このスキルでは、PredictRLM を取り巻く再利用可能なパッケージ、つまりスキーマ、DSPy のシグネチャと戦略、機能定義、サービスラッパー、スモークテストを作成または拡張します。ここでは RLM-GEPA の最適化処理を追加しないでください。ベースとなる RLM が動作し、最適化目標が定まったら、別の rlm-gepa スキルを使用してください。

次の 2 つのフェーズで作業します。

  1. 計画 — ユーザーとともに RLM を定義し、実現可能性を調査して、具体的な実装計画を作成します。
  2. 構築 — 承認された計画を実装し、生成されたパッケージをスモークテストします。

フェーズ 1:計画

以下の順序を守ってください。これにより、一見もっともらしくても境界が使いものにならない、ランタイム機能が不足している、または出力を検証できない RLM の構築を防げます。

ステップ 1:目標の定義

ユーザーが何を構築したいのかを把握します。

以下を尋ねてください。

  • 望ましい成果は何で、成功とはどのような状態ですか?
  • 入力素材は何ですか? 文書、コード、データ、API、それとも状態を持つシステムですか?
  • 出力は何ですか? 構造化データ、変更済みファイル、スプレッドシート、あるいは別の成果物ですか?

次に、RLM が適しているかを検証します。以下のいずれかが必要な場合、RLM は適しています。

  • 文書、データセット、コードベースなど、大規模な入力を選択的に探索すること。
  • ツールを使った複数ステップの作業。たとえば、抽出 → 変換 → 検証。
  • ファイルやその他の制御された状態境界を変更する操作。
  • 多数の項目に対する並列のサブ LM 呼び出し。
  • PDF からスプレッドシートへの変換や、文書からレポートへの変換など、ファイル間の変換。

単一の LM 呼び出しまたは決定論的なスクリプトのほうが適している場合は、その旨を伝え、代わりにそちらを提案してください。

ステップ 2:入力の設計

実装ファイルを定義する前に、すべての入力を定義します。

各入力について、名前、型、ソース、説明、および外側の LM が値全体をすぐに必要とするかどうかを決めます。

  • 大きなファイルには File または list[File] を使用します。入力は /sandbox/input/<field>/ の下のサンドボックスにコピーされ、RLM は必要に応じてアクセスします。
  • メタデータや設定には、通常の str、プリミティブ型、または軽量な Pydantic モデルを使用します。
  • 外側の LM が内容全体を見る必要がある、小〜中程度の文字列(評価基準やタスクの指示など)に限って CtxStr を使用します。CtxStr は入力専用で、クラスベースの DSPy シグネチャにおけるフィールドの直接注釈としてのみ有効です。
  • File の参照と対象を絞った抽出によってコンテキストを小さく保てる場合は、生のドキュメント内容や大きな表をプロンプトに直接含めないでください。

次に進む前に、入力の境界を確認します。

ステップ 3:出力の設計

パッケージを選択したり、プロンプトを書いたりする前に、構造化出力を定義します。

各出力フィールドについて、名前、型、説明、およびプリミティブ型、Pydantic モデル、File、list[File] のいずれかを決めます。

具体的で、観測可能なフィールドを優先します。わかりにくいモデルフィールドには、Pydantic の Field(description=...) を使用します。呼び出し元が必要とするデータのみをモデル化し、内部 ID や中間推論は公開しないでください。

ユーザーが最初に確認するもの、重要な計算値、出力ファイルが必要かどうかを確認します。次に進む前に、スキーマを確定します。

ステップ 4:実現可能性の調査

自律的に調査し、明確な実現可能性評価を報告します。

  1. ドメイン向けライブラリと既存プロジェクトのパターンを探します。
  2. サンドボックスとの互換性を確認します。デフォルトの実行環境は WASM 上の Pyodide です。純粋な Python の wheel と Pyodide 向けにビルドされたパッケージは動作しますが、ネイティブバイナリと通常の C 拡張は動作しません。
  3. ネットワーク要件を特定し、allowed_domains に指定するドメインを正確に列挙します。
  4. ホスト側の要件を特定します。ネイティブライブラリ、認証が必要な API、データベースアクセス、ホストのファイルシステムに対する負荷の高い処理、未対応パッケージは、型付きのホスト側ツールの背後に配置します。
  5. pdf、spreadsheet、docx の組み込みスキルでタスクをすでにカバーできるか確認します。
  6. ランタイム拡張全体を設計する前に、境界が File、Workspace、CtxStr、既存のアダプター、または PreparedInput のパス宣言にすでに適合しているか確認します。

Pyodide で動作しないパッケージは、実装時に想定外の問題とせず、設計上の判断事項として扱います。ホスト側ツールを使用するか、アプローチを変更してください。

ステップ 5:機能の設計

ワークフローを機能させるために必要な、最小限の機能範囲を選択します。

組み込みスキル

必要な組み込みスキルとその理由を示します。

  • PDF のレンダリング、テキスト抽出、変更、墨消しには pdf を使用します。
  • Excel ブック、数式、書式設定には spreadsheet を使用します。
  • Word 文書の読み書きには docx を使用します。
カスタムスキル

Skill は、複数の RLM で再利用できる機能に対してのみ作成します。スキルは、PDF の確認と編集、スプレッドシートの操作、ドケットシステムへの問い合わせなど、あるものを適切に使う方法をモデルに教えます。その手順は、同じ機能を必要とする別の RLM にそのまま添付しても役立つものでなければなりません。

ワークフロー固有の指示は、代わりに DSPy シグネチャの docstring に記述します。シグネチャの docstring は外側の LM に対する指示プロンプトなので、現在の RLM の目的、入力固有の手順、ビジネスルール、出力要件、検証手順、完了条件を担います。

次の基準を使います。

  • ガイダンスが再利用可能な機能の使い方を説明している場合は、Skill に記述します。
  • ガイダンスがこの RLM が行うべきことを説明している場合は、シグネチャの docstring に記述します。
  • テキストでこの RLM のフィールド、出力スキーマ、個別のポリシー、ワークフローの段階に言及している場合は、ほぼ間違いなくシグネチャ固有の内容です。

長いシグネチャから指示を移すだけの目的でスキルを作成してはいけません。また、同じガイダンスを両方の場所に重複して記述してはいけません。単発のホスト呼び出し可能な関数は tools= に直接指定します。その呼び出し可能な関数と使用ガイダンスが、他の RLM でも再利用できる機能を構成する場合にのみ、スキルにまとめます。

再利用可能なスキルごとに、次の項目を指定します。

  • name — 簡潔な機能識別子
  • instructions — 現在の RLM に依存しない、一般的な操作ガイダンス
  • packages — その機能に必要な Pyodide 互換のサンドボックスパッケージ
  • modules — 再利用可能なインポート可能サンドボックスモジュールにマッピングされるホストパス
  • tools — 再利用可能な機能に属するホスト呼び出し可能な関数

instructions は、短いパッケージ説明や関数一覧ではなく、操作マニュアルにします。有用なスキルには通常、次の内容が含まれます。

  1. 機能を使う場面と、各アプローチの選び方
  2. 成果物を確認、変更、作成するための順序立てたワークフロー
  3. モデルが間違えやすい操作に対する、実行可能なコードパターン
  4. SUBMIT の前に確認すべき正確性の不変条件とチェック項目
  5. 既知の失敗モード、サンドボックスの制限、復旧ガイダンス

組み込みスキルは意図的に内容を充実させています。PDF スキルでは、視覚的なレンダリングとテキスト抽出の使い分け、および並列 predict() 呼び出しを説明しています。DOCX スキルでは、文書構造、編集パターン、書式設定の落とし穴、制限事項を扱います。スプレッドシートスキルでは、数式のポリシー、再計算、レンダリング、スタイルの保持、出力の検証を扱います。

次の再利用可能な HTML 機能は、より小規模な形で期待される構成を示しています。

from predict_rlm import Skill


html_skill = Skill(
    name="html",
    instructions="""Use BeautifulSoup to inspect and extract static HTML documents.

## Workflow

1. Read the source without modifying it and record its path and byte size.
2. Parse with `html.parser`. Remove scripts, styles, and `noscript` blocks, but
   preserve headings, lists, links, tables, labels, and form controls.
3. Inventory the semantic structure before extracting: title, headings, main
   content container, tables, links, and repeated navigation/footer regions.
4. Use deterministic selectors and extraction first. Use `predict()` only for
   interpretation of one bounded, cleaned section with a typed result; never
   send an entire large page when a section or table is sufficient.

## Parse and inventory

    from bs4 import BeautifulSoup

    with open(path, "r", encoding="utf-8", errors="replace") as handle:
        soup = BeautifulSoup(handle.read(), "html.parser")

    for node in soup(["script", "style", "noscript"]):
        node.decompose()

    root = soup.find("main") or soup.find("article") or soup.body or soup
    title = soup.title.get_text(" ", strip=True) if soup.title else None
    headings = [
        {
            "level": node.name,
            "text": node.get_text(" ", strip=True),
            "id": node.get("id"),
        }
        for node in root.find_all(["h1", "h2", "h3", "h4", "h5", "h6"])
    ]

## Extract links and tables

    links = [
        {"text": a.get_text(" ", strip=True), "href": a.get("href")}
        for a in root.find_all("a", href=True)
    ]

    tables = []
    for table in root.find_all("table"):
        rows = [
            [cell.get_text(" ", strip=True) for cell in row.find_all(["th", "td"])]
            for row in table.find_all("tr")
        ]
        tables.append(rows)

## Correctness and verification

- Preserve document order, exact link targets, table row order, element IDs,
  and the nearest heading as source context. Do not invent text hidden behind
  missing JavaScript data.
- Check that the selected root is nonempty, expected headings and tables were
  found, and extracted row/link counts match the parsed elements.
- Keep raw source text for quoted evidence. Re-open and verify important quotes
  or values against the original element before submitting.

## Failure modes

- Static HTML may omit content rendered by JavaScript. Report that limitation
  and use a host-side browser tool when rendered DOM access is required.
- `errors="replace"` can hide encoding damage; flag replacement characters in
  relevant text and retry with an identified encoding when necessary.
- `rowspan` and `colspan` require explicit normalization when table geometry
  matters. Do not pretend a flattened row list preserves merged-cell layout.
""",
    packages=["beautifulsoup4"],
)

この例は、特定の RLM のフィールド、出力スキーマ、ビジネスルール、完了ポリシーに言及せずに HTML の扱い方を教えているため、再利用可能です。

ホスト側のツール

各ツールについて、型付きシグネチャ、有用な docstring、戻り値の形式、ホスト上で実行する必要がある理由を定義します。プレーンな JSON 形式のデータまたは Pydantic モデルを返します。PredictRLM は、サンドボックス境界を越える前に、ネストされた値も含めて Pydantic の値をマッピングとリストに正規化します。

範囲を絞った型付きツールを優先します。ツールはシステム境界であり、ホストへの任意アクセスの抜け道ではありません。

カーネル拡張

ワークフローでカスタムのランタイム境界が必要な場合は、実装中に見つけるのではなく、計画段階で指定します。

  • 呼び出し側に公開するシグネチャの型と、モデルから見える値
  • 組み込みのファイル、ワークスペース、スキル、ホストツールでは不十分な理由
  • 前述のカーネルの判断順序における、最小の拡張ポイント
  • すべてのサンドボックスパス、コピーとマウントの動作、バックエンド要件
  • アダプターが所有するリソース、呼び出し単位の状態、永続化のポイント、成功時・失敗時・キャンセル時・セットアップの一部失敗時のクリーンアップ
  • 拡張が JSPI と SBX の両方で移植可能かどうか
  • 複数の要素をまとめる場合の RuntimeContribution の構成境界
  • 焦点を絞ったライフサイクルテストと並行性テスト

ステップ 6:戦略とアーキテクチャ

DSPy のシグネチャの docstring に記載する戦略を作成します。これは RLM のプレイブックです。

  1. 利用可能な入力を調査し、理解します。
  2. ファイルスキル、predict()、ホストツールを使って証拠を収集します。
  3. 証拠を処理し、相互に照合して統合します。
  4. 宣言されたデータを出力し、出力ファイルがあれば所定の場所に書き込みます。

共有状態があり、反復回数に無理のない範囲がある一貫したワークフローには、単一の RLM を選びます。各段階で必要な機能、後続段階が消費する出力アーティファクト、またはモデル/反復の要件が実質的に異なる場合に限り、RLM を連鎖させます。連鎖を構成する場合は、実装前に型付きの段階境界と DAG を定義します。

ワークロードに応じて、初期値の max_iterations、max_llm_calls、max_output_chars を選びます。必要な allowed_domains、抽出に十分な能力を持つ sub_lm が必要かどうか、生成ファイルを扱うために呼び出し元が output_dir を必要とするかどうかを記録します。

実現可能性チェックリスト

計画を確定する前に、次の項目を確認します。

  • すべてのサンドボックスパッケージが Pyodide と互換性があるか、ホストツールに置き換えられています。
  • ネットワークドメインは明示され、最小限に絞られています。
  • ホスト側ツールが、サポートされていないホスト機能をすべて補っています。
  • 反復回数と LM 呼び出し回数の予算は、ワークフローに対して妥当です。
  • 大きな入力は File 参照または必要に応じて取得するメタデータのまま扱われています。
  • 出力スキーマは検証に十分な具体性を備えています。
  • 連鎖させる段階には、型付きの必要な境界が設定されています。

計画の出力

次の内容を含む計画を提示します。

  1. 概要と RLM への適合性の判断。
  2. 提供範囲とファイルマニフェスト。
  3. 入力と出力の完全なスキーマ。
  4. シグネチャの完全な戦略。
  5. スキルとホストツールの契約。
  6. サービスアーキテクチャ。連鎖させる場合は型付き DAG を含めます。
  7. 実現可能性の制約、代替案、初期予算。
  8. スモークテストケースと正確な検証コマンド。

フェーズ 2:構築

承認された設計を、保守可能な最小限のパッケージ構成で実装します。 ベンチマークや RLM-GEPA の最適化を、先回りしてスキャフォールドしないでください。ユーザーがサンプルを持ち、スコアリングの必要性がある場合にのみ eval レイヤーを追加し、最適化の配線には rlm-gepa を使います。

デフォルトのパッケージ構成

my_rlm/
├── pyproject.toml
├── src/
│   └── my_rlm/
│       ├── __init__.py
│       ├── schema.py       # Pydantic inputs and outputs
│       ├── signature.py    # DSPy signature and strategy
│       ├── service.py      # PredictRLM wiring
│       ├── skills.py       # Only when custom skills are needed
│       └── tools.py        # Only when host-side tools are needed

schema.py、signature.py、service.py、パッケージのエクスポートを作成します。選択した境界で必要な場合にのみ、ファイルを追加します。

依存関係

バージョンをハードコードせず、対象リポジトリに predict-rlm をインストールします。

uv add predict-rlm

組み込みのドキュメントまたはスプレッドシートスキルを使う場合にのみ examples エクストラを追加し、ドメイン固有の依存関係は実行場所にのみ追加します。エージェントのみのプロジェクトには、GEPA や可視化のエクストラを含めないでください。

スキーマ

from pydantic import BaseModel, Field


class KeyDate(BaseModel):
    name: str = Field(description="What deadline or effective date this is")
    date: str = Field(description="ISO-8601 calendar date")


class DocumentAnalysis(BaseModel):
    summary: str = Field(description="Grounded Markdown summary")
    key_dates: list[KeyDate] = Field(
        default_factory=list,
        description="Dates supported by the input documents",
    )

シグネチャと戦略

シグネチャの docstring は、1 行の要約ではなく、RLM が実行する戦略として扱います。優れた指示では、情報源の優先順位、探索方法、範囲を限定したツールの使用、中間状態、証拠の規則、検証、情報の欠落や矛盾への対処、出力の契約、停止条件を定義します。

import dspy

from predict_rlm import CtxStr, File

from .schema import DocumentAnalysis


class AnalyzeDocuments(dspy.Signature):
    """Analyze a related document set into a grounded, structured report.

    Read `criteria` first and treat the supplied documents as the sole authority
    for document facts.

    ## Method

    1. Inventory every file before deep reading. Record its exact name, format,
       page or sheet count, likely role, and which criteria it may answer.
    2. Inspect each file with deterministic, format-appropriate tools. Search
       and extract structure to narrow the work; render pages or use focused
       `predict()` calls only on bounded sections that need interpretation.
       Never send the whole document corpus through one giant sub-LM call.
    3. Keep a compact evidence map in Python state with the source file, page,
       sheet, section, or other locator for each relevant fact. Retain evidence,
       not repeated full-document text.
    4. Reconcile overlapping sources. Prefer explicit and more current evidence,
       deduplicate repeated facts, and preserve meaningful disagreements.

    ## Evidence rules

    - Every conclusion and key date must trace to a source locator.
    - Never turn missing, ambiguous, or contradictory evidence into a confident
      claim. Mark it unresolved and explain what is missing.
    - Use `criteria` to control emphasis and format, but never let it justify an
      unsupported fact or silently exclude a supplied file.

    ## Verification and stopping

    Before submitting, confirm that every file was inspected, every criterion is
    answered or explicitly unresolved, important facts were cross-checked, and
    the result satisfies the declared schema. Stop only after those checks pass.

    ## Output contract

    Return one `DocumentAnalysis`. Its summary must be a standalone grounded
    report that follows `criteria`; `key_dates` must contain only supported dates
    with their meaning and normalized value. Use an empty list when no key date
    is supported.
    """

    documents: list[File] = dspy.InputField(desc="Documents to inspect")
    criteria: CtxStr = dspy.InputField(desc="Rubric to apply in full")
    analysis: DocumentAnalysis = dspy.OutputField(desc="Grounded result")

呼び出し元は criteria にプレーンな文字列を渡します。CtxStr はその文字列をサンドボックス変数にすると同時に、プロンプトの完全な追記情報として扱います。RLM がサンドボックスから値を確認できる場合は、通常の str を使います。

サービス

import dspy

from predict_rlm import File, PredictRLM
from predict_rlm.skills import pdf

from .signature import AnalyzeDocuments


class DocumentAnalyzer(dspy.Module):
    def __init__(
        self,
        *,
        lm: dspy.LM | str | None = None,
        sub_lm: dspy.LM | str | None = None,
        max_iterations: int = 30,
        verbose: bool = False,
        debug: bool = False,
    ) -> None:
        self.predictor = PredictRLM(
            AnalyzeDocuments,
            lm=lm,
            sub_lm=sub_lm,
            max_iterations=max_iterations,
            verbose=verbose,
            debug=debug,
            skills=[pdf],
        )

    async def aforward(self, documents: list[File], criteria: str):
        return await self.predictor.acall(documents=documents, criteria=criteria)

呼び出し可能オブジェクトの名前が適切な場合は tools=[callable] を使い、意図的にツール名を指定する場合は tools={"name": callable} を使います。再利用可能なサンドボックス機能には skills=[...] を使います。File または list[File] 型の出力を、呼び出し元が選択したルートディレクトリ以下に収集する必要がある場合は、PredictRLM に output_dir を渡します。

ランタイムリファレンス

コアコンストラクター

PredictRLM(
    signature,
    lm=None,
    sub_lm=None,
    max_iterations=30,
    max_llm_calls=50,
    max_output_chars=50_000,
    verbose=True,
    tools=None,
    skills=None,
    adapters=(),
    execution=None,
    modules=(),
    events=(),
    allowed_domains=None,
    output_dir=None,
    interpreter=None,
    runtime_hooks=None,
    submit_confirmation=None,
    debug=False,
)

lm は外側のコード生成を担い、sub_lm はサンドボックス内の predict() 呼び出しを担います。どちらも DSPy LM またはモデル文字列を受け取ります。predict() は常に利用できます。

カーネル拡張の契約については上記で説明しています。新しいセッションネイティブなバックエンドには execution= を使い、CodeInterpreter 形式の互換性統合には interpreter= を使います。ライフサイクルパラメーターを推測せず、正確なシグネチャについては docs/api.md を参照してください。

ファイル、スキル、ツール

  • File(path="report.pdf") は入力ファイルを表し、File.from_dir(path) はファイル参照を再帰的に検索し、ソートしたリストを作成します。

  • 入力ファイルは /sandbox/input/<field>/ にコピーされます。ファイル出力は /sandbox/output/<field>/ に書き込まれ、実行後に同期されて戻されます。

  • Skill(name, instructions, packages, modules, tools) は再利用可能な機能をまとめたものです。スキル間でツール名が衝突するとエラーになります。

  • pdf、spreadsheet、docx は組み込みのスキルです。

    from predict_rlm.skills import docx, pdf, spreadsheet
    
  • ホストツールは WASM の外部で実行されます。生成されたコードから安全に呼び出せるよう、docstring、引数、戻り値のデータを十分に明確にしてください。

サンドボックスの制約

  • サンドボックスのスキルでは、純粋な Python パッケージまたは Pyodide 対応パッケージを使用してください。
  • サブプロセス、ネイティブバイナリ、一般的な C 拡張機能は利用できるものと想定しないでください。
  • デフォルトではネットワークアクセスが拒否されます。サンドボックスからネットワークサービスへのアクセスが必要な場合は、最小限の allowed_domains リストを設定してください。
  • ネイティブコード、認証情報、データベース、ホストファイルにはホスト側のツールを使用してください。

コメント