Understanding how RLM-REPL works under the hood.
RLM-REPL was created by Remy Gakwaya after reading the MIT paper on Recursive Language Models. The original concept involved using a REPL where the language model would generate Python functions to process and query documents. However, this approach faced significant challenges:
- Smaller LLMs struggled to generate complex, correct Python functions
- Reliability issues with function execution and error handling
- Complexity in managing dynamically generated code
After hundreds of iterations and experiments, Remy developed the RLM-REPL v8 concept - a human-like reading strategy specifically optimized for local, smaller language models. The development philosophy was: if it works reliably with poor and small models on limited computation, it will perform exceptionally well with leading LLMs.
The library evolved to use SQL-based retrieval with DuckDB, which provides:
- Structured interface: SQL is more predictable than generated Python code
- Universal compatibility: Works reliably with models of all sizes, from small local models to leading cloud-based LLMs
- Performance: Database indexes enable efficient querying
- Safety: No dynamic code execution required
This SQL-based approach implements the proven v8 human-like reading strategy (overview → search → deep read → synthesize) while being more practical and reliable for production use. The strategy was refined through extensive testing to ensure it works effectively even with resource-constrained local models.
RLM-REPL implements a two-sided architecture that separates data storage from inference logic:
┌─────────────────────────────────────────────────────────┐
│ RLM-REPL System │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Data Layer │ │ Inference Layer │ │
│ │ │ │ │ │
│ │ DocumentDatabase│◄────►│ ReadingStrategy │ │
│ │ (DuckDB) │ │ InferenceClient │ │
│ │ │ │ AnswerSynthesizer│ │
│ └──────────────────┘ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
Purpose: Store and query documents efficiently using SQL.
Technology: DuckDB (in-memory or persistent)
Responsibilities:
- Parse documents into line-level records
- Detect strategic markers (headers, section starts)
- Provide SQL query interface
- Maintain indexes for fast queries
Schema:
CREATE TABLE documents (
line_num INTEGER, -- Line number (1-indexed)
text STRING, -- Line content
word_count INTEGER, -- Words in this line
is_header BOOLEAN, -- True if header/title
is_list_item BOOLEAN, -- True if list item
is_code BOOLEAN, -- True if code content
is_section_start BOOLEAN,-- True if section start
is_strategic BOOLEAN -- True if header or section start
);Key Features:
- Automatic strategic marker detection
- Indexes on
line_numandis_strategic - Support for in-memory and persistent storage
Purpose: Generate prompts that guide the LLM to read documents strategically.
Strategy Pattern:
- Overview - Read beginning (lines 1-100)
- Search - Find keywords using
LIKE '%term%' - Read - Focused reading (20-50 lines)
- Deep Read - Detailed analysis (50-100 lines)
Prompt Engineering:
- Provides schema information
- Shows reading history
- Guides iteration-specific behavior
- Includes examples of correct queries
Purpose: Abstract interface to LLM APIs.
Features:
- OpenAI-compatible API support
- Handles authentication
- Manages API calls
- Parses LLM responses
Response Format:
{
"thought": "What I've learned...",
"reading_mode": "overview|search|read|deep_read",
"goal": "What I hope to find",
"sql_query": "SELECT ...",
"satisfied": false,
"next_move": "What I'll do next"
}Purpose: Combine gathered information into a final answer.
Process:
- Collects all reading results
- Builds context from gathered lines
- Generates synthesis prompt
- Calls LLM to generate answer
┌─────────────────────────────────────────────────────────┐
│ Question Asked │
└────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Iteration 1: Overview │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 1. Build schema info (total lines, columns) │ │
│ │ 2. Generate iteration prompt │ │
│ │ 3. Call LLM for reading strategy │ │
│ │ 4. Parse LLM response (SQL query) │ │
│ │ 5. Auto-fix SQL if needed │ │
│ │ 6. Execute SQL query │ │
│ │ 7. Store results in history │ │
│ └──────────────────────────────────────────────────┘ │
└────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Iteration 2: Search │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 1. Build prompt with history │ │
│ │ 2. Guide toward keyword search │ │
│ │ 3. Call LLM for search strategy │ │
│ │ 4. Execute search query │ │
│ │ 5. Store results │ │
│ └──────────────────────────────────────────────────┘ │
└────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Iteration 3+: Deep Read (if needed) │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 1. Read around findings │ │
│ │ 2. Extract detailed information │ │
│ │ 3. Continue until satisfied or max iterations │ │
│ └──────────────────────────────────────────────────┘ │
└────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Answer Synthesis │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 1. Combine all reading results │ │
│ │ 2. Build synthesis prompt │ │
│ │ 3. Generate final answer │ │
│ └──────────────────────────────────────────────────┘ │
└────────────────────┬────────────────────────────────────┘
│
▼
Final Answer
RLM-REPL includes automatic SQL query fixing to improve results:
- Missing ORDER BY: Adds
ORDER BY line_numfor readability - Missing LIMIT: Adds
LIMIT 50for search queries - Missing word_count: Ensures
word_countis in SELECT - Header-only queries: Detects and fixes queries that would return only headers
Example fix:
-- LLM generates:
SELECT * FROM documents WHERE is_strategic = true LIMIT 50
-- Auto-fixed to:
SELECT line_num, text, word_count, is_header
FROM documents
WHERE line_num BETWEEN 1 AND 100
ORDER BY line_numDocument Loaded → Question Start → Iteration Start → SQL Execute →
Results → Iteration End → [Repeat] → Synthesis Start → Answer →
Question End
- Lifecycle:
SESSION_START,SESSION_END,DOCUMENT_LOADED - Question Processing:
QUESTION_START,QUESTION_END - Iterations:
ITERATION_START,ITERATION_END - SQL:
SQL_EXECUTE,SQL_RESULT - LLM:
LLM_REQUEST,LLM_RESPONSE - Results:
RESULTS,SYNTHESIS_START,SYNTHESIS_END,ANSWER - Errors:
ERROR,WARNING
Manages event subscription and emission:
- Subscribers register callbacks
- Events are emitted to all subscribers
- Errors in callbacks don't break main flow
When a document is loaded:
- Read file line by line
- Detect metadata for each line:
- Headers: Lines starting with
#or all uppercase short lines - List items: Lines starting with
-,*, or numbers - Code: Lines containing code markers
- Section starts: Headers or lines ending with
:
- Headers: Lines starting with
- Calculate word count per line
- Store in DuckDB with all metadata
Strategic markers help the LLM navigate the document:
is_header: True for headers/titlesis_strategic: True for headers or section starts- Used to find document structure quickly
Goal: Understand document type and structure
Query Pattern:
SELECT line_num, text, word_count, is_header
FROM documents
WHERE line_num BETWEEN 1 AND 100
ORDER BY line_numExpected Result: 1000-2000 words of actual content
Goal: Find where topic is discussed
Query Pattern:
SELECT line_num, text, word_count
FROM documents
WHERE LOWER(text) LIKE '%keyword%'
ORDER BY line_num
LIMIT 40Expected Result: 20-40 matching lines
Goal: Extract detailed information
Query Pattern:
SELECT line_num, text, word_count, is_header
FROM documents
WHERE line_num BETWEEN X AND Y
ORDER BY line_numExpected Result: 500-1200 words of detailed content
- Collect Results: All DataFrames from reading iterations
- Deduplicate: Remove duplicate lines by
line_num - Build Context: Combine text from all unique lines
- Generate Prompt: Include question, reading history, and context
- Synthesize: Call LLM to generate final answer
Answer the question based on the document excerpts provided.
QUESTION: [user question]
READING PROCESS:
- Iteration 1 (overview): X lines, Y words
- Iteration 2 (search): X lines, Y words
...
DOCUMENT EXCERPTS:
[combined text from all readings]
INSTRUCTIONS:
- Provide a clear, comprehensive answer
- Base answer ONLY on excerpts
- Cite line numbers: [Lines X-Y]
- Acknowledge missing information if incomplete
- Indexes: Created on
line_numandis_strategic - In-memory: Fast for single-session use
- Persistent: Cached for multi-session use
- Temperature: Lower for reading strategy (more focused)
- Max Iterations: Balance between thoroughness and speed
- Parallel Queries: Not currently supported (sequential)
- In-memory DB: Stores entire document in memory
- DataFrames: Reading results stored temporarily
- History: Reading history kept for context
You can influence reading by:
- Asking specific questions
- Using direct SQL queries
- Adjusting
max_iterations - Modifying temperature settings
Subscribe to events for:
- Progress tracking
- Logging
- Metrics collection
- Custom UI updates
- Custom table names
- Persistent storage paths
- Additional metadata columns (via DataFrame loading)
- Sequential Processing: Iterations run sequentially
- Context Window: Still limited by LLM's context window for synthesis
- SQL Complexity: LLM must generate valid SQL
- Document Format: Works best with structured text documents
Potential enhancements:
- Parallel iteration processing
- Advanced query optimization
- Multi-document support
- Custom reading strategy plugins
- Vector similarity search integration