Skip to content

feat: add Evaluation + Optimization closed-loop pipeline (#91)#194

Open
DNKYr wants to merge 16 commits into
trpc-group:mainfrom
DNKYr:feature/eval-optimize-loop
Open

feat: add Evaluation + Optimization closed-loop pipeline (#91)#194
DNKYr wants to merge 16 commits into
trpc-group:mainfrom
DNKYr:feature/eval-optimize-loop

Conversation

@DNKYr

@DNKYr DNKYr commented Jul 16, 2026

Copy link
Copy Markdown

Summary

Implements the Evaluation + Optimization automated regression and prompt optimization closed loop as described in #91.

What was built

A new examples/optimization/eval_optimize_loop/ package with:

Pipeline (EvalOptimizePipeline)

  • Baseline evaluation — Runs AgentEvaluator on train and val evalsets
  • Failure attribution — Rule-based clustering of failures into 6 categories (final_response_mismatch, format_violation, tool_trajectory_mismatch, llm_judge/rubric_not_passing, knowledge_recall_insufficient)
  • Optimization — Live mode delegates to AgentOptimizer; trace mode uses pre-cooked prompts
  • Candidate validation — Re-evaluates best_prompts on both train and val
  • Per-case delta analysis — Identifies newly_passing, newly_failing, score deltas
  • Configurable acceptance gate — 6 rules: min_improvement, allow_new_fails, protected_case_ids, max_cost_usd, max_duration_seconds, plus built-in overfitting detection
  • Audit reportsoptimization_report.json (machine-readable) + optimization_report.md (human-readable)

Sample data

  • 6 trace-mode evalsets (3 train + 3 val, baseline + candidate variants each)
  • Demonstrates optimizable, unoptimizable, and regression scenarios
  • Trace mode runs without API keys

Test coverage

  • 43 tests, all passing
  • 94% overall coverage (100% on models, delta, failure_attribution, gate, reporting)
  • Integration tests verify ACCEPT and REJECT gate decisions

Closes #91

DNKYr added 13 commits July 16, 2026 10:44
… remove unused import

- Remove unused GateDecision import from test_reporting.py
- Add test_write_reports_per_case_delta_all_transitions covering all 4 transition types in per-case delta table: newly_passing, newly_failing, passed (both), failed (both)
- Coverage: reporting.py 100% (119/119 lines)
…rator

- Fix Optional[callable] -> Optional[Callable] with typing.Callable import
- Add tests for _write_eval_config_temp, _run_optimization injection hook, and run() trace mode
- Remove unused imports (Path, EvalConfig, EvalSetAggregateResult, GateDecision from pipeline.py)
- Remove unused imports (AgentEvaluator, EvalConfig, PipelineResult, GateConfig from tests)
- Add 3 integration tests: ACCEPT, REJECT, and overfitting scenario
- Fix pipeline._run_eval to catch _EvaluationCasesFailed (expected when
  eval cases fail; result is populated before the exception is raised,
  matching the pattern used by run_evaluator in the SDK)
- All 43 tests pass (40 existing + 3 new)
@CongkeChen

Copy link
Copy Markdown
Contributor

AI Code Review

我已经获取了所有行号。现在让我来撰写审查意见。

发现的问题

⚠️ Warning

  • examples/optimization/eval_optimize_loop/pipeline.py:116run() 始终用硬编码的 cost_usd=0.0 调用 apply_gate 并写回 PipelineResult,导致 gate.max_cost_usd 规则在真实流水线中永不生效(仅在 test_gate.py 直接传参时被测到)。应在评估/优化阶段采集实际开销传入,或显式标注 cost 暂未实现并在 gate 中跳过该规则,避免给用户"已做预算保护"的错误印象。

  • examples/optimization/eval_optimize_loop/pipeline.py:116gate.py:61max_duration_seconds 仅在 run() 结束后用实际耗时做"事后判定",运行中不会超时中止。live 模式下 AgentOptimizer.optimize 可能长时间挂起,gate 只能记录超时但无法止损。建议用 asyncio.wait_for 包裹 live 评估/优化调用以真正强制超时,或将该字段语义明确改为"事后审计"。

  • examples/optimization/eval_optimize_loop/run_pipeline.py:43REJECTsys.exit(1),而默认 pipeline.json(trace 模式、allow_new_fails:false)按示例数据必然 REJECT(见 example_output/optimization_report.json)。README 的 Quickstart 让用户直接 python run_pipeline.py,命令会以退出码 1 结束,既误导使用者"运行失败",也易在 CI/脚本中被当作错误。建议 REJECT 时退出 0(或单独提供 --fail-on-reject 开关),把验收结论与进程退出码解耦。

  • examples/optimization/eval_optimize_loop/pipeline.py:54-58:live 模式仅校验 call_agent/target_prompt,未校验 live_train_evalsetlive_val_evalsetoptimizer_config_path 是否存在或非空,缺配置时要等到 _run_eval_with_agent/AgentOptimizer.optimize 内部才报错,定位困难。建议在 from_config 对 live 模式一并校验这些必填字段并给出清晰错误。

💡 Suggestion

总结

整体为新增示例 pipeline,逻辑闭环、单测覆盖较全,未发现安全或核心功能阻塞性缺陷。主要风险集中在三处"已实现但未真正接入"的 gate 规则(cost 硬编码为 0、duration 不强制超时)以及 run_pipeline.py 默认配置必然 REJECT 却退出码 1 的对外行为,建议合并前修复上述 Warning。

测试建议

  • 补充一个 live 模式 run() 的集成测试(用注入的 _optimizer_call hook + mock call_agent),验证 baseline→optimize→candidate 的实际串联与 update_source 后 candidate 评估使用新 prompt 的时序。
  • 补充 max_cost_usd 配置下 run() 行为的测试,明确当前 cost 恒为 0 的预期(或修复后验证真实 cost 传入路径)。

- run_pipeline.py: REJECT exits 0 by default; added --fail-on-reject for CI
- pipeline.py: live mode validates evalset/optimizer config file existence
- pipeline.py: note cost_usd=0 is intentional (not yet collected from optimizer)
- pipeline.py: add asyncio.wait_for timeout enforcement for live mode
- test_pipeline.py: fix mock to return different baseline/candidate data
- test_models.py: remove dead code (unused path variable, discarded dump)
@CongkeChen

Copy link
Copy Markdown
Contributor

AI Code Review

发现的问题

🚨 Critical

  • examples/optimization/eval_optimize_loop/pipeline.py:122:live 模式缺少 import asyncio,运行即崩
    • run() 在 live 分支调用了 asyncio.wait_for()pipeline.py:122)和 asyncio.TimeoutErrorpipeline.py:124),但文件顶部仅导入了 os/time/tempfile/datetime/typing,并未 import asyncio。一旦进入 live 模式会立刻抛 NameError: name 'asyncio' is not defined,整个 live 流水线无法运行。修复:在顶部添加 import asyncio
      import os
      import time
      import tempfile
      ...
      # 缺少 import asyncio

⚠️ Warning

  • examples/optimization/eval_optimize_loop/pipeline.py:18:依赖 SDK 私有内部符号 _EvaluationCasesFailed

    • from trpc_agent_sdk.evaluation._agent_evaluator import _EvaluationCasesFailed 导入了下划线前缀的私有异常类,SDK 升级时该符号可能被重命名或移除而导致导入失败。建议向 SDK 请求公开该异常,或在评估失败时改用更稳健的判定方式(如检查 executer.get_result() 是否为 None / 状态字段)。
  • examples/optimization/eval_optimize_loop/pipeline.py:94:路径解析对 /tmp 做硬编码白名单,绕过相对路径解析

    • _resolve_pathsnot value.startswith("/tmp") 判断是否跳过拼接,意图是兼容测试中的临时绝对路径,但任何以 /tmp 开头的真实配置路径(或用户业务路径)都不会被相对解析,行为依赖实现细节且语义模糊。建议改为仅按 os.path.isabs(value) 判断,测试改用 tempfile 产生的真实绝对路径。
  • examples/optimization/eval_optimize_loop/pipeline.py:1515cost_usd 恒为 0.0,gate 的 cost 规则形同虚设

    • apply_gate(..., cost_usd=0.0, ...) 写死,max_cost_usd 规则永远不会触发拒绝,用户配置该预算上限得不到任何保护。虽然代码注释已说明此局限,但属于未完成的功能缺口;建议在未实现成本采集前于 from_config 阶段对 max_cost_usd 非 None 的情况显式告警/报错,避免用户误以为成本门控生效。
  • examples/optimization/eval_optimize_loop/tests/test_pipeline.py:2809-2811:测试在共享 /tmp 路径创建文件并依赖执行顺序

    • test_pipeline_from_config_live_modePath("/tmp/train.json").touch() 等创建共享文件,test_pipeline_live_mode_missing_params 又复用同一路径且未传递 optimizer_config_path,二者之间存在隐式的执行顺序与状态耦合,且污染全局 /tmp。建议改用 tmp_path/TemporaryDirectory 隔离,并显式补全/校验配置字段。

💡 Suggestion

总结

存在一个必须修复的阻塞问题:pipeline.py live 模式使用 asyncio 却未导入,会直接 NameError 导致核心 live 流水线无法运行;其余为依赖私有 API、成本门控失效、路径解析与测试隔离等需关注但不立即阻塞的问题。

测试建议

  • 补充一个 live 模式 run() 的最小集成测试(可用 _optimizer_call 注入桩 + mock 的 _evaluate_live_*),覆盖 live 分支能正常返回结果,可直接暴露缺失的 import asyncio
  • max_cost_usd 非 None 时 cost_usd 恒 0 的行为补充断言或告警测试,明确当前成本门控不生效的预期边界。

DNKYr added 2 commits July 16, 2026 12:31
- Add missing import asyncio (live-mode path would NameError)
- Guard _EvaluationCasesFailed private import with ImportError fallback
- Remove /tmp whitelist hack in _resolve_paths (use isabs() only)
- Warn via stderr when max_cost_usd is set but cost tracking unimplemented
- Fix test isolation: use tempfile instead of shared /tmp paths
- Add example tests to CI (testpaths + workflow command)
Critical fixes:
- _build_split_result: skip empty case_results (all([])=True phantom pass)
- overfitting detection: require val_pass_rate_delta < 0 (not <= 0)
- total_cases: count only evaluable cases, not dict key count
- _EvaluationCasesFailed fallback: warn on ImportError before using AssertionError

Important fixes:
- gate.py: protected_case_ids check both train and val score deltas
- reporting.py: metric breakdown title shows correct split label
- run_pipeline.py: use public output_dir property instead of private _config
- pipeline.py: expose output_dir property, _collect_cost method

Other:
- failure_attribution.py: document format patterns as heuristic defaults
@DNKYr

DNKYr commented Jul 16, 2026

Copy link
Copy Markdown
Author

Second review round addressed in c681780. Additionally ran an adversarial self-review which caught 4 more critical issues:

Fixes from your review:

  • Critical: Added missing import asyncio (live mode would NameError)
  • Critical: _EvaluationCasesFailed private import now has ImportError fallback with RuntimeWarning
  • Warning: Removed /tmp hardcoded whitelist in _resolve_paths — uses os.path.isabs() only
  • Warning: max_cost_usd non-None now emits stderr warning that cost tracking is unimplemented
  • Warning: Test isolation: test_pipeline_from_config_live_mode now uses tempfile.NamedTemporaryFile instead of shared /tmp paths
  • Suggestion: Added example tests to CI (testpaths in pyproject.toml and pytest command in ci.yml)

Extra fixes from adversarial self-review:

  • _build_split_result: skip empty case_results (all([])=True would phantom-pass)
  • gate.py: overfitting now requires strict val degradation (< 0, not <= 0)
  • failure_attribution.py: total_cases counts only evaluable cases
  • gate.py: protected_case_ids checks both train and val score deltas
  • reporting.py: metric breakdown title shows correct split label
  • run_pipeline.py: uses public output_dir property instead of private _config
  • pipeline.py: added output_dir property and _collect_cost() method

@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@e113610). Learn more about missing BASE report.

Additional details and impacted files
@@            Coverage Diff             @@
##             main        #194   +/-   ##
==========================================
  Coverage        ?   87.88291%           
==========================================
  Files           ?         467           
  Lines           ?       44103           
  Branches        ?           0           
==========================================
  Hits            ?       38759           
  Misses          ?        5344           
  Partials        ?           0           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

构建 Evaluation + Optimization 的自动回归与提示词优化闭环

2 participants