# 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 最后) ```python @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__` 方法中) ```python 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` 方法之后添加新方法 ```python 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` 方法末尾) ```python 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 配置 ```yaml # experiment_config.yaml evolution: # ... 现有配置 ... eval_service_url: "http://localhost:8765" # 启用 eval service ``` ### 方式 2: Python 代码 ```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: 不使用(默认) ```python # 不设置 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 分钟) 测试基础功能: ```python # 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(向后兼容) ```bash # 运行现有实验 python my/run_circle_packing_WITHOUT_vision_WITH_refined_aux.py # 预期:正常运行,无任何变化 ``` **测试场景 2**:启用 service 但未启动(容错) ```python # 在实验脚本中添加 evolution_config = EvolutionConfig( # ... 现有配置 ... eval_service_url="http://localhost:8765", ) # 运行实验(eval service 未启动) # 预期:演化正常运行,debug 日志显示连接失败 ``` **测试场景 3**:完整集成(正常工作) ```bash # 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. **无缝启用**: ```python 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. 测试验证(确保一切正常)