中文 | English
A next-generation agent infrastructure that integrates evaluation and training, supporting rapid agent onboarding, fast integration of community benchmarks, concurrent rollout execution, trajectory collection, and reinforcement learning training across domains such as OS, Android, Minecraft, embodied AI, QA, data processing, and scientific discovery. It is the first to validate a trustworthy scaling law for agents, achieving improved safety capabilities without an alignment tax.
The built-in Gateway is a session-aware OpenAI-compatible API layer that routes model requests to configured upstream LLM services, applies concurrency and step controls, and records request telemetry into the same trajectory storage used by rollouts.
Quick Start | Demo | Environments | RL Training | Custom Environments | Configuration | Data | Report
Safactory is an agent sandbox for teams that need one pipeline for evaluation, data generation, and RL training. It helps teams plug in new agents and community benchmarks quickly, run them concurrently through scalable rollout pools, route OpenAI-compatible model traffic through the Gateway, persist trajectories, and bridge completed data into Slime / GRPO training.
| Need | Safactory provides |
|---|---|
| Evaluate agents and benchmarks | Run LLM or VLM agents against realistic interactive tasks and community benchmarks, then collect rewards. |
| Build trajectory data | Persist messages, actions, observations, rewards, and environment state to SQLite. |
| Train with RL | Stream rollout trajectories into Slime through the built-in Buffer Server. |
| Add new agents and benches | Onboard agent runtimes and benchmark suites quickly, then scale them with concurrent rollout workers. |
Core features:
- Multi-domain agent and benchmark adapters: OS, Android, Minecraft, RoboTrustBench, Embodied ALFRED, QA, DABStep, DiscoveryWorld, DeepEyes, Geo3K-VL, and Math500.
- High-concurrency rollouts through runtime pools and async workers.
- OpenAI-compatible model integration for vLLM, SGLang, hosted APIs, and local proxies.
- Local single-machine mode and remote RayJob-backed cluster mode.
demo.1.mp4
点击播放查看完整演示
git clone https://github.com/AI45Lab/Safactory.git
cd Safactory
pip install -r requirements.txtIf you want to use LanceDB/cloud storage features, install the optional cloud dependencies as well:
pip install -r requirements-cloud.txtDocker mode requires Docker and an agent image that matches the selected adapter. RJob mode additionally requires a valid RJob client configuration.
Copy the example and replace route placeholders with your own OpenAI-compatible model endpoint:
cp gateway/config.example.yaml gateway/config.local.yamlIn gateway/config.local.yaml, make sure the gateway and launcher share the same SQLite DB:
listen_port: 8000
storage_type: sqlite
storage_config:
db_url: sqlite://env_trajs.db
llm_routes:
YOUR_ROUTE_KEY:
base_url: http://YOUR_LLM_HOST/v1
api_key: YOUR_API_KEY
supports_stream: true
max_concurrency: 64Start the gateway:
python -m gateway --config gateway/config.local.yamlCheck readiness in another terminal:
curl http://127.0.0.1:8000/readyzThe remaining quick-start commands follow the recommended path: start with a minimal local Docker run, switch to RJob when you need more concurrency, then add evaluation parameters when you need scoring.
This example runs the checked-in OpenClaw adapter in Docker mode:
python launcher.py \
--agent-config env/openclaw/openclaw_config.yaml \
--agent-start-config env/openclaw/openclaw_start.yaml \
--gateway-base-url http://127.0.0.1:8000/v1/sessions \
--llm-model YOUR_ROUTE_KEY \
--db-path sqlite://env_trajs.db \
--pool-size 1 \
--max-workers 1 \
--max-steps 20Important details:
--llm-modelis a gatewayllm_routeskey, not an arbitrary upstream model name.--agent-configdefines tasks and datasets.--agent-start-configdefines how the agent runtime is started.--gateway-base-urlshould point at the gateway session root.--db-pathmust matchgateway.storage_config.db_urlwhenstorage_typeissqlite.
After the local Docker path works, switch to RJob when you need higher concurrency or cluster resources. RJob mode uses the same launcher but replaces Docker allocation with RJob submission:
python launcher.py \
--mode rjob \
--rjob-config config.yaml \
--agent-config env/openrt/openrt_config.rjob.yaml \
--agent-start-config env/openrt/openrt_start.rjob.yaml \
--gateway-base-url http://YOUR_GATEWAY_HOST:8000/v1/sessions \
--llm-model YOUR_ROUTE_KEY \
--storage-type cloud \
--pool-size 8Global RJob auth belongs in config.yaml or --rjob-config. Per-agent image, resources, mounts, embedded files, and run command belong in --agent-start-config. --pool-size controls the concurrency target, bounded by cluster resources and the agent start config.
Use --mode sandbox to allocate rollout instances from a pre-created Brainbox Sandbox Environment. Connection settings and the Environment ID belong in --sandbox-config; the agent runner is still defined by --agent-start-config.
export OPEN_SANDBOX_API_KEY='<ak>:<sk>'
python launcher.py \
--mode sandbox \
--sandbox-config config.sandbox.example.yaml \
--agent-config env/openrt/openrt_config.yaml \
--agent-start-config env/openrt/openrt_start.yaml \
--gateway-base-url http://YOUR_GATEWAY_HOST:8000/v1/sessions \
--llm-model YOUR_ROUTE_KEY \
--pool-size 8See Sandbox mode for Environment, volume, lifecycle, and evaluation requirements.
After Docker, RJob, or Sandbox startup works, add evaluator parameters when you need scoring:
python launcher.py \
--agent-config env/openrt/openrt_config.yaml \
--agent-start-config env/openrt/openrt_start.yaml \
--gateway-base-url http://127.0.0.1:8000/v1/sessions \
--llm-model YOUR_ROUTE_KEY \
--enable-evaluation \
--db-path sqlite://env_trajs.db \
--pool-size 1Evaluation dynamically discovers <agent-root>/<env_name>/rule_evaluator.py by convention. RJob and Sandbox modes use the same --enable-evaluation flag. See Evaluation.
Local runs write task rows and trajectories to env_trajs.db by default. Pass an explicit --job-id my-openrt-smoke when launching to make later querying, reproduction, and training filters clearer.
job_id: onelauncher.pyrun.session_id: one environment/task instance, matchingjob_environments.env_idandsession_steps.session_id.
Find recent runs:
sqlite3 env_trajs.db "
SELECT id, job_id, env_id AS session_id, env_name, group_id, finished, created_at
FROM job_environments
ORDER BY id DESC
LIMIT 20;"Inspect one session's steps, rewards, and completion state:
sqlite3 env_trajs.db "
SELECT step_id, llm_model, step_reward, reward,
is_terminal, is_session_completed, is_trainable, created_at
FROM session_steps
WHERE session_id = '<session-id>'
ORDER BY step_id, id;"Default local artifacts:
| Artifact | Default |
|---|---|
| SQLite trajectory DB | env_trajs.db |
| Launcher logs | logs/<timestamp>/main.log |
| Gateway log | logs/gateway.log |
| Gateway request log | logs/gateway_requests.jsonl |
| Adapter outputs | results/ or adapter-mounted directories |
See Data Manager for the full schema, row types, and more queries.
Safactory can feed Slime through rl/buffer_server.py. The current RL scripts live under rl/examples/<task>/ and source task-specific env.sh files:
cd rl/examples/math500
./run_buffer_server.shThe Buffer Server starts launcher.py, reads completed trainable rows, groups samples by group_id, and exposes batches through /get_rollout_data. See RL Training.
| Guide | What it covers |
|---|---|
| Gateway | Gateway endpoints, routing, telemetry, request logs, and storage matching. |
| Configuration | Current launcher.py, gateway, agent config, agent start config, and RJob fields. |
| Supported Environments | Checked-in v2 adapters and their runtime requirements. |
| Evaluation | Rule evaluator configuration and reward commit behavior. |
| Data Manager | SQLite/cloud storage behavior, tables, event types, and useful queries. |
| Custom Runtime | How to add a v2 external agent runtime and the two required YAML files. |
| RL Training | Buffer Server and Slime integration details. |
At a high level, launcher.py loads environment YAML files, starts or connects to environment services, sends observations to an OpenAI-compatible model endpoint, records every interaction through the data manager, and optionally forwards completed rollouts to RL training.
Safactory can generate reusable trajectory datasets. The public OS trajectory release is available on Hugging Face:
- AI45Research/SATraj-OS, a Safactory-generated OS trajectory dataset for agent training and analysis.
Contributions are welcome for new custom environments, bug fixes, and reproducible examples.
When adding an environment, Safactory usually treats a new agent or benchmark as an external runtime: add a runner such as runner.py or runner.mjs, dataset files, and an optional rule_evaluator.py under env/<name>/, then provide <name>_config.yaml and <name>_start.yaml. The config describes task data, image, and evaluation parameters; the start config describes the Docker/RJob launch method, entrypoint command, environment variables, and mounts. Each dataset row should represent one independent task/case. Run a small launcher.py smoke test before opening a PR. See Custom Environments for the full guide.
- Add or update the runner, dataset, and optional evaluator under
env/<name>/. - Provide both
<name>_config.yamland<name>_start.yaml, including all required fields. - Keep secrets and private endpoints out of committed configs.
- Run a local smoke test with
launcher.py. - Include setup notes, expected outputs, and storage requirements in the pull request.
If Safactory or Safactory-generated datasets are useful in your work, cite the repository and the specific dataset or report you used.
@misc{chen2026safactoryscalableagenticinfrastructure,
title={Safactory: A Scalable Agentic Infrastructure for Training Trustworthy Autonomous Intelligence},
author={Shanghai AI Lab},
year={2026},
eprint={2605.06230},
archivePrefix={arXiv},
primaryClass={cs.AI},
url={https://arxiv.org/abs/2605.06230},
}
