Loading repository data…
Loading repository data…
codecrack3 / repository
Using Python and DSpy’s Recursive Language Model implementation to handle unbounded context lengths.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
Using Python and DSpy’s Recursive Language Model implementation to handle unbounded context lengths.
Based on the paper by Alex Zhang and Omar Khattab (MIT, 2025)
Based on the source code by ysz
RLM enables language models to process extremely long contexts (100k+ tokens) by:
Instead of this:
llm.complete(prompt="Summarize this", context=huge_document) # Context rot!
RLM does this:
rlm = RLM(model="gpt-5-mini")
result = rlm.completion(
query="Summarize this",
context=huge_document # Stored as variable, not in prompt
)
The LM can then peek, search, and recursively process the context adaptively.
Note: This package is not yet published to PyPI. Install from source:
# Clone the repository
git clone https://github.com/codecrack3/recursive-llm.git
cd recursive-llm
# Install in editable mode
pip install -e .
# Or install with dev dependencies
pip install -e ".[dev]"
Future: Once published to PyPI, you'll be able to install with pip install recursive-llm
from rlm import RLM
# Initialize with any LLM (auto-selects best backend)
rlm = RLM(model="gpt-4o-mini")
# Process long context
result = rlm.completion(
query="What are the main themes in this document?",
context=long_document
)
print(result)
from rlm import RLM
# RLM uses DSPy for LLM orchestration with E2B cloud sandbox
rlm = RLM(
model="gpt-4o-mini",
sandbox='e2b' # E2B cloud sandbox (or 'auto' to auto-detect)
)
result = rlm.completion(query, context)
Set your API key via environment variable or pass it directly:
export OPENAI_API_KEY="sk-..." # or ANTHROPIC_API_KEY, etc.
Or pass directly in code:
rlm = RLM(model="gpt-5-mini", api_key="sk-...")
Works with 100+ LLM providers via DSPy and OpenRouter:
# OpenAI
rlm = RLM(model="gpt-4o-mini")
rlm = RLM(model="gpt-4o")
# Anthropic
rlm = RLM(model="claude-sonnet-4")
rlm = RLM(model="claude-sonnet-4-20250514")
# OpenRouter (100+ models with single API key)
rlm = RLM(model="openrouter/anthropic/claude-3.5-sonnet")
rlm = RLM(model="openrouter/openai/gpt-4o-mini")
rlm = RLM(model="openrouter/google/gemini-pro")
rlm = RLM(model="openrouter/meta-llama/llama-3.1-70b")
# Ollama (local)
rlm = RLM(model="ollama/llama3.2")
rlm = RLM(model="ollama/mistral")
# llama.cpp (local)
rlm = RLM(
model="openai/local",
api_base="http://localhost:8000/v1"
)
# Azure OpenAI
rlm = RLM(model="azure/gpt-4-deployment")
# And many more...
Use a cheaper model for recursive calls:
rlm = RLM(
model="gpt-5", # Root LM (main decisions)
recursive_model="gpt-5-mini" # Recursive calls (cheaper)
)
For better performance with parallel recursive calls:
import asyncio
async def main():
rlm = RLM(model="gpt-5-mini")
result = await rlm.acompletion(query, context)
print(result)
asyncio.run(main())
rlm = RLM(
model="gpt-5-mini",
max_depth=5, # Maximum recursion depth
max_iterations=20, # Maximum REPL iterations
temperature=0.7, # LLM parameters
timeout=60
)
# Peek at context
context[:1000]
# Search with regex
import re
re.findall(r'pattern', context)
# Recursive processing
recursive_llm("extract dates", context[1000:2000])
FINAL(answer) statementVisualize recursive LLM calls with interactive NetworkX graphs:
from rlm import RLM
# Enable graph tracking
rlm = RLM(
model="gpt-4o-mini",
enable_graph_tracking=True,
graph_output_path="./rlm_graph.html"
)
result = rlm.completion(query="Analyze this", context=document)
# Graph automatically saved to ./rlm_graph.html
The interactive HTML visualization shows:
Programmatic access:
import networkx as nx
# Get the graph object
graph = rlm.get_graph()
print(f"Total nodes: {graph.number_of_nodes()}")
# Analyze the graph structure
for node_id, node_data in graph.nodes(data=True):
print(f"Depth {node_data['depth']}: {node_data['iterations']} iterations")
# Save to different location
rlm.save_graph("./analysis/custom_graph.html")
Learn more: See docs/GRAPH_TRACKING.md for full documentation.
Track and inspect all LLM calls for debugging prompts and responses:
# Enable history tracking
rlm = RLM(
model="gpt-4o-mini",
enable_history=True, # Enable LLM call history
history_output_path="./logs/history.json" # Auto-save to JSON (optional)
)
result = rlm.completion(query="Your query", context=document)
# Print history summary (shows model, messages, outputs)
rlm.print_history(detailed=False)
# Print detailed history with full prompts/responses
rlm.print_history(detailed=True, max_length=2000)
# Get raw history for programmatic access
history = rlm.get_history()
print(f"Total LLM calls: {len(history)}")
# Save history to JSON manually
rlm.save_history("./my_history.json", pretty=True)
# Clear history for new run
rlm.clear_history()
Use cases:
Tip: Combine enable_history=True and enable_graph_tracking=True for comprehensive debugging!
See the examples/ directory for complete working examples:
basic_usage.py - Simple completion with OpenAIdspy_usage.py - DSPy backend with E2B sandboxopenrouter_usage.py - OpenRouter multi-model accesse2b_usage.py - E2B cloud sandbox featuresollama_local.py - Using Ollama locallytwo_models.py - Cost optimization with two modelslong_document.py - Processing 50k+ token documentsdata_extraction.py - Extract structured data from textmulti_file.py - Process multiple documentscustom_config.py - Advanced configurationgraph_tracking.py - NetworkX visualization of recursive callsRun an example:
# Set your API key first
export OPENAI_API_KEY="sk-..."
# Run example
python examples/basic_usage.py
On OOLONG benchmark (132k tokens):
Tested with GPT-5-Mini on structured data queries (counting, filtering) across 5 different test cases:
60k token contexts:
RLM wins on accuracy. Both complete requests, but only RLM gives correct answers.
150k+ token contexts:
Token efficiency: RLM uses ~2-3k tokens per query vs 95k+ for direct approach, since context is stored as a variable instead of being sent in prompts.
# Clone repository
git clone https://github.com/codecrack3/recursive-llm.git
cd recursive-llm
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Run tests with coverage
pytest tests/ -v --cov=src/rlm --cov-report=term-missing
# Type checking
mypy src/rlm
# Linting
ruff check src/rlm
# Format code
black src/rlm tests examples
RLM uses DSPy for LLM orchestration with flexible sandbox options:
RLM (DSPy Backend)
├── Custom RLMModule (DSPy module for REPL pattern)
├── E2B Sandbox (cloud code execution)
└── RestrictedPython Fallback (local execution)
Key Features:
RLMModule optimized for recursive REPL pattern# Auto-selects E2B if API key set, otherwise RestrictedPython
rlm = RLM(model="gpt-4o-mini")
# Use E2B cloud sandbox (requires E2B_API_KEY)
rlm = RLM(model="gpt-4o-mini", sandbox='e2b')
# Use RestrictedPython (no API key needed, runs locally)
rlm = RLM(model="gpt-4o-mini", sandbox='restricted')
Configure sandbox preferences via environment variables:
# Sandbox selection
export RLM_SANDBOX=e2b # or 'restricted', 'auto'
# E2B API key (get from https://e2b.dev)
export E2B_API_KEY=your-key-here
The LiteLLM backend has been removed in v0.2.0. If you were using the backend parameter, simply remove it:
Before (v0.1.0):
from rlm import RLM
rlm = RLM(model="gpt-4o-mini", backend='dspy')
result = rlm.completion(query, context)
After (v0.2.0):
from rlm import RLM
rlm = RLM(model="gpt-4o-mini") # backend parameter removed
result = rlm.completion(query, context)
Breaking Changes:
backend parameter (only DSPy is supported now)RLMLiteLLM classBackend type from exportslitellm dependency.env file:
E2B_API_KEY=your-key-here
OpenRouter provides access to 100+ models through a single API key:
.env file:
OPENROUTER_API_KEY=your-key-here
**Usage: