Loading...
Loading...
Plan and build an RLM (Recursive Language Model) with predict-rlm. Interactively defines inputs, outputs, skills, and architecture from a goal, then implements the code. Use when the user wants to create a new RLM or explore whether one is feasible.
npx skill4agent add trampoline-ai/predict-rlm rlmFilelist[File]strFilelist[File]FileField(description=...)networkxtree-sitterbeautifulsoup4py3-none-anyallowed_domainspdfspreadsheetdocxmax_iterationsallowed_domainssub_lmschema.pyschema.pysignature.pySkill(...)Stage1(documents) --[ExtractedData]--> Stage2(extracted) --[Report]--> Stage3(report)my_rlm/
├── __init__.py # Public exports (service class, schema, signature)
├── schema.py # Pydantic models for inputs AND outputs
├── signature.py # DSPy Signature (inputs/outputs + strategy docstring)
├── service.py # DSPy Module wiring signature + PredictRLM + skills
└── skills.py # (optional) Custom skill definitions beyond built-in skillsschema.pysignature.pyservice.py__init__.pyskills.pyField(description=...)from pydantic import BaseModel, Field
class KeyDate(BaseModel):
"""A key date extracted from a document."""
name: str = Field(description="e.g. 'Submission Deadline', 'Effective Date'")
date: str = Field(description="ISO format date (YYYY-MM-DD)")
time: str | None = Field(
None, description="24-hour format (HH:MM), e.g. '14:00', '09:30'"
)
timezone: str | None = Field(
None, description="Timezone code, e.g. 'EST', 'EDT', 'PST', 'UTC'"
)
class DocumentAnalysis(BaseModel):
"""Structured analysis of a document set."""
report: str = Field(
description="Full analysis as a well-formatted markdown report"
)
key_dates: list[KeyDate] = Field(
default_factory=list, description="Important dates found in the documents"
)import dspy
from predict_rlm import File
from .schema import DocumentAnalysis
class AnalyzeDocuments(dspy.Signature):
"""Analyze documents and produce a structured report.
1. **Read the report criteria** (appended below) to understand what
information to extract and in what format.
2. **Survey the documents** to understand what you're working with:
file names, page counts, document types.
3. **Gather information** systematically by rendering pages as images
and using predict() to extract content.
4. **Produce the report** following the format specified in the criteria.
Use tables for structured data, prose for analysis and context.
"""
documents: list[File] = dspy.InputField(
desc="PDF documents to analyze"
)
analysis: DocumentAnalysis = dspy.OutputField(
desc="Structured analysis with markdown report, key dates, and key entities"
)import dspy
from predict_rlm import File, PredictRLM
from predict_rlm.skills import pdf as pdf_skill
from .schema import DocumentAnalysis
from .signature import AnalyzeDocuments
class DocumentAnalyzer(dspy.Module):
def __init__(
self,
sub_lm: dspy.LM | str | None = None,
max_iterations: int = 30,
verbose: bool = False,
debug: bool = False,
):
self.sub_lm = sub_lm
self.max_iterations = max_iterations
self.verbose = verbose
self.debug = debug
async def aforward(
self, documents: list[File], criteria: str
) -> DocumentAnalysis:
signature = AnalyzeDocuments.with_instructions(
AnalyzeDocuments.instructions + "\n\n# Task\n\n" + criteria.strip()
)
predictor = PredictRLM(
signature,
sub_lm=self.sub_lm,
skills=[pdf_skill],
max_iterations=self.max_iterations,
verbose=self.verbose,
debug=self.debug,
)
result = await predictor.acall(documents=documents)
return result.analysisfrom predict_rlm.skills import pdf as pdf_skill
from predict_rlm.skills import spreadsheet as spreadsheet_skill
async def aforward(self, documents: list[File]) -> MyOutput:
predictor = PredictRLM(
MySignature,
sub_lm=self.sub_lm,
skills=[pdf_skill, spreadsheet_skill],
tools={"fetch_exchange_rate": fetch_exchange_rate},
...
)async def aforward(self, documents: list[File]):
# Stage 1: Extract
extractor = PredictRLM(ExtractSignature, sub_lm=self.sub_lm, skills=[pdf_skill])
extracted = await extractor.acall(documents=documents)
# Stage 2: Analyze (uses output from stage 1)
analyzer = PredictRLM(AnalyzeSignature, sub_lm=self.sub_lm, skills=[analysis_skill])
result = await analyzer.acall(data=extracted.data)
return resultfrom predict_rlm import Skill
from predict_rlm.skills import pdf as pdf_skill
redaction_skill = Skill(
name="redaction",
instructions="""How to redact content from PDFs using pymupdf.
## Text redaction
Search for text, create redaction annotations, then apply:
page = doc[page_num]
hits = page.search_for("sensitive text")
for rect in hits:
page.add_redact_annot(rect, fill=(0, 0, 0))
page.apply_redactions()
...""",
)
__all__ = ["pdf_skill", "redaction_skill"]predict()predict()predict()File/sandbox/input/{field_name}//sandbox/output/{field_name}/from predict_rlm import File
# Input: File(path="/absolute/path/to/file.pdf")
# Output: declared as File output field, RLM writes to /sandbox/output/<field>/PredictRLM(
signature: type[Signature] | str, # DSPy signature class
lm: dspy.LM | str | None = None, # Main LM (code generation)
sub_lm: dspy.LM | str | None = None, # Sub-LM for predict() calls
max_iterations: int = 30,
max_llm_calls: int = 50,
verbose: bool = False,
tools: dict[str, Callable] | list[Callable] | None = None,
allowed_domains: list[str] | None = None,
skills: list[Skill] | None = None,
debug: bool = False,
output_dir: str | Path | None = None,
)lmsub_lm"openai/gpt-5.4"dspy.LMlmdspy.context(lm=...)from predict_rlm import Skill
Skill(
name="my-skill", # Short identifier
instructions="How to approach...", # Prose injected into the RLM prompt
packages=["pandas", "openpyxl"], # PyPI packages installed in the sandbox
modules={"helper": "/path/to/helper.py"}, # Python files mounted as importable modules
tools={"fetch": fetch_fn}, # Host-side callable functions exposed to the RLM
)tools=from predict_rlm.skills import pdf as pdf_skill # pymupdf
from predict_rlm.skills import spreadsheet as spreadsheet_skill # openpyxl, pandas, formulas
from predict_rlm.skills import docx as docx_skill # python-docx| Skill | Packages | Modules | What it teaches the RLM |
|---|---|---|---|
| — | Read, render, modify, and redact PDFs | |
| spreadsheet | | | Build and modify Excel workbooks with formulas and formatting |
| docx | | | Read, write, and modify Word documents with tables, formatting, and styles |
async def fetch_exchange_rate(currency: str, date: str) -> str:
"""Fetch the exchange rate for a currency on a given date.
Args:
currency: ISO currency code (e.g. "EUR", "GBP")
date: Date in YYYY-MM-DD format
Returns:
JSON string with the exchange rate data
"""
async with httpx.AsyncClient() as client:
resp = await client.get(f"https://api.example.com/rates/{currency}/{date}")
return resp.texttools={"name": fn}tools=| Use a Skill when... | Use |
|---|---|
| The RLM needs a package installed in the sandbox | The function must run on the host (API calls, DB queries, filesystem) |
| You need to teach the RLM how to use something | The tool's docstring is self-explanatory |
| The knowledge is reusable across RLMs | It's a single specific function for one RLM |
predict()result = await predict(
"image: dspy.Image -> items: list[Item]",
instructions="Extract all line items from this invoice page",
image=page_image,
)dspy.Imagefrom predict_rlm import PredictRLM, Skill, File
from predict_rlm.skills import pdf, spreadsheet, docxallowed_domains