构建 Evaluation + Optimization 的自动回归与提示词优化闭环 - #274
Conversation
…kend BaselineEvaluator now delegates to an injected EvalBackend instead of building its own trace-mode executer. This drops the duplicated _build_report (already in _eval_backend.py) and removes the blanket `except Exception: pass` that silently turned a missing evalset file into an all-zero score, which Stage 2 would then misattribute to the prompt. Also drops the now-unused Path import left in _eval_backend.py.
trace/ holds the three demo-mode datasets (train + val_baseline + val_optimized) carrying actual_conversation; live/ holds two non-trace datasets (no actual_conversation, eval_mode=non-trace) for the real-mode optimizer that calls the agent via call_agent. Train and val live datasets live at distinct paths so AgentOptimizer does not trigger its data-leak ValueError. Generator is idempotent and removes the legacy flat train_baseline/val_baseline.evalset.json files on each run.
Fixes from review round 1: - Extract _expected_turn_body helper; both _make_turn (trace) and generate_live_evalset (live) now build the shared user_content + intermediate_data + final_response shape from a single source. Trace still adds invocation_id via _with_invocation_id between intermediate_data and final_response to preserve key order. - Drop dead scenario_map parameter from generate_optimized_evalset; the function derives scenario from eval_id suffix only. - Make regression_responses lookup strict: missing key now raises KeyError instead of silently producing a non-degraded "optimized" case. Likewise the unknown-suffix else branch now raises ValueError instead of defaulting to optimization_regression. - Move `import os` to module level (was inside main()). Pure refactor: generator output is byte-identical (md5 verified across all five .evalset.json files).
The plan's runner spec dropped val_candidate_eval_path, so Stage 4 re-scored the baseline evalset in both modes. Under TraceBackend that replays the same pre-recorded outputs, so every delta was zero and the gate could never reject val_003_regression — the behaviour this example exists to demonstrate. Demo now passes empty best_prompts so applied_prompts degrades to a no-op: trace replay ignores the prompt, and writing it back only pollutes system.md.
…meout, skip_perfect)
run_pipeline.py was the only place demo_mode should appear in the
codebase. Now all demo/real divergence collapses into one
if/else block: datasets, backend (Trace vs Live), agent factory,
demo result path, and real-mode train path. The 40-entry
SCENARIO_MAP dict is replaced by derive_scenario(eval_id), which
maps eval_id suffix to scenario and is importable at module
level for downstream tests. The PipelineRunner(...) call matches
the current _runner.py signature (incl. val_candidate_eval_path
and gate_metrics_config_path). scenario_map is passed via the
public constructor kwarg, not by private-attribute mutation. The
final summary now reports args.output_dir as the parent
(the runner's UTC-timestamp subdir holds the actual artifacts)
so the printed path is not misleading.
Verify:
python -c "import run_pipeline; print(run_pipeline.derive_scenario('val_003_regression'))"
-> optimization_regression
python run_pipeline.py --help exits 0 with all flags
python run_pipeline.py --output-dir /tmp/eo_task14
-> full demo pipeline runs to REJECTED (5 deliberate regressions
in trace/val_optimized.evalset.json), baseline 0.25 / candidate 0.50
system.md hash and mtime unchanged after demo run
…cstring
Three review-driven cleanups:
- run_pipeline.py: drop _agent_factory_lazy(). LiveBackend's default
agent_factory=create_agent already does the right thing, and agent.agent
is imported at module load via pipeline/_eval_backend.py regardless of
mode, so the wrapper was misleading dead code.
- pipeline/_runner.py: PipelineRunner.run_dir attribute, assigned right
after the UTC-timestamp mkdir. run_pipeline.py now prints the actual
run directory, not the parent.
- pipeline/_stage_validation.py: replace stale `scenario_map=SCENARIO_MAP`
in the module docstring example with the derive_scenario() approach.
test_pipeline_fake.py's local SCENARIO_MAP intentionally left alone.
Verify: python run_pipeline.py --output-dir /tmp/eo_task14_fix prints
"报告已写入: /tmp/eo_task14_fix/20260731T024326Z" and that directory
contains both optimization_report.{json,md}. Verdict still REJECTED
(baseline 0.25, candidate 0.50, 5 deliberate regressions). system.md
hash unchanged.
- Replace 40-line SCENARIO_MAP with derive_scenario import + fixture - Update all paths: train_baseline → trace/train, val_baseline → trace/val_baseline, test_config → gate_metrics - Add backend=TraceBackend() and gate_metrics_config_path params - Use runner.run_dir for report path assertions Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace test_config.json references with gate_metrics.json and document the two-layer metric strategy: gate metrics ⊇ optimizer metrics. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- test_live_datasets_no_trace: guard live datasets against trace cases - test_datasets_complete: guard all 5 dataset files exist and non-empty - test_call_agent_rebuild: guard agent rebuild per invocation - test_applied_prompts: guard baseline restore on exception/success - test_gate_superset_of_optimizer: guard gate ⊇ optimizer metrics - test_scenario_derivation: guard suffix-based scenario derivation - test_eval_backend: guard EvalBackend protocol conformance Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅ |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #274 +/- ##
==========================================
Coverage ? 88.43514%
==========================================
Files ? 491
Lines ? 46036
Branches ? 0
==========================================
Hits ? 40712
Misses ? 5324
Partials ? 0 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
AI Code Review基于我对 发现的问题🚨 Critical
|
| """ | ||
| num_regressions = len(regressed_ids) | ||
|
|
||
| if self._config.no_new_hard_failures and num_regressions > 0: |
There was a problem hiding this comment.
回归检查分支优先级使 max_regressions_allowed / --max-regressions 失效
_check_regressions 先判断 no_new_hard_failures and num_regressions > 0 即直接失败,永远到不了 elif num_regressions > max_regressions_allowed 分支。导致 --max-regressions N 单独使用时对回归完全无效,只有配合 --allow-regressions 才生效。建议先比较 num_regressions > max_regressions_allowed,再在 no_new_hard_failures 为真且 max_regressions_allowed == 0 时才走严格拒绝,并补充 no_new_hard=True、max_regressions_allowed=2 且存在 1 个回归应通过的测试。
|
I have read the CLA Document and I hereby sign the CLA |
|
have read the CLA Document and I hereby sign the CLA |
AI Code Review我已经获取了所有行号。现在我来编写审查报告。基于我对 发现的问题🚨 Critical未发现 Critical 问题。核心 SDK 改动(
|
…on swallow - _stage_acceptance_gate: max_regressions_allowed > 0 now overrides the no_new_hard_failures strict check (was shadowed by branch priority, so --max-regressions alone had no effect); strict-mode rejection keeps the no_new_hard_failures report name - _eval_backend: swallow only _EvaluationCasesFailed instead of all AssertionError, so unrelated assertion failures propagate instead of feeding a half-finished report into the gate; guard temp metrics file cleanup across all exception paths - _stage_validation: merge write-back/non-write-back branches into a single evaluate call via contextlib.nullcontext - add tests for gate override semantics and backend error paths Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
AI Code Review多个用例修改了共享购物车。现在我来完成审查报告。 发现的问题🚨 Critical
|
| writer.writerows(rows) | ||
|
|
||
|
|
||
| def _init_data() -> None: |
There was a problem hiding this comment.
real 模式共享 CSV 状态无锁,并发评测触发读写竞争
实时模式下 agent 工具通过全局共享 cart.csv/orders.csv 维护状态,且 _read_csv→修改→_write_csv 无文件锁。eval_case_parallelism=2 与 num_runs=2 的并发评测会触发读写竞争,导致购物车/订单文件互相覆盖或损坏,候选评测结果不可复现。建议按 session_id 隔离状态或对写操作加锁。
|
我按照你的意见进行了修改: 🚨 Critical — 门控分支优先级(pipeline/_stage_acceptance_gate.py:139)
💡 Suggestion — 重复调用合并(pipeline/_stage_validation.py:70)
|
|
所有测试已经通过,不过按照建议我还是增加了tools 会话并发隔离机制 |
AI Code Review我已完成审查。结合 diff 与仓库上下文(SDK 源码、evalset 数据、README 设计意图、trace/live 数据集),以下是结论。 发现的问题🚨 Critical
|
已经加入了电商场景的agent,并做出了评估+优化+失败归因的闭环pipeline