name: iterative-code-evolution description: 通过结构化分析-变异-评估循环系统性地改进代码。改编自ALMA(用于智能体系统的记忆设计自动元学习框架)。适用于迭代改进代码质量、优化实现、调试顽固问题,或通过多个改进周期演进设计。用纪律性的反思、变体追踪和有原则的下一步变更选择,取代临时的“尝试与修复”方法。
迭代式代码演进
一种通过纪律性的 反思 → 变异 → 验证 → 评分 循环来改进代码的结构化方法,改编自用于元学习代码设计的ALMA研究框架。
何时使用此技能
- 迭代改进效果不佳的代码(性能、正确性、设计)
- 通过多轮变更优化实现
- 调试顽固或反复出现的问题,简单修复不断失败时
- 通过结构化实验演进系统设计
- 任何你已经尝试过2种以上方法,并且需要对下一步尝试内容进行纪律性约束的任务
- 构建或改进提示词、流水线、智能体或任何受益于迭代精炼的“程序”
何时不应使用此技能
- 简单的一次性代码生成(直接编写即可)
- 具有明确解决方案的机械性任务(重构、格式化、迁移)
- 用户已明确指定需要更改的内容时
核心概念
演进循环
每个改进周期遵循以下顺序:
┌─────────────────────────────────────────────────────┐
│ 1. 分析 — 对当前代码进行结构化诊断 │
│ 2. 计划 — 确定优先、具体的变更 │
│ 3. 变异 — 实施变更 │
│ 4. 验证 — 运行代码,检查错误 │
│ 5. 评分 — 衡量相对于基线的改进程度 │
│ 6. 归档 — 记录尝试的内容和发生的情况 │
│ │
│ 带着新知识回到第1步 │
└─────────────────────────────────────────────────────┘
演进日志
在项目根目录的.evolution/log.json中跟踪所有迭代。这是使每个周期都比上一个更聪明的记忆。
{
"baseline": {
"description": "演进开始前的初始实现",
"score": 0.0,
"timestamp": "2025-01-15T10:00:00Z"
},
"variants": {
"v001": {
"parent": "baseline",
"description": "添加了输入验证和错误处理",
"changes_made": [
{
"what": "为所有公共方法添加了类型检查",
"why": "3/10的测试用例中因输入格式错误导致运行时崩溃",
"priority": "High"
}
],
"score": 0.6,
"delta": "+0.6 vs parent",
"timestamp": "2025-01-15T10:30:00Z",
"learned": "输入验证是主要的故障模式 — 其他大部分逻辑是合理的"
},
"v002": {
"parent": "v001",
"description": "重构解析逻辑以处理边缘情况",
"changes_made": [
{
"what": "重写parse_input(),使用状态机代替正则表达式",
"why": "正则表达式方法在处理嵌套结构时失败(见于测试用例7,8)",
"priority": "High"
}
],
"score": 0.85,
"delta": "+0.25 vs parent",
"timestamp": "2025-01-15T11:00:00Z",
"learned": "状态机方法比正则表达式更能泛化处理此语法"
}
},
"principles_learned": [
"输入验证修复能带来最大的早期收益",
"基于正则表达式的解析在递归结构上会失效 — 优先选择状态机",
"小范围、有针对性的变更比大规模重写得分更高"
]
}
详细流程
阶段1:分析 — 结构化诊断
在进行任何更改之前,对当前代码及其输出进行结构化分析。这是最重要的阶段 — 它能防止无效的变异。
步骤1 — 从过去的编辑中学习(首次迭代跳过)
回顾演进日志。对于每个先前的变更:
- 分数是提高了还是降低了?
- 是什么模式使其成功或失败?
- 提取2-3条要采纳的原则和2-3条要避免的陷阱
步骤2 — 组件级评估
对于每个有意义的组件(函数、类、模块、流水线阶段),为其标记:
| 标签 | 含义 |
|---|---|
| 正常 | 产生正确输出,未观察到问题 |
| 脆弱 | 在理想路径上工作,但在边缘情况或特定输入上失败 |
| 损坏 | 产生错误输出或错误 |
| 冗余 | 重复其他地方存在的逻辑,增加复杂性而无价值 |
| 缺失 | 尚不存在但需要的组件 |
对于每个标签,写一行解释 为什么 — 链接到具体的测试输出或观察到的行为。
步骤3 — 质量和一致性检查
寻找跨领域问题:
- 数据流:组件之间是否传递结构化数据,还是依赖隐式状态?
- 错误处理:错误是否被捕获和处理,还是被静默忽略?
- 重复:相同的逻辑是否在多个地方重复?
- 硬编码:是否存在魔法数字、硬编码路径或环境特定假设?
- 泛化性:哪些部分适用于新输入,哪些部分过度拟合了测试用例?
步骤4 — 生成优先建议
基于步骤1-3,生成具体的变更建议。每个建议必须包含:
- 优先级:高 | 中 | 低
- 内容:变更的精确描述(代码层面,非模糊描述)
- 原因:链接到步骤1-3中的具体观察结果
- 风险:如果此变更实施不正确,可能导致什么问题
规则:每个建议必须链接到一个观察结果。 不允许“这可能有用”的建议 — 只允许基于你在代码或输出中实际看到的内容提出的变更。
规则:每个周期最多3个建议。 一次超过3个变更将无法将改进或回归归因于特定变更。
阶段2:计划 — 选择要更改的内容
从分析中选取1-3个建议。选择原则:
- 高优先级优先 — 在优化正常工作的内容之前,先修复损坏的内容
- 每个周期一个主题 — 不要混合不相关的变更(例如,不要在同一变异中同时修复解析和重构错误处理)
- 倾向于针对性而非全面性 — 对一个函数进行精准更改优于重写三个模块
- 如果卡住,则探索 — 如果最近2+个周期在同一组件上显示出收益递减,则选择修改不同的组件(这是ALMA的“访问惩罚”原则 — 不要在同一件事上持续消耗)
阶段3:变异 — 实施变更
编写新代码。关键纪律:
- 只更改计划中规定的内容。 抵制“顺便再修复一个”的冲动。
- 保留接口。 除非计划明确要求,否则不要更改函数签名或返回类型。
- 注释理由。 在每个更改附近添加简短注释,引用演进周期(例如,
# evo-v003: 根据边缘情况故障切换到状态机)
阶段4:验证 — 运行和检查
针对用于评分的相同输入/测试执行修改后的代码。
如果崩溃(最多重试3次):
使用反思-修复协议:
- 阅读完整的错误回溯
- 识别根本原因(而非症状)
- 仅修复根本原因 — 不要进行无关的改进
- 重新运行
在3次重试失败后,恢复到父变体并记录失败:
{
"attempted": "尝试内容的描述",
"failure_mode": "无法解决的错误",
"learned": "为什么这种方法行不通"
}
这些失败数据很有价值 — 它防止重新尝试相同的有问题的方法。
如果运行但产生错误输出:
不要立即重试。回到阶段1(分析),使用新的输出。错误的输出是诊断数据。
阶段5:评分 — 衡量改进
比较新变体与其父变体(不仅仅是基线)的性能。评分取决于上下文:
| 上下文 | 评分方法 |
|---|---|
| 存在测试 | 通过率:tests_passed / total_tests |
| 性能优化 | 指标差异(延迟、吞吐量、内存) |
| 代码质量 | 加权检查表(正确性、边缘情况、可读性) |
| 用户反馈 | 二元:根据用户判断的更好/更差/相同 |
| LLM/提示词输出质量 | 根据标准对样本输出进行评分 |
始终计算相对于父变体的差异。 这是你了解哪些更改有帮助或有害的方式。
阶段6:归档 — 记录和学习
更新.evolution/log.json:
- 记录新变体,包括父变体、描述、变更、分数、差异
- 编写
learned字段:关于此周期所学内容的一句话 - 如果分数提高,将底层原则添加到
principles_learned - 如果分数降低,将失败模式作为陷阱添加到
principles_learned
变体管理
何时分支 vs. 修改
- 原地修改(同一文件,新版本):当变更明显是增量性的(修复错误、添加检查、调整参数)
- 分支(复制到新文件):当尝试根本不同的方法时(不同算法、不同架构、不同策略)
将分支保存在.evolution/variants/中,并赋予描述性名称。演进日志跟踪哪个是活跃的。
选择:迭代哪个变体
如果你有多个变体,使用以下方法选择下一个要改进的变体:
score(variant) = normalized_reward - 0.5 * log(1 + visit_count)
其中:
normalized_reward= 相对于基线的变体分数(0-1范围)visit_count= 此变体被选中进行迭代的次数
这平衡了利用(迭代最佳变体)和探索(尝试最近未接触的变体)。它防止陷入局部最优。
快速参考:分析模板
在执行阶段1时,将你的思考结构化为:
## 演进周期 [N] — 分析
### 从前几个周期中吸取的教训
- 周期 [N-1] 更改了 [X],分数 [上升/下降] 了 [数量]
- 原则:[我们学到了什么]
- 陷阱:[要避免什么]
### 组件评估
| 组件 | 状态 | 证据 |
|-----------|--------|----------|
| function_a() | 正常 | 所有测试用例通过 |
| function_b() | 脆弱 | 在空输入上失败(测试 #4) |
| class_C | 损坏 | 返回None而不是dict |
### 跨领域问题
- [问题1及具体证据]
- [问题2及具体证据]
### 计划变更(最多3个)
1. **[高]** 内容:... | 原因:... | 风险:...
2. **[中]** 内容:... | 原因:... | 风险:...
示例:完整的演进周期
上下文: 用户要求改进一个在40%的目标页面上失败的网页爬虫。
周期1 — 分析:
- 组件评估:
parse_html()损坏(在没有<article>标签的页面上崩溃),fetch_page()正常,extract_links()脆弱(遗漏相对URL) - 跨领域:无错误处理 — 一个坏页面会终止整个批次
- 过去的编辑:无(第一个周期)
- 计划:[高] 在
parse_html()中添加后备选择器,用于没有<article>的页面
周期1 — 变异: 添加级联选择器逻辑:尝试<article>,回退到<main>,再回退到<body>。
周期1 — 验证: 运行无崩溃。
周期1 — 评分: 通过率 40% → 72%。差异:+32%。
周期1 — 归档: 学到的:“大多数失败是选择器未命中,而非逻辑错误。后备链具有高价值。”
周期2 — 分析:
- 教训:后备选择器带来+32%。原则:在修复逻辑之前处理结构变化。
- 组件评估:
parse_html()现在正常。extract_links()仍然脆弱 — 相对URL未解析。 - 计划:[高] 在
extract_links()中使用urljoin解析相对URL
周期2 — 变异: 添加基础URL解析。
周期2 — 评分: 72% → 88%。差异:+16%。
周期2 — 归档: 学到的:“URL解析是第二大失败模式。始终在提取时规范化URL。”
关键原则
- 每个变更必须链接到一个观察结果 — 无推测性修复
- 每个周期最多3个变更 — 准确归因改进
- 记录一切 — 失败的尝试与成功的尝试同样有价值
- 相对于父变体评分,而不仅仅是基线 — 跟踪边际改进
- 卡住时探索 — 如果同一组件上连续2+个周期显示收益递减,则转移到不同组件
- 3次重试失败后恢复 — 不要陷入困境;记录失败并尝试不同方法
- 原则会累积 — 演进日志中的
principles_learned列表是最有价值的产物;它编码了针对此特定代码库有效的方法