Skip to content
learn
  1. Learn
  2. Artificial Intelligence
  3. Evaluation

AI AI-10.06

Online evaluation and monitoring

Evaluate an LLM app on live traffic: explicit and implicit feedback signals, sampled grading, A/B tests for prompts and models, and catching input drift.

Intermediate 10 min Last reviewed

The big idea

Your offline eval set passed, so you ship the new prompt. A week later, support tickets mention answers that "sound confident but skip my question". None of your test cases looked like that, because your users started asking things you never collected. Offline evals test the questions you thought of; production is where you meet the ones you did not.

Online evaluationMeasuring an AI system's quality on live traffic, using user feedback, behaviour signals and automatic grading of sampled outputs. closes that gap. You watch three things on real traffic: what users tell you, what users do, and what your graders say about a sample of outputs. You compare versions with controlled experiments, and you watch the inputs themselves for change.

Think of a restaurant. Tasting in the kitchen (offline evals) catches most problems before a dish goes out. But you also watch what comes back on the plates, read the comment cards, and notice when the neighbourhood starts ordering dishes that are not on the menu.

How it works

Online evaluation loop Step 1: users are randomly assigned to prompt version A or B, and every request is logged as a trace. Step 2: explicit feedback such as thumbs and comments, and implicit signals such as retries, edits and escalations, are attached to the traces. Step 3: a sample of traces is graded by code checks and a validated judge, and all signals feed dashboards and alerts. Step 4: new failures and new kinds of input found in production are added to the offline eval set, which gates the next change. random split feedback sample new cases gates next change users your app prompt A or B traces every request sampled grading code checks + judge dashboards per version, alerts offline eval set grows from production Figure 1. Production traffic feeds feedback, sampled grading and drift checks, and what you learn flows back into the offline eval set. Step through it.
  1. Split and log Each user is randomly assigned version A or B. Every request becomes a trace: input, output, tool calls, cost, latency.
  2. Feedback signals Thumbs and comments are explicit. Retries, edits, copies, abandoned sessions and escalations are implicit.
  3. Sampled grading Code checks and a validated judge grade a sample of traces. Dashboards track every metric per version and alert on change.
  4. Back to offline New failure types and new kinds of input become eval cases, so the next change is tested against them before it ships.

User feedback signals

Explicit feedbackFeedback a user gives on purpose, such as a thumbs up or down, a star rating or a written comment. is the obvious one: a thumbs up or down, a rating, a comment box. It is cheap to collect and easy to read, but it is sparse (most users never click), skewed towards people who are very pleased or very annoyed, and it rewards what users like in the moment. People tend to like answers that agree with them, which is not the same as answers that are right.

Implicit signalsFeedback inferred from what users do, such as accepting a suggestion, retrying, editing the output or asking for a human. come from behaviour, so you get them for every session:

  • Acceptance: the user copies the answer, accepts the code suggestion or sends the drafted email.
  • Rework: the user regenerates, rephrases the same question or heavily edits the output.
  • Abandonment and escalation: the session ends without an answer, or the user asks for a human.
  • Task outcome: the ticket is closed, the order goes through, the query returns rows.

None of these is a quality score on its own. A user may copy a wrong answer, or leave because the first answer was perfect. Use them as trends: a sudden rise in regenerations after a release is a strong hint, even if no single session proves anything.

Sampled grading in production

You cannot read every trace, but you can grade a sample. Run your cheap code checks on everything (valid format, no leaked internal IDs, tool calls that succeed) and your validated judges ( LLM-as-judge ) on a random sample, for example a few hundred traces a day per version. Track guardrail metrics alongside quality: latency, cost per request, error rate and refusal rate. A change that improves answers but doubles latency may still be a loss.

A/B tests for prompts and models

To know whether prompt B is better than prompt A, randomly assign users to one or the other and compare a metric chosen in advance. This is an A/B testA controlled experiment that randomly splits live traffic between two versions and compares a pre-chosen metric, so the difference can be attributed to the change.. Randomisation is what makes it work: both groups face the same mix of users, topics and days, so a difference in outcome is caused by the change, up to chance.

The practical rules:

  • Randomise by user, not by request, so each person gets a consistent experience and one heavy user cannot land in both groups.
  • Pick one primary metric and a few guardrails before you start, such as task success as primary, and latency, cost and complaint rate as guardrails.
  • Decide the sample size up front and run until you reach it. Small effects need far more users than intuition suggests (see Going deeper).
  • Ramp up gradually. A safer path is to run the new version in shadow mode first (it answers a copy of the traffic, users never see its output, you grade it offline), then a small canary, then the full test.

Drift in inputs

Your eval set is a snapshot of past traffic. Over time the inputs change: a new product launches, a policy changes, a marketing campaign brings a new kind of user, or people start pasting longer documents. This is input driftA change over time in the kind of inputs a system receives, so the data it was evaluated on no longer represents real use., and a system tuned on last quarter's questions can quietly degrade on this quarter's.

Watch the input distribution, not just the output quality. Classify incoming requests into topics (with keywords, clustered embeddings ( From symbols to vectors ), or a small classifier), track each topic's share week by week, and pay special attention to the share that fits no known topic. When something new grows, read those traces, run error analysis on them ( Error analysis ) and add representative cases to your eval set.

There is a second kind of drift if you call a hosted model through a name that the provider can update: the model itself may change under you. Pin model versions where the provider allows it, and re-run your eval set whenever a version changes.

Try it

This interactive needs JavaScript. The diagrams and text above cover the same idea.

  1. Keep the defaults (B is truly 2 points better, 500 users per day, 21 days). The band clears zero long before the planned size marker. Compare the early estimates with the true 2 points. Why would stopping early overstate the gain?
  2. Set the true effect to 0 and press "Rerun with new users" several times. How often do some daily dots look significant even though B is no better?
  3. Set the true effect to plus 1 point. How many days would you need at 500 users per day, and at 10,000?

A simple drift check over two weeks of messages to a support assistant:

drift.pyruns with python3 (standard library)
# Input drift check: bucket each week's user messages into known topics,
# compare topic shares, and watch the bucket nothing was designed for.
from collections import Counter

TOPICS = {
    "billing": ["invoice", "refund", "charge", "payment"],
    "shipping": ["delivery", "parcel", "tracking", "shipped"],
    "account": ["password", "login", "email", "account"],
}

def topic(msg):
    words = msg.lower().split()
    for name, keys in TOPICS.items():
        if any(k in words for k in keys):
            return name
    return "unknown"

week_1 = (["where is my parcel"] * 30 + ["refund for a double charge"] * 40
          + ["reset my password"] * 25 + ["do you sell gift cards"] * 5)
week_4 = (["where is my parcel"] * 28 + ["refund for a double charge"] * 30
          + ["reset my password"] * 20 + ["cancel my subscription now"] * 14
          + ["subscription renewal price went up"] * 8)

def shares(msgs):
    counts = Counter(topic(m) for m in msgs)
    return {t: counts[t] / len(msgs) for t in [*TOPICS, "unknown"]}

before, after = shares(week_1), shares(week_4)
print(f"{'topic':<10}{'week 1':>8}{'week 4':>8}{'change':>9}")
for t in before:
    flag = "  <- investigate" if after[t] - before[t] > 0.05 else ""
    print(f"{t:<10}{before[t]:>8.0%}{after[t]:>8.0%}{after[t] - before[t]:>+9.0%}{flag}")

unknown = [m for m in week_4 if topic(m) == "unknown"]
print("\nmost common unknown messages:")
for msg, n in Counter(unknown).most_common(3):
    print(f"  {n:>3}  {msg}")

Output

topic       week 1  week 4   change
billing        40%     30%     -10%
shipping       30%     28%      -2%
account        25%     20%      -5%
unknown         5%     22%     +17%  <- investigate

most common unknown messages:
   14  cancel my subscription now
    8  subscription renewal price went up

The known topics all shrank a little, while messages that fit no topic grew from 5 to 22 percent. Reading them shows why: subscription cancellations, a request type the assistant was never designed or evaluated for. That is the cue to run error analysis on those traces and add subscription cases to the eval set.

Going deeper

How many users does an A/B test need?

To detect a difference between success rates and , with a 5 percent false positive rate and 80 percent power (the chance of detecting a real effect of that size), each version needs roughly

users. With and : the numerator is , and , so users per version. Halving the effect to 1 point multiplies the sample by four, to about 37,500. Small improvements to a prompt are real but expensive to prove.

Do not stop at the first good-looking day

If you check the result every day and stop as soon as it looks significant, you raise your false positive rate well above 5 percent, because you give chance many tries. In the lab's simulation with no real effect, 500 users per version per day and 14 days, about 5 percent of runs end significant on day 14, but about 22 percent look significant on at least one daily check. Fix the sample size in advance, or use a sequential testing method designed for repeated looks.

Other traps

  • Novelty effects: users may react to a change because it is new. Run long enough to see the effect settle.
  • Too many metrics: compare 20 metrics and one will look significant by chance. Name the primary metric before the test.
  • Mismatched units: if you randomise by user but compute the metric per request, heavy users dominate and the confidence interval is too narrow.

Trade-offs

OptionWins whenLoses when
Explicit feedback Cheap, direct, easy to explain Sparse, skewed to extremes, rewards agreeable answers
Implicit signals Available for every session; shows real behaviour Ambiguous on its own; read as trends, not verdicts
Sampled grading Measures your failure categories on real traffic Judges need validation and upkeep; costs per graded trace
A/B test Shows cause and effect on real outcomes Needs many users for small effects; exposes users to the worse version
Shadow mode No user impact; grade a new version on real inputs No user reactions; doubles inference cost for that traffic

Common mistakes

  • Treating the thumbs-up rate as the quality metric and optimising for it alone.
  • Stopping an A/B test the first day it looks significant, or running it with a few hundred users to detect a 1 point change.
  • Randomising per request, so the same user bounces between versions.
  • Monitoring output quality but never looking at how the inputs are changing.
  • Calling a model name the provider can update without pinning a version or re-running evals when it changes.

In the wild

Ziegler et al., 2022 (paper)

Productivity Assessment of Neural Code Completion (opens in a new tab)

The GitHub Copilot team matched 2,047 developer survey responses to usage data, to find which measurable signal best reflected developers' perceived productivity. The rate at which shown suggestions were accepted predicted perceived productivity better than more detailed measures, such as how much accepted code persisted unchanged. The authors conclude that acceptance rate suits coarse-grained monitoring, while finer investigation still needs other methods: a good example of an implicit signal, and of its limits.

Chen, Zaharia and Zou, 2023 (paper)

How is ChatGPT's behavior changing over time? (opens in a new tab)

The authors evaluated the March and June 2023 versions of two hosted models on the same tasks. One model's accuracy at identifying prime numbers fell from 84 to 51 percent, partly because it followed chain-of-thought prompting less well, and both models made more formatting mistakes in generated code in June. Their conclusion is the one this lesson draws: the behaviour of the "same" hosted model can change substantially in a short time, so it needs continuous monitoring.

Check yourself

  1. Why is a thumbs-up rate a risky primary quality metric?

    Show answer

    B. It is sparse, skewed to extremes and can reward answers that please rather than answers that are correct Explicit feedback is useful, but on its own it can pull a system towards agreeable answers. Pair it with sampled grading and targeted evals.

  2. After a release, regenerations per session rise by 30 percent while thumbs-up stays flat. What do you do?

    Show answer

    B. Treat it as a strong hint, read a sample of the regenerated sessions and run error analysis Implicit signals are trends, not verdicts. A sharp change after a release tells you where to look.

  3. You want to detect a 2 point improvement in a 60 percent success rate. Roughly how many users per version do you need for 80 percent power?

    Show answer

    C. About 9,300 7.84 x (0.24 + 0.2356) / 0.02 squared is about 9,300. Small effects need large samples.

  4. An A/B test shows B significantly better on day 3 of a planned 14 days. What should you do?

    Show answer

    B. Keep running to the planned sample size; early peeks inflate false positives Checking daily and stopping at the first significant result gives chance many tries. Stick to the plan or use a sequential method.

  5. Messages that fit none of your known topics grow from 5 to 22 percent of traffic in a month. What does this suggest?

    Show answer

    B. Input drift: users ask for things your eval set does not cover; read them and add cases A growing unknown share is the classic sign of drift. Error analysis on those traces tells you what to add to your evals.

Recap

  • Offline evals test what you anticipated; online evaluation watches real traffic for what you did not.
  • Combine explicit feedback, implicit behaviour signals and sampled grading with validated judges, plus latency and cost guardrails.
  • A/B tests randomise users between versions; choose the metric and sample size in advance and do not stop at the first good-looking day.
  • Monitor input drift by tracking topic shares and the unknown bucket, and pin hosted model versions.
  • Feed new failures and new kinds of input back into the offline eval set so the next change is tested against them.

Get new lessons by email

Get new posts on backend and AI internals. No spam, unsubscribe anytime.

Your email is only used to send new posts. Privacy