seeder.js
8.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/**
* 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,
};