Both functions live in the RLM's REPL. One makes a single model call. The other starts a whole child RLM, when the settings let it.
The short version: both are Python functions that RLM code calls inside the REPL. llm_query makes one plain model call and returns text. rlm_query starts a child RLM with its own REPL, which can run code and make its own sub-calls. In the reference library, rlm_query only recurses when max_depth is 2 or more. At the default of 1, it quietly becomes an llm_query.
Yes, in the reference library. We read the source of alexzhang13/rlm on October 15, 2026. The local REPL puts four functions into the namespace of model-written code: llm_query, llm_query_batched, rlm_query and rlm_query_batched (see local_repl.py). The recursive pair arrived in February 2026 with a commit titled "add depth>1 recursive subcalls with limits and cost tracking." A parallel version of rlm_query_batched followed in March.
dspy.RLM has no function named rlm_query. Its built-in tools are llm_query and llm_query_batched. DSPy reaches recursion another way, covered below.
The RLM paper does not name either function in its method text. It says the model gets a REPL "where all tools, including sub-LM or sub-RLM calls, are available as modules." The two library functions are those two kinds of call.
It sends one prompt to a model and returns the reply as a string. The docstring calls it "a single plain completion (no REPL, no recursion)" and says it "always makes a direct LM call via the handler, regardless of depth." The child model sees only the prompt string. It cannot read the context variable, run code, or call anything else.
The library's system prompt tells the root model to use it "for simple extraction, summarization, or Q&A over a chunk of text," and says the sub-LLM "can handle around 500K chars." llm_query_batched sends a list of prompts at once and returns the answers in the same order.
Which model answers? The LM handler routes a request by depth. A call from the root's REPL goes to the model in other_backends if you set one, otherwise to the root model. A model= argument that names a registered client overrides that. This is how you run a large root model with a cheaper sub-call model, the setup the paper used with GPT-5 at the root and GPT-5-mini for sub-calls.
It hands the prompt to a callback, _subcall, in rlm.py. If depth allows, the callback builds a new RLM object one level deeper. The child gets a fresh REPL, with the prompt loaded as its own context. It inherits the backend, environment type, iteration cap and system prompt. It then runs the full loop: it writes code, reads output, calls sub-models, and ends with a final answer. The parent receives only that final string.
The child also receives what is left of the parent's limits. If you set max_budget or max_timeout, the child gets the remaining dollars and seconds. If either is spent, rlm_query returns an error string such as "Budget exhausted" and does not start a child. Custom tools pass down through custom_sub_tools.
rlm_query_batched starts one child per prompt. It runs them in a thread pool capped by max_concurrent_subcalls, which defaults to 4, and keeps the output order. Our post on running sub-calls in parallel covers the same trade-off for plain calls.
More often than the name suggests. There are three cases:
max_depth defaults to 1. The API docs say that when depth >= max_depth, rlm_query() "falls back to a plain llm_query() call (no REPL, no iteration)." With the default, the root never gets the callback, so every rlm_query is a plain call.max_depth=2, the root's rlm_query starts a child RLM. The child's own rlm_query would reach depth 2, so it becomes a plain call.local, ipython and docker environments. The modal, e2b, prime and daytona environment files do not mention rlm_query at all. In those sandboxes, plan for plain calls only.The fallback is silent. Code that calls rlm_query still works, but you pay for a plain call and get a plain answer. If you expected a child to reason in code, check the trajectory log.
The paper evaluates "max recursion depths allowable to the RLM, from 0-3." It defines them this way: "Max recursion depth 0 is an RLM without sub-calling capabilities. Max recursion depth 1 allows sub-calling LLMs, while max depth >1 allows sub-calling RLMs." It assumes depth 1 unless it says otherwise.
So paper depth 1 is a root that uses llm_query. That is the library default, max_depth=1. Paper depth 2 is a root whose rlm_query calls start child RLMs, and whose children make plain calls. That is max_depth=2. Most published RLM results, including the headline OOLONG and BrowseComp-Plus numbers, are depth 1 runs. They use llm_query, not rlm_query. Our post on how deep an RLM should recurse covers the depth sweep in detail.
The library's own prompt draws the line. Use llm_query "for simple, one-shot tasks: extracting info from a chunk, summarizing text, answering a factual question, classifying content." Use rlm_query "when the subtask itself requires deeper thinking: multi-step reasoning, solving a sub-problem that needs its own REPL and iteration."
In practice, the deciding question is whether the sub-task input fits in one prompt. A 20,000-character chunk that needs a label is an llm_query. A sub-task whose input is itself too large to read in one call, such as one file of a large repository, is a candidate for rlm_query. The child can slice that input with code the same way the root does.
Cost and latency set the bar high. Each child runs its own loop of up to max_iterations turns, and each turn can fan out. The paper found that higher depths did worse on average with Qwen3-Coder-480B-A35B, because its frequent syntax errors carried into sub-RLM calls. Start at depth 1 and raise max_depth only when an evaluation shows a gain.
dspy.RLM exposes llm_query and llm_query_batched, both backed by sub_lm, and caps all sub-calls with max_llm_calls (default 50). Since a DSPy commit on October 2, 2026 ("Implement sub-dspy interpreters"), the main branch also lets REPL code build DSPy modules as sub-agents. Its prompt lists dspy.RLM("context, query -> answer") as "a recursive sub-agent with its own REPL on the same interpreter backend as yours." It calls this "the heaviest option" and tells the model to prefer llm_query for one-shot prompts.
That is the DSPy equivalent of rlm_query, under a different name and with a typed signature. It is new, so check that your installed release includes it. Our comparison of dspy.RLM and the reference library predates this change.
llm_query is one model call on one prompt. rlm_query is a full child RLM with its own REPL and its own sub-calls. In the reference library, you get the second only with max_depth of 2 or more, in the local, ipython or docker environment. Everywhere else it falls back to the first. Most RLM work, including the paper's main results, needs only llm_query. Reach for rlm_query when a sub-task's input is too large or too hard for one call.
Not by that name. The paper says the REPL exposes sub-LM and sub-RLM calls as modules. The function names llm_query and rlm_query come from the reference library, which added the recursive pair in February 2026.
The most likely cause is max_depth. It defaults to 1, and at that setting rlm_query falls back to a plain model call. Set max_depth=2 and use the local, ipython or docker environment to get a child RLM.
Yes. rlm_query takes an optional model argument, and the child RLM uses that model name in place of the parent's. Without it, the child inherits the parent's backend settings.
Usually much more. A child RLM runs its own loop of up to max_iterations turns, and each turn can make further sub-calls. The library passes the parent's remaining max_budget and max_timeout to the child, so set those limits before you raise max_depth.
No. dspy.RLM exposes llm_query and llm_query_batched. Since early October 2026 its main branch lets REPL code build a nested dspy.RLM as a sub-agent, which plays the same role.