Eval Service 重新设计 - 核心要点
🎯 两个关键问题
1. 泛化性不足 ❌
原设计:
# 假设了 circle packing 特定格式
def load_program_output(results_dir):
data = np.load("extra.npz")
return data['centers'], data['radii'] # ← 只适用于 circle packing
新设计 ✅:
# 任务无关的通用接口
def evaluate_auxiliary_metrics(program_output) -> dict:
"""
Args:
program_output: 任意格式
- Circle packing: {"centers": ndarray, "radii": ndarray}
- TSP: {"tour": list, "distance": float}
- Code: {"code": str, "ast": dict, "runtime": float}
"""
# Agent 自己适应不同的格式
pass
2. 职责不清 ❌
原设计:
ShinkaEvolve → scheduler → evaluate.py → metrics.json
↓
通知 Eval Service
↓
[只是旁观者,生成 auxiliary_metrics.py]
新设计 ✅:
ShinkaEvolve → 提交评估请求 → Eval Service
↓
运行 primary evaluator
↓
运行 auxiliary evaluators
↓
保存完整 metrics.json
↓
返回结果给 ShinkaEvolve
🏗️ 核心设计原则
1. 职责明确分离
| 组件 | 职责 | 不负责 |
|---|---|---|
| ShinkaEvolve | • 生成代码 • 演化决策 • 数据库管理 |
❌ 评估程序 |
| Eval Service | • 运行 primary evaluator • 运行 auxiliary evaluators • 生成完整 metrics |
❌ 演化逻辑 |
2. 通用接口契约
Evaluator Contract (任何任务必须遵循):
# Primary evaluator 输出标准格式
{
"combined_score": float, # 必须
"correct": bool, # 必须
"public_metrics": dict, # 可选
"private_metrics": dict, # 可选
"program_output": Any # 可选,任务特定
}
# Auxiliary evaluator 标准接口
def evaluate_auxiliary_metrics(program_output) -> dict:
"""接受任意格式的 program_output"""
pass
3. 一次性完成
# 新流程:一次 API 调用完成所有评估
POST /api/v1/evaluate
↓
run_full_evaluation:
1. run_primary_evaluator() → primary metrics
2. run_dynamic_auxiliary() → auxiliary metrics (agent-generated)
3. run_static_auxiliary() → auxiliary metrics (pre-defined)
4. merge_and_save() → 完整 metrics.json
📊 API 设计
提交评估 (异步)
# POST /api/v1/evaluate
{
"program_path": "gen_42/main.py",
"results_dir": "gen_42/results",
"generation": 42,
"experiment_root": "/path/to/experiment",
"evaluation_config": {
"primary_evaluator": "examples/circle_packing/evaluate.py",
"timeout": 300
},
"auxiliary_config": {
"enabled": true,
"use_dynamic": true, # agent 生成的
"use_static": false # 预定义的
}
}
# Response
{
"status": "accepted",
"job_id": "eval_job_42"
}
查询结果
# GET /api/v1/evaluate/{job_id}
{
"status": "completed",
"evaluation_result": {
"combined_score": 2.34,
"public_metrics": {
"num_circles": 26,
"aux_radius_std_dev": 0.031, # ← auxiliary
"aux_spatial_uniformity": 0.82 # ← auxiliary
},
"auxiliary_metric_definitions": {
"aux_radius_std_dev": {
"name": "Radius Standard Deviation",
"description": "...",
"interpretation": "lower_better"
}
}
}
}
🔄 完整数据流
┌──────────────────────────────────────────┐
│ ShinkaEvolve (Generation 42) │
│ 1. 生成代码: gen_42/main.py │
│ 2. 提交评估请求 → Eval Service │
│ 3. 轮询状态,等待完成 │
└──────────────────────────────────────────┘
↓ POST /api/v1/evaluate
┌──────────────────────────────────────────┐
│ Eval Service (后台任务) │
│ 1. 运行 primary: evaluate.py │
│ → combined_score, program_output │
│ │
│ 2. 加载 auxiliary_metrics.py (如果存在) │
│ │
│ 3. 运行 auxiliary: │
│ evaluate_auxiliary_metrics( │
│ program_output │
│ ) │
│ → aux_radius_std_dev, aux_... │
│ │
│ 4. 合并结果,保存 metrics.json │
│ { │
│ "combined_score": 2.34, │
│ "public_metrics": { │
│ "num_circles": 26, │
│ "aux_*": ... │
│ }, │
│ "auxiliary_metric_definitions": { │
│ ... │
│ } │
│ } │
└──────────────────────────────────────────┘
↓ 结果准备好
┌──────────────────────────────────────────┐
│ ShinkaEvolve (继续演化) │
│ 1. GET /api/v1/evaluate/{job_id} │
│ 2. 读取 combined_score │
│ 3. 演化决策 (选择、交叉、变异) │
│ 4. [可选] auxiliary metrics → LLM │
└──────────────────────────────────────────┘
🎨 Agent Prompt 通用化
旧 Prompt (针对 circle packing)
分析 centers 和 radii...
新 Prompt (任务无关)
<TASK_CONTEXT>
Task: {{ task_name }}
Primary Metric: {{ primary_metric_name }}
</TASK_CONTEXT>
<PROGRAM_OUTPUT_FORMAT>
The program output structure:
{{ program_output_structure }}
Example:
{{ program_output_example }}
</PROGRAM_OUTPUT_FORMAT>
<REQUIRED_INTERFACE>
def evaluate_auxiliary_metrics(program_output) -> dict:
"""
Args:
program_output: 根据任务不同,格式不同
Circle packing: {"centers": ndarray, "radii": ndarray}
TSP: {"tour": list, "distance": float}
Code: {"code": str, "ast": dict}
Returns:
dict: Auxiliary metrics
"""
# 你的代码适应 program_output 的格式
pass
</REQUIRED_INTERFACE>
📋 实施路径
Phase 1: 向后兼容 (1周)
class EvolutionConfig:
use_eval_service_for_evaluation: bool = False # 新选项
False: 使用旧方案 (scheduler → evaluate.py)True: 使用新方案 (eval service 负责)
Phase 2: 实现新 API (2周)
-
/api/v1/evaluateendpoint -
run_full_evaluation()pipeline - 通用
load_program_output() - 通用
run_dynamic_auxiliary()
Phase 3: 更新 Agent (1周)
- 通用化 prompt 模板
- 测试不同任务
Phase 4: 全面切换 (1周)
- 默认启用新模式
- 废弃旧方案
- 文档更新
🎯 验证标准
通用性测试
在 3 个不同任务上验证:
Circle Packing (几何)
program_output = {"centers": ndarray, "radii": ndarray}TSP (组合)
program_output = {"tour": [0,3,1,4,2], "distance": 142.5}Code Optimization (程序)
program_output = { "code": "def foo(): ...", "ast": {...}, "runtime": 0.05 }
✅ 如果同样的架构适用于所有 3 个任务 → 验证通过
💡 关键优势
vs 原设计
| 方面 | 原设计 | 新设计 |
|---|---|---|
| 泛化性 | ❌ 只适用 circle packing | ✅ 适用任意任务 |
| 职责 | ❌ ShinkaEvolve 负责评估 | ✅ Eval Service 负责 |
| 效率 | ❌ 需要重新加载数据 | ✅ 一次完成 |
| 可维护性 | ❌ 逻辑分散 | ✅ 职责清晰 |
📄 文档位置
- 详细设计:
docs/eval_service_redesign_v2.md - 原分析:
docs/eval_service_metrics_analysis.md - 原计划:
docs/eval_service_integration_plan.md(已过时)