Reading DeepSeek DSec: agents build the environments that train agents
TL;DR DSec is the sandbox platform behind DeepSeek's agentic RL training and evaluation from V3.2 through V4.1: four isolation backends behind one Python SDK, about 3 million sandboxes a day and over 5,000 creations per second per scale unit. The binding constraint is not compute but environment supply — 11,266 base images against 102,171 workspaces in a single week — so DeepSeek let agents build the environments other agents are then trained in, checkpointing a live sandbox into a reusable image with pack_diff. From V4.1 the agent loop also runs outside the preemptible GPU pool, so rollout state survives preemption without replaying a command log.
Part of a series on structuring agentic systems. Previous: Reading software factories: artifacts on the edges, humans at merge. First of three on DeepSeek’s DSec paper.
Notes from reading DeepSeek Elastic Compute (DSec), by DeepSeek-AI and Tsinghua University. Its arXiv comment says an extended abstract went through first-round review for the Operational Systems Track of ACM SIGOPS ATC 2026, which tells you how to read it: an operations report, not a model paper.
It describes the platform serving every sandbox workload in DeepSeek’s RL training and evaluation from V3.2 through V4.1.
I am taking it on its own terms in this post. My objections come in the next two.
The claim: rollout needs a platform, not a runtime
The abstract states the thesis directly: these workloads “require an elastic execution platform rather than a single sandbox runtime.” §1 lists seven workload properties as the argument. Four of them carry the weight.
- Bursty. A single rollout or evaluation job may request up to 32K sandbox instances, and they arrive in a short window because a training batch cannot use an instance until its environment is ready.
- Sparse in CPU. About 90% of both container and microVM sandboxes average no more than 5% of requested CPU, because the sandbox sits idle while the model generates the next action.
- Stateful and long-lived. Median lifetime is 17.4 minutes for containers and 15.5 for microVMs, with p99 above three hours for both, sampled from 30K containers and 10K microVMs. File edits, installed dependencies, and running services have to survive across turns.
- Diverse. In one production week the container backend served 11,266 base images and 102,171 workspaces.
Put together, that is a combination with no published precedent. Serverless platforms assume short, stateless invocations over a small set of images reused at high fanout, and the Azure Functions characterization measured exactly that concentration. DSec’s sandboxes are serverless-shaped in CPU sparsity, VM-shaped in lifetime, and long-tailed in reuse: median per-task image fanout is 3 for containers and 1 for microVMs, measured over more than 1.5 million containers and 390K microVMs.
Sparse CPU is what makes the rest affordable. If a sandbox burns 5% of what it asked for, you can overcommit hard. DSec reports observed per-node peaks of 1,048 containers and 524 microVMs, and claims stable production operation at 3,200 containers or 800 microVMs per node — with the paper’s own hedge that these are “demonstrated operating points rather than hard limits.”
Four backends, and the SDK refuses to hide them
Users reach DSec through libdsec, a Python client. A request names the backend, the image or environment, CPU and memory limits, a lifetime policy, and network rules. The network rules are per-service, not per-CIDR — the paper’s own example allows PyPI and denies NPM.
Four backends span the isolation and startup tradeoff:
| Backend | Isolation | For |
|---|---|---|
| FnCall | none beyond the container | short stateless work: OJ-style tasks, compilation, GPU kernel benchmarks |
| Container | shared host kernel | the bulk of software-engineering and tool-use work |
| Firecracker microVM | own kernel | security-sensitive tasks needing a VM boundary with Linux compatibility |
| Full VM (QEMU) | own kernel, full OS | Android, GUI, graphics rendering via virtio-gpu and DXVK |
The SDK gives one access path and a similar operational model, and then stops: “the caller remains responsible for selecting a backend that matches the workload.” Startup cost, filesystem semantics, and OS capabilities genuinely differ across those four, and a uniform abstraction would have lied about it. FnCall does not even use the same request path — no per-sandbox proxy, no shell-session component, just execution in a precreated container.
Consider what the unified version would have cost the caller. A single create_sandbox() that silently picks a backend has to either expose the worst common denominator, so nobody gets a fast function call, or hide a hundred-fold startup difference behind one signature, so a task that needed a VM boundary quietly lands on a shared kernel. I respect the refusal more than I would have respected the abstraction.
Containers and microVMs dominate production in both instance count and resource use. FnCall handles many lightweight invocations against a small resident set.
The bottleneck is environment construction
A sandbox is three parts: a base image with OS-level dependencies, a workspace holding the task’s repository and its dependencies, and one or more frequently-updated toolkits. In one production week:
| Backend | Base images | Workspaces | Snapshots | Size |
|---|---|---|---|---|
| Container | 11,266 | 102,171 | — | 82.8 TB |
| MicroVM | 2 | 53,590 | 4,889 | 50.9 TB |
Plus 103 toolkits, and 67.8% of sandboxes needing at least one workspace or toolkit beyond the base image.
Fuse those three parts into one OCI image and the maintenance cost is combinatorial. With M base images, N workspaces, and K toolkits, upgrading m base images costs O(m·N) rebuilds, and upgrading k toolkits costs O(k·N). Update the DeepSeek Harness toolkit once and every image containing it needs rebuilding, even though no base image or workspace changed.
That O(k·N) term is the test-fixture problem in a large codebase. Bump one shared test helper and every fixture built on it has to be regenerated, even though the cases under test never changed — k is the helper, N is the fixtures. DSec’s storage design breaks the multiplication the same way a well-factored suite does: compose the three parts as independently versioned read-only layers at sandbox creation instead of pre-fusing them, and the rebuild cost drops to O(m) and O(k). What matters here is the count that mechanism operates on: six figures of workspaces, from a single week.
Those workspaces are not synthetic. The evaluation workloads the paper names are internal software-engineering benchmarks, SWE-bench, Terminal-Bench, and security exploit tasks — every task carrying its own repository, dependency versions, and verifier.
pack_diff: the environment supply answer
§6.1 is the most consequential idea in the paper and it is titled, in the paper’s own words, “Build environments of Agents, by Agents, for Agents.”
The premise is an admission: “Manually constructing the large number of environments required by agentic RL is impractical.” So agents build them, interactively, on the same infrastructure used for training and evaluation. At any point an agent can checkpoint its sandbox with pack_diff, taking an incremental disk snapshot that can later be restored as a new sandbox. An interactive session becomes a reusable environment with no separate image-building pipeline.
Three controls sit around it, and they are worth naming because they are the whole governance story:
- An internal rule set that packed environments must obey to bound their runtime cost on shared infrastructure. It is supplied to the building agents as instructions.
- An internal platform, built by their researchers, that quality-checks agent-built environments and exports them in standardized formats for RL and evaluation to consume.
- Separate accounts for builder agents and runtime agents, plus removal of build-time residual data from the writable layer before packing, so reference answers do not travel into the resulting image.
DSec publishes no numbers here at all — no count of agent-built environments, no pass rate for the quality checker, no measure of how often leakage was caught. The nearest public figures come from the V3.2 paper, which reports 1,827 environments across 4,417 tasks, and 24,667 code-agent tasks gated on fail-to-pass and pass-to-fail checks. Take that as the order of magnitude the supply problem operates at.
The self-reference is the point. Agents manufacture the environments that other agents are then trained and graded in. I went looking for a comparable public account and did not find one: the RL training frameworks describe how they schedule GPUs and pipeline rollouts, and treat the environment as something that already exists. If environment supply is the real constraint on agentic RL, then automating it is the move that matters, and every other mechanism in the platform exists to make that automation cheap.
The rollout left the GPU pod
The second co-design change is smaller and cleaner. GPU training jobs at DeepSeek are “routinely preempted to improve utilization.” For a long agentic rollout, preemption used to destroy the agent loop while the sandbox survived, so recovery replayed a command log, reusing recorded results instead of re-executing non-idempotent commands.
From V4.1 they stopped doing that. Rollout execution moved onto DSec and split in two: an agent sandbox hosting the scaffold and its tools, and a worker container managing that sandbox and providing a scaffold-agnostic control layer. Both run outside the preemptible GPU pool. Together they hold the complete rollout state as its single source of truth, so a preempted GPU job reconnects and continues rather than reconstructing execution from a log. The V4.1-Flash paper describes the same split independently, which is a useful corroboration.
This is the same lesson as long-horizon agent state: give the state an explicit owner outside the component that dies, and the recovery protocol disappears. Replacing a log-replay reconciliation with a relocation is the stronger fix, because there is no longer a second copy to reconcile.
Idle sandboxes still cost memory while training is suspended, so the RL framework proactively pauses every sandbox belonging to a preempted job, and any later request transparently resumes it first. Containers freeze with docker pause and give memory back through cgroup reclaim; microVMs snapshot their state and then terminate the Firecracker process outright. Both keep execution state and surrender the memory, which is the whole trick — a paused rollout costs storage, not DRAM, and the memory returns to the sandboxes still doing work.
Scale, and the escape valve
One scale unit is roughly 160 CPU nodes, 30K cores, and about 250 TB of DRAM, managing petabytes of images and layers on 3FS, their distributed filesystem. A typical day is about 3 million sandbox instances, peaking near 380K concurrent, sustaining over 5,000 creations per second.
When on-premise utilization passes 80%, the placement engine offloads eligible requests to cloud VMs. The interesting part is what they did not build: instead of a managed container service over object storage, they reuse the same container runtime and image-loading path on the cloud VMs. A de-duplicated 30 TB image set covers the files accessed by 70% of container tasks, and only tasks whose dependencies fall entirely inside that set are cloud-eligible. In production, 200 cloud VMs absorb about 30% of peak overflow.
The escape valve is shaped by the same constraint as everything else. Bursting is limited not by cloud capacity but by which environments are already staged there.
Key takeaways
- Count your environments before designing your runtime. The image-to-workspace ratio is what dictates the storage layout, the automation, and the bursting policy. DSec’s design follows from that one measurement, so get yours first.
- FaaS intuitions mislead on this workload. Sparse CPU invites overcommit, and then long lifetimes and near-zero image reuse break the cache and lifecycle assumptions serverless platforms are built on. Take the overcommit, leave the cache design.
- A single abstraction over unlike runtimes is worth refusing. Startup cost, filesystem semantics, and OS capabilities differ too much across a function call and an Android VM to paper over. Give one access path and make the caller choose.
- Move state, do not reconcile it. The command-log replay protocol did not get better. It got deleted, once the thing holding the state stopped being the thing that dies.
- What transfers at a smaller scale: composable read-only layers instead of monolithic images, which is cheap to adopt and pays immediately. What does not: bursting against a pre-synced image subset, quota delegation, a dedicated 160-node CPU tier. Most of the remaining mechanisms are stock Linux.
The paper is honest that §6 is unevaluated — §8 states the framework integration is outside its evaluation scope. So the environment-supply story, which I think is the best thing in it, is also the part with no numbers attached.