|
| 1 | +# Evaluation + Optimization Loop |
| 2 | + |
| 3 | +This example demonstrates a reproducible pipeline that connects evaluation, |
| 4 | +failure attribution, prompt optimization, validation regression checks, gate |
| 5 | +decisions, and audit reports. |
| 6 | + |
| 7 | +It is intentionally different from `ci_integration/`: CI integration focuses on |
| 8 | +PR gates and nightly write-back, while this example focuses on the complete |
| 9 | +review loop before deciding whether a candidate prompt is worth accepting. |
| 10 | + |
| 11 | +## Run |
| 12 | + |
| 13 | +The default mode is deterministic and does not require an API key: |
| 14 | + |
| 15 | +```bash |
| 16 | +cd examples/optimization/eval_optimize_loop |
| 17 | +PYTHONPATH=../../.. python run_pipeline.py --mode fake |
| 18 | +``` |
| 19 | + |
| 20 | +If your environment only exposes `python3`, use: |
| 21 | + |
| 22 | +```bash |
| 23 | +PYTHONPATH=../../.. python3 run_pipeline.py --mode fake |
| 24 | +``` |
| 25 | + |
| 26 | +To refresh the committed sample reports: |
| 27 | + |
| 28 | +```bash |
| 29 | +PYTHONPATH=../../.. python run_pipeline.py --mode fake --update-sample-outputs |
| 30 | +``` |
| 31 | + |
| 32 | +Trace replay mode also runs without model credentials. It first records fake |
| 33 | +outputs into generated `eval_mode: "trace"` evalsets, then evaluates those |
| 34 | +`actual_conversation` records without invoking `call_agent`: |
| 35 | + |
| 36 | +```bash |
| 37 | +PYTHONPATH=../../.. python run_pipeline.py --mode trace |
| 38 | +``` |
| 39 | + |
| 40 | +The optional real optimizer path delegates candidate search to |
| 41 | +`AgentOptimizer.optimize` and requires the normal optimization dependencies and |
| 42 | +model environment variables: |
| 43 | + |
| 44 | +```bash |
| 45 | +export TRPC_AGENT_API_KEY="<your-key>" |
| 46 | +export TRPC_AGENT_BASE_URL="<your-endpoint>" |
| 47 | +export TRPC_AGENT_MODEL_NAME="<your-model>" |
| 48 | +PYTHONPATH=../../.. python run_pipeline.py --mode optimizer |
| 49 | +``` |
| 50 | + |
| 51 | +## Inputs |
| 52 | + |
| 53 | +| File | Role | |
| 54 | +| --- | --- | |
| 55 | +| `train.evalset.json` | Training split used for baseline scoring and optimization feedback. | |
| 56 | +| `val.evalset.json` | Validation split used for regression and gate decisions. | |
| 57 | +| `optimizer.json` | Shared metric, optimizer, fake candidate, and gate configuration. | |
| 58 | +| `agent/prompts/system.md` | Baseline prompt source registered as `TargetPrompt("system_prompt")`. | |
| 59 | + |
| 60 | +The fake mode still uses `AgentEvaluator` for all train and validation scoring. |
| 61 | +Only candidate generation is deterministic, so the example can run in CI or on a |
| 62 | +laptop without model credentials. |
| 63 | + |
| 64 | +## Outputs |
| 65 | + |
| 66 | +Each run writes to `runs/<mode_timestamp>/`: |
| 67 | + |
| 68 | +| File or directory | Contents | |
| 69 | +| --- | --- | |
| 70 | +| `optimization_report.json` | Machine-readable baseline, candidate, delta, attribution, gate, and audit payload. | |
| 71 | +| `optimization_report.md` | Human-readable report for review. | |
| 72 | +| `candidate_prompts/` | Candidate prompt text per target field. | |
| 73 | +| `eval_*` | Raw `AgentEvaluator` result files for every phase. | |
| 74 | +| `config.snapshot.json` | Reproducible copy of the input config. | |
| 75 | +| `eval_metrics.snapshot.json` | Evaluator-compatible metric config extracted from `optimizer.json.evaluate`. | |
| 76 | + |
| 77 | +Committed examples live in `sample_outputs/`. |
| 78 | + |
| 79 | +## Case Coverage |
| 80 | + |
| 81 | +The six sample cases cover the required outcomes: |
| 82 | + |
| 83 | +| Case | Split | Expected behavior | |
| 84 | +| --- | --- | --- | |
| 85 | +| `train_refund_double_charge` | train | Candidate fixes a baseline failure. | |
| 86 | +| `train_password_reset` | train | Already passing; candidate is unchanged. | |
| 87 | +| `train_legacy_sync` | train | Candidate does not help. | |
| 88 | +| `val_vip_refund` | validation | Candidate creates a new pass. | |
| 89 | +| `val_plan_question` | validation | Candidate has no effect. | |
| 90 | +| `val_checkout_outage` | validation | Candidate regresses a critical case. | |
| 91 | + |
| 92 | +The default fake candidate improves train score but does not improve validation |
| 93 | +overall because it also introduces a new hard fail. The gate therefore rejects |
| 94 | +the candidate and records the overfitting reason. |
| 95 | + |
| 96 | +## Design Notes |
| 97 | + |
| 98 | +The pipeline treats evaluation results as the source of truth and converts |
| 99 | +`AgentEvaluator.get_executer(...).get_result()` into a stable per-case report. |
| 100 | +For each split, it records score, pass/fail status, normalized actual and |
| 101 | +expected final responses, metric details, and a short trace summary. Failure |
| 102 | +attribution is deterministic: invalid JSON or missing keys are classified as |
| 103 | +format violations; category mismatches indicate knowledge-recall gaps; priority |
| 104 | +mismatches are parameter errors; action mismatches are final-response errors. |
| 105 | +This keeps fake mode explainable and also gives real optimizer runs a fallback |
| 106 | +when no LLM judge reason is available. |
| 107 | + |
| 108 | +Candidate prompts are validated on the held-out validation set before any source |
| 109 | +prompt is updated. The configurable gate checks minimum validation improvement, |
| 110 | +new hard failures, critical-case regressions, and cost budget. It also includes |
| 111 | +an explicit overfitting guard: when training improves but validation does not, |
| 112 | +the candidate is rejected even if some individual validation case improves. All |
| 113 | +decisions include concrete reasons, so a reviewer can see whether rejection came |
| 114 | +from score, hard-fail, critical-case, cost, or overfitting policy. |
| 115 | + |
| 116 | +Auditability is handled by snapshotting config, writing candidate prompt files, |
| 117 | +preserving raw evaluator outputs, and emitting both JSON and Markdown reports. |
| 118 | +The JSON report is suitable for CI parsing, while the Markdown report summarizes |
| 119 | +score deltas, per-case outcomes, failure clusters, and the final accept/reject |
| 120 | +decision for humans. Fake mode makes this loop reproducible without API keys; |
| 121 | +real mode can swap in `AgentOptimizer` while keeping the same validation, gate, |
| 122 | +and report machinery. The source prompt is never overwritten by this example; |
| 123 | +reviewers can inspect `candidate_prompts/` and decide whether to copy or submit |
| 124 | +the change through a normal PR. Hidden samples can reuse the same gate because |
| 125 | +all decisions are based on held-out validation deltas rather than train-set |
| 126 | +scores alone. Trace-style replay can also be added by replacing `call_agent` |
| 127 | +with eval cases that provide `actual_conversation`, while the attribution, delta, |
| 128 | +gate, and report stages remain unchanged. |
0 commit comments