/** * Skill Seeder — 从单个 Skill 基因组生成种群变体 * * 解决的问题 (F1/A2): * RFC 要求种群中同一 Skill 有 N 个策略变体同时存在, * 通过变异→选择→遗传的竞争来进化。 * 但此前 forager 只为每个 SKILL.md 创建 1 个基因组 = 种群只有 1 个个体。 * * 生成策略: * 给定一个 Gen 0 基因组,通过 LLM 变异产生 N-1 个变体: * - Variant A: 模式库增强(多加 solutionPatterns) * - Variant B: 判断力增强(多加 decisionRules + boundaries) * - Variant C: 伤疤记忆增强(从外部案例中注入 antiPatterns) * - Variant D: 随机混合变异 * * 这样 crossover 就能真正触发(pool.length >= 2)。 */ const evolutionQueries = require('../queries').evolutionQueries; function parseDim(raw) { if (!raw) return {}; return typeof raw === 'string' ? JSON.parse(raw) : raw; } // ════════════════════════════════════════════════════════ // 维度变异器 (不需 LLM,纯结构变异) // ════════════════════════════════════════════════════════ /** * 策略 A: 增强判断力 — 添加更激进的决策规则 */ function mutateTowardJudgment(genome) { const judgment = parseDim(genome.judgment); if (!judgment.decisionRules) judgment.decisionRules = []; if (!judgment.boundaries) judgment.boundaries = []; // 注入标准变异规则 const injectedRules = [ '修改超过 3 个文件时,先用 grep 确认影响面再动手', '遇到不熟悉的 API 时,先搜索项目中已有用法而非查文档', '如果前 5 步都是信息收集且未发现关键信息,切换搜索策略', ]; const existing = new Set(judgment.decisionRules.map(r => typeof r === 'string' ? r : r.decision || r.rule)); for (const rule of injectedRules) { if (!existing.has(rule)) { judgment.decisionRules.push({ situation: 'auto-seeded', decision: rule, confidence: 0.5 }); } } if (judgment.boundaries.length === 0) { judgment.boundaries.push('不擅长低层优化(内存布局/SIMD)'); judgment.boundaries.push('不熟悉的框架先做 spike 验证'); } return { judgment: JSON.stringify(judgment), variant_strategy: 'judgment-enhanced' }; } /** * 策略 B: 增强伤疤记忆 — 注入通用 antiPatterns */ function mutateTowardScarTissue(genome) { const scars = parseDim(genome.scar_tissue); if (!scars.antiPatterns) scars.antiPatterns = []; if (!scars.antiRationalizations) scars.antiRationalizations = []; const genericAntiPatterns = [ { pattern: '先实现后测试', symptom: '上线后暴雷', correction: 'TDD 或至少先写断言' }, { pattern: 'try-catch 吞错误', symptom: '问题被掩盖', correction: '至少 log error,不要空 catch' }, { pattern: '信文档不验证', symptom: 'API 实际行为与文档不符', correction: '先 spike-test' }, ]; const existingPatterns = new Set(scars.antiPatterns.map(a => a.pattern)); for (const ap of genericAntiPatterns) { if (!existingPatterns.has(ap.pattern)) scars.antiPatterns.push(ap); } if (scars.antiRationalizations.length === 0) { scars.antiRationalizations.push( { excuse: '这个太简单不需要查', rebuttal: '简单任务最容易犯已知错误' }, { excuse: '没时间写测试', rebuttal: '不写测试花的时间 > 写测试时间的 3 倍' }, ); } return { scar_tissue: JSON.stringify(scars), variant_strategy: 'scar-enhanced' }; } /** * 策略 C: 增强模式库 — 注入元模式 */ function mutateTowardPatterns(genome) { const patterns = parseDim(genome.pattern_library); if (!patterns.solutionPatterns) patterns.solutionPatterns = []; if (!patterns.classificationRules) patterns.classificationRules = []; const metaPatterns = [ { id: 'explore-then-act', applicableWhen: '任何代码修改任务', solution: '先 grep/view 理解上下文 → 再 write/replace', notApplicableWhen: '只需要回答问题不需要改代码', }, { id: 'convention-first', applicableWhen: '调用基础设施(HTTP/DB/Auth)', solution: '先搜项目中已有用法,复制约定而非用框架默认', notApplicableWhen: '项目中没有已有用法', }, ]; const existingIds = new Set(patterns.solutionPatterns.map(p => p.id)); for (const mp of metaPatterns) { if (!existingIds.has(mp.id)) patterns.solutionPatterns.push(mp); } return { pattern_library: JSON.stringify(patterns), variant_strategy: 'pattern-enhanced' }; } /** * 策略 D: 混合变异 — 同时微调多个维度 */ function mutateHybrid(genome) { const result = {}; // 取每个策略的一小部分 Object.assign(result, mutateTowardJudgment(genome)); Object.assign(result, mutateTowardScarTissue(genome)); result.variant_strategy = 'hybrid'; return result; } // 变异策略表 const MUTATION_STRATEGIES = [ { name: 'judgment-enhanced', mutate: mutateTowardJudgment }, { name: 'scar-enhanced', mutate: mutateTowardScarTissue }, { name: 'pattern-enhanced', mutate: mutateTowardPatterns }, { name: 'hybrid', mutate: mutateHybrid }, ]; // ════════════════════════════════════════════════════════ // 公开 API // ════════════════════════════════════════════════════════ /** * 从一个 Gen 0 基因组产生 N 个变体,形成初始种群 * * @param {string} genomeId - 基础基因组 ID * @param {string} runId - Evolution Run ID * @param {number} populationSize - 目标种群大小(含原始个体) * @returns {object[]} 新创建的变体基因组 */ async function seedPopulation(genomeId, runId, populationSize = 5) { const baseGenome = await evolutionQueries.getGenome(genomeId); if (!baseGenome) throw new Error(`Base genome ${genomeId} not found`); const variantsNeeded = populationSize - 1; // 原始个体已存在 const variants = []; for (let i = 0; i < variantsNeeded && i < MUTATION_STRATEGIES.length; i++) { const strategy = MUTATION_STRATEGIES[i]; const mutations = strategy.mutate(baseGenome); // 创建变体基因组 const variantData = { runId, skillName: baseGenome.skill_name, generation: baseGenome.generation, // 同代 parentIds: [baseGenome.id], mental_models: baseGenome.mental_models, pattern_library: mutations.pattern_library || baseGenome.pattern_library, judgment: mutations.judgment || baseGenome.judgment, tool_fluency: baseGenome.tool_fluency, taste: baseGenome.taste, scar_tissue: mutations.scar_tissue || baseGenome.scar_tissue, }; const variant = await evolutionQueries.insertGenome(variantData); variants.push({ ...variant, strategy: strategy.name }); console.log(` 🌱 ${baseGenome.skill_name} 变体 ${i + 1}: ${strategy.name} (${variant.id.slice(0, 8)})`); } return variants; } /** * 对 run 中所有 Gen 0 基因组进行种群初始化 */ async function seedRunPopulation(runId, populationSize = 5) { const genomes = await evolutionQueries.getGenomesByRun(runId, { generation: 0, aliveOnly: true }); console.log(`🌱 种群初始化: ${genomes.length} 个 Skill × ${populationSize} 变体\n`); let totalVariants = 0; for (const genome of genomes) { try { const variants = await seedPopulation(genome.id, runId, populationSize); totalVariants += variants.length; } catch (err) { console.error(` ⚠️ ${genome.skill_name}: ${err.message}`); } } console.log(`\n✅ 种群初始化完成: ${totalVariants} 个变体`); return totalVariants; } module.exports = { seedPopulation, seedRunPopulation, // 暴露策略用于测试 MUTATION_STRATEGIES, mutateTowardJudgment, mutateTowardScarTissue, mutateTowardPatterns, mutateHybrid, };