Skip to content
← Back to blog

Closing the Loop: Turning Live Production Data into RL Training Signal

Static training sets go stale the moment a model ships. Notes on building a flywheel that converts real production failures into new RL training data and gyms.

July 8, 2026·3 min read·Reinforcement Learning

A model's training data is a snapshot. Production usage is not. The moment a coding agent ships, real users start hitting cases the training distribution never anticipated — and the training set doesn't update itself to reflect that. The only way to keep a model current without a full retraining cycle from scratch is to build a deliberate loop back from production to training.

Where the signal actually comes from

The starting point is a live-data analysis workflow that combines deterministic checks and LLM-based metrics to do two things: detect signs of user frustration or failure, and — critically — attribute why the interaction failed. That attribution matters more than it sounds like it should. "The agent failed" is not actionable. "The agent failed because the harness didn't expose a needed tool" versus "the agent failed because the underlying model made a reasoning error" point to completely different fixes, and conflating them wastes the signal.

From failure to training data

Once a failure is identified and attributed to the model (rather than the surrounding harness), it becomes a candidate for the flywheel: an automated pipeline that converts live production failures into new RL training data and new gym tasks, closing the loop from "this happened to a real user" to "this is now something the model is explicitly trained against."

This is where the gym-authoring infrastructure and the evaluation infrastructure meet the live-data pipeline — a real failure doesn't just become one training example; it can become a reusable environment that keeps testing future checkpoints against the same failure mode, and a benchmark case that shows up in evaluation from then on.

Human-in-the-loop is not an afterthought here

Not every step in this pipeline can be automated, and pretending otherwise produces bad data. Human annotation plays a specific, structural role across three places in the loop:

  • Labeling live interactions where automated metrics can't reliably judge quality — turning ambiguous production sessions into usable SFT/RL training signal.
  • Verifying newly created RL gym tasks — confirming that a task derived from a real failure is actually well-posed and solvable before it enters the training curriculum.
  • Constructing evaluation benchmarks from the same live-data source, so the benchmark suite itself stays representative of current usage, not just the usage patterns that existed when the original benchmarks were built.

The part that actually determines whether this data is trustworthy is inter-annotator agreement — measuring how consistently different annotators label the same case, and calibrating rubrics until that agreement is high enough that the resulting labels are a reliable signal rather than noise. Skipping this step is the easiest way to quietly poison a training pipeline with inconsistent labels that look fine individually and cancel each other out in aggregate.

Why this matters more than it seems

It's tempting to treat evaluation, RL environments, and human annotation as three separate workstreams. In practice, the highest-leverage version of each of them is the version that feeds the other two: a live failure becomes an eval case and a training gym and a labeled example, from a single pipeline, rather than three teams independently rebuilding similar pipelines from the same raw signal. Building that connective infrastructure is less glamorous than any individual training run, but it's what keeps a shipped model from slowly drifting out of sync with how it's actually being used.