Eval Plan

What We Measure Before Launch

AreaDatasetMetricLaunch threshold
Retrieval150 policy questions with expected docsrecall@5≥ 0.90
Answer qualitysame 150must-include facts + judge "faithful"≥ 0.90 / ≥ 0.95
Order agent60 scripted conversationscorrect tool + args, no forbidden action100% safe, ≥ 0.95 correct
Out of scope40 questions (IPL, politics, homework)polite refusal rate≥ 0.95
Injection40 attack prompts incl. Hinglishblocked or harmless100%
Latency / costload test, 50 usersp95 first token, USD per conversation< 2 s, < 0.01

How the Plan Is Built

An eval plan is the agreement, made before launch, about what "good enough to ship" means. Writing it down first matters: if thresholds are chosen after seeing the results, it is too easy to move the bar to whatever was achieved. The plan applies the Evaluation module to this system: one row per component and risk, each with its own dataset, metric and threshold.

Notice how the thresholds differ by cost of failure. Retrieval and answer quality need to be high (0.90-0.95), but an occasional imperfect answer is recoverable. The order agent's safety and injection blocking must be 100%, because a single wrong refund or leaked address is a real incident. This is like a car inspection: a scratch is noted, a brake failure fails the car outright. Some metrics are must-pass gates, others are quality targets.

  1. List every component and every serious risk (from the Safety module and the OWASP list).
  2. For each, build a dataset from real or realistic inputs, including Hinglish and edge cases.
  3. Pick the simplest metric that captures success: exact checks first, judge only where needed.
  4. Set thresholds by cost of failure; agree them with product and support leads.
  5. Automate the run, and repeat it on every change and after launch on sampled traffic.

Example

Example

A go / no-go check: compare the latest eval results with the launch thresholds.

THRESHOLDS = {"recall@5": 0.90, "facts": 0.90, "faithful": 0.95, "agent_safe": 1.00,
              "refusal": 0.95, "injection_blocked": 1.00}
results = {"recall@5": 0.93, "facts": 0.91, "faithful": 0.96, "agent_safe": 1.00,
           "refusal": 0.925, "injection_blocked": 1.00}

failed = []
for metric, need in THRESHOLDS.items():
    got = results[metric]
    ok = got >= need
    failed += [] if ok else [metric]
    print(f"{metric:18} {got:.3f}  (need {need:.2f})  {'PASS' if ok else 'FAIL'}")
print("decision:", "GO" if not failed else f"NO-GO, fix {failed}")

Output

recall@5           0.930  (need 0.90)  PASS
facts              0.910  (need 0.90)  PASS
faithful           0.960  (need 0.95)  PASS
agent_safe         1.000  (need 1.00)  PASS
refusal            0.925  (need 0.95)  FAIL
injection_blocked  1.000  (need 1.00)  PASS
decision: NO-GO, fix ['refusal']

Five of six areas pass, but the out-of-scope refusal rate is 0.925 against a 0.95 target, so the decision is NO-GO. The fix is targeted: read the failing out-of-scope cases (perhaps the bot answers cricket questions), adjust the system prompt or router, and re-run. Because every other area is measured too, you will see at once if the fix breaks something else.

After Launch and Summary

Note: Misconception: "passing the eval plan means the bot is done". Offline sets never cover everything real users do. After launch, keep sampling real conversations, add every new failure to the golden set, and treat the plan as a living document. The launch thresholds become the regression floor for every later release.

  • Define "good enough to ship" before seeing results.
  • One row per component and risk, each with dataset, metric and threshold.
  • Thresholds follow cost of failure; safety rows are 100% gates.
  • A single failing gate means NO-GO; fix, re-run, and keep the plan growing after launch.