@@ -29,6 +29,30 @@ To refresh the committed sample reports:
2929PYTHONPATH=../../.. python run_pipeline.py --mode fake --update-sample-outputs
3030```
3131
32+ The fake and trace modes support three deterministic scenarios:
33+
34+ ``` bash
35+ PYTHONPATH=../../.. python run_pipeline.py --mode fake --scenario overfit
36+ PYTHONPATH=../../.. python run_pipeline.py --mode fake --scenario accepted
37+ PYTHONPATH=../../.. python run_pipeline.py --mode fake --scenario cost_exceeded
38+ ```
39+
40+ - ` overfit ` is the default: train improves, validation does not improve, and a
41+ critical case regresses, so the gate rejects the candidate.
42+ - ` accepted ` : train and validation both improve with no new hard fail, so the
43+ gate accepts the candidate.
44+ - ` cost_exceeded ` : quality improves, but the estimated cost exceeds
45+ ` gate.max_cost_usd ` , so the gate rejects the candidate.
46+
47+ For CI-style scripts, add ` --ci-exit-code ` . Normal demo runs always exit 0 after
48+ writing the report; CI mode exits 0 for accepted candidates and 1 for rejected
49+ candidates:
50+
51+ ``` bash
52+ PYTHONPATH=../../.. python run_pipeline.py --mode fake --scenario accepted --ci-exit-code
53+ PYTHONPATH=../../.. python run_pipeline.py --mode fake --scenario overfit --ci-exit-code
54+ ```
55+
3256Trace replay mode also runs without model credentials. It first records fake
3357outputs into generated ` eval_mode: "trace" ` evalsets, then evaluates those
3458` actual_conversation ` records without invoking ` call_agent ` :
@@ -48,81 +72,166 @@ export TRPC_AGENT_MODEL_NAME="<your-model>"
4872PYTHONPATH=../../.. python run_pipeline.py --mode optimizer
4973```
5074
75+ ## Verification Commands
76+
77+ Use these commands to exercise the important review paths:
78+
79+ ``` bash
80+ cd examples/optimization/eval_optimize_loop
81+ PYTHONPATH=../../.. python run_pipeline.py --mode fake --scenario overfit
82+ PYTHONPATH=../../.. python run_pipeline.py --mode fake --scenario accepted
83+ PYTHONPATH=../../.. python run_pipeline.py --mode fake --scenario cost_exceeded
84+ PYTHONPATH=../../.. python run_pipeline.py --mode trace --scenario overfit
85+ cd ../../..
86+ pytest tests/evaluation/test_eval_optimize_loop_example.py -q
87+ ```
88+
5189## Inputs
5290
5391| File | Role |
5492| --- | --- |
5593| ` train.evalset.json ` | Training split used for baseline scoring and optimization feedback. |
5694| ` val.evalset.json ` | Validation split used for regression and gate decisions. |
5795| ` optimizer.json ` | Shared metric, optimizer, fake candidate, and gate configuration. |
58- | ` agent/prompts/system.md ` | Baseline prompt source registered as ` TargetPrompt("system_prompt") ` . |
96+ | ` case_meta.json ` | Public-case attribution labels used for local self-checking. |
97+ | ` agent/prompts/router.md ` | Router prompt source registered as ` TargetPrompt("router_prompt") ` . |
98+ | ` agent/prompts/system.md ` | System prompt source registered as ` TargetPrompt("system_prompt") ` . |
99+ | ` agent/prompts/skill.md ` | Skill prompt source registered as ` TargetPrompt("skill_prompt") ` . |
59100
60101The fake mode still uses ` AgentEvaluator ` for all train and validation scoring.
61102Only candidate generation is deterministic, so the example can run in CI or on a
62103laptop without model credentials.
63104
105+ At startup, the pipeline validates that all required input files exist, train and
106+ validation evalsets are distinct and non-empty, gate keys are present, critical
107+ case IDs refer to validation cases, and evaluator parallelism is positive.
108+
109+ Fake judge behavior is implemented by local exact-match final-response scoring
110+ (` final_response_avg_score ` ). The report records this as
111+ ` run.judge_mode = "local_exact_match_fake_judge" ` , so the evaluation path does
112+ not need an LLM judge or API key.
113+
114+ For tool-only and rubric-only failure classes, fake judge mode uses
115+ deterministic attribution hints from ` case_meta.json ` . This lets the no-key
116+ example exercise the full attribution taxonomy without requiring real tool
117+ execution or an LLM rubric judge.
118+
64119## Outputs
65120
66- Each run writes to ` runs/<mode_timestamp>/ ` :
121+ Each run writes to ` runs/<mode>_<scenario>_<timestamp>/ ` by default :
67122
68123| File or directory | Contents |
69124| --- | --- |
70- | ` optimization_report.json ` | Machine-readable baseline, candidate, delta, attribution, gate, and audit payload. |
125+ | ` optimization_report.json ` | Machine-readable baseline, candidate, per-round prompts, delta, attribution, gate, and audit payload. |
71126| ` optimization_report.md ` | Human-readable report for review. |
72127| ` candidate_prompts/ ` | Candidate prompt text per target field. |
73128| ` eval_* ` | Raw ` AgentEvaluator ` result files for every phase. |
74129| ` config.snapshot.json ` | Reproducible copy of the input config. |
75130| ` eval_metrics.snapshot.json ` | Evaluator-compatible metric config extracted from ` optimizer.json.evaluate ` . |
76131
132+ The report also includes ` prompt_audit ` , which records each target prompt's
133+ source path, baseline SHA-256, candidate SHA-256, character counts, and whether
134+ the candidate changed the prompt. Each prompt audit entry also includes a capped
135+ unified diff preview, so reviewers can see what changed without opening the
136+ candidate prompt files. This makes the score-to-prompt relationship auditable
137+ even when reports are copied outside the run directory.
138+
139+ ` input_audit ` records stable SHA-256 hashes and byte counts for the train
140+ evalset, validation evalset, optimizer config, case metadata, and prompt source
141+ files. This makes a report reproducible even after it is detached from the
142+ working tree.
143+
144+ ` audit.cost ` splits the total estimated spend into optimizer and evaluation
145+ components, then applies the same total to the configurable budget gate. In
146+ fake/trace mode both components are deterministic and normally zero except for
147+ the dedicated ` cost_exceeded ` scenario.
148+
149+ ` failure_attribution.self_check ` compares attribution results against the public
150+ gold labels in ` case_meta.json ` . Gold labels live in ` expected_failure_types ` .
151+ For categories that cannot naturally arise in the no-key black-box path, such as
152+ tool-call and LLM-rubric failures, ` fake_attribution_hints ` provides an explicit
153+ fake-judge hint. The report marks those cases as ` hint_assisted ` and also reports
154+ rule-only accuracy separately. This is not a hidden-set proof, but it provides a
155+ local accuracy guard for the bundled examples and fails report validation if the
156+ labeled-case accuracy drops below 75%.
157+
77158Committed examples live in ` sample_outputs/ ` .
78159
160+ The JSON report includes both human reasons and structured gate checks:
161+
162+ ``` json
163+ {
164+ "gate" : {
165+ "decision" : " rejected" ,
166+ "reasons" : [" ..." ],
167+ "checks" : [
168+ {"name" : " min_validation_score_delta" , "passed" : false },
169+ {"name" : " no_new_hard_fail" , "passed" : false }
170+ ]
171+ }
172+ }
173+ ```
174+
175+ ## Gate Decision Contract
176+
177+ A candidate is accepted only when every configured gate check passes:
178+
179+ | Check | Accept condition | Reject condition |
180+ | --- | --- | --- |
181+ | ` min_validation_score_delta ` | Validation score delta is greater than or equal to ` gate.min_validation_score_delta ` . | Validation score delta is below the configured threshold. |
182+ | ` no_new_hard_fail ` | No validation case changes from pass to fail, unless ` gate.allow_new_hard_fail ` is true. | At least one validation case becomes a new hard fail while new hard fails are disallowed. |
183+ | ` critical_case_regression ` | No case in ` gate.critical_case_ids ` loses score. | Any critical validation case regresses. |
184+ | ` overfitting_guard ` | Validation improves, or training does not improve. | Training improves while validation does not improve. |
185+ | ` max_cost_usd ` | Estimated candidate cost is less than or equal to ` gate.max_cost_usd ` . | Estimated candidate cost exceeds the budget. |
186+
187+ This contract is intentionally validation-first: training improvements alone
188+ never justify acceptance, and hidden samples are expected to follow the same
189+ structured decision rules.
190+
79191## Case Coverage
80192
81- The six sample cases cover the required outcomes:
193+ The ten sample cases exceed the minimum requirement and cover the required outcomes:
82194
83195| Case | Split | Expected behavior |
84196| --- | --- | --- |
85197| ` train_refund_double_charge ` | train | Candidate fixes a baseline failure. |
86198| ` train_password_reset ` | train | Already passing; candidate is unchanged. |
87199| ` train_legacy_sync ` | train | Candidate does not help. |
200+ | ` train_plan_question ` | train | Stable non-target billing question remains passing. |
201+ | ` train_policy_tool_missing ` | train | Tool lookup failure attribution with an incomplete JSON response. |
88202| ` val_vip_refund ` | validation | Candidate creates a new pass. |
89203| ` val_plan_question ` | validation | Candidate has no effect. |
90204| ` val_checkout_outage ` | validation | Candidate regresses a critical case. |
205+ | ` val_mobile_crash ` | validation | Stable technical troubleshooting case remains passing. |
206+ | ` val_rubric_tone_fail ` | validation | Deterministic rubric failure attribution remains failing. |
91207
92208The default fake candidate improves train score but does not improve validation
93209overall because it also introduces a new hard fail. The gate therefore rejects
94210the candidate and records the overfitting reason.
95211
212+ ## Requirement Mapping
213+
214+ | #91 requirement | Implementation |
215+ | --- | --- |
216+ | Baseline train/validation evaluation | ` run_pipeline.py::evaluate_dataset ` uses ` AgentEvaluator.get_executer(...).get_result() ` . |
217+ | Per-case metric, pass/fail, reason, trace | Report cases include query, expected, actual, metric details, status, failure types, and reason. |
218+ | Failure attribution clustering | ` attribute_failure ` and ` build_failure_stats ` . |
219+ | Full attribution taxonomy | Public sample failures include ` final_response_mismatch ` , ` tool_call_error ` , ` parameter_error ` , ` llm_rubric_not_met ` , ` knowledge_recall_insufficient ` , and ` format_violation ` . |
220+ | Attribution accuracy guard | ` case_meta.json ` plus ` failure_attribution.self_check ` validates public labeled cases and marks fake hint-assisted cases. |
221+ | Prompt optimization target | ` TargetPrompt ` registers ` router_prompt ` , ` system_prompt ` , and ` skill_prompt ` . |
222+ | AgentOptimizer or equivalent extension | ` --mode optimizer ` delegates to ` AgentOptimizer ` ; fake/trace modes use deterministic candidate generation for no-key CI. |
223+ | Candidate validation and per-case delta | ` build_case_deltas ` marks ` new_pass ` , ` new_fail ` , ` score_improved ` , ` score_regressed ` , and ` unchanged ` . |
224+ | Configurable gate | ` optimizer.json.gate ` plus ` apply_gate ` , including structured ` gate.checks ` . |
225+ | Overfitting rejection | Default ` --scenario overfit ` improves train but rejects because validation does not improve and a critical case regresses. |
226+ | Cost budget rejection | ` --scenario cost_exceeded ` improves quality but fails ` max_cost_usd ` . |
227+ | Audit artifacts | ` input_audit ` , ` prompt_audit ` with diff previews, ` optimization_rounds ` , ` candidate_prompts/ ` , raw ` eval_* ` outputs, config snapshots, JSON report, and Markdown report. |
228+ | No API key mode | ` --mode fake ` and ` --mode trace ` . |
229+ | 6 public cases | ` train.evalset.json ` has 5 cases and ` val.evalset.json ` has 5 cases. |
230+
96231## Design Notes
97232
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.
233+ 本示例把 ` AgentEvaluator.get_executer(...).get_result() ` 作为唯一评测事实来源,分别对训练集和验证集生成逐 case 记录,包含输入、期望输出、实际输出、metric 分数、pass/fail、失败类型和原因。失败归因采用可复现规则:JSON 解析失败或缺字段归为格式不符合要求,category 不一致归为知识召回不足,priority 不一致归为参数错误,action 不一致归为最终回复不匹配;对必须依赖真实工具轨迹或 LLM rubric judge 的类别,fake mode 通过 ` case_meta.json ` 的 ` fake_attribution_hints ` 标记 ` tool_call_error ` 和 ` llm_rubric_not_met ` ,并在 self-check 中区分 hint-assisted 与 rule-only 准确率,避免把公开标签直接当成黑盒判断结果。
234+
235+ 候选 prompt 不会直接写回源文件,而是先在验证集回归,并和 baseline 做逐 case delta,标记新增通过、新增失败、分数提升、分数下降和无变化。gate 由 ` optimizer.json ` 配置,检查验证集总分提升阈值、是否新增 hard fail、关键 case 是否退化以及成本预算;额外防过拟合规则是训练集提升但验证集没有提升时拒绝候选。这样即使优化器记住训练失败样例,只要验证集没有真实收益,或者牺牲了关键 case,也不会进入可接受状态。
236+
237+ 审计产物包括配置快照、随机种子、候选 prompt 文件、` optimization_rounds ` 、原始 evaluator 输出、JSON 报告和 Markdown 报告,便于完整复现实验配置,也便于后续 CI 读取结构化字段。` prompt_audit ` 记录源路径、baseline/candidate 哈希、字符数和是否变更,reviewer 可以把分数变化追溯到具体 prompt。trace mode 会生成 ` eval_mode: "trace" ` 数据并回放 ` actual_conversation ` ,保证无 API key 环境也能复现 baseline、归因、优化、验证、gate 和审计闭环。
0 commit comments