Month: July 2026

From Data Factories to Dynamic Systems: The Evolution of LLM Orchestration

For a few years, the recipe for a capable language model resembled manufacturing: gather or synthesize large volumes of training rows, run gradient descent, ship the weights. Magpie is a clean example of that philosophy. By feeding an aligned model nothing but its own pre-query template, researchers got it to generate millions of plausible user instructions, then answer them — an assembly line that produced alignment data at scale with no human in the loop. The model was both the factory and the raw material.

That approach worked, and it still matters. But the center of gravity in LLM systems has moved. Capability is no longer something you bake entirely into weights at training time; it is increasingly assembled at runtime, through typed message formats, function schemas, and interoperability standards like the Model Context Protocol. This post traces that shift — from static data production to dynamic composition — and maps out what it means for anyone building software on top of these models. It picks up where my earlier piece on Harmony and training formats left off: if channels are the interface layer between weights and runtime, the question here is how that interface came to carry more of the system’s intelligence than the training corpus itself.

The Data Factory Era and Its Ceiling

Static dataset generation solved a real bottleneck. Human-written instruction data was scarce, expensive, and legally fraught, and techniques like Magpie, Self-Instruct, and Evol-Instruct showed that models could manufacture their own curriculum. The Magpie method — exploiting the autoregressive template so the model completes the “user” side of a conversation it was never given — raises a question worth sitting with: how much conversational structure do post-trained weights already contain, waiting to be extracted?

The ceiling, however, is built into the method. A synthesized corpus is a snapshot: its distribution is frozen the moment training ends. Every new API, coding convention, or enterprise system the model should interact with would require fresh rows and fresh gradient steps. Facts and behaviors also get entangled — teach a model about a specific weather API by memorization, and the knowledge rots the day the API changes. The factory could produce volume; it could not produce currency or context.

The Escape Route, Stage by Stage

The escape route emerged in stages, and the sequence is easier to follow if each stage is read as an answer to the previous one’s open problem.

Stage one: act by prompting. ReAct interleaved reasoning traces with actions expressed as plain text — the model wrote “Action: search[…]” and a wrapper script parsed it, ran the query, and pasted the result back into the prompt. This proved a base model could operate external systems with no special training at all.

The open problem: everything hinged on heuristic parsing of free-form text, which broke whenever the model phrased an action differently.

Stage two: learn the habit from synthesized data. Toolformer had the model annotate its own training text with candidate API calls, kept the insertions that measurably improved next-token prediction, and fine-tuned on the result. It is a transitional artifact — a data-factory technique in service of a dynamic behavior — and it made tool invocation a learned reflex rather than a prompting trick.

The open problem: the tool set was fixed at training time, so every new capability meant another training run.

Stage three: pass the tools in at runtime. Native function calling moved the schemas into the request itself. The model reads JSON descriptions of available functions in context and emits arguments that validate against them. What the weights retain is a structural pattern — read schema, select function, construct arguments — which is why a model fine-tuned on a few thousand examples can call APIs it has never seen.

The open problem: output still arrived as one undifferentiated stream, leaving the runtime to guess whether a given blob of JSON was a call, a draft, or an answer.

Stage four: type the conversation itself. ChatML gave messages explicit roles and boundaries; Harmony extended this with output channels — analysis for internal reasoning, commentary for actions bound to the runtime, final for the user-facing answer. Ambiguity that stage three left to heuristics became a typed contract the serving stack can rely on.

The open problem: every model vendor and every capability provider still wired their integrations one-off.

Stage five: standardize the boundary. MCP defines how a client discovers tools, resources, and prompt templates from independent servers at connection time. Nothing about a specific database, ticketing system, or search index needs to live in the weights; the capability arrives with the connection, described in text the model already knows how to read. Integration stops being a training problem and becomes a configuration problem.

What LSP Taught MCP

Stage five has a precedent in developer tooling. Before the Language Server Protocol, every editor needed a bespoke integration with every programming language — an M×N growth in glue code. LSP collapsed it to M+N with one contract: any editor speaking the protocol gets completions, diagnostics, and refactoring from any compliant language server.

MCP applies the same compression to models and capabilities, and the analogy runs deeper than architecture. LSP succeeded because it let editors and compilers evolve on separate schedules; the protocol boundary is what made independent progress possible. The same decoupling is what lets a tool server built today work with a model released next year.

The Breakdown of Monolithic Training

Seen through this lens, training itself has decomposed into layers with distinct jobs. Pretraining supplies linguistic and world priors. Instruction tuning teaches the conventions of roles and turns. A further fine-tuning pass teaches the grammar of action — when to act, how to construct arguments, how to integrate returned results. Channelized formats teach the model to separate deliberation from invocation from presentation.

None of these layers tries to be the whole system anymore. The monolith — one corpus meant to instill every fact and behavior — has given way to a division of labor: weights learn transferable patterns, while the runtime supplies the specifics of the moment. One way to compress this: training provides the grammar, the environment provides the vocabulary. Synthetic data generation still has a role, but its target changed. You generate examples to sharpen the pattern — schema reading, argument construction, result integration — not to enumerate the world.

A Conceptual Map: How Models Actually Write Code

Code generation makes the dynamic view concrete, because correctness is externally checkable. Picture the system as four concentric layers. At the core sit the weights, trained on mixed text-and-code corpora — they contribute priors about syntax, idiom, and likely program structure. Around them sits the format layer: channels and schemas that let planning, action, and presentation travel as distinct, machine-readable streams. Around that sits the runtime loop: compilers, test runners, linters, static analyzers, and protocol-connected services the model can invoke. The outermost layer is feedback — execution results flowing back into context, reshaping the next generation step.

A coding agent drafts a plan in its reasoning lane, requests a test run through the action lane, receives a traceback, and revises. Functional correctness emerges from this circulation between model and environment, not from a hidden verification oracle inside the parameters. The training corpus made the first draft plausible; the loop makes the final artifact correct. That distinction is the argument of this post in miniature: a model that writes working software is not reciting its dataset — it is participating in a feedback system whose most important components live outside the network.

Actionable Insights for Developers

First, treat schemas as prompts. The descriptions in your function and server definitions are read by the model at inference time; an afternoon spent on precise parameter docs often beats a week of fine-tuning. Second, keep one model on the hot path. Channels exist so that a single inference stream can serve the UI, the executor, and the logger — add model hops only when a validator or router earns its latency.

Third, log per lane. When reasoning, actions, and answers are typed separately, you can evaluate structural validity — did the arguments parse and validate? — independently from answer quality, and you can mask or weight lanes differently if you later train on your own traces. Fourth, aim synthetic generation at patterns rather than facts: Magpie-style pipelines work well for teaching argument construction and result integration, and poorly for anything that changes monthly. Finally, build against open contracts rather than vendor endpoints — a capability exposed through a standard protocol survives model swaps; a bespoke integration does not.

Toward Circular, Modular — and Legible — Systems

The endpoint of this evolution is not the death of the data factory but its relocation. Agent deployments now generate the artifact that factories once had to fabricate: complete, structured traces of plans, invocations, results, and outcomes. Filter those traces by success, and they become training rows; fine-tune on them, and the improved weights produce better traces. The pipeline has bent into a circle, with the production environment as its own curriculum generator. Typed lanes, schema-described capabilities, and protocol boundaries make each component of that circle — weights, runtime, servers, evaluators — replaceable on its own schedule, the way LSP let editors and compilers evolve independently.

There is a newer force reshaping the training side of this loop: research into what happens inside the network, at the level of activations. Sparse autoencoders showed that the hidden states of a transformer can be decomposed into thousands of individually interpretable features — concepts, personas, syntactic roles — as demonstrated in early dictionary-learning work and scaled to production models in Anthropic’s monosemanticity research. In parallel, representation engineering and activation addition showed that behavior can be shifted by adding directions in that feature space at inference time — no gradient steps required. Read against the arc of this post, that is a familiar move: yet another capability migrating from the weights to the runtime.

This line of work is starting to change how training decisions get made. OpenAI’s study of persona features and emergent misalignment traced a fine-tuning failure — narrow training on insecure code producing broadly misaligned behavior — to identifiable directions in the model’s internal representations, then used that diagnosis to design a small corrective fine-tune. Anthropic’s attribution graphs trace multi-step computations through a model, offering a way to check whether a fine-tune changed the mechanism or merely the surface behavior. The practical pattern emerging from both: inspect the feature space before and after training, and let what you find decide what to retrain, what to steer, and what to leave alone.

The field is still early here, and the open questions are the interesting part. Do features stay stable across fine-tunes, so that a monitor built today survives next quarter’s training run? Can feature-level checks run cheaply enough to sit inside the agent loop itself, alongside the compilers and test runners? And if conversation formats gave us typed channels for text, will some future contract expose internal state the same way? The trajectory of the last few years suggests a consistent direction: systems built from parts that are separately trainable, separately swappable, and — increasingly — separately inspectable. The teams that internalize this will spend less time manufacturing static corpora and more time designing the contracts and feedback loops through which their systems teach themselves.

Kata Containers vs gVisor: security and performance trade-offs

Running untrusted workloads in a multi-tenant Kubernetes cluster is one of the hardest security problems in modern cloud infrastructure. The default container runtime gives you Linux namespaces and cgroups — solid isolation for cooperative tenants, but a single kernel-level CVE can let a motivated attacker or agent escape a container on the node. Two projects take radically different approaches to closing that gap: Kata Containers wraps each pod in a lightweight virtual machine, while gVisor interposes a user-space kernel between the application and the host. This post is a ground-level engineering guide to help you choose between them for AI agent sandboxing, CI runners, multi-tenant function execution, or any workload where you cannot trust the code you are running.

Why stock runc Is Not Enough

The Linux kernel attack surface reachable from inside a container is enormous. Even with seccomp profiles, AppArmor, and a stripped-down capability set, the container shares the host kernel. A single exploitable bug in a syscall handler — dirty pipe (CVE-2022-0847), runc symlink-race (CVE-2019-5736), Netfilter UAF (CVE-2023-32233) — can escalate from inside a container to root on the host node. OWASP’s Top 10 for LLM Applications explicitly calls out LLM08: Excessive Agency and LLM04: Model Denial of Service as prime risks for agent runtimes executing tool calls, code, or shell commands on behalf of an LLM. Any agentic architecture that lets an LLM invoke arbitrary code without a strong isolation boundary is accepting kernel-level blast radius.

Kata Containers – Hardware VM Isolation

Kata Containers uses a real hypervisor (QEMU/KVM, Cloud Hypervisor, or Firecracker) to run each pod inside its own VM. The guest has its own kernel; the host kernel never sees the workload’s syscalls directly.

  • Containerd shim (containerd-shim-kata-v2) is the Kubernetes-side entry point — it speaks the standard OCI runtime interface.
  • A minimal guest kernel boots in <100 ms via a stripped initrd. Firecracker’s microVM gets this under 125 ms cold-start end-to-end.
  • The virtio-vsock channel connects the shim on the host to the kata-agent inside the VM — all container lifecycle operations flow through this channel.
  • Storage is presented via virtio-blk or virtiofs; networking via macvtap or tc-redirect-tap.
  • The only thing shared with the host is the hypervisor binary and its narrow VMM interface (MMIO, virtio ring buffers) — not the kernel.

Threat model: An attacker who escapes the guest kernel still faces the hypervisor boundary. Exploiting QEMU or Cloud Hypervisor is dramatically harder than a kernel syscall bug and requires a separate VMM vulnerability. Firecracker’s ~50 000-line Rust VMM further shrinks the attack surface by dropping legacy device models entirely.

gVisor – User-Space Syscall Interception

gVisor (Google’s open-source sandbox) implements a large subset of the Linux syscall ABI in Go — the Sentry. Instead of letting application syscalls reach the host kernel, the Sentry intercepts every call and re-implements it in user space. The host kernel only sees a narrow set of calls from the Sentry itself.

  • KVM platform: the Sentry runs as a guest in a VM context for each sandbox, using /dev/kvm to switch rings. This gives hardware-accelerated syscall interception without booting a full guest kernel. Memory overhead: ~20 MB per sandbox.
  • ptrace platform: purely software-based — the Sentry attaches to the sandboxed process via ptrace. Portable but significantly slower; only needed when KVM is unavailable (e.g., nested virtualization without hardware assist).
  • OCI integration: runsc is a drop-in OCI-compatible runtime, so runtimeClass: gvisor in a Kubernetes PodSpec is all you need.
  • The Gofer process mediates all filesystem access between the Sentry and the host, providing an additional isolation layer for path traversal and file descriptor leaks.

Threat model: An attacker inside a gVisor sandbox must exploit the Sentry (Go code, ~200 KLOC) rather than the kernel. The Sentry’s seccomp profile allows only ~50 host syscalls — compared to >400 exposed by a bare container. However, gVisor shares the host kernel (the Sentry’s calls still reach it), so a kernel CVE in one of those ~50 syscalls can still be exploitable.

Head-to-Head Comparison
DimensionKata ContainersgVisor (runsc)
Isolation MechanismHardware VM (KVM / QEMU, Cloud Hypervisor, Firecracker)User-space kernel (Sentry process, Go)
Kernel Shared With Host?No – guest has its own kernelYes – Sentry still calls host kernel (~50 syscalls)
Syscall InterceptionNone — guest kernel handles all app syscallsFull — Sentry re-implements every syscall in Go
Host Attack SurfaceVMM interface (virtio, MMIO) — very narrow~50 host syscalls from Sentry’s seccomp profile
Memory Overhead Per Pod~100–180 MB (guest kernel + initrd + agent)~20–40 MB (Sentry + Gofer processes)
Cold-Start Latency100–500 ms (Firecracker ≈ 125 ms; QEMU ≈ 300–500 ms)10–50 ms (KVM platform); 50–200 ms (ptrace)
Runtime PerformanceNear-native CPU; I/O overhead from virtio5–15% CPU overhead on syscall-heavy workloads; near-native for compute-bound
Syscall CompatibilityFull Linux ABI — anything the guest kernel supportsPartial — ~240 of ~400 syscalls implemented; gaps in io_uring, eBPF, some ioctls
Filesystemvirtio-blk / virtiofs — near-native throughputGofer-mediated 9P or overlay — higher latency on metadata-heavy workloads
NetworkingCNI via macvtap / tc-redirect-tap — full kernel netstack in guestSentry’s own netstack or passthrough — minor overhead
Kubernetes IntegrationruntimeClass: kata-containers via containerd shimruntimeClass: gvisor via runsc / containerd-shim-runsc
EKS SupportEKS with self-managed node groups; not on FargateEKS with self-managed nodes; GKE Sandbox (GA)
Privileged ContainersNot supported — by designNot supported — by design
eBPF / io_uringFull (host kernel features available to guest)Partial / none — major compatibility gap
Best ForMaximum isolation; multi-tenant LLM agent execution; regulated environmentsLow-overhead sandboxing; CI pipelines; serverless functions
Weakest LinkVMM CVE (rare); cold-start adds latencyHost kernel reachable via Sentry; syscall gaps break some workloads
Performance in Practice

For CPU-intensive tasks (ML inference, numerical computation, compilation), both runtimes approach native performance. Kata has essentially zero steady-state CPU overhead — the guest kernel is real. gVisor’s KVM platform imposes overhead only on syscall paths, so compute-bound loops run near-native speed.

gVisor’s overhead is proportional to syscall frequency. Workloads that issue thousands of syscalls per second — small file I/O, stat() storms, high-frequency network connections — can see 5–15× higher syscall latency versus native. Kata’s virtio I/O path typically stays within 2–3× of native for network and disk throughput.

Kata’s memory overhead (100–180 MB per pod baseline) is non-trivial on nodes running hundreds of sandboxes. gVisor’s ~20–40 MB Sentry footprint is significantly lighter. For high-density deployments — hundreds of short-lived agent sessions per node — gVisor’s footprint advantage is material.

Security Trade-offs

Kata provides stronger isolation: exploiting it requires breaking the hypervisor. gVisor requires breaking the Sentry or exploiting one of the ~50 host syscalls it allows. For threat models where the adversary attempts kernel escape — LLM-generated exploits, red-team scenarios, multi-tenant SaaS — Kata’s VM boundary is the more defensible choice.

gVisor’s seccomp profile for the Sentry allows ~50 host syscalls. Standard containers with a tight seccomp policy might allow 150–200. The Sentry’s Go implementation of the remaining ~350 syscalls constitutes its own attack surface. Kata sidesteps this entirely — the guest kernel is a full Linux kernel, not user-space emulation.

Choose Kata Containers When
  • Threat model includes motivated adversaries attempting kernel escape (LLM-generated exploits, multi-tenant SaaS, red-team scenarios)
  • Regulated environment (SOC 2, PCI, FedRAMP) where VM-level isolation is required by compliance
  • Full Linux ABI compatibility needed – eBPF programs, io_uring, kernel modules, raw sockets
  • Cold-start latency of 100–500 ms is acceptable, or you implement a warm-pool via Kubernetes CRDs
  • You can afford 100–180 MB baseline overhead per pod
Choose gVisor When
  • Low-latency cold starts (10-50 ms) for short-lived sandboxes are needed – CI jobs, serverless functions, per-request isolation
  • Memory density matters – hundreds of sandboxes per node, cannot afford 150+ MB per pod
  • Compute-bound workloads with infrequent syscalls (ML inference, data transformation)
  • Running on GKE with GKE Sandbox (gVisor GA)
  • Syscall compatibility validated for your specific workload

References: Kata Containers Architecture · gVisor Documentation · AWS Builder Hub: EKS Agent Sandboxes · OWASP Top 10 for LLM Applications · Firecracker MicroVM