Skip to content

Commit 30419d5

Browse files
committed
examples: add eval-attribution-optimize-gate loop example
Add a self-contained example under examples/optimization that demonstrates a six-stage closed loop: baseline evaluation, failure attribution, candidate optimization, gate decision and audit reporting. It ships a deterministic fake backend that needs no API key, plus an optional real backend backed by an OpenAI-compatible model. Updates #214 RELEASE NOTES: Add an evaluation-optimization loop example under examples/optimization.
1 parent f2a34ff commit 30419d5

31 files changed

Lines changed: 3187 additions & 0 deletions
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# 复制本文件为 .env 并填入你的 hy3 凭据(不要把真实 .env 提交到 git)
2+
#
3+
# 三件套是 tRPC-Agent 框架约定(trpc_agent_sdk 直接读 os.environ):
4+
# TRPC_AGENT_API_KEY 你的 hy3 API Key
5+
# TRPC_AGENT_BASE_URL hy3 的 OpenAI 兼容 endpoint,例如 https://<host>/v1
6+
# TRPC_AGENT_MODEL_NAME 模型名,例如 hy3
7+
#
8+
# 两种生效方式(二选一):
9+
# A. 直接导出到当前 shell:
10+
# export TRPC_AGENT_API_KEY=xxx
11+
# export TRPC_AGENT_BASE_URL=https://<host>/v1
12+
# export TRPC_AGENT_MODEL_NAME=hy3
13+
# B. 用 .env 文件:在 run_pipeline.py 入口加 `from dotenv import load_dotenv; load_dotenv()`
14+
# (python-dotenv 已随 requirements 安装),框架即可从 .env 读到上述变量。
15+
TRPC_AGENT_API_KEY=your-hy3-api-key
16+
TRPC_AGENT_BASE_URL=https://your-hy3-endpoint/v1
17+
TRPC_AGENT_MODEL_NAME=hy3
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# 本地真实凭据,切勿提交(只提交 .env.example 占位模板)
2+
.env
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# Eval → Attribution → Optimize → Gate 自动闭环示例
2+
3+
本示例演示如何把 tRPC-Agent 的 `AgentEvaluator` 与一个"等价扩展机制"的优化器,
4+
串成一个**可复现、可审计、带质量闸门**的自动闭环:先评测,再对失败做可解释归因,
5+
然后生成候选 prompt 并回归验证,最后由 gate 判定候选"是否真的提升、是否牺牲其他
6+
指标、是否过拟合、是否值得回写源 prompt"。
7+
8+
整条流程默认**完全不需要任何 API Key**(确定性 fake 后端),同时提供一个可选的
9+
真实 LLM 后端(OpenAI 兼容,如 hy3),两套后端共用同一套编排、归因、gate 与审计逻辑。
10+
11+
## 关键特性
12+
13+
- **六阶段闭环**:评测 → 失败归因 → 优化执行 → 回归验证 → 接受策略(gate) → 产物审计。
14+
- **无 Key 可跑**:确定性 Fake Model / Fake Judge,秒级完成,结果完全可复现(固定 `seed`)。
15+
- **可解释失败归因**:把失败稳定归到 6 大类,并给出一句话原因与 `regression` 标记。
16+
- **防过拟合 gate**:关键 case 退化 / 新增 hard fail 一律拒绝,即使验证集总分提升。
17+
- **完整审计产物**:结构化 + 人读报告、每轮候选快照、可复现配置全部落盘。
18+
- **可选真实后端**:`EVAL_BACKEND=real` 一键切换到真实 LLM 生成 + `llm_rubric_response` judge。
19+
20+
## 目录结构
21+
22+
```text
23+
eval_optimize_loop/
24+
├── run_pipeline.py # 入口:组装配置、运行闭环、落盘报告
25+
├── pipeline.py # 编排层:把 6 个阶段串起来
26+
├── attribution.py # 失败归因(6 大类可解释分类)
27+
├── gate.py # 接受策略(可配置 gate)
28+
├── optimizer.py # 规则式优化器(与 GEPA 等价的确定性机制)
29+
├── fake_agent.py # 确定性 Fake Model / Fake Judge(call_agent)
30+
├── real_call_agent.py # 真实 LLM call_agent(接入 OpenAI 兼容后端,如 hy3)
31+
├── verify_real.py # 真实凭据连通性自检(单条调用)
32+
├── prompts/
33+
│ ├── baseline_system.md # fake 模式 baseline prompt
34+
│ └── baseline_real.md # 真实模式 baseline prompt
35+
├── config/
36+
│ ├── optimizer.json # fake 模式配置:指标 / gate / 候选池 / 种子
37+
│ ├── real_optimizer.json # 真实模式配置:llm_rubric_response judge / gate / 候选池
38+
│ └── real_optimizer_smoke.json # 真实模式轻量变体(低配额验证用)
39+
├── data/
40+
│ ├── train.evalset.json # fake 模式 3 条训练 case
41+
│ ├── val.evalset.json # fake 模式 3 条验证 case(含过拟合退化样本)
42+
│ ├── real/ # 真实模式 3 训练 + 3 验证(含退化哨兵 val_robust)
43+
│ └── real_smoke/ # 真实模式轻量变体(1 训练 + 2 验证)
44+
├── .env.example # 环境变量模板(TRPC_AGENT_*)
45+
├── .gitignore # 忽略本地 .env(避免真实凭据入库)
46+
├── artifacts/ # 运行产物(报告 + 候选快照 + 配置快照)
47+
└── optimization_report.json # 示例输出(fake 模式,与 artifacts 一致)
48+
```
49+
50+
## 快速开始(无需 API Key,验收主路径)
51+
52+
```bash
53+
# 首次安装依赖
54+
pip install -r ../../requirements.txt
55+
56+
# 从仓库根运行
57+
python examples/optimization/eval_optimize_loop/run_pipeline.py
58+
```
59+
60+
运行结束后,报告写入 `artifacts/`:结构化 `optimization_report.json`、人读
61+
`optimization_report.md`、每轮候选快照 `candidates/<label>.md`、可复现配置
62+
`optimizer.snapshot.json`
63+
64+
## 可选:真实 LLM 后端
65+
66+
把三项凭据写入本目录的 `.env`(该文件已被 `.gitignore` 忽略,不会随 PR 提交):
67+
68+
```bash
69+
TRPC_AGENT_API_KEY=你的真实key
70+
TRPC_AGENT_BASE_URL=https://your-endpoint/v1
71+
TRPC_AGENT_MODEL_NAME=your-model
72+
```
73+
74+
先用自检脚本确认凭据可用,再用 `EVAL_BACKEND=real` 切换后端:
75+
76+
```bash
77+
# 单条调用自检
78+
python examples/optimization/eval_optimize_loop/verify_real.py
79+
80+
# 完整真实闭环(需配额充足;生成 + judge 约 60 次调用)
81+
EVAL_BACKEND=real python examples/optimization/eval_optimize_loop/run_pipeline.py
82+
83+
# 轻量变体:约 12 次调用,适合配额/限流较紧时验证完整闭环
84+
EVAL_BACKEND=real REAL_SMOKE=1 python examples/optimization/eval_optimize_loop/run_pipeline.py
85+
```
86+
87+
真实模式复用同一套 6 阶段编排、gate、归因与审计逻辑,只替换两处:
88+
89+
- **生成**:`real_call_agent.call_agent` 用真实模型跑一次推理(system prompt 即当前候选);
90+
- **判定**:`config/real_optimizer.json``llm_rubric_response`,让真实模型当 judge
91+
(rubric 从 `${TRPC_AGENT_*}` 占位符展开,框架自动注入 judge 模型)。
92+
93+
> **说明(框架约束与限流)**
94+
> 1. `llm_rubric_response` 的 rubric 是**全局**的(每条 case 共用同一组判据),无法逐 case
95+
> 定制。真实模式因此使用一致的多 rubric 判据(中文 / 问候 / 天气恰当 / 自然文本 /
96+
> 实时数据真实);最丰富的"逐 case 三类情况"演示保留在 fake 模式。
97+
> 2. 真实后端在高并发下可能触发限流(429)。真实模式已做串行评估 + 节流;若仍遇限流,
98+
> 个别 case 会被保守判失败,待配额充足或低峰重跑即可得到干净结果。
99+
100+
## Pipeline 六阶段
101+
102+
1. **Baseline 评测**:`AgentEvaluator.evaluate_eval_set` 对训练/验证集分别打分,
103+
记录每条 case 的 metric 分、pass/fail、失败原因与关键轨迹。
104+
2. **失败归因**:`attribution.analyze_set` 解析实际回复 + query + 期望,把失败归到
105+
`tool_call_error / format_error / final_mismatch / param_error / knowledge_recall / llm_rubric` 之一。
106+
3. **优化执行**:`RuleBasedOptimizer` 从候选池(对应归因发现的能力缺口)生成候选,
107+
`TargetPrompt` 注册并可在接受后写回源文件。
108+
4. **回归验证**:每个候选重新跑验证集,与 baseline 做逐 case 对比(new_pass / new_fail / kept_*)。
109+
5. **接受策略**:`gate.evaluate_gate` 按可配置规则决策(见下)。
110+
6. **产物审计**:每轮候选 prompt、评测结果、接受/拒绝理由、成本、耗时、种子全部落盘。
111+
112+
## 失败归因方法
113+
114+
归因由确定性规则驱动(fake 模式不依赖 LLM,故稳定、可解释、可复现):解析 fake agent
115+
的协议文本 `[TOOL]/[FMT]/[FINAL]`,结合 query 与期望——天气类问题未见 `[TOOL]` 调用 →
116+
`tool_call_error`(并说明知识未召回);期望 `[FMT] json` 而实际为 text → `format_error`;
117+
最终回复不含期望文本 → `final_mismatch`。每条失败 case 至少给出一句话原因,并标记
118+
`regression`(baseline 通过、当前候选失败)。真实模式则叠加 judge 输出的可解释 reason。
119+
120+
## 接受策略(gate)
121+
122+
四类可配置规则,全部命中才接受:
123+
124+
- `min_val_improvement`:验证集总分提升 ≥ 阈值;
125+
- `no_new_hard_fail`:不允许 baseline 通过的 case 在候选下失败;
126+
- `key_cases_no_regression`:关键 case(如 `val_robust`)绝不能退化;
127+
- `max_cost_usd`:成本硬上限(fake 模式为 0,不触发)。
128+
129+
## 防过拟合策略
130+
131+
过拟合的典型表现是"训练集提升但验证集退化"。本示例用验证集里的 `val_robust`
132+
(baseline 已通过、且不依赖任何优化能力)作为哨兵:任何让该 case 退化的候选
133+
(如"对所有问题都调 weather"的过度候选、或强制 JSON 破坏纯文本回复的候选)都会触发
134+
`key_cases_no_regression` / `no_new_hard_fail`**拒绝**,即使其验证集总分看似未降。
135+
136+
## 产物审计
137+
138+
`artifacts/` 下保存:结构化 `optimization_report.json`(含 meta 种子/耗时/预算、
139+
baseline 与每个 candidate 的逐 case 分数、delta、gate 决策与理由、失败归因统计)、
140+
人读 `optimization_report.md``candidates/<label>.md` 候选快照、
141+
`optimizer.snapshot.json` 复现配置。结合固定 `seed`,整条 pipeline 可完全复现。
142+
143+
## 方案设计说明
144+
145+
本闭环把"评测—优化"从一次性的 prompt 改写升级为带质量闸门的回归实验。评测直接复用
146+
`AgentEvaluator`,但通过 `call_agent` 黑盒接入一个确定性 Fake Model:它解析当前 prompt
147+
中的自然语言指令(如"调用 weather 工具")改变行为并返回结构化协议文本,从而在没有 LLM
148+
的情况下仍能体现"优化→分数变化"的反馈信号,保证无 Key 可跑。失败归因在 pipeline 层
149+
补齐:框架只给 pass/fail,本模块解析 `[TOOL]/[FMT]/[FINAL]` 把失败归到 6 大类并给出可
150+
解释原因,使"为什么失败"可被人与后续优化消费。优化器采用与 GEPA 等价的确定性规则搜索
151+
(候选池对应归因发现的能力缺口),而非依赖真实 reflection_lm,既满足"等价扩展机制"也
152+
满足可复现。接受策略是防过拟合的核心:即便验证集总分提升,只要出现"关键 case 退化"或
153+
"新增 hard fail"一律拒绝,成本/耗时作为硬上限兜底。产物审计把每轮候选、评测、决策理由、
154+
成本、种子全部落盘,使任何一次"是否回写生产"都可被人工复核与复现——这与真实业务中
155+
"评测差则优化过拟合、不可审计则改出的 prompt 难以上线"的痛点直接对应。
156+
157+
## 验收对照
158+
159+
- 样例 case 全部可运行并生成完整报告 ✅
160+
- 接受/拒绝决策:好候选接受,过度/无效候选拒绝 ✅
161+
- 过拟合场景(训练提升、验证退化)被拒绝 ✅
162+
- 失败归因有可解释原因、分类稳定 ✅
163+
- 无 Key 下完整 pipeline 耗时 ≪ 3 分钟(实测秒级)✅
164+
- 报告含 baseline/candidate 分数、逐 case delta、gate 决策与理由 ✅
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
你是一个助手,用中文简洁地回答用户的问题。
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
回答天气类问题时必须调用 weather 工具并直接给出天气结论。
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
用 JSON 格式回复用户。
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
对用户提出的每一个问题都必须先调用 weather 工具。
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
请礼貌地回答用户。

0 commit comments

Comments
 (0)