Recursive Language Model (RLM) Tool and Parallel Sub-LLM Orchestration in DeepSeek-TUI
The Recursive Language Model (RLM) tool enables parallel sub-LLM orchestration by spawning a sandboxed Python REPL where the model can invoke cheap child LLMs via rlm_query_batched, aggregate token usage, and return unified results while keeping the main conversation responsive.
DeepSeek-TUI implements a sophisticated Recursive Language Model architecture that transforms how AI assistants handle complex task decomposition. By providing a sandboxed Python REPL with built-in parallel sub-LLM orchestration capabilities, the system allows the model to spawn multiple cheap deepseek-v4-flash children simultaneously for batch classification and analysis. This design, maintained in the Hmbown/DeepSeek-TUI repository, isolates heavy computation from the main conversation thread while enforcing recursion budgets and maintaining full cost visibility.
RLM Architecture and Source Files
The RLM implementation spans seven critical components across the Rust codebase, each handling a specific aspect of tool registration, execution, or UI feedback.
Tool Entry Point and Registry
The rlm_process tool implementation lives in crates/tui/src/tools/rlm.rs. This file validates incoming requests, loads file content (or inline text), and orchestrates the initial REPL bridge setup. The tool family registration occurs in crates/tui/src/tools/registry.rs, which maps the rlm namespace to the engine dispatcher, enabling the system to route /rlm invocations to the correct handler.
Core Turn Engine
crates/tui/src/rlm/turn.rs contains the recursive turn logic via run_rlm_turn_with_root and run_rlm_turn_inner. These functions manage the sandboxed Python REPL lifecycle, extract llm_query and rlm_query calls from model output, spawn child LLM requests, and aggregate token usage across all sub-calls. Lines 506-511 specifically handle the cost folding that merges child token consumption back into the parent session budget.
Prompt Contract and Constraints
The system prompt that forces the model to use sub-LLM capabilities resides in crates/tui/src/rlm/prompt.rs. This contract requires the model to invoke the REPL at least once and to use llm_query or rlm_query before emitting a final answer. The bridge rejects any response that lacks at least one sub-LLM invocation, ensuring the recursive capabilities are actually utilized.
UI Visualization Components
Parallel execution feedback surfaces through three UI files:
crates/tui/src/tui/widgets/tool_card.rs: Renders the "rlm" fan-out card showing active workers (e.g., "w_1 … w_4") and completion statuscrates/tui/src/tui/sidebar.rs: Tracks theforeground_rlm_runningflag to update global UI statecrates/tui/src/tui/subagent_routing.rs: Implements the generic fan-out abstraction used by RLM for routing multiple concurrent sub-agents
Execution Flow of Parallel Sub-LLM Orchestration
When a user triggers the RLM tool, the system follows a strict seven-phase pipeline:
-
Request Ingestion: The engine receives a
/rlmcommand (e.g.,/rlm file_path=src/main.rs) and dispatches to therlmfamily via the registry intools/registry.rs -
Tool Initialization:
rlm_processintools/rlm.rsvalidates inputs and callsrun_rlm_turn_with_rootfromrlm/turn.rsto initialize the session -
REPL Bridge Creation: The turn engine spawns a sandboxed Python REPL exposing four helper functions:
llm_query(prompt, model=None)llm_query_batched([p1, …], model=None)rlm_query(prompt, model=None)rlm_query_batched([p1, …], model=None)
-
Model-Driven Recursion: Inside the REPL, the model invokes these helpers, which translate into async LLM requests—typically targeting the cheap
deepseek-v4-flashmodel—returning raw responses to the REPL for further reasoning -
Parallel Fan-Out: When using
rlm_query_batchedorllm_query_batched, the bridge fires N concurrent LLM calls, aggregating results into a single response object while updating token-cost counters -
Termination Validation: The REPL must emit a
FINAL(...)block. The bridge verifies that at least one sub-LLM call occurred; otherwise, it rejects the answer per the contract inrlm/prompt.rs -
Result Propagation:
run_rlm_turn_with_rootreturns the final string torlm_process, which packages it as a tool result and streams it to the transcript, with UI components automatically clearing the fan-out card
Safety and Budget Constraints
The RLM tool implements strict guardrails to prevent runaway recursion and uncontrolled costs.
Recursion Depth Limiting: The RLM_RECURSION_BUDGET parameter (default = 1) caps how deeply a sub-LLM may invoke sub_rlm(). When calling nested RLM instances, authors must pass recursion_budget=0 to disable further nesting, preventing infinite recursive loops.
Cost Aggregation: After turn completion, run_rlm_turn_inner folds all child-LLM token usage into the parent session metrics. This ensures that cheap deepseek-v4-flash sub-calls are tracked against the overall conversation budget, providing transparent cost accounting even during massive parallel fan-outs.
UI Feedback: The fan-out card in tool_card.rs provides real-time visibility into worker status, while sidebar.rs tracks foreground RLM activity to prevent conflicting operations.
Practical Implementation Examples
Basic UI Invocation
Trigger the RLM tool directly from the chat interface:
/rlm file_path=src/main.rs
The engine loads the specified file, starts the REPL with the system prompt from rlm/prompt.rs, and streams reasoning steps. The sidebar displays an "rlm" fan-out card while child LLMs execute.
Batched Parallel Queries
Inside the sandboxed REPL, use rlm_query_batched to classify or analyze multiple items simultaneously:
# Inside the REPL (automatically opened by the tool)
prompts = [
"Summarize the function `parse_args` in 1 sentence.",
"Identify any unsafe Rust patterns in `parse_args`.",
"Suggest a test case for `parse_args`."
]
# Fire 3 concurrent sub-LLM calls (default: deepseek-v4-flash)
answers = rlm_query_batched(prompts)
for i, a in enumerate(answers):
print(f"=== Answer {i+1} ===\n{a}\n")
The bridge sends three concurrent requests, aggregates the responses, and returns them to the REPL. When the model finally emits FINAL(...), the concatenated output returns to the main transcript.
Nested Recursive Analysis
Invoke a child RLM from within a parent REPL for hierarchical decomposition:
# First level REPL
summary = llm_query("Summarize the project architecture.")
print("Summary:", summary)
# Spawn nested RLM with disabled further recursion
deep_analysis = sub_rlm(
file_path="src/lib.rs",
recursion_budget=0 # prevents additional nesting
)
print("Deep analysis:", deep_analysis)
The sub_rlm call invokes run_rlm_turn_with_root again with a reduced budget, creating a child context that can complete without risking runaway depth.
Skill Integration
Wrap the RLM tool in a reusable skill definition:
---
name: rlm-batch-analyze
description: Batch-analyze source files using parallel sub-LLM orchestration.
---
# Skill: rlm-batch-analyze
{{#if files}}
/rlm content={{files}}
{{/if}}
When loaded via /skill rlm-batch-analyze, the engine substitutes the file list and runs a single REPL that internally parallelizes analysis across all inputs.
Summary
- DeepSeek-TUI implements recursive language model capabilities through a sandboxed Python REPL that exposes
llm_queryandrlm_queryhelpers - Parallel orchestration occurs via
rlm_query_batched, which fires N concurrent calls to cheapdeepseek-v4-flashmodels and aggregates results - Safety mechanisms include the
RLM_RECURSION_BUDGET(default 1), mandatory sub-LLM invocation requirements, and comprehensive token usage folding inrlm/turn.rs - UI components in
tool_card.rsandsidebar.rsprovide real-time visibility into fan-out workers and foreground RLM status - Source locations: Tool logic resides in
crates/tui/src/tools/rlm.rs, core engine incrates/tui/src/rlm/turn.rs, and prompt constraints incrates/tui/src/rlm/prompt.rs
Frequently Asked Questions
How does the RLM tool prevent infinite recursion loops?
The system enforces a hard RLM_RECURSION_BUDGET (defaulting to 1) that decrements with each nested sub_rlm() call. When a child RLM invokes the helper, it must pass a reduced budget; reaching zero disables further nesting. Additionally, the prompt contract in rlm/prompt.rs requires at least one sub-LLM call per turn, but the turn engine validates termination via the FINAL(...) block syntax.
What is the performance benefit of using rlm_query_batched over sequential calls?
rlm_query_batched executes all sub-LLM requests concurrently rather than waiting for each response serially. According to the implementation in rlm/turn.rs, this parallel fan-out reduces round-trip latency from O(N) to roughly O(1) relative to the slowest child request, making it ideal for batch classification of thousands of items or parallel code review of multiple source files.
How are token costs tracked across child and parent LLM calls?
The run_rlm_turn_inner function in rlm/turn.rs (lines 506-511) implements cost folding that aggregates token usage from all child LLM invocations into the parent session's budget counters. Whether using single llm_query or batched calls, the system maintains a unified accounting of prompt and completion tokens across the entire recursive tree.
Can I use models other than deepseek-v4-flash for sub-LLM queries?
While the default model for llm_query and rlm_query is deepseek-v4-flash to optimize cost, the helper functions accept an optional model parameter. You can specify alternative models supported by the DeepSeek API, though the implementation in tools/rlm.rs and rlm/turn.rs optimizes for the flash model's speed and pricing characteristics during parallel orchestration.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →