ReCode: Recursive Code Generation for LLM Agents

11月5日 Published inAI Agent Frameworks

ReCode introduces a recursive code generation mechanism that unifies planning and execution for large language model (LLM) agents. This framework provides fine-grained control, enabling agents to transition seamlessly from high-level strategy to concrete implementation. ReCode decomposes complex tasks into tree-structured, executable code blocks using a divide-and-conquer strategy. The LLM recursively expands placeholder functions into environment-specific calls or specialized subroutines. A dynamic execution loop reacts to environmental feedback in real time, determining whether to proceed, retry, or terminate a task. A shared, restricted Python executor manages the environment state, validates code blocks, and exposes available tools to the agent.

Across diverse environments, ReCode outperforms established baselines such as ReAct and CodeAct, as well as planning-centric frameworks like AdaPlanner and ADaPT. It achieves an average score of 60.8—marking a 20.9% improvement over the leading baseline. On the ALFWorld benchmark, ReCode achieves a perfect score of 100.

How ReCode Compares to Other Paradigms

ReAct agents operate within a repetitive “reason-act” loop, while agents utilizing a separate planner often decouple planning from execution. ReCode bridges this gap by translating pseudo-code decisions directly into executable logic, resulting in a more tightly integrated plan-action cycle.

Four Key Design Elements

  • Tree-structured code: Each node in the tree represents a specific subtask and maintains its own execution trace. For instance, a cook_breakfast task might branch into cook_bacon and cook_eggs.

  • Recursive expansion: The LLM expands placeholder functions into granular calls or smaller routines, guided by environment-specific prompts and few-shot examples.

  • Dynamic execution loop: The agent executes each node immediately. New observations from the environment dictate whether the agent should expand the current path, retry the action, or stop.

  • Shared executor state: A sandboxed Python executor manages environment variables, validates code integrity, and grants the agent access to the necessary toolset.

Installation and Setup

ReCode requires a Conda environment running Python 3.10 or newer. Because dependencies for different environments may conflict, it is recommended to create a dedicated Conda environment for each.

  1. Create a base Conda environment:
conda create -n recode-envname python=3.10
conda activate recode-envname
  1. Environment-specific configuration

ALFWorld: Follow the official ALFWorld installation guide. Set the ALFWORLD_DATA environment variable to your dataset root or modify envs/alfworld/base_config.yaml:

export ALFWORLD_DATA=/path/to/alfworld

ScienceWorld: Follow the setup instructions provided in the ScienceWorld repository.

WebShop: Use the setup script provided by ETO:

cd envs/webshop
pip install -e .
conda install -y -c conda-forge openjdk=11
pip install "en_core_web_lg @ https://github.com/explosion/spacy-models/releases/download/en_core_web_lg-3.6.0/en_core_web_lg-3.6.0-py3-none-any.whl"
bash setup.sh
pip install -r requirements.txt

LLM Access Configuration

Named configurations are stored in configs/profiles.yaml. The --profile argument in run.py determines which configuration is passed to the AsyncLLM module.

Example configuration:

models:
  default:
    api_key: "sk-your_api_key"
    base_url: "https://api.openai.com/v1"
    model: "gpt-4o-mini"
    temperature: 0.0
    track_costs: true

Cost tracking functionality utilizes configs/prices.json. To disable this feature, set track_costs: false. As a fallback, you can set the OPENAI_API_KEY environment variable. Initialize your config by copying the template:

cp configs/profiles_example.yaml configs/profiles.yaml

Running ReCode

The run.py script serves as the primary entry point. It manages agent and environment aliases, handles concurrency, streams logs, and generates structured execution summaries.

Example commands:

  • Single ALFWorld instance:
python run.py -a recode -e alfworld -n 1 --split test --profile default
  • WebShop with increased recursion depth:
python run.py -a recode -e webshop -n 3 --split test --profile default --max-depth 12
  • ScienceWorld with two concurrent instances:
python run.py -a recode -e sciworld -n 5 -c 2 --profile gpt-4o

Key CLI arguments:

  • -a/--agent: The class path or alias (e.g., recode maps to agents.recode.agent.ReCodeAgent).
  • -e/--env: The environment alias (alfworld, webshop, sciworld).
  • -n/--instances: Number of evaluation runs to perform.
  • -c/--concurrent: Maximum number of concurrent runs.
  • --split, --seed, --max-depth, --profile: Parameters passed to both the agent and the environment.
  • -C/--config: A YAML file used to override CLI arguments.

Example YAML configuration (configs/example.yaml):

agent: recode
env: alfworld
instances: 10
concurrent: 2
profile: gpt-4o
split: test
task_types: ["put", "clean"]
max_depth: 12
max_retry: 4

Execute using:

python run.py -C configs/example.yaml

Logs and Results

Each execution generates a logs/<run_id>/ directory containing:

  • running_logs/run.log: Combined logs for the agent and environment.
  • running_logs/instance_<id>.log: Individual traces for each instance.
  • <results.json>: A structured summary including performance metrics and aggregate statistics.

A brief summary, including success rates and per-task breakdowns, is printed to the console upon completion.

Extending to New Environments

  1. Implement the Env interface in envs/<your_env>/env.py. Your class should inherit from base.environment.Env. Implement the reset, _run, is_done, is_success, and report methods. The reset method must return a dictionary: {"observations": [...], "env_name": <name>, "env": self}.

  2. Provide prompts and examples in agents/recode/resources/:

    • prompts/<env_name>/actions.txt: Define valid run("...") calls or available tools.
    • fewshots/<env_name>/: Include one or more .txt files illustrating the thought-to-execution pattern.
  3. Adapt task types: Update the _load_resources method in agents/recode/agent.py and parse_raw_observation in agents/recode/utils.py to ensure initial observations are parsed correctly.

  4. Register the alias (optional): Add your environment class to the ENV_ALIASES dictionary in run.py.

  5. Add a setup script (optional): Create a script similar to envs/webshop/setup.sh to automate dataset retrieval and environment initialization.

Programmatic Embedding

ReCode can be integrated directly into custom workflows. Below is an example of programmatic usage:

import asyncio
from agents.recode.agent import ReCodeAgent
from envs.alfworld.env import AlfworldEnv

async def solve_once():
    config = {"split": "test", "task_types": ["put"], "max_depth": 10}
    env = AlfworldEnv(logger=None)
    agent = ReCodeAgent()
    init_info = env.reset(config)
    agent.reset(config, init_info)
    observations = init_info["observations"]
    
    while not env.is_done():
        actions = await agent.act(observations)
        observations = await env.run(actions)
    
    print(env.report())
    await env.close()

asyncio.run(solve_once())

This pattern is compatible with any environment that implements the Env interface. If file-based trace logging is required, pass a logger instance to the environment during initialization.