| # 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. 测试验证(确保一切正常) |
|
|