@wsl8297: 在 GitHub 上发现一个递归式多 Agent 框架:ROMA(Recursive Open Meta-Agent),它通过层次化的递归结构来解决复杂问题,把任务拆解成可并行处理的组件,让 Agent 能处理更复杂的推理任务。 GitH…
摘要
ROMA 是一个基于 DSPy 构建的递归式多 Agent 框架,旨在通过层次化递归结构解决复杂推理任务,支持任务拆解、并行处理及多种 LLM 提供商。
查看缓存全文
缓存时间: 2026/05/13 14:21
在 GitHub 上发现一个递归式多 Agent 框架:ROMA(Recursive Open Meta-Agent),它通过层次化的递归结构来解决复杂问题,把任务拆解成可并行处理的组件,让 Agent 能处理更复杂的推理任务。 GitHub:https://github.com/sentient-agi/ROMA… 核心工作流程: - Atomizer:判断任务是否可以直接执行,还是需要进一步规划 - Planner:如果需要规划,就把任务拆解成更小的子任务 - Executor:执行原子任务,支持调用 LLM、API 或其他 Agent - Aggregator:收集并整合子任务结果,生成父任务的答案 - Verifier(可选):验证聚合结果是否符合原始目标 信息流是三向的:任务自上而下递归分解,结果自下而上聚合,依赖关系从左到右按顺序执行,这种结构让系统能灵活处理复杂问题,同时保持清晰的透明度。 框架基于 DSPy 构建,支持多种预测策略(CoT、ReAct、CodeAct 等)。提供两种安装方式:最小安装 30 秒上手,只需 pip 安装即可使用核心功能;完整安装支持 Docker 部署,包含 PostgreSQL 持久化、MLflow 可观测性、REST API 服务器等生产级功能。 默认配置使用 OpenRouter(Claude Sonnet 4.5 + Gemini 2.5 Flash),也支持 OpenAI、Anthropic 等其他 LLM 提供商。内置计算器、文件操作等工具包,还可以接入 E2B 代码执行沙箱、S3 存储等扩展功能。 适合需要构建层次化多 Agent 系统、处理复杂推理任务的开发者,或者想了解递归式 Agent 框架设计的人。
sentient-agi/ROMA
Source: https://github.com/sentient-agi/ROMA
ROMA: Recursive Open Meta-Agents
Building hierarchical high-performance multi-agent systems made easy! (Beta)
📑 Table of Contents
- 🧠 Conceptual Overview
- 📦 Installation & Setup
- ⚡ Quickstart: End-to-End Workflow
- ⚙️ Configuration & Storage
- 🧰 Toolkits
- 🌐 REST API & CLI
- 🏗️ Core Building Block:
BaseModule - 📚 Module Reference
- 🎯 Advanced Patterns
- 🧪 Testing
- 💡 Troubleshooting & Tips
- 📖 Glossary
🎯 What is ROMA?
ROMA is a meta-agent framework that uses recursive hierarchical structures to solve complex problems. By breaking down tasks into parallelizable components, ROMA enables agents to tackle sophisticated reasoning challenges while maintaining transparency that makes context-engineering and iteration straightforward. The framework offers parallel problem solving where agents work simultaneously on different parts of complex tasks, transparent development with a clear structure for easy debugging, and proven performance demonstrated through our search agent’s strong benchmark results. We’ve shown the framework’s effectiveness, but this is just the beginning. As an open-source and extensible platform, ROMA is designed for community-driven development, allowing you to build and customize agents for your specific needs while benefiting from the collective improvements of the community.
🏗️ How It Works
ROMA framework processes tasks through a recursive plan–execute loop:
def solve(task):
if is_atomic(task): # Step 1: Atomizer
return execute(task) # Step 2: Executor
else:
subtasks = plan(task) # Step 2: Planner
results = []
for subtask in subtasks:
results.append(solve(subtask)) # Recursive call
return aggregate(results) # Step 3: Aggregator
# Entry point:
answer = solve(initial_request)
- Atomizer – Decides whether a request is atomic (directly executable) or requires planning.
- Planner – If planning is needed, the task is broken into smaller subtasks. Each subtask is fed back into the Atomizer, making the process recursive.
- Executors – Handle atomic tasks. Executors can be LLMs, APIs, or even other agents — as long as they implement an
agent.execute()interface. - Aggregator – Collects and integrates results from subtasks. Importantly, the Aggregator produces the answer to the original parent task, not just raw child outputs.
📐 Information Flow
- Top-down: Tasks are decomposed into subtasks recursively.
- Bottom-up: Subtask results are aggregated upwards into solutions for parent tasks.
- Left-to-right: If a subtask depends on the output of a previous one, it waits until that subtask completes before execution.
This structure makes the system flexible, recursive, and dependency-aware — capable of decomposing complex problems into smaller steps while ensuring results are integrated coherently.
Click to view the system flow diagram
flowchart TB
A[Your Request] --> B{Atomizer}
B -->|Plan Needed| C[Planner]
B -->|Atomic Task| D[Executor]
%% Planner spawns subtasks
C --> E[Subtasks]
E --> G[Aggregator]
%% Recursion
E -.-> B
%% Execution + Aggregation
D --> F[Final Result]
G --> F
style A fill:#e1f5fe
style F fill:#c8e6c9
style B fill:#fff3e0
style C fill:#ffe0b2
style D fill:#d1c4e9
style G fill:#c5cae9
🚀 Quick Start
Fastest Way: Minimal Installation (Recommended for Evaluation)
Get started in under 30 seconds with no infrastructure required:
# Install with uv (10-100x faster)
uv pip install roma-dspy
# Or with pip
pip install roma-dspy
# Set your OpenRouter API key (default uses Claude Sonnet 4.5 + Gemini 2.5 Flash)
export OPENROUTER_API_KEY="sk-or-v1-..."
# Start solving tasks immediately
python -c "from roma_dspy.core.engine.solve import solve; print(solve('What is 2+2?'))"
Note: The default configuration uses OpenRouter with Claude Sonnet 4.5 (executor) and Gemini 2.5 Flash (other agents). You can also use OpenAI directly by setting
OPENAI_API_KEYand customizing the config.
What you get:
- ✅ Core agent framework (Atomizer, Planner, Executor, Aggregator, Verifier)
- ✅ All DSPy prediction strategies (CoT, ReAct, CodeAct, etc.)
- ✅ File storage (no database required)
- ✅ Built-in toolkits (Calculator, File operations)
- ✅ Works with any LLM provider (OpenRouter, OpenAI, Anthropic, etc.)
No Docker, no database, no setup - just install and go!
Production Setup: Full Features with Docker
For production use with persistence, observability, and API server:
# One-command setup (builds Docker, starts services)
just setup
# Or with specific profile
just setup crypto_agent
# Verify services running
curl http://localhost:8000/health
# Solve tasks via API
just solve "What is the capital of France?"
Additional features with Docker:
- 📊 PostgreSQL persistence (execution history, checkpoints)
- 📈 MLflow observability (experiment tracking, visualization)
- 🌐 REST API server (FastAPI with interactive docs)
- 📦 S3-compatible storage (MinIO)
- 🔧 E2B code execution sandboxes
- 🎨 Interactive TUI visualization
Services Available:
- 🚀 REST API: http://localhost:8000/docs
- 🗄️ PostgreSQL: Automatic persistence
- 📦 MinIO: S3-compatible storage (http://localhost:9001)
- 📊 MLflow: http://localhost:5000 (with
docker-up-full)
See Quick Start Guide and Deployment Guide for details.
🧠 Conceptual Overview
ROMA’s module layer wraps canonical DSPy patterns into purpose-built components that reflect the lifecycle of complex task execution:
- Atomizer decides whether a request can be handled directly or needs decomposition.
- Planner breaks non-atomic goals into an ordered graph of subtasks.
- Executor resolves individual subtasks, optionally routing through function/tool calls.
- Aggregator synthesizes subtask outputs back into a coherent answer.
- Verifier (optional) inspects the aggregate output against the original goal before delivering.
Every module shares the same ergonomics: instantiate it with a language model (LM) or provider string, choose a prediction strategy, then call .forward() (or .aforward() for async) with the task-specific fields.
All modules ultimately delegate to DSPy signatures defined in roma_dspy.core.signatures. This keeps interfaces stable even as the internals evolve.
📦 Installation & Setup
Option 1: Minimal Installation (Fastest - Recommended for Evaluation)
Perfect for: Evaluating ROMA, development, testing, quick prototyping
Install in under 30 seconds:
# With uv (recommended - 10-100x faster)
uv pip install roma-dspy
# Or with pip
pip install roma-dspy
Set your API key:
export OPENROUTER_API_KEY="sk-or-v1-..." # Recommended
# OR
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
Start using immediately:
from roma_dspy.core.engine.solve import solve
# Solve any task
result = solve("What is the capital of France?")
print(result)
What’s included:
- ✅ All core modules (Atomizer, Planner, Executor, Aggregator, Verifier)
- ✅ All DSPy prediction strategies
- ✅ File-based storage (no database needed)
- ✅ Core toolkits (Calculator, File operations)
- ✅ Works with any LLM provider
What’s NOT included (install separately if needed):
- PostgreSQL persistence →
uv pip install roma-dspy[persistence] - MLflow observability →
uv pip install roma-dspy[observability] - E2B code execution →
uv pip install roma-dspy[e2b] - REST API server →
uv pip install roma-dspy[api] - S3 storage →
uv pip install roma-dspy[s3] - All features →
uv pip install roma-dspy[all]
Option 2: Full Installation with Docker (Production)
Perfect for: Production deployment, teams, full observability
Prerequisites:
- Docker & Docker Compose
- Python 3.12+ (for local development)
- Just command runner (optional, recommended)
One-command setup:
# Interactive setup (prompts for E2B, S3, etc.)
just setup
# Or with specific profile
just setup crypto_agent
Manual Docker start:
just docker-up # Basic (PostgreSQL + MinIO + API)
just docker-up-full # With MLflow observability
Environment variables (auto-configured by just setup):
# LLM Provider (required)
OPENROUTER_API_KEY=... # Recommended
# OR
OPENAI_API_KEY=...
ANTHROPIC_API_KEY=...
# Optional: Advanced features
E2B_API_KEY=... # Code execution
COINGECKO_API_KEY=... # Crypto toolkit
Additional Docker features:
- 📊 PostgreSQL (execution history, checkpoints)
- 📈 MLflow (experiment tracking, metrics)
- 🌐 REST API (FastAPI with docs)
- 📦 MinIO (S3-compatible storage)
- 🎨 TUI visualization
Option 3: Development Installation
For contributing or extending ROMA:
# Clone repository
git clone https://github.com/sentient-agi/roma.git
cd roma
# Install with dev tools (includes pytest, ruff, mypy)
uv pip install -e ".[dev]"
# Run tests
just test
# Format code
just format
# Type check
just typecheck
Comparison: Which Installation is Right for You?
| Feature | Minimal (pip install roma-dspy) | Docker (just setup) |
|---|---|---|
| Installation time | < 30 seconds | ~5-10 minutes |
| Infrastructure required | None | Docker |
| Core agent framework | ✅ | ✅ |
| File storage | ✅ | ✅ |
| PostgreSQL persistence | ❌ (install [persistence]) | ✅ |
| MLflow observability | ❌ (install [observability]) | ✅ |
| REST API | ❌ (install [api]) | ✅ |
| Best for | Evaluation, development | Production, teams |
⚡ Quickstart: End-to-End Workflow
The following example mirrors a typical orchestration loop. It uses three different providers to showcase how easily each module can work with distinct models and strategies.
import dspy
from roma_dspy import Aggregator, Atomizer, Executor, Planner, Verifier, SubTask
from roma_dspy.types import TaskType
# Optional tool that the Executor may call
def get_weather(city: str) -> str:
"""Return a canned weather report for the city."""
return f"The weather in {city} is sunny."
# Executor geared toward ReAct with a Fireworks model
executor_lm = dspy.LM(
"fireworks_ai/accounts/fireworks/models/kimi-k2-instruct-0905",
temperature=0.7,
cache=True,
)
executor = Executor(
lm=executor_lm,
prediction_strategy="react",
tools=[get_weather],
context_defaults={"track_usage": True},
)
# Atomizer decides when to branch into planning
atomizer = Atomizer(
lm=dspy.LM("openrouter/google/gemini-2.5-flash", temperature=0.6, cache=False),
prediction_strategy="cot",
context_defaults={"track_usage": True},
)
# Planner produces executable subtasks for non-atomic goals
planner = Planner(
lm=dspy.LM("openrouter/openai/gpt-4o-mini", temperature=0.85, cache=True),
prediction_strategy="cot",
context_defaults={"track_usage": True},
)
aggregator = Aggregator(
lm=dspy.LM("openrouter/openai/gpt-4o-mini", temperature=0.65),
prediction_strategy="cot",
)
verifier = Verifier(
lm=dspy.LM("openrouter/openai/gpt-4o-mini", temperature=0.0),
)
def run_pipeline(goal: str) -> str:
atomized = atomizer.forward(goal)
if atomized.is_atomic or atomized.node_type.is_execute:
execution = executor.forward(goal)
candidate = execution.output
else:
plan = planner.forward(goal)
results = []
for idx, subtask in enumerate(plan.subtasks, start=1):
execution = executor.forward(subtask.goal)
results.append(
SubTask(
goal=subtask.goal,
task_type=subtask.task_type,
dependencies=subtask.dependencies,
)
)
aggregated = aggregator.forward(goal, results)
candidate = aggregated.synthesized_result
verdict = verifier.forward(goal, candidate)
if verdict.verdict:
return candidate
return f"Verifier flagged the output: {verdict.feedback or 'no feedback returned'}"
print(run_pipeline("Plan a weekend in Barcelona and include a packing list."))
Highlights:
- Different modules can run on different LMs and temperatures.
- Tools are provided either at construction or per-call.
context_defaultsensures each.forward()call enters a properdspy.context()with the module’s LM.
⚙️ Configuration & Storage
ROMA-DSPy uses OmegaConf for layered configuration with Pydantic validation, and provides execution-scoped storage for complete task isolation.
Quick Configuration Example
from roma_dspy.config import load_config
# Load with profile and overrides
config = load_config(
profile="crypto_agent",
overrides=["agents.executor.llm.temperature=0.3"]
)
Available Profiles: general, crypto_agent (list with just list-profiles)
See: Configuration Guide for complete documentation on profiles, agent configuration, LLM settings, toolkit configuration, and task-aware agent mapping.
Storage
Storage is automatic and execution-scoped - each task gets an isolated directory. Large toolkit responses (>100KB) are automatically stored as Parquet files.
from roma_dspy.core.engine.solve import solve
# Storage created automatically at: {base_path}/executions/{execution_id}/
result = solve("Analyze blockchain transactions")
Features: Execution isolation, S3-compatible, automatic Parquet storage, Docker-managed
See: Deployment Guide for production storage configuration including S3 integration.
🧰 Toolkits
ROMA-DSPy includes 9 built-in toolkits that extend agent capabilities:
Core: FileToolkit, CalculatorToolkit, E2BToolkit (code execution) Crypto: CoinGeckoToolkit, BinanceToolkit, DefiLlamaToolkit, ArkhamToolkit Search: SerperToolkit (web search) Universal: MCPToolkit (connect to any MCP server)
Quick Configuration
agents:
executor:
toolkits:
- class_name: "FileToolkit"
enabled: true
- class_name: "E2BToolkit"
enabled: true
toolkit_config:
timeout: 600
See: Toolkits Reference for complete toolkit documentation including all tools, configuration options, MCP integration, and custom toolkit development.
🌐 REST API & CLI
ROMA-DSPy provides both a REST API and CLI for production use.
REST API
FastAPI server with interactive documentation:
# Starts automatically with Docker
just docker-up
# API Documentation: http://localhost:8000/docs
# Health check: http://localhost:8000/health
Endpoints: Execution management, checkpoints, visualization, metrics
CLI
# Local task execution
roma-dspy solve "Your task" --profile general
# Server management
roma-dspy server start
roma-dspy server health
# Execution management
roma-dspy exec create "Task"
roma-dspy exec status <id> --watch
# Interactive TUI visualization (requires MLflow for best results)
just viz <execution_id>
# Full help
roma-dspy --help
See: API documentation at /docs endpoint for complete OpenAPI specification and interactive testing.
🏗️ Core Building Block: BaseModule
All modules inherit from BaseModule, located at roma_dspy/core/modules/base_module.py. It standardizes:
- signature binding via DSPy prediction strategies,
- LM instantiation and context management,
- tool normalization and merging,
- sync/async entrypoints with safe keyword filtering.
Context & LM Management
When you instantiate a module, you can either provide an existing dspy.LM or let the module build one from a provider string (model) and optional keyword arguments (model_config).
from roma_dspy import Executor
executor = Executor(
model="openrouter/openai/gpt-4o-mini",
model_config={"temperature": 0.5, "cache": True},
)
Internally, BaseModule ensures that every .forward() call wraps the predictor invocation in:
with dspy.context(lm=self._lm, **context_defaults):
...
You can inspect the effective LM configuration via get_model_config() to confirm provider, cache settings, or sanitized kwargs.
Working with Tools
Tools can be supplied as a list, tuple, or mapping of callables accepted by DSPy’s ReAct/CodeAct strategies.
executor = Executor(tools=[get_weather])
executor.forward("What is the weather in Amman?", tools=[another_function])
BaseModule automatically deduplicates tools based on object identity and merges constructor defaults with per-call overrides.
Prediction Strategies
ROMA exposes DSPy’s strategies through the PredictionStrategy enum (roma_dspy/types/prediction_strategy.py). Use either the enum or a case-insensitive string alias:
from roma_dspy.types import PredictionStrategy
planner = Planner(prediction_strategy=PredictionStrategy.CHAIN_OF_THOUGHT)
executor = Executor(prediction_strategy="react")
Available options include Predict, ChainOfThought, ReAct, CodeAct, BestOfN, Refine, Parallel, majority, and more. Strategies that require tools (ReAct, CodeAct) automatically receive any tools you pass to the module.
Async Execution
Every module offers an aforward() method. When the underlying DSPy predictor supports async (acall/aforward), ROMA dispatches asynchronously; otherwise, it gracefully falls back to the sync implementation while preserving awaitability.
result = await executor.aforward("Download the latest sales report")
📚 Module Reference
⚛️ Atomizer
Location: roma_dspy/core/modules/atomizer.py
Purpose: Decide whether a goal is atomic or needs planning.
Constructor:
Atomizer(
prediction_strategy: Union[PredictionStrategy, str] = "ChainOfThought",
*,
lm: Optional[dspy.LM] = None,
model: Optional[str] = None,
model_config: Optional[Mapping[str, Any]] = None,
tools: Optional[Sequence|Mapping] = None,
**strategy_kwargs,
)
Inputs (AtomizerSignature):
goal: str
Outputs (AtomizerResponse):
is_atomic: bool— whether the task can run directly.node_type: NodeType—PLANorEXECUTEhint for downstream routing.
Usage:
atomized = atomizer.forward("Curate a 5-day Tokyo itinerary with restaurant reservations")
if atomized.is_atomic:
... # send directly to Executor
else:
... # hand off to Planner
The Atomizer is strategy-agnostic but typically uses ChainOfThought or Predict. You can pass hints (e.g., max_tokens) via call_params:
atomizer.forward(
"Summarize this PDF",
call_params={"max_tokens": 200},
)
📋 Planner
Location: roma_dspy/core/modules/planner.py
Purpose: Break a goal into ordered subtasks with optional dependency graph.
Constructor: identical pattern as the Atomizer.
Inputs (PlannerSignature):
goal: str
Outputs (PlannerResult):
subtasks: List[SubTask]— each hasgoal,task_type, anddependencies.dependencies_graph: Optional[Dict[str, List[str]]]— explicit adjacency mapping when returned by the LM.
Usage:
plan = planner.forward("Launch a B2B webinar in 6 weeks")
for subtask in plan.subtasks:
print(subtask.goal, subtask.task_type)
SubTask.task_type is a TaskType enum that follows the ROMA MECE framework (Retrieve, Write, Think, Code Interpret, Image Generation).
⚙️ Executor
Location: roma_dspy/core/modules/executor.py
Purpose: Resolve atomic goals, optionally calling tools/functions through DSPy’s ReAct, CodeAct, or similar strategies.
Constructor: same pattern; the most common strategies are ReAct, CodeAct, or ChainOfThought.
Inputs (ExecutorSignature):
goal: str
Outputs (ExecutorResult):
output: str | Anysources: Optional[List[str]]— provenance or citations.
Usage:
execution = executor.forward(
"Compile a packing list for a 3-day ski trip",
config={"temperature": 0.4}, # per-call LM override
)
print(execution.output)
To expose tools only for certain calls:
execution = executor.forward(
"What is the weather in Paris?",
tools=[get_weather],
)
🔀 Aggregator
Location: roma_dspy/core/modules/aggregator.py
Purpose: Combine multiple subtask results into a final narrative or decision.
Constructor: identical pattern.
Inputs (AggregatorResult signature):
original_goal: strsubtasks_results: List[SubTask]— usually the planner’s proposals augmented with execution outputs.
Outputs (AggregatorResult base model):
synthesized_result: str
Usage:
aggregated = aggregator.forward(
original_goal="Plan a data migration",
subtasks_results=[
SubTask(goal="Inventory current databases", task_type=TaskType.RETRIEVE),
SubTask(goal="Draft migration timeline", task_type=TaskType.WRITE),
],
)
print(aggregated.synthesized_result)
Because it inherits BaseModule, you can still attach tools (e.g., a knowledge-base retrieval function) if your aggregation strategy requires external calls.
✅ Verifier
Location: roma_dspy/core/modules/verifier.py
Purpose: Validate that the synthesized output satisfies the original goal.
Inputs (VerifierSignature):
goal: strcandidate_output: str
Outputs:
verdict: boolfeedback: Optional[str]
Usage:
verdict = verifier.forward(
goal="Draft a GDPR-compliant privacy policy",
candidate_output=aggregated.synthesized_result,
)
if not verdict.verdict:
print("Needs revision:", verdict.feedback)
🎯 Advanced Patterns
Swapping Models at Runtime
Use replace_lm() to reuse the same module with a different LM (useful for A/B testing or fallbacks).
fast_executor = executor.replace_lm(dspy.LM("openrouter/anthropic/claude-3-haiku"))
Per-Call Overrides
You can alter LM behavior or provide extra parameters without rebuilding the module.
executor.forward(
"Summarize the meeting notes",
config={"temperature": 0.1, "max_tokens": 300},
context={"stop": ["Observation:"]},
)
call_params (or keyword arguments) are filtered to match the DSPy predictor’s accepted kwargs, preventing accidental errors.
Tool-Only Execution
If you want deterministic tool routing, you can set a dummy LM (or a very low-temperature model) and pass pure Python callables.
from roma_dspy import Executor
executor = Executor(
prediction_strategy="code_act",
lm=dspy.LM("openrouter/openai/gpt-4o-mini", temperature=0.0),
tools={"get_weather": get_weather, "lookup_user": lookup_user},
)
ROMA will ensure both constructor and per-call tools are available to the strategy.
🧪 Testing
# Run all tests
just test
# Run specific tests
pytest tests/unit/ -v
pytest tests/integration/ -v
See: justfile for all available test commands.
💡 Troubleshooting & Tips
ValueError: Either provide an existing lm— supplylm=ormodel=when constructing the module.Invalid prediction strategy— check spelling; strings are case-insensitive but must match a known alias.- Caching — pass
cache=Trueon your LM or set it inmodel_configto reutilize previous completions. - Async contexts — when mixing sync and async calls, ensure your event loop is running (e.g., use
asyncio.run). - Tool duplicates — tools are deduplicated by identity; create distinct functions if you need variations.
📖 Glossary
Core Concepts
- DSPy: Stanford’s declarative framework for prompting, planning, and tool integration.
- Prediction Strategy: The DSPy class/function that powers reasoning (CoT, ReAct, etc.).
- SubTask: Pydantic model describing a decomposed unit of work (
goal,task_type,dependencies). - NodeType: Whether the Atomizer chose to
PLANorEXECUTE. - TaskType: MECE classification for subtasks (
RETRIEVE,WRITE,THINK,CODE_INTERPRET,IMAGE_GENERATION). - Context Defaults: Keyword arguments provided to
dspy.context(...)on every call.
Configuration & Storage
- FileStorage: Execution-scoped storage manager providing isolated directories per task execution.
- DataStorage: Automatic Parquet storage system for large toolkit responses (threshold-based).
- Execution ID: Unique identifier for each task execution, used for storage isolation.
- Base Path: Root directory for all storage operations (local path or S3 bucket).
- Profile: Named configuration preset (e.g.,
general,crypto_agent). - Configuration Override: Runtime value that supersedes profile/default settings.
Toolkits
- BaseToolkit: Abstract base class for all toolkits providing storage integration and tool registration.
- REQUIRES_FILE_STORAGE: Metadata flag indicating a toolkit requires FileStorage (e.g., FileToolkit).
- Toolkit Config: Toolkit-specific settings like API keys, timeouts, and thresholds.
- Tool Selection: Include/exclude lists to filter which tools from a toolkit are available.
- Storage Threshold: Size limit (KB) above which responses are stored in Parquet format.
Architecture
- Execution-Scoped Isolation: Pattern where each execution gets unique storage directory.
- Parquet Integration: Automatic columnar storage for large structured data.
- S3 Compatibility: Ability to use S3-compatible storage via Docker volume mounts.
- Tool Registration: Automatic discovery and registration of toolkit methods as callable tools.
Happy building! If you extend or customize a module, keep the signatures aligned so your higher-level orchestration remains stable.
Additional Resources:
- Quick Start Guide - Get started in under 10 minutes
- Configuration Guide - Complete configuration reference
- Toolkits Reference - All built-in and custom toolkits
- Deployment Guide - Production deployment with Docker
- E2B Setup - Code execution toolkit setup
- Observability - MLflow tracking and monitoring
- Configuration System - Configuration profiles and examples
📊 Benchmarks
We evaluate our simple implementation of a search system using ROMA, called ROMA-Search across three benchmarks: SEAL-0, FRAMES, and SimpleQA.
Below are the performance graphs for each benchmark.
SEAL-0
SealQA is a new challenging benchmark for evaluating Search-Augmented Language models on fact-seeking questions where web search yields conflicting, noisy, or unhelpful results.

FRAMES
View full results
A comprehensive evaluation dataset designed to test the capabilities of Retrieval-Augmented Generation (RAG) systems across factuality, retrieval accuracy, and reasoning.

SimpleQA
View full results
Factuality benchmark that measures the ability for language models to answer short, fact-seeking questions.

🧩 Foundations & Lineage
While ROMA introduces a practical, open-source framework for hierarchical task execution, it is directly built upon two foundational research contributions introduced in WriteHERE:
-
Heterogeneous Recursive Planning — The overall architecture of ROMA follows the framework first introduced in prior work on heterogeneous recursive planning, where complex tasks are recursively decomposed into a graph of subtasks, each assigned a distinct cognitive type.
-
Type Specification in Decomposition — ROMA’s “Three Universal Operations” (THINK 🤔, WRITE ✍️, SEARCH 🔍) generalize the type specification in decomposition hypothesis, which identified reasoning, composition, and retrieval as the three fundamental cognitive types.
These contributions are described in detail in the WriteHERE repository and paper. By explicitly adopting and extending this foundation, ROMA provides a generalizable scaffold, agent system, versatility, and extensibility that builds upon these insights and makes them usable for builders across domains.
🙏 Acknowledgments
This framework would not have been possible if it wasn’t for these amazing open-source contributions!
- Inspired by the hierarchical planning approach described in “Beyond Outlining: Heterogeneous Recursive Planning” by Xiong et al.
- Pydantic - Data validation using Python type annotations
- DSPy) - Framework for programming AI agents
- E2B - Cloud runtime for AI agents
📚 Citation
If you use the ROMA repo in your research, please cite:
@misc{alzubi2026romarecursiveopenmetaagent,
title={ROMA: Recursive Open Meta-Agent Framework for Long-Horizon Multi-Agent Systems},
author={Salaheddin Alzu'bi and Baran Nama and Arda Kaz and Anushri Eswaran and Weiyuan Chen and Sarvesh Khetan and Rishab Bala and Tu Vu and Sewoong Oh},
year={2026},
eprint={2602.01848},
archivePrefix={arXiv},
primaryClass={cs.AI},
url={https://arxiv.org/abs/2602.01848},
}
🌟 Star History
📄 License
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.
相似文章
@vintcessun: 原来 LLM 还能自己写工作脚本,把任务拆给一群子代理并行干。 单个助手顺序思考,遇到代码库审计、大型重构这种活,要么慢,要么思路串。 pi-dynamic-workflows 让模型直接生成一段 JS 脚本,用 agent()、para…
介绍 pi-dynamic-workflows,一个让 LLM 通过生成 JavaScript 脚本动态编排多个子代理并行执行任务的工具,适用于代码审计、大型重构等场景。
@realfxw: 在分布式架构里跑多智能体(Multi-Agent),最怕的其实不是模型推理慢,而是“状态丢失”和“协同死锁”。 最近很多做 Agent 的团队都在讨论把编排逻辑迁移到边缘。Pi 配合 Cloudflare Durable Objects(…
文章介绍 Pi Durable 配合 Cloudflare Durable Objects 的边缘多智能体编排思路:每个会话映射为一个有状态 Durable Object,实现状态持久化、休眠唤醒与子代理并行调度,摆脱传统 Redis/消息队列的重后台架构。
@realfxw: 做 Agent 工作流或自主智能体循环时,一个极度影响体验的瓶颈在于:每一个细小的分支判断、工具路由、任务完成度检查或安全拦截,如果全部塞给昂贵的推理大模型(Reasoning LLM),不仅每次调用带来数秒的延迟,Token 成本也会呈…
这篇文章介绍了开源清单awesome-jev-projects,它通过解耦System 1快速决策模型和System 2推理大模型来优化AI代理工作流,降低延迟和成本,并提供代码级参考。
@lidangzzz: 我开源了一款非常简单但是极度好用的multi-agent system。 名字就叫goal-driven(目标驱动) https://github.com/lidangzzz/goal-driven… 原理非常简单,就像我说过的,让一个m…
开发者lidangzzz开源了goal-driven多智能体框架,通过主代理监督子代理循环执行直至满足预设判据,声称可自动完成编译器开发等复杂任务,并展示了C++版TypeScript编译器、Rust版SQLite等示例项目。
@AxtonLiu: https://x.com/AxtonLiu/status/2073791557547794579
本文讨论了Agent OS的概念,强调通过分工将任务拆解为多个工位(抓取、提炼、核查、确认),每个工位由独立的Agent负责,以实现可控的自动化。作者通过消化浏览器标签的例子,展示了如何通过分工隔离上下文、责任和风险,确保AI输出的准确性和可靠性。