//! 进化引擎中枢 //! 协调 L1/L2/L3 三层进化的触发和执行 //! L1 (记忆进化) 在 GrowthIntegration 中处理 //! L2 (技能进化) 通过 PatternAggregator + SkillGenerator + QualityGate 协调 //! L3 (工作流进化) 通过 WorkflowComposer 协调 //! 反馈闭环通过 FeedbackCollector 管理 use std::sync::Arc; use crate::experience_store::ExperienceStore; use crate::feedback_collector::{ FeedbackCollector, FeedbackEntry, TrustUpdate, }; use crate::pattern_aggregator::{AggregatedPattern, PatternAggregator}; use crate::quality_gate::{QualityGate, QualityReport}; use crate::skill_generator::{SkillCandidate, SkillGenerator}; use crate::workflow_composer::{ToolChainPattern, WorkflowComposer}; use crate::VikingAdapter; use zclaw_types::Result; /// 进化引擎配置 #[derive(Debug, Clone)] pub struct EvolutionConfig { /// 经验复用次数达到此阈值触发 L2 pub min_reuse_for_skill: u32, /// 置信度阈值 pub quality_confidence_threshold: f32, /// 是否启用进化引擎 pub enabled: bool, } impl Default for EvolutionConfig { fn default() -> Self { Self { min_reuse_for_skill: 3, quality_confidence_threshold: 0.7, enabled: true, } } } /// 进化引擎中枢 pub struct EvolutionEngine { viking: Arc, feedback: FeedbackCollector, config: EvolutionConfig, } impl EvolutionEngine { pub fn new(viking: Arc) -> Self { Self { viking: viking.clone(), feedback: FeedbackCollector::with_viking(viking), config: EvolutionConfig::default(), } } /// Backward-compatible constructor /// 从 ExperienceStore 中提取共享的 VikingAdapter 实例 pub fn from_experience_store(experience_store: Arc) -> Self { let viking = experience_store.viking().clone(); Self { viking: viking.clone(), feedback: FeedbackCollector::with_viking(viking), config: EvolutionConfig::default(), } } pub fn with_config(mut self, config: EvolutionConfig) -> Self { self.config = config; self } pub fn set_enabled(&mut self, enabled: bool) { self.config.enabled = enabled; } /// L2 检查:是否有可进化的模式 pub async fn check_evolvable_patterns( &self, agent_id: &str, ) -> Result> { if !self.config.enabled { return Ok(Vec::new()); } let store = ExperienceStore::new(self.viking.clone()); let aggregator = PatternAggregator::new(store); aggregator .find_evolvable_patterns(agent_id, self.config.min_reuse_for_skill) .await } /// L2 执行:为给定模式构建技能生成 prompt /// 返回 (prompt_string, pattern) 供上层通过 LLM 调用后 parse pub fn build_skill_prompt(&self, pattern: &AggregatedPattern) -> String { SkillGenerator::build_prompt(pattern) } /// L2 执行:解析 LLM 返回的技能 JSON 并进行质量门控 pub fn validate_skill_candidate( &self, json_str: &str, pattern: &AggregatedPattern, existing_triggers: Vec, ) -> Result<(SkillCandidate, QualityReport)> { let candidate = SkillGenerator::parse_response(json_str, pattern)?; let gate = QualityGate::new(self.config.quality_confidence_threshold, existing_triggers); let report = gate.validate_skill(&candidate); Ok((candidate, report)) } /// 获取当前配置 pub fn config(&self) -> &EvolutionConfig { &self.config } // ----------------------------------------------------------------------- // L3: 工作流进化 // ----------------------------------------------------------------------- /// L3: 从轨迹数据中提取重复的工具链模式 pub fn analyze_trajectory_patterns( &self, trajectories: &[(String, Vec)], // (session_id, tools_used) ) -> Vec<(ToolChainPattern, Vec)> { if !self.config.enabled { return Vec::new(); } WorkflowComposer::extract_patterns(trajectories) } /// L3: 为给定工具链模式构建工作流生成 prompt pub fn build_workflow_prompt( &self, pattern: &ToolChainPattern, frequency: usize, industry: Option<&str>, ) -> String { WorkflowComposer::build_prompt(pattern, frequency, industry) } // ----------------------------------------------------------------------- // 反馈闭环 // ----------------------------------------------------------------------- /// 提交反馈并获取信任度更新,自动持久化 pub async fn submit_feedback(&mut self, entry: FeedbackEntry) -> TrustUpdate { let update = self.feedback.submit_feedback(entry); // 非阻塞持久化:失败仅打日志,不影响返回值 if let Err(e) = self.feedback.save().await { tracing::warn!("[EvolutionEngine] Failed to persist trust records: {}", e); } update } /// 获取需要优化的进化产物 pub fn get_artifacts_needing_optimization(&self) -> Vec { self.feedback .get_artifacts_needing_optimization() .iter() .map(|r| r.artifact_id.clone()) .collect() } /// 获取建议归档的进化产物 pub fn get_artifacts_to_archive(&self) -> Vec { self.feedback .get_artifacts_to_archive() .iter() .map(|r| r.artifact_id.clone()) .collect() } /// 获取推荐产物 pub fn get_recommended_artifacts(&self) -> Vec { self.feedback .get_recommended_artifacts() .iter() .map(|r| r.artifact_id.clone()) .collect() } /// 获取反馈收集器的引用(用于高级查询) pub fn feedback(&self) -> &FeedbackCollector { &self.feedback } /// 启动时加载已持久化的信任度记录 pub async fn load_feedback(&mut self) -> Result { self.feedback .load() .await .map_err(|e| zclaw_types::ZclawError::Internal(e)) } } #[cfg(test)] mod tests { use super::*; use crate::experience_store::Experience; #[tokio::test] async fn test_disabled_returns_empty() { let viking = Arc::new(crate::VikingAdapter::in_memory()); let mut engine = EvolutionEngine::new(viking); engine.set_enabled(false); let patterns = engine.check_evolvable_patterns("agent-1").await.unwrap(); assert!(patterns.is_empty()); } #[tokio::test] async fn test_no_evolvable_patterns() { let viking = Arc::new(crate::VikingAdapter::in_memory()); let engine = EvolutionEngine::new(viking); let patterns = engine.check_evolvable_patterns("unknown-agent").await.unwrap(); assert!(patterns.is_empty()); } #[tokio::test] async fn test_finds_evolvable_pattern() { let viking = Arc::new(crate::VikingAdapter::in_memory()); let store_inner = ExperienceStore::new(viking.clone()); let mut exp = Experience::new( "agent-1", "report generation", "researcher", vec!["query db".into(), "format".into()], "success", ); exp.reuse_count = 5; store_inner.store_experience(&exp).await.unwrap(); let engine = EvolutionEngine::new(viking); let patterns = engine.check_evolvable_patterns("agent-1").await.unwrap(); assert_eq!(patterns.len(), 1); assert_eq!(patterns[0].pain_pattern, "report generation"); } #[test] fn test_build_skill_prompt() { let viking = Arc::new(crate::VikingAdapter::in_memory()); let engine = EvolutionEngine::new(viking); let exp = Experience::new( "a", "report", "researcher", vec!["step1".into()], "ok", ); let pattern = AggregatedPattern { pain_pattern: "report".to_string(), experiences: vec![exp], common_steps: vec!["step1".into()], total_reuse: 5, tools_used: vec!["researcher".into()], industry_context: None, }; let prompt = engine.build_skill_prompt(&pattern); assert!(prompt.contains("report")); } #[test] fn test_validate_skill_candidate() { let viking = Arc::new(crate::VikingAdapter::in_memory()); let engine = EvolutionEngine::new(viking); let exp = Experience::new( "a", "report", "researcher", vec!["step1".into()], "ok", ); let pattern = AggregatedPattern { pain_pattern: "report".to_string(), experiences: vec![exp], common_steps: vec!["step1".into()], total_reuse: 5, tools_used: vec!["researcher".into()], industry_context: None, }; let json = r##"{"name":"报表技能","description":"生成报表","triggers":["报表","日报"],"tools":["researcher"],"body_markdown":"# 报表\n步骤","confidence":0.9}"##; let (candidate, report) = engine .validate_skill_candidate(json, &pattern, vec!["搜索".to_string()]) .unwrap(); assert_eq!(candidate.name, "报表技能"); assert!(report.passed); } }