/** * Darwinian Mutator — 达尔文式变异算子 * * 变异来源: * 1. 随机扰动 (随机丢弃 5-20% + shuffle) * 2. Agent 智能变异 (LLM 生成新知识片段) * 3. 学习事件注入 (如有 learning_events 可用) * * 父代基因组保持不变,变异创建新子代。 */ const evolutionQueries = require('../queries').evolutionQueries; const { generateMutationKnowledge } = require('../evaluator'); // ════════════════════════════════════════ // 工具函数 // ════════════════════════════════════════ function parseDim(raw) { if (!raw) return {}; return typeof raw === 'string' ? JSON.parse(raw) : raw; } function deepClone(obj) { return JSON.parse(JSON.stringify(obj)); } /** * 随机扰动: 随机丢弃/重排数组元素 */ function perturbArray(arr, dropRate = 0.1, shuffle = false) { if (!Array.isArray(arr) || arr.length === 0) return arr; let result = arr.filter(() => Math.random() > dropRate); // 保底: 至少保留一半 if (result.length < arr.length / 2) { const shuffled = [...arr].sort(() => Math.random() - 0.5); result = shuffled.slice(0, Math.ceil(arr.length / 2)); } if (shuffle) { for (let i = result.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [result[i], result[j]] = [result[j], result[i]]; } } return result; } // ════════════════════════════════════════ // 维度→可变异字段映射 // ════════════════════════════════════════ const DIMENSION_FIELDS = { mental_models: ['causalChains', 'ironLaws', 'analogies'], pattern_library: ['solutionPatterns', 'problemPatterns', 'classificationRules'], judgment: ['decisionRules', 'exclusions', 'boundaries', 'tradeoffs'], tool_fluency: ['coreTools', 'idioms', 'dataAccess', 'automations'], taste: ['qualitySignals', 'exemplars', 'outputStandards'], scar_tissue: ['failures', 'antiPatterns', 'antiRationalizations'], }; // ════════════════════════════════════════ // 核心变异函数 // ════════════════════════════════════════ /** * 对基因组应用随机扰动 */ function applyPerturbation(child, dropRate) { for (const [dim, fields] of Object.entries(DIMENSION_FIELDS)) { // 因果链和铁律更珍贵,少丢弃 const rate = dim === 'mental_models' ? dropRate * 0.5 : dropRate; for (const field of fields) { if (child[dim][field]) { child[dim][field] = perturbArray(child[dim][field], rate, Math.random() > 0.7); } } } } /** * 用 Agent 为指定维度生成新知识片段 */ async function applyAgentMutation(child, genome, dimension) { try { const result = await generateMutationKnowledge(genome, dimension); const newEntries = result.newEntries || []; if (newEntries.length === 0) return 0; // 找到该维度中最适合注入的字段 const fields = DIMENSION_FIELDS[dimension] || []; const targetField = fields.find(f => Array.isArray(child[dimension][f])) || fields[0]; if (targetField) { if (!Array.isArray(child[dimension][targetField])) { child[dimension][targetField] = []; } child[dimension][targetField].push(...newEntries.map(e => ({ ...e, mutationSource: 'agent', }))); } return newEntries.length; } catch (err) { console.error(` ⚠️ Agent 变异 ${dimension} 失败: ${err.message}`); return 0; } } /** * 注入 learning_events(如有可用) */ function applyLearningEvents(child, scarLearnings, patternLearnings, mentalModelLearnings) { if (!child.scar_tissue.failures) child.scar_tissue.failures = []; if (!child.scar_tissue.antiPatterns) child.scar_tissue.antiPatterns = []; if (!child.pattern_library.solutionPatterns) child.pattern_library.solutionPatterns = []; for (const event of scarLearnings) { const content = typeof event.content === 'string' ? JSON.parse(event.content) : event.content; child.scar_tissue.failures.push({ incident: content.rawError?.slice(0, 200) || content.lesson, lesson: content.lesson, preventionRule: content.preventionRule, mutationSource: 'darwinian', }); if (content.severity === 'high') { child.scar_tissue.antiPatterns.push({ pattern: content.category, correction: content.preventionRule, mutationSource: 'darwinian', }); } } for (const event of patternLearnings) { const content = typeof event.content === 'string' ? JSON.parse(event.content) : event.content; child.pattern_library.solutionPatterns.push({ ...content, mutationSource: 'darwinian' }); } if (!child.mental_models.causalChains) child.mental_models.causalChains = []; if (!child.mental_models.analogies) child.mental_models.analogies = []; for (const event of (mentalModelLearnings || [])) { const content = typeof event.content === 'string' ? JSON.parse(event.content) : event.content; if (content.type === 'causalChain') child.mental_models.causalChains.push({ ...content, mutationSource: 'darwinian' }); else if (content.type === 'analogy') child.mental_models.analogies.push({ ...content, mutationSource: 'darwinian' }); } } /** * 创建一个变异子代 * * @param {object} parent - 父代基因组 * @param {object} options * @param {number} options.dropRate - 随机丢弃率 (0-1) * @param {boolean} options.useAgent - 是否使用 Agent 智能变异 * @param {string} options.agentDimension - Agent 变异的目标维度 * @param {object[]} options.scarLearnings - 伤疤学习事件 * @param {object[]} options.patternLearnings - 模式学习事件 * @param {object[]} options.mentalModelLearnings - 心智模型学习事件 * @returns {object} 子代 6 维数据 */ async function mutateGenome(parent, options = {}) { const { dropRate = 0.1, useAgent = false, agentDimension = null, scarLearnings = [], patternLearnings = [], mentalModelLearnings = [], } = options; // 1. 深拷贝父代 const child = {}; for (const dim of Object.keys(DIMENSION_FIELDS)) { child[dim] = deepClone(parseDim(parent[dim])); } // 2. 随机扰动 applyPerturbation(child, dropRate); // 3. Agent 智能变异(如启用) if (useAgent && agentDimension) { await applyAgentMutation(child, parent, agentDimension); } // 4. 注入学习事件 applyLearningEvents(child, scarLearnings, patternLearnings, mentalModelLearnings); return child; } // ════════════════════════════════════════ // 公开 API // ════════════════════════════════════════ /** * 为 Run 中所有存活基因组创建变异子代 * * 每个子代的变异策略随机选择: * - 30% 纯随机扰动 (强 drop) * - 40% Agent 智能变异 (选一个弱维度增强) * - 30% 学习事件注入 (如有可用) */ async function applyMutations(runId, generation) { const parents = await evolutionQueries.getGenomesByRun(runId, { aliveOnly: true }); if (parents.length === 0) return []; // 收集可用的学习事件 const scarEvents = await evolutionQueries.getLearningEvents(runId, { dimension: 'scar_tissue', applied: false }); const patternEvents = await evolutionQueries.getLearningEvents(runId, { dimension: 'pattern_library', applied: false }); const mmEvents = await evolutionQueries.getLearningEvents(runId, { dimension: 'mental_models', applied: false }); const hasLearnings = scarEvents.length + patternEvents.length + mmEvents.length > 0; console.log(` 🧬 变异 ${parents.length} 个父代: ${scarEvents.length} 伤疤 + ${patternEvents.length} 模式 + ${mmEvents.length} 心智模型`); const dimensions = Object.keys(DIMENSION_FIELDS); const children = []; for (const parent of parents) { const roll = Math.random(); let strategy; let options = { dropRate: 0.05 + Math.random() * 0.15 }; if (roll < 0.3) { // 纯随机扰动 (强 drop) strategy = 'perturb'; options.dropRate = 0.1 + Math.random() * 0.2; } else if (roll < 0.7) { // Agent 智能变异 strategy = 'agent'; options.useAgent = true; // 随机选一个维度 options.agentDimension = dimensions[Math.floor(Math.random() * dimensions.length)]; } else if (hasLearnings) { // 学习事件注入 strategy = 'learning'; const samplingRate = 0.6 + Math.random() * 0.3; const sample = (events) => events.filter(e => e.genome_id === parent.id || (!e.genome_id && Math.random() < samplingRate), ); options.scarLearnings = sample(scarEvents); options.patternLearnings = sample(patternEvents); options.mentalModelLearnings = sample(mmEvents); } else { // 没有学习事件,改用 Agent strategy = 'agent'; options.useAgent = true; options.agentDimension = dimensions[Math.floor(Math.random() * dimensions.length)]; } try { const childDims = await mutateGenome(parent, options); const child = await evolutionQueries.insertGenome({ runId, skillName: parent.skill_name, generation, parentIds: [parent.id], mentalModels: childDims.mental_models, patternLibrary: childDims.pattern_library, judgment: childDims.judgment, toolFluency: childDims.tool_fluency, taste: childDims.taste, scarTissue: childDims.scar_tissue, }); children.push(child); console.log(` ${parent.id.slice(0, 6)} → ${child.id.slice(0, 6)} [${strategy}${options.agentDimension ? ':' + options.agentDimension : ''}]`); } catch (err) { console.error(` ❌ ${parent.id.slice(0, 6)} 变异失败: ${err.message}`); } } // 标记学习事件已应用 const allEventIds = [...scarEvents, ...patternEvents, ...mmEvents].map(e => e.id); if (allEventIds.length > 0) { await evolutionQueries.markLearningApplied(allEventIds); } console.log(` ✅ 变异完成: ${children.length} 个子代`); return children; } module.exports = { mutateGenome, perturbArray, applyMutations, };