Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions examples/optimization/eval_optimize_loop/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# SDK live 运行产物(本地生成,不入库)
baseline_prompts/
best_prompts/
config.snapshot.json
result.json
summary.txt
rounds/
run.log
__pycache__/
*.pyc

# 示例输出(保留 optimization_report 作为参考,其余本地产物忽略)
sample_output/baseline_prompts/
sample_output/best_prompts/
sample_output/config.snapshot.json
sample_output/result.json
sample_output/summary.txt
sample_output/rounds/
sample_output/run.log
115 changes: 115 additions & 0 deletions examples/optimization/eval_optimize_loop/DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Eval + Optimize Loop — 架构设计

## 概述

本项目实现了 "评测 → 失败归因 → prompt 优化 → 回归验证 → 产物审计" 的自动化闭环。

输入一组评测集(evalset JSON)和优化器配置(optimizer.json),输出优化后的 prompt 和完整的审计报告。

## 架构

```
run_pipeline.py # CLI 入口,编排 7 阶段流水线
├── pipeline/ # 统一包入口(from pipeline import ...)
│ ├── comparator.py # trace 回放评测器(期望 vs 实际,分层规则)
│ ├── config.py # 配置加载(optimizer.json + evalset JSON)
│ ├── baseline.py # 基线评测(fake 回放 / SDK AgentEvaluator)
│ ├── attribution.py # 失败归因(9 类根因分析)
│ ├── optimize.py # 候选生成(三场景)+ 优化执行
│ ├── validate.py # 候选重评分 + 验证集回归对比
│ ├── gate.py # 多维度接受决策
│ ├── report.py # JSON + Markdown 报告生成
│ └── tracing.py # 审计追踪(seed/timing/cost/reproduce)
├── agent/
│ ├── agent.py # build_call_agent() / run_agent()(优化目标)
│ ├── config.py # Agent 配置
│ └── prompts.py # 初始系统 prompt(优化目标)
├── data/
│ ├── train.evalset.json # 训练评测集(34 cases,含 10 个 _fail)
│ ├── val.evalset.json # 验证评测集(16 cases)
│ ├── large_train.evalset.json # 压力评测集(50 cases)
│ ├── holdout.evalset.json # hidden 集(12 cases)
│ ├── optimizer.json # 优化器配置
│ └── prompts/system.md # 被优化的 prompt 源文件
└── tests/ # 317 测试(6 维度)
```

## 7 阶段流水线

```
[1] config → 加载 evalset JSON + optimizer.json
[2] baseline → 在训练集和验证集上运行基线评测(trace 回放)
[3] attribution → 将失败 case 归因到 9 个根因类别
[4] optimize → 按场景生成候选(fix_attributed/noop/overfit)
[5] validate → 候选在验证集上重评,对比基线
[6] gate → 6 维度决策:提升/关键case/新失败/过拟合/成本/负回归
[7] report → 生成 JSON + Markdown 报告 + 审计追踪
```

## 两种执行模式

### Fake Mode(默认,无需 API Key)
- **trace 回放评测**:`comparator.py` 逐 case 比较 `conversation`(期望)
与 `actual_conversation`(实际回放),判定通过/失败
- 三场景候选生成(`--scenario`):可优化成功 / 优化无效 / 过拟合退化
- 确定性、可复现、零成本,单次运行 < 3 秒
- 适合 CI、本地验证、快速迭代

### Live Mode(需要 SDK + API Key)
- 调用 `AgentEvaluator.evaluate_eval_set()` 进行真实评测(trace 格式可离线)
- 调用 `AgentOptimizer.optimize()` 执行 GEPA reflective 优化(需 `call_agent`)
- 需要 `pip install trpc-agent-python[gepa]`
- SDK 不可用 / 配置不全时自动降级到离线 trace 回放,不崩溃

## 失败归因(9 类)

| 类别 | 描述 |
|------|------|
| `final_response_mismatch` | 最终回复与预期不匹配 |
| `tool_call_error` | 工具调用整体失败 |
| `wrong_tool_selected` | 选择了错误的工具 |
| `tool_parameter_error` | 工具参数错误 |
| `llm_rubric_not_met` | LLM rubric 评分未达标 |
| `knowledge_recall_insufficient` | 知识召回不足 |
| `format_not_as_required` | 输出格式不符合要求 |
| `missing_expected_output` | 缺少预期的输出内容 |
| `unknown` | 无法归类 |

归因准确率通过 `tests/test_gold_verdicts.py` 的黄金判定表锁定(≥90%),
每个失败 case 都带 `detail` + `evidence`(可解释原因)。

## 三候选场景

| 场景 | 行为 | 预期 gate |
|------|------|----------|
| `fix_attributed`(默认)| 候选修复归因的失败类别 | ACCEPT |
| `noop` | 候选无实质改动 | NEEDS_REVIEW |
| `overfit` | train 记住 + val 回归 | REJECT(过拟合)|

## Gate 决策(6 维度)

1. **提升阈值**:候选 pass_rate 相较于基线的最小绝对提升
2. **负回归拒绝**:候选 pass_rate 低于基线直接 REJECT
3. **关键 case 保护**:指定的关键 case 不能退化
4. **新增失败检测**:候选不能引入新的 hard fail
5. **过拟合检测**:候选在验证集新增失败 → REJECT(验收标准 #3)
6. **成本预算**:优化总成本不超过预算上限

决策结果:`accept` / `reject` / `needs_review`

## 审计追踪

每条 pipeline 运行记录:
- 随机种子(seed)
- 每个阶段的耗时(wall clock)
- 优化成本(USD)
- 输入文件 SHA-256 哈希
- 完整的复现命令

## 关键设计决策

1. **SDK 原生集成**:使用 `AgentEvaluator` 和 `AgentOptimizer` 的完整能力,而非自己重新实现
2. **Fake mode 优先**:默认模式不依赖外部 API,可离线运行
3. **模块化**:每个 pipeline 阶段是独立可测试的模块
4. **确定性可复现**:固定 seed 下结果一致,适合 CI 集成
5. **防御性设计**:每个阶段失败不影响其他阶段,错误记录在 audit trail 中
193 changes: 193 additions & 0 deletions examples/optimization/eval_optimize_loop/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
# Eval + Optimize Closed-Loop Pipeline

自动化 **"评测 → 失败归因 → prompt 优化 → 回归验证 → 产物审计"** 闭环示例。
本示例基于 tRPC-Agent 的 `AgentEvaluator` / `AgentOptimizer` 能力,演示如何判断
优化是否真正提升、是否牺牲其他指标、是否过拟合、是否值得回写源 prompt。

## 快速开始

```bash
# Fake mode(默认,无需 API Key,离线可跑)
python run_pipeline.py --mode fake

# 演示"可优化成功"场景(默认):候选修复失败 → 优化成功 → gate ACCEPT
python run_pipeline.py --mode fake --scenario fix_attributed

# 演示"优化无效"场景:候选无实质改动 → gate NEEDS_REVIEW
python run_pipeline.py --mode fake --scenario noop

# 演示"过拟合退化"场景:train 提升但 val 回归 → gate REJECT
python run_pipeline.py --mode fake --scenario overfit \
--val-regression-cases val_simple_math_001,val_reasoning_001

# CI 模式(gate 拒绝时 exit 1,可用于自动化回归)
python run_pipeline.py --mode fake --scenario overfit --ci
echo $? # → 1(REJECT)

# Live mode:真实 SDK AgentOptimizer(需配置 TRPC_AGENT_API_KEY)
# 未配置时自动降级到离线 trace 回放,不会崩溃
python run_pipeline.py --mode live

# 详细输出
python run_pipeline.py --mode fake --verbose
```

### 三场景快速体验

| 场景 | 命令 | 预期结果 |
|------|------|---------|
| 优化成功 | `python run_pipeline.py --mode fake` | baseline ~71% → candidate ~97%,gate **ACCEPT** |
| 优化无效 | `python run_pipeline.py --mode fake --scenario noop` | candidate = baseline,gate **NEEDS_REVIEW** |
| 过拟合退化 | `python run_pipeline.py --mode fake --scenario overfit --val-regression-cases ...` | train 提升但 val 新增失败,gate **REJECT** |

## 工作原理

1. **评测**:trace 回放评测器(`pipeline/comparator.py`)逐 case 比较
`conversation`(期望)与 `actual_conversation`(实际回放),判定通过/失败。
2. **失败归因**:将失败 case 聚类到 9 类根因(最终回复不匹配、工具调用错误、
工具选择错误、参数错误、rubric 不达标、知识召回不足、格式不符、缺失输出、未知)。
3. **优化**:按归因类别生成候选 prompt(模拟 GEPA 反射式变异,离线确定性)。
4. **回归验证**:候选在验证集上逐 case 重评,与 baseline 对比,检测过拟合。
5. **接受决策**:多维 gate(提升阈值、关键 case 保护、新失败检测、过拟合拒绝、成本预算)。
6. **产物审计**:JSON/Markdown 报告 + 完整审计追踪(seed/耗时/成本/复现命令)。

## 文件结构

```
eval_optimize_loop/
├── run_pipeline.py # 唯一 CLI 入口
├── pipeline/ # 7 阶段流水线
│ ├── __init__.py # 统一导出(from pipeline import ...)
│ ├── comparator.py # trace 回放评测器(期望 vs 实际)
│ ├── config.py # 配置加载(PipelineConfig / evalset / optimizer)
│ ├── baseline.py # baseline 评测(fake 回放 / SDK)
│ ├── attribution.py # 失败归因(9 类根因)
│ ├── optimize.py # 候选生成(三场景)+ AgentOptimizer 集成
│ ├── validate.py # 候选重评分 + 过拟合检测
│ ├── gate.py # 多维接受决策
│ ├── report.py # JSON/Markdown 报告
│ └── tracing.py # 审计追踪
├── agent/ # 被优化的目标 Agent + call_agent
│ ├── agent.py # build_call_agent() / run_agent()
│ ├── config.py # AgentConfig
│ └── prompts.py # 基线系统提示词
├── data/ # 评测集 + 配置
│ ├── train.evalset.json # 34 cases(含 10 个 _fail 标注)
│ ├── val.evalset.json # 16 cases(held-out 验证集)
│ ├── large_train.evalset.json # 50 cases(压力测试)
│ ├── holdout.evalset.json # 12 cases(hidden 集)
│ ├── optimizer.json # 优化器配置
│ └── prompts/system.md # 被优化的系统提示词
├── tests/ # 300+ 测试(6 维度)
└── sample_output/ # 示例报告输出
```

## 运行测试

```bash
# 全部测试(317 个)
python -m pytest tests/ -q

# 按维度
python -m pytest tests/test_comparator.py tests/test_gold_verdicts.py -q # 评测器 + 归因锁
python -m pytest tests/test_scenarios.py -q # 三场景端到端
python -m pytest tests/test_attribution_accuracy.py -q # 归因准确率
python -m pytest tests/test_live_mode_import.py -q # live 健壮性
python -m pytest tests/test_performance.py -q --durations=20 # 性能

# CI 模式
python run_pipeline.py --mode fake --scenario overfit --ci; echo $? # → 1
```

## 配置

### optimizer.json

```json
{
"evaluate": {
"metrics": [
{"metric_name": "final_response_avg_score", "threshold": 0.7},
{"metric_name": "response_match_score", "threshold": 0.5}
]
},
"optimize": {
"algorithm": {
"name": "gepa_reflective",
"seed": 42,
"reflection_lm": {"provider_name": "fake", "model_name": "fake", "api_key": ""},
"max_metric_calls": 100,
"timeout_seconds": 600
}
}
}
```

### Evalset 格式

```json
{
"eval_set_id": "my-evalset",
"eval_cases": [
{
"eval_id": "case_001",
"eval_mode": "trace",
"conversation": [{
"user_content": {"parts": [{"text": "问题"}], "role": "user"},
"final_response": {"parts": [{"text": "期望答案"}], "role": "model"}
}],
"actual_conversation": [{
"user_content": {"parts": [{"text": "问题"}], "role": "user"},
"final_response": {"parts": [{"text": "实际回放"}], "role": "model"},
"intermediate_data": {"tool_uses": [], "tool_responses": []}
}]
}
]
}
```

可选字段:
- `candidate_conversation`:候选优化后的回放内容(隐藏样本场景下按真实回放评分)。
- `intermediate_data.tool_uses` / `tool_responses`:工具轨迹(用于工具层归因)。

## 输出

- `sample_output/optimization_report.json` — 机器可读完整报告
- `sample_output/optimization_report.md` — 人类可读总结报告

报告包含:
- **baseline**:train/validation 通过率、失败 case、指标分解
- **candidate**:候选 train/validation 评分 + 逐 case delta
- **attribution**:失败归因统计 + 每个失败 case 的可解释原因(detail + evidence)
- **gate**:决策(accept/reject/needs_review)+ 理由 + 各检查项明细
- **audit**:seed / 耗时 / 成本 / 复现命令

## CLI 参数

| 参数 | 默认值 | 描述 |
|------|--------|------|
| `--mode` | `fake` | 执行模式:`fake`(零成本离线)或 `live`(真实 SDK)|
| `--scenario` | `fix_attributed` | 候选场景:`fix_attributed` / `noop` / `overfit` |
| `--train-evalset` | `data/train.evalset.json` | 训练评测集路径 |
| `--val-evalset` | `data/val.evalset.json` | 验证评测集路径 |
| `--holdout-evalset` | `data/holdout.evalset.json` | holdout 集路径(可选)|
| `--optimizer-config` | `data/optimizer.json` | 优化器配置路径 |
| `--val-regression-cases` | `` | overfit 场景下要扰动的 val case id(逗号分隔)|
| `--seed` | `42` | 随机种子(确保可复现)|
| `--max-iterations` | `3` | 最大优化迭代轮数 |
| `--min-improvement` | `0.05` | 最小接受提升阈值 |
| `--max-cost` | `10.0` | 优化成本预算(USD)|
| `--output-dir` | `sample_output` | 报告输出目录 |
| `--verbose` / `-v` | `false` | 详细输出 |
| `--ci` | `false` | CI 模式(gate 拒绝时 exit 1)|

## 验收标准对照

| 验收标准 | 实现方式 |
|---------|---------|
| 6 条样例可运行 + 完整报告 | 4 个 evalset 全可运行,报告含 baseline/candidate/delta/gate |
| 决策准确率 ≥ 80% | SDK 忠实 comparator + 真实候选重评分 |
| 拒绝过拟合候选 | gate 检测验证集新增失败 → REJECT |
| 归因准确率 ≥ 75% | 分层归因 + gold-verdict 回归锁(≥90%)|
| fake/trace ≤ 3 分钟 | 纯 Python 评测,单次 < 3 秒 |
| 报告完整性 | 含 baseline/candidate/逐 case delta/gate/理由 |
11 changes: 11 additions & 0 deletions examples/optimization/eval_optimize_loop/agent/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Agent under evaluation — a simple calculator agent for optimization testing.

This agent serves as the optimization target: its system prompt is what
gets optimized by the pipeline to improve evaluation scores.
"""

from .agent import create_agent, run_agent
from .config import AgentConfig
from .prompts import BASELINE_SYSTEM_PROMPT

__all__ = ["create_agent", "run_agent", "AgentConfig", "BASELINE_SYSTEM_PROMPT"]
Loading
Loading