Skip to content

Feature/eval optimize loop - #221

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

Feature/eval optimize loop#221
guocfu wants to merge 22 commits into
trpc-group:mainfrom
guocfu:feature/eval-optimize-loop

Conversation

@guocfu

@guocfu guocfu commented Jul 22, 2026

Copy link
Copy Markdown

关联 Issue

Closes #91

变更说明

本 PR 实现 Evaluation + Optimization 自动回归与提示词优化闭环,覆盖离线验证、Trace 回放和真实模型集成三种运行方式。

主要流程:

  1. 校验 pipeline、optimizer、evalset 和 Prompt 配置。
  2. 创建隔离的 Prompt 工作区并记录输入哈希。
  3. 完整评测 baseline train 和 validation。
  4. 生成候选 Prompt。
  5. 完整评测 candidate train 和 validation。
  6. 标准化评测结果,生成失败归因和 Case Diff。
  7. 根据效果、过拟合、关键 Case 和资源预算执行 Gate。
  8. Gate 接受后,通过源文件哈希校验、回读验证和失败回滚安全写回 Prompt。
  9. 输出 JSON、Markdown、artifact index 和失败报告。

主要能力

  • 提供确定性的 Offline Model 和 Candidate Provider,无 API Key 也能验证核心闭环。
  • 支持 Trace Mode,直接回放预录制 Agent 结果,不重复执行 Agent。
  • 提供显式启用的真实集成入口,支持真实业务 Agent 和真实反思优化模型。
  • 接入 AgentOptimizer(update_source=False),候选生成期间不直接修改源 Prompt。
  • Baseline 和 Candidate 分别执行完整 train/validation 评测。
  • 支持多次运行结果标准化、失败归因、Case Diff 和过拟合识别。
  • Gate 支持验证集提升、通过率下降、hard/critical regression 和预算限制。
  • Prompt 写回包含源哈希校验、回读验证和失败回滚。
  • 保存优化器原生产物、四次评测结果、Prompt 快照和资源观测结果。
  • 对运行时配置、失败报告和 CLI 异常进行敏感信息脱敏。
  • 支持原子报告发布、路径越界防护和符号链接检查。

运行模式

  • offline:真实 LlmAgent 配合确定性模型和确定性评测规则。
  • trace:回放预录制轨迹,不执行 Agent。
  • real:真实业务模型配合真实 AgentOptimizer 反思模型。

真实模式必须显式传入 --run-real,连接信息从环境变量读取,优化模型参数通过命令行参数传入。

测试覆盖

  • Offline 三种候选场景:
    • improve
    • no improvement
    • overfit
  • 四次完整评测及多 run 场景。
  • 评测标准化、失败归因和 Case Diff。
  • Gate 接受、拒绝、过拟合、关键 Case 和预算规则。
  • Prompt 漂移检测、安全写回和回滚。
  • Trace 回放及路径安全校验。
  • 报告、artifact index、失败报告和敏感信息脱敏。
  • 真实集成入口的离线契约测试。
  • CI 子进程在非 editable-install 环境中的 CLI 导入验证。

执行:

pytest -q tests/evaluation/test_eval_optimize_loop_*.py

本功能相关测试全部通过。

guocfu added 19 commits July 15, 2026 15:07
仅实现 Pipeline 配置校验和 Prompt 隔离工作区创建,不执行实际评测、提示词优化、Gate 或报告生成。
添加 Prompt 感知的 fake agent 与确定性候选提供器。

完成 baseline/candidate 的 train/validation 四次评测,并补充输入漂移保护和离线回归测试。
@helloopenworld

Copy link
Copy Markdown
Contributor

AI Code Review

我已经完成了全面审查。让我来撰写最终的审查结论。

发现的问题

⚠️ Warning

  • examples/optimization/eval_optimize_loop/report_builder.py:53-68redact_error_message 只按值替换 TRPC_AGENT_API_KEY/TRPC_AGENT_BASE_URL 两个环境变量的明文,其他来源(如自定义环境变量名、SDK 内部展开后传入的凭据)只能依赖正则兜底。

    • 真实模式下若 SDK 异常文本里出现非预期形态的凭据(例如被拆分到多行、或出现在 URL 的 userinfo 部分 https://user:key@host),_SENSITIVE_KEY_VALUE 正则不一定会命中,存在泄露风险。建议将 on_unavailable 失败路径上的异常信息一律先经环境变量值替换,再叠加正则与 URL 脱敏,并补充覆盖 userinfo 形态 URL 的测试用例。
  • examples/optimization/eval_optimize_loop/artifact_writer.py:157-232_rename_directory_no_replace 在 Linux 上依赖 renameat2(RENAME_NOREPLACE),遇到 ENOSYS/EINVAL/EOPNOTSUPP 时直接 ArtifactWriteError 失败关闭。

    • 这是显式安全取舍,但在较旧内核或受限容器(如某些 CI runner)上会令整条报告发布链路失败、阻塞 CI。建议在不可用时回退到「先 mkdir 探测 + os.replace」的原子替换策略,或至少在错误信息中提示可手动开启的兼容路径,避免 CI 在环境不支持时被静默阻塞。

💡 Suggestion

  • examples/optimization/eval_optimize_loop/schemas.py:87OptimizerRuntimeParameters.temperature 仅约束 ge=0.0,无上界。真实反思模型若被传入极高温度(如 1000),会显著放大成本与不稳定输出,且 BudgetConfig 无法在事前拦截。可加上合理上限(如 le=2.0)并在 README 中说明有效区间。

总结

整体风险较低,无必须修复的 Critical 问题。代码在路径穿越、符号链接、原子发布、源 Prompt 回滚与凭据脱敏上均有较完整的防御;两个 Warning 分别集中在异常脱敏的覆盖面与原子发布的平台兼容性上,建议在合入前评估真实运行环境是否会触发。

测试建议

  • 暂无额外测试建议。现有 test_failure_report_redacts_environment_values_and_common_secret_formstest_real_cli_redacts_environment_secrets_from_pipeline_error 已覆盖主要脱敏路径;如采纳上述 Warning,可补充 userinfo 形态 URL(https://user:secret@host)的脱敏断言,以及 _rename_directory_no_replacerenameat2 不可用时的回退行为断言。

@raychen911

Copy link
Copy Markdown
Contributor

这里提几个建议:
1、当中这个issue是基于框架做一个shiji 例子,所以这里单测不应该放在tests目录下,tests目录下是框架接口的单测,这里可以不写单测,
2、当前的examples看着写的比较丰富,是否把代码整合一下,看着可能比较松散,可以看看其他的例子的模式。例如:

examples/quickstart/
├── agent
│   ├── agent.py
│   ├── config.py
│   ├── __init__.py
│   ├── prompts.py
│   └── tools.py
├── README.md
└── run_agent.py

这样用户看起来比较方便,期望按照这种方式整理代码,数据类的专门放在data目录中
3、在readme中将使用方式写详细,我这边可以快速浮现效果,

@@ -0,0 +1,125 @@
# Evaluation + Optimization Pipeline 实施阶段路线图

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个文档建议放在examples/optimization/eval_optimize_loop目录下

@codecov

codecov Bot commented Aug 4, 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        #221   +/-   ##
==========================================
  Coverage        ?   88.44269%           
==========================================
  Files           ?         491           
  Lines           ?       46118           
  Branches        ?           0           
==========================================
  Hits            ?       40788           
  Misses          ?        5330           
  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.

@helloopenworld

Copy link
Copy Markdown
Contributor

AI Code Review

发现的问题

🚨 Critical

  • examples/optimization/eval_optimize_loop/run_pipeline.py:141:real 模式成功运行后 _print_result 必崩
    • _print_result 无条件访问 result.scenario,但 RealStageResultdata/schemas.py:449-453)只定义了 candidateoptimize_result,没有 scenario 字段;只有 OfflineStageResult/TraceStageResult 才有。real 模式在 run_pipeline.py:202mode="real" 调用本函数,会在已产生真实 API 费用的运行成功后抛 AttributeError,导致进程以失败结束且不打印任何结果。修复:对 real 模式跳过 scenario(如 f" ({result.scenario})" if mode != "real" else ""),或改用 getattr(result, "scenario", None)
    print(f"Candidate: {result.candidate.candidate_id} ({result.scenario})")

⚠️ Warning

  • examples/optimization/eval_optimize_loop/core/reporting.py:197-212:错误信息脱敏对非环境变量形态的凭据存在覆盖盲区

    • redact_error_message 仅替换 TRPC_AGENT_API_KEY/TRPC_AGENT_BASE_URL 两个环境变量原值,以及 api_key|base_url|authorization 前缀后的值;像 token: sk-...X-Api-Key: ... 这类前缀不在 _SENSITIVE_KEY_VALUE 交替项中的敏感字段不会被脱敏,若异常文本里出现这些形态的凭据则会写入 failure_report.json。建议扩充前缀白名单(如 tokenxapikey),与 _SENSITIVE_CONFIG_KEYS 保持一致。
  • examples/optimization/eval_optimize_loop/core/pipeline.py:939-967run_real_stage):成功路径缺乏 --run-real 之外的费用/超时保护

    • real 模式无整体超时与重试上限控制,AgentOptimizer.optimize 可能长时间运行并持续产生费用;budget.max_duration_seconds 只在 Gate 阶段对已观测的 duration_seconds 判定,无法中断进行中的运行。建议在 _execute_real_stage 外层加可取消的超时包裹(如 asyncio.wait_for),避免失控费用。
  • examples/optimization/eval_optimize_loop/core/optimization.py:157:运行时配置写入路径与产物索引假设耦合,跨文件系统无保护

    • runtime_path = request.output_dir.parent / "optimizer.runtime.json" 假设 output_dir 已有父目录且与 run 目录同文件系统;若 output_dir.parent 不可写或跨文件系统,write_textOSError 会被转成 CandidateProviderError,但 publish_report_bundlenative_paths 过滤(reporting.py:706-711)依赖该文件恰好位于 run 根目录且名为 optimizer.runtime.json,一旦路径变化会导致原生产物不被索引。建议显式校验 output_dir.parent 可写,或将运行时配置路径固定为 run_dir/optimizer.runtime.json 而非 output_dir.parent 推导。

💡 Suggestion

总结

存在一个必须修复的 Critical 问题:real 模式成功运行后 _print_result 会因 RealStageResultscenario 字段而崩溃,且该路径无测试覆盖;其余为脱敏盲区、费用超时保护与路径耦合等 Warning 级风险。建议优先修复 Critical 后再合入。

测试建议

  • 补充 real 模式端到端冒烟测试(可用 fake call_agent + mock AgentOptimizer.optimize 替代真实 API),覆盖 run_real_stage 成功后 _print_result("real", ...) 不抛异常。
  • redact_error_message 增加单测,覆盖 token:/X-Api-Key: 等非 api_key 前缀的凭据形态是否被脱敏。


def _print_result(mode: str, prepared: object, result: object) -> None:
print(f"Completed {mode} pipeline: {prepared.workspace.run_dir}")
print(f"Candidate: {result.candidate.candidate_id} ({result.scenario})")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

real 模式成功后 _print_result 必崩

_print_result 无条件访问 result.scenario,但 RealStageResult 未定义该字段,real 模式成功运行后会抛 AttributeError,导致已产生真实 API 费用的运行以失败结束且不打印结果。建议对 real 模式跳过 scenario 或改用 getattr(result, "scenario", None)

@helloopenworld

Copy link
Copy Markdown
Contributor

AI Code Review

确认:os.link 没有处理 EXDEV。现在让我来写最终的审查报告。

发现的问题

⚠️ Warning

  • examples/optimization/eval_optimize_loop/core/reporting.py:937write_failure_report 使用 os.link 跨设备硬链接会失败

    • os.link(temporary, target) 在临时目录与 run 目录分属不同文件系统(EXDEV/OSError)时会抛错,被外层 except 转成 ArtifactWriteError,导致失败报告本身无法写入——恰好在最需要保留故障证据的路径上丢失证据。建议改用 shutil.move 或捕获 OSError 后回退为 write_text(target, ...) 的非原子写入。
  • examples/optimization/eval_optimize_loop/core/reporting.py:4420:Windows 分支的 os.rename 不满足“原子 no-replace”承诺

    • 注释声称每个平台都使用“atomic no-replace primitive”,但 Windows 分支仅用 os.rename:跨卷时会退化为非原子复制,且与前置 target.exists() 检查之间存在 TOCTOU 窗口。建议 Windows 上也使用支持原子语义的 API(如 MoveFileEx + MOVEFILE_REPLACE_EXISTING 的反向校验,或显式 os.replace 仅在目标不存在时),或至少在文档中收窄“原子”承诺。
  • examples/optimization/eval_optimize_loop/data/config.py:5080ReportingConfigArtifactConfig.audit_all_candidates 被校验但从未被消费

    • write_jsonwrite_markdowninclude_case_evidence 以及 audit_all_candidatespublish_report_bundle 中从未读取:JSON 与 Markdown 报告始终被写入,case evidence 始终包含。用户配置这些项后不会生效,属于配置-行为不一致的兼容性隐患。建议要么实现这些开关,要么从 schema 中移除并在文档说明默认行为,避免误导使用者。

💡 Suggestion

  • examples/optimization/eval_optimize_loop/run_pipeline.py:6090main() 在非 real 模式下未拒绝 --optimizer-* 系列参数
    • --run-real 做了互斥校验,--optimizer-model-name 等参数在 offline/trace 模式下会被静默忽略,容易让使用者误以为已生效。可在非 real 模式下对这些参数报 parser.error,或在 help 中明确其仅在 real 模式生效。

总结

整体风险较低:核心的隔离 staging、源 Prompt 哈希校验、回滚、敏感值脱敏与占位符化、路径穿越/symlink 防护等关键链路实现严谨,无明显逻辑或安全 Critical 问题。主要问题集中在失败报告写入的跨设备稳定性、Windows 原子发布承诺过强,以及部分配置项未真正生效,建议修复前两者以保证故障证据可靠落盘。

测试建议

  • 建议补充 write_failure_report 在跨文件系统(EXDEV)场景下的回退测试,以及 publish_report_bundle 在 Windows/非 renameat2 平台的发布测试,验证故障证据始终可落盘。
  • 建议为 ReportingConfig.write_json/write_markdown 等开关补一条“配置关闭后报告确实不生成”的测试,否则应移除这些未实现字段。

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 的自动回归与提示词优化闭环

3 participants