shinka-backup / eval_agent /design_draft /INTEGRATION_PLAN.md
JustinTX's picture
Add files using upload-large-folder tool
3f6526a verified

EV2 Service Integration Plan - Minimal Changes

🎯 设计目标

最小侵入性集成

  • ✅ 不改变现有演化逻辑
  • ✅ 不阻塞演化流程
  • ✅ 失败时不影响主流程
  • ✅ 可选功能(默认禁用)
  • ✅ 向后兼容(不破坏现有代码)

📊 架构分析

当前 ShinkaEvolve 流程

EvolutionRunner.run()
  ↓
_submit_new_job()  →  创建演化任务
  ↓
scheduler.run()  →  执行评估
  ↓
_check_completed_jobs()  →  检查完成
  ↓
_process_completed_job()  →  处理结果
  ├── 获取 results (line 792)
  ├── 提取 combined_score (line 821)
  ├── 保存到数据库 (line 851)
  └── 更新 meta memory (line 857)

集成点

最佳位置_process_completed_job() 方法的末尾(line 886 之后)

理由

  1. ✅ 所有数据已准备好(generation, score, results_dir)
  2. ✅ 数据库已保存(不影响核心流程)
  3. ✅ 不阻塞关键路径
  4. ✅ 失败不影响演化

🔧 最小改动方案

改动 1: 添加配置选项(1 行)

文件shinka/core/runner.py
位置:Line 64(EvolutionConfig 最后)

@dataclass
class EvolutionConfig:
    task_sys_msg: Optional[str] = None
    # ... 其他现有字段 ...
    use_text_feedback: bool = False
    
    # ===== 新增字段 =====
    eval_service_url: Optional[str] = None  # e.g., "http://localhost:8765"

影响

  • 向后兼容:默认 None,不启用
  • 不影响现有代码
  • 可以通过 YAML 配置启用

改动 2: 初始化通知器(~10 行)

文件shinka/core/runner.py
位置:Line 95-101(__init__ 方法中)

class EvolutionRunner:
    def __init__(
        self,
        evo_config: EvolutionConfig,
        job_config: JobConfig,
        db_config: DatabaseConfig,
        verbose: bool = True,
    ):
        # 保存 evo_config(如果还没有的话)
        self.evo_config = evo_config  # 可能已存在
        
        self.job_config = job_config
        self.db_config = db_config
        self.verbose = verbose
        
        # ... 现有初始化代码 ...
        
        # ===== 新增:初始化 eval service 通知器 =====
        self.eval_service_url = evo_config.eval_service_url
        if self.eval_service_url:
            logger.info(f"EV2 Eval Service enabled: {self.eval_service_url}")

影响

  • 仅在配置了 URL 时记录日志
  • 不导入额外依赖(requests 延迟导入)

改动 3: 添加通知方法(~30 行)

文件shinka/core/runner.py
位置:在 _process_completed_job 方法之后添加新方法

def _notify_eval_service(
    self, 
    generation: int, 
    combined_score: float, 
    results_dir: str
):
    """
    Notify eval service of generation completion (non-blocking, fire-and-forget).
    
    This is a best-effort notification that does not affect the evolution process.
    If the service is unavailable or the notification fails, evolution continues normally.
    """
    if not self.eval_service_url:
        return
    
    try:
        import requests
        
        # Prepare notification
        payload = {
            "generation": generation,
            "results_dir": str(results_dir),
            "primary_score": float(combined_score),
        }
        
        # Send notification (short timeout, non-blocking)
        response = requests.post(
            f"{self.eval_service_url}/api/v1/notify/generation_complete",
            json=payload,
            timeout=1.0  # Very short timeout (fire-and-forget)
        )
        
        if response.status_code == 200:
            logger.debug(f"Notified eval service for generation {generation}")
        else:
            logger.debug(
                f"Eval service notification failed: HTTP {response.status_code}"
            )
    
    except Exception as e:
        # Silently ignore errors (evolution continues)
        logger.debug(f"Failed to notify eval service: {e}")
        pass

特点

  • ✅ 非阻塞(timeout=1.0 秒)
  • ✅ Fire-and-forget(失败不抛异常)
  • ✅ 仅在启用时运行
  • ✅ 延迟导入 requests(不增加启动开销)
  • ✅ 使用 debug 级别日志(不干扰主日志)

改动 4: 调用通知(1 行)

文件shinka/core/runner.py
位置:Line 886(_process_completed_job 方法末尾)

def _process_completed_job(self, job: RunningJob):
    """Process a completed job and add results to database."""
    # ... 现有代码(line 788-886)...
    
    # 保存最佳程序
    self.db_path = self.results_dir / BEST_PROGRAM_FNAME
    if db_program.combined_score > self.best_score:
        self.best_score = db_program.combined_score
        self.best_program_path = Path(job.exec_fname)
        
        # Save best program copy
        if self.best_program_path.exists():
            shutil.copy(
                self.best_program_path,
                Path(self.results_dir) / BEST_PROGRAM_FNAME,
            )
    
    # ===== 新增:通知 eval service =====
    self._notify_eval_service(
        generation=job.generation,
        combined_score=combined_score,
        results_dir=job.results_dir
    )

影响

  • 仅在 eval_service_url 配置时生效
  • 不阻塞(timeout=1.0s)
  • 失败不影响演化

📋 完整改动总结

文件 位置 改动类型 行数
shinka/core/runner.py Line 64 添加配置字段 +1
shinka/core/runner.py Line 95-101 初始化变量 +3
shinka/core/runner.py 新方法 添加通知方法 +35
shinka/core/runner.py Line 886+ 调用通知 +5
总计 +44 行

🎯 使用方式

方式 1: YAML 配置

# experiment_config.yaml
evolution:
  # ... 现有配置 ...
  eval_service_url: "http://localhost:8765"  # 启用 eval service

方式 2: Python 代码

from shinka.core import EvolutionRunner, EvolutionConfig
from shinka.launch import JobConfig
from shinka.database import DatabaseConfig

# 创建配置
evo_config = EvolutionConfig(
    num_generations=100,
    # ... 其他配置 ...
    eval_service_url="http://localhost:8765",  # 启用 eval service
)

# 运行演化(无需其他改动)
runner = EvolutionRunner(evo_config, job_config, db_config)
runner.run()

方式 3: 不使用(默认)

# 不设置 eval_service_url,则不启用
evo_config = EvolutionConfig(
    num_generations=100,
    # eval_service_url=None  # 默认值,可以不写
)

runner = EvolutionRunner(evo_config, job_config, db_config)
runner.run()  # 正常运行,无任何改变

✅ 验证兼容性

1. 向后兼容性

测试:运行现有实验配置(不设置 eval_service_url

预期

  • ✅ 完全相同的行为
  • ✅ 无额外日志
  • ✅ 无性能影响
  • ✅ 无依赖问题

2. 前向兼容性

测试:设置 eval_service_url 但服务未启动

预期

  • ✅ 演化正常运行
  • ✅ Debug 日志显示通知失败
  • ✅ 不抛异常
  • ✅ 不影响结果

3. 完整集成

测试:启动 eval service 并运行演化

预期

  • ✅ 演化正常运行
  • ✅ 每代完成后发送通知
  • ✅ Eval service 自主决策触发
  • ✅ Agent 生成辅助指标

🚀 实施步骤

Step 1: 代码修改(20 分钟)

  1. 备份 shinka/core/runner.py
  2. 按照上述方案修改 4 处
  3. 语法检查:python -m py_compile shinka/core/runner.py

Step 2: 单元测试(10 分钟)

测试基础功能:

# test_integration.py
from shinka.core import EvolutionConfig

# Test 1: 默认配置(不启用)
config1 = EvolutionConfig()
assert config1.eval_service_url is None

# Test 2: 启用配置
config2 = EvolutionConfig(eval_service_url="http://localhost:8765")
assert config2.eval_service_url == "http://localhost:8765"

print("✅ Configuration tests passed")

Step 3: 集成测试(30 分钟)

测试场景 1:不启用 service(向后兼容)

# 运行现有实验
python my/run_circle_packing_WITHOUT_vision_WITH_refined_aux.py

# 预期:正常运行,无任何变化

测试场景 2:启用 service 但未启动(容错)

# 在实验脚本中添加
evolution_config = EvolutionConfig(
    # ... 现有配置 ...
    eval_service_url="http://localhost:8765",
)

# 运行实验(eval service 未启动)
# 预期:演化正常运行,debug 日志显示连接失败

测试场景 3:完整集成(正常工作)

# Terminal 1: 启动 eval service
uv run eval_agent/ev2_service_standalone.py --config eval_agent/ev2_service_config.yaml

# Terminal 2: 运行演化(小规模测试:5 代,interval=5)
# 修改实验脚本添加 eval_service_url
python my/test_with_eval_service.py

# 预期:
# - 演化正常运行
# - 第 5 代触发 eval agent
# - Agent 生成 EVAL_AGENTS.md

Step 4: 文档更新(10 分钟)

创建 eval_agent/USAGE_GUIDE.md

  • 如何启动 eval service
  • 如何在实验中启用
  • 示例配置
  • 故障排除

📊 性能影响分析

不启用时(eval_service_url=None)

  • CPU 开销:**0%**(完全不运行)
  • 内存开销:0 字节
  • 延迟:0 毫秒
  • 网络:0 请求

启用时(service 正常运行)

  • CPU 开销:**< 0.1%**(仅构建 JSON + 发送)
  • 内存开销:**< 1 KB**(payload 数据)
  • 延迟:**< 5 毫秒**(本地网络)
  • 网络:1 请求/代

启用时(service 不可用)

  • CPU 开销:**< 0.1%**(timeout 快速失败)
  • 延迟:1-2 毫秒(connection refused 立即返回)
  • 影响:(catch 所有异常)

结论:✅ 性能影响可以忽略不计


🔒 安全性考虑

  1. 网络隔离

    • 默认 localhost:8765
    • 不暴露到公网
    • 可以配置防火墙规则
  2. 数据隐私

    • 仅发送:generation, score, results_dir
    • 不发送代码内容
    • Results_dir 路径已知(本地路径)
  3. 失败处理

    • 所有异常被捕获
    • 不影响主流程
    • 日志级别 DEBUG(不泄露敏感信息)
  4. 依赖安全

    • requests 是常用库(已在依赖中)
    • 无新增外部依赖

🎯 优势总结

对 ShinkaEvolve

  • 最小侵入:仅 44 行代码,4 处修改
  • 零风险:失败不影响演化
  • 可选功能:默认禁用
  • 向后兼容:不破坏现有代码
  • 无性能损失:开销可忽略
  • 易于维护:代码清晰,注释完整

对用户

  • 透明集成:无需修改实验脚本
  • 灵活配置:YAML 或代码都可以
  • 即插即用:启动 service 即可
  • 故障隔离:service 崩溃不影响演化
  • 增量采用:可以先测试,再推广

对 Eval Service

  • 完全解耦:不依赖 ShinkaEvolve 内部实现
  • 通用接口:可以服务其他演化框架
  • 自主决策:何时分析由 service 决定
  • 持久化:跨演化运行累积经验

📝 检查清单

实施前检查:

  • 已阅读并理解集成方案
  • 已备份 shinka/core/runner.py
  • 已准备测试环境(eval service 配置好)
  • 已准备测试实验(小规模:5-10 代)

实施中检查:

  • 代码修改完成(4 处)
  • 语法检查通过
  • 向后兼容测试通过
  • 容错测试通过

实施后检查:

  • 完整集成测试通过
  • 文档更新完成
  • 示例配置创建
  • 团队成员知晓

🎉 预期成果

实施后,用户可以:

  1. 无缝启用

    evo_config = EvolutionConfig(
        # ... 现有配置 ...
        eval_service_url="http://localhost:8765"
    )
    
  2. 自动分析

    • 演化运行时,service 自动接收通知
    • 根据策略(periodic/plateau)触发分析
    • Agent 生成辅助指标和洞察
  3. 实时监控

    • 访问 http://localhost:8765/docs 查看 API
    • 查看 results_dir/eval_agent_memory/EVAL_AGENTS.md
    • 实时了解演化进展
  4. 灵活控制

    • 可以随时停止/启动 service
    • 调整触发策略(interval, plateau)
    • 手动触发分析(通过 API)

准备好实施了吗? 🚀

下一步:

  1. 确认计划(你觉得这个方案怎么样?)
  2. 开始实施(我可以帮你逐步完成)
  3. 测试验证(确保一切正常)