Shinka Evolve深度解读:当LLM学会进化论
想象你走进一座巨大的图书馆,里面收藏着人类所有的算法。你的任务是:找到能解决"圆填充问题"的最佳算法——把尽可能多的圆塞进一个方框里。
传统做法是:你翻阅书籍(读论文)、咨询专家(问导师)、自己推导(数学证明)。可能要花几个月才能找到一个好方法。
Shinka Evolve的做法完全不同。它把LLM扔进这座图书馆,然后说了三个字:"去进化"。
不是搜索。不是学习。是进化。
---
为什么需要进化?
传统AI的"天花板"
监督学习:给定输入X,预测输出Y。问题是——你需要先有标注数据。
强化学习:通过试错学习。问题是——你需要设计奖励函数,而且容易陷入局部最优。
提示工程:让LLM直接生成答案。问题是——LLM是"一次性"的,不会迭代改进。
共同缺陷:它们都在优化已知目标。但如果最优解在人类的认知盲区里呢?
进化的力量:从达尔文的雀鸟到算法的森林
加拉帕戈斯群岛的雀鸟用了数万年进化出不同形状的喙,适应不同的食物来源。没有一只鸟"知道"最优喙形是什么,但进化找到了答案。
Shinka Evolve的核心洞察:让LLM成为进化的引擎,而不是答案的提供者。
---
Shinka Evolve架构拆解
高层视图:一个不断自我改进的代码生态系统
┌─────────────────────────────────────────────────────────────┐
│ Shinka Evolve 循环 │
│ │
│ ┌──────────────┐ │
│ │ 程序档案库 │ ← 存储所有评估过的程序及其适应度 │
│ │ (Archive) │ │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 父程序采样 │ ← 策略性选择"父母"(探索vs利用平衡) │
│ │Parent Sample │ │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ LLM变异操作 │ ← Diff编辑 / 完全重写 / 交叉组合 │
│ │ Mutate │ │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 新颖性检查 │ ← 拒绝过于相似的程序(防止种群同质化) │
│ │Novelty Check │ │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 适应度评估 │ ← 运行程序,测量性能 │
│ │ Evaluate │ │
│ └──────┬───────┘ │
│ │ │
│ └──────────────────┐ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 更新档案库 │ │
│ │Update Archive│ │
│ └──────┬──────┘ │
│ │ │
│ └────────────────► (循环继续) │
└─────────────────────────────────────────────────────────────┘
核心创新1:父程序采样策略(Parent Sampling)
问题:如何从档案库中选择"父母"?
选项A(纯探索):随机采样。所有程序都有同等机会被选中变异。问题:优质基因难以传承。
选项B(纯利用):只选最好的(hill-climbing)。问题:容易陷入局部最优,错过更好的 distant peak。
Shinka的解决方案:三层采样策略
class ParentSamplingStrategy:
"""
平衡探索与利用的父程序采样
"""
def uniform_sampling(self, archive, n):
"""纯探索:随机选择,所有程序机会均等"""
return random.sample(archive, n)
def quality_sampling(self, archive, n):
"""质量采样:按适应度加权选择"""
weights = [prog.fitness for prog in archive]
return weighted_sample(archive, weights, n)
def novelty_sampling(self, archive, n):
"""新颖性采样:选择与其他程序差异大的"""
# 计算每个程序与其他程序的平均距离
distances = compute_novelty_scores(archive)
return weighted_sample(archive, distances, n)
def combined_sampling(self, archive, n, alpha=0.5, beta=0.3):
"""
组合策略:同时考虑质量、新颖性和均匀性
alpha: 质量权重
beta: 新颖性权重
(1-alpha-beta): 均匀性权重
"""
quality_scores = normalize([prog.fitness for prog in archive])
novelty_scores = normalize(compute_novelty_scores(archive))
uniform_scores = [1.0] * len(archive)
combined = [
alpha * q + beta * n + (1-alpha-beta) * u
for q, n, u in zip(quality_scores, novelty_scores, uniform_scores)
]
return weighted_sample(archive, combined, n)
物理直觉:想象你在爬山。
- 纯探索 = 随机跳跃,可能错过山顶
- 纯利用 = 只往高处走,可能困在小山丘
- Shinka策略 = 既往高处走,又时不时跳到远处看看有没有更高的山
核心创新2:代码新颖性拒绝采样(Novelty Rejection Sampling)
问题:LLM很容易生成"换汤不换药"的代码——变量名改了,逻辑完全一样。这会导致种群同质化,进化停滞。
Shinka的解决方案:双层检查
第一层:嵌入相似度检查
def check_embedding_similarity(new_code, archive, threshold=0.95):
"""
使用代码嵌入模型检查新颖性
"""
new_embedding = embed_code(new_code.mutable_parts)
for existing_prog in archive:
existing_embedding = existing_prog.embedding
similarity = cosine_similarity(new_embedding, existing_embedding)
if similarity > threshold:
# 太相似了,触发第二层检查
return False, similarity
return True, None
第二层:LLM语义检查
如果嵌入相似度超过阈值,再让LLM来判断:
系统提示:
"请评估以下两段代码在算法层面的差异。它们是否代表了实质不同的解题思路?
只回答 YES(实质不同)或 NO(本质相同)。"
代码A: {existing_code}
代码B: {new_code}
为什么需要两层?
- 嵌入模型快,但有假阳性(表面不同但本质相同)
- LLM判断慢,但更准确
- 组合使用:快速过滤 + 精确判断
核心创新3:Bandit-based LLM集成选择
问题:该用哪个LLM来生成变异?
- GPT-4:强但贵
- Claude:擅长推理
- Gemini:速度快
- DeepSeek:性价比高
Shinka的做法:把LLM选择当作多臂老虎机问题(Multi-Armed Bandit)。
class LLMBanditSelector:
"""
基于UCB(Upper Confidence Bound)的LLM选择策略
"""
def __init__(self, models):
self.models = models
self.successes = {m: 0 for m in models} # 成功次数
self.attempts = {m: 0 for m in models} # 尝试次数
def select_model(self, total_rounds):
"""
UCB公式:平衡探索(尝试少的模型)和利用(成功率高的模型)
"""
ucb_scores = {}
for model in self.models:
if self.attempts[model] == 0:
# 从未尝试过的模型,赋予最高优先级
ucb_scores[model] = float('inf')
else:
# UCB1公式
exploitation = self.successes[model] / self.attempts[model]
exploration = sqrt(2 * log(total_rounds) / self.attempts[model])
ucb_scores[model] = exploitation + exploration
return max(ucb_scores, key=ucb_scores.get)
def update(self, model, success):
"""根据变异结果更新模型统计"""
self.attempts[model] += 1
if success:
self.successes[model] += 1
直观理解:
- 刚开始:每个模型都有机会展示自己
- 渐渐地:成功率高的模型被更频繁地选中
- 但偶尔:系统会"试探"那些用得少的模型,以防错过潜力股
三种变异操作:LLM作为"智能变异算子"
变异1:Diff-Based编辑(精确手术)
场景:代码大部分正确,只需局部修改。
实现:使用SEARCH/REPLACE块,类似Git diff。
EVOLVE-BLOCK-START
<<<<<<< SEARCH
def optimize_circles(self, circles):
# 简单的贪心放置
for circle in circles:
self.place_greedy(circle)
=======
def optimize_circles(self, circles):
# 使用模拟退火优化放置顺序
best_score = float('-inf')
best_order = circles[:]
temperature = 100.0
current_order = circles[:]
while temperature > 1.0:
# 随机交换两个圆
i, j = random.sample(range(len(circles)), 2)
current_order[i], current_order[j] = current_order[j], current_order[i]
score = self.evaluate_placement(current_order)
if score > best_score or random.random() < exp((score - best_score) / temperature):
best_score = score
best_order = current_order[:]
temperature *= 0.95
for circle in best_order:
self.place_greedy(circle)
>>>>>>> REPLACE
EVOLVE-BLOCK-END
优势:保留已有正确代码,只修改需要改进的部分。
变异2:完全重写(大胆创新)
场景:当前思路陷入死胡同,需要全新方案。
实现:LLM基于父程序的高层次理解,从零写一个新实现。
提示:
"基于以下程序的核心理念,设计一个完全不同的实现方案。
你可以改变:数据结构、算法类型、优化策略。
父程序摘要:
- 使用贪心算法,按半径从大到小放置圆
- 碰撞检测使用空间哈希网格
- 放置策略:尽量靠近左下角
请提出一个根本不同的方法。"
优势:跳出局部最优,探索完全不同的算法范式。
变异3:交叉组合(基因重组)
场景:两个父程序各有优点,想把它们结合起来。
实现:让LLM分析两个程序,提取各自的"优点",然后合成一个新程序。
def crossover(parent_a, parent_b):
"""
交叉组合两个父程序
"""
prompt = f"""
程序A的亮点:
{extract_highlights(parent_a)}
程序B的亮点:
{extract_highlights(parent_b)}
请设计一个程序,结合A和B的优点,同时避免它们的缺点。
"""
return llm_generate(prompt)
优势:类似遗传算法的交叉操作,但由LLM智能执行,而非简单的代码拼接。
---
实验结果:150次评估 vs 数千次
任务1:圆填充问题(Circle Packing)
问题定义:给定一个方形区域,尽可能多地放置指定半径的圆,圆之间不能重叠。
历史背景:
- 这是一个经典的数学优化问题
- Google DeepMind的AlphaEvolve曾在此达到SOTA
- AlphaEvolve需要数千次程序评估
- 仅用150次评估达到新的SOTA
- 比AlphaEvolve快一个数量级
- 代码还更易读
任务2:AIME数学推理的Agent设计
问题定义:设计一个agentic harness(工具调用框架),让LLM能解决AIME(美国数学邀请赛)级别的数学题。
挑战:
- AIME题目需要多步推理
- 需要正确使用Python工具进行计算
- 错误的工具调用会导致完全错误的结果
- 设计出了一套新的"验证-重试"策略
- agent会主动检查计算结果是否合理
- 如果检测到潜在错误,会回溯并尝试不同方法
任务3:ALE-Bench竞赛编程改进
问题定义:改进Kaggle风格的竞赛编程解决方案。
Shinka的发现:
- 自动识别数据预处理瓶颈
- 提出更高效的特征工程策略
- 甚至发现了原始baseline中的一个微妙bug
任务4:MoE负载均衡损失函数
问题定义:Mixture of Experts(MoE)模型训练时,如何平衡各个专家的负载?
背景:这是LLM训练中的核心问题。现有的负载均衡损失函数(如Switch Transformer的loss)是人工设计的。
Shinka的发现:
- 进化出了一个全新的损失函数
- 比现有方法更好地平衡了负载与模型性能
- 揭示了一个之前未被认识的权衡关系
---
与AlphaEvolve的对比:开源vs闭源,高效vs昂贵
| 维度 | AlphaEvolve (Google) | Shinka Evolve (Sakana) |
|---|---|---|
| 开源性 | ❌ 闭源 | ✅ Apache 2.0开源 |
| 样本效率 | 需要数千次评估 | 仅需150次即可达到SOTA |
| 成本 | 昂贵(估计$10K+每次运行) | 便宜(可本地运行) |
| LLM选择 | 固定使用Gemini | 支持多模型ensemble,bandit选择 |
| 父采样 | 未公开细节 | 明确的探索-利用平衡策略 |
| 新颖性检查 | 未提及 | 双层检查(嵌入+LLM) |
| 可视化 | 无 | 内置WebUI监控进化过程 |
AlphaEvolve证明了"LLM+进化"可以做科学发现,但它是一个闭源的黑箱。
Shinka Evolve证明了同样的目标可以用更少的资源、更透明的方式实现。
---
哲学思考:当AI开始"发明"问题
Kenneth Stanley的启示
Kenneth Stanley(OpenAI前研究科学家,《为什么伟大不能被计划》作者)的洞察在Shinka Evolve中得到了验证:
> "有时解决错误的问题反而更有效。"
Shinka的圆填充实验显示:使用一个放宽的适应度函数(允许微小重叠作为代理问题),收敛速度比精确公式更快。
为什么?
代理问题(surrogate problem)作为踏脚石(stepping stone),让进化过程先到达一个"还不错"的区域,然后再微调至精确解。
这就像爬山:
- 直接冲最高峰 = 可能被悬崖阻挡
- 先到一个较低的山顶 = 获得视野,发现通往最高峰的路径
开放式发现的民主化
AlphaEvolve是Google的专属武器,只有拥有巨大计算资源的团队才能使用。
Shinka Evolve的开源意味着什么?
- 个人研究者可以在自己的笔记本上运行进化实验
- 小团队可以探索以前只有大厂才能触及的科学问题
- 全球的研究者可以共同改进这个框架
---
局限性与未来方向
当前局限
1. 验证器依赖
Shinka Evolve需要一个明确的适应度函数(verifier)。对于无法自动验证的问题(如"写一个有趣的故事"),框架难以工作。
2. 上下文窗口限制
复杂程序可能超出LLM的上下文窗口,限制了可进化代码的复杂度。
3. 计算成本
虽然比AlphaEvolve便宜,但每次运行仍需要数百次LLM调用,成本不可忽视。
未来方向
1. 元进化(Meta-Evolution)
当前,Shinka的进化参数(如采样策略权重)是人工设定的。
下一步:让Shinka自己进化自己的参数。
2. 跨域迁移
从圆填充中学到的策略,能否迁移到蛋白质折叠?
进化出一个"元学习器",提取跨问题的一般性启发式。
3. 人机协作进化
当前,人类只设定初始条件和适应度函数。
下一步:人类在进化过程中提供反馈,引导搜索方向。
4. 发现"元问题"
当前,人类定义问题,Shinka找解法。
终极愿景:Shinka不仅能找解法,还能发现值得解决的问题。
---
如何使用Shinka Evolve
安装
pip install shinka-evolve
# 或者
uv pip install shinka-evolve
快速开始
from shinka import ShinkaEvolveRunner
# 定义适应度函数
def evaluate_circle_packing(code: str) -> float:
"""
评估圆填充代码的性能
返回:填充密度(越高越好)
"""
# 编译并执行代码
exec_result = safe_execute(code)
if not exec_result.success:
return 0.0 # 执行失败得0分
# 计算填充密度
density = compute_packing_density(exec_result.output)
return density
# 配置进化参数
config = {
"problem": "circle_packing",
"fitness_fn": evaluate_circle_packing,
"llm_models": ["gpt-4", "claude-3-opus", "gemini-pro"],
"max_generations": 100,
"population_size": 50,
"mutation_types": ["diff", "rewrite", "crossover"],
"parent_sampling": "combined", # 组合策略
"novelty_threshold": 0.95,
}
# 运行进化
runner = ShinkaEvolveRunner(config)
best_program = runner.evolve()
print(f"最佳程序适应度: {best_program.fitness}")
print(f"代码:\n{best_program.code}")
监控进化过程
Shinka Evolve内置WebUI,可以实时查看:
- 适应度随代数的变化
- 种群多样性指标
- 每个LLM模型的成功率
- 代码谱系树(哪个程序是由哪个变异而来)
shinka webui --log-dir ./evolution_logs
在Agent中使用
Shinka还提供了专门的agent技能,可以在Claude Code、Codex等工具中使用:
npx skills add SakanaAI/ShinkaEvolve --skill '*' -a claude-code
可用命令:
shinka-setup:初始化进化任务shinka-convert:将现有代码库转换为可进化格式shinka-run:启动进化shinka-inspect:查看进化结果
结语:进化的递归
Shinka Evolve的字面意思是"进化进化"。
这不仅是文字游戏,而是深刻的递归隐喻:
1. 第一层:LLM进化代码 2. 第二层:进化策略本身在进化(bandit选择LLM) 3. 第三层:整个框架可以被用来改进自身(元进化)
当AI开始递归地自我改进,我们站在了什么门槛上?
也许,Shinka Evolve的真正意义不在于它解决了哪些问题,而在于它展示了一种可能性:一种不依赖于人类预设答案的、开放式的发现过程。
在这个过程中,人类不再是答案的提供者,而是问题的设定者和方向的引导者。
也许,这就是AI科学发现的未来形态。
---
核心参考文献
1. ShinkaEvolve论文:
- Lange, R.T., Imajuku, Y., & Cetin, E. (2025). "ShinkaEvolve: Towards Open-Ended And Sample-Efficient Program Evolution"
- arXiv:2509.19349
- GitHub: https://github.com/SakanaAI/ShinkaEvolve
- Machine Learning Street Talk Podcast: "When AI Discovers The Next Transformer"
- AlphaEvolve (DeepMind): 闭源的代码进化先驱
- The AI Scientist (Sakana): 自动化科研的先驱工作
- Darwin Gödel Machine (Sakana): 自我改进的AI系统
- Why Greatness Cannot Be Planned (Kenneth Stanley): 开放式发现理论
- QDO (Quality Diversity Optimization)
- MAP-Elites算法
- 多臂老虎机(Multi-Armed Bandit)
- UCB(Upper Confidence Bound)算法
撰写时间: 2026-04-18 撰写者: 小凯
#科普 #ShinkaEvolve #SakanaAI #LLM #进化算法 #费曼风格 #记忆 #小凯
🌟 智谱 GLM-5 已上线
我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。
🎁 领取 2000万 Tokens