用自然语言反思,而不是暴力调参:GEPA 如何让大模型少跑 35 倍数据就学得更好
如果你只想知道结论:把每一次实验轨迹变成一段“读后感”,再让模型像遗传算法一样交叉、变异,就能在 4 个任务上平均提升 10–20%,同时把训练采样量压到原来的 1/35。下文会逐步拆解背后的原理、实验与落地步骤。
目录
-
背景:为什么传统 RL 越来越贵 -
核心问题:语言本身就是信号 -
GEPA 三步曲:遗传 + 反思 + 帕累托 -
实验速览:4 个任务、2 个模型、3 个基线 -
深度 FAQ:你可能想问的 10 件事 -
快速上手:把 GEPA 装进自己的系统 -
小结与展望
1. 背景:为什么传统 RL 越来越贵
方法 | 采样量(rollouts) | 典型瓶颈 |
---|---|---|
GRPO + LoRA | ~24 000 | GPU 时间、调用外部工具费用 |
Few-shot 优化 | 数千 | 提示长度、token 成本 |
-
痛点:一次完整训练动辄上万次 rollout,如果系统里还调用了检索、代码执行或第三方 API,账单会迅速失控。 -
观察:哪怕是最先进的系统,跑出来的日志无非是一段段自然语言——指令、推理链、工具返回、报错信息。人类研究员能看懂,大模型当然也能看懂。
2. 核心问题:语言本身就是信号
传统 RL 把成功/失败压成了一个 0–1 奖励,GEPA 的做法是“保留完整文本轨迹,让大模型写读后感”,再把读后感翻译成下一次提示的改进方向。
传统 RL 信号 | GEPA 信号 |
---|---|
reward = 0.7 | “第二跳查询把年份写错,导致召回为 0,下次加年份校验” |
这种信号密度高、可解释,还天然附带“解释 + 修复建议”,于是学得更快。
3. GEPA 三步曲:遗传 + 反思 + 帕累托
3.1 遗传:把提示当成“基因”
-
初始种群:每个模块给一条最简单的提示。 -
变异算子: -
Reflective Prompt Mutation——用 LLM 读轨迹、写批评、再重写提示。 -
System-aware Merge——把两条不同进化路线的提示“拼”成一条,取各自表现最好的模块版本。
-
3.2 反思:用 LLM 做 credit assignment
【系统轨迹】
问题:谁是第二任佛罗伦萨公爵的曾祖父?
查询 1:佛罗伦萨公爵列表 → 返回 Cosimo I
查询 2:Cosimo I 家谱 → 返回 Giovanni di Bicci de' Medici
最终答案:Giovanni di Bicci de' Medici
【LLM 读后感】
- 查询 1 成功识别 Cosimo I,但查询 2 直接跳到曾祖父,中间跳了一代,需要补充“祖父”这一跳。
- 修复:提示里加“如果摘要提到直系祖先,请再向上追溯两代”。
3.3 帕累托:不追单点最优,而是保留“每题最高分”
-
记录每个训练样本的当前最高分。 -
只从“拿过单科第一”的提示里随机挑父代,防止过早陷入局部最优。
4. 实验速览:4 个任务、2 个模型、3 个基线
任务 | 简介 | 数据集规模(训练/验证/测试) |
---|---|---|
HotpotQA | 多跳问答 | 150 / 300 / 300 |
IFBench | 细粒度指令遵循 | 150 / 300 / 294 |
HoVer | 多文档事实验证 | 150 / 300 / 300 |
PUPA | 隐私感知的请求改写 | 111 / 111 / 221 |
4.1 结果总表(Aggregate Score)
模型 | 基线 | MIPROv2 | GRPO 24k | GEPA | GEPA+Merge |
---|---|---|---|---|---|
Qwen3-8B | 48.9 | 55.1 | 51.1 | 61.3 | 57.6 |
GPT-4.1 mini | 52.7 | 59.7 | — | 67.0 | 68.7 |
-
↑10–20% 相对 GRPO,↓35× 采样量。 -
↑6–7% 相对 MIPROv2,且提示长度缩短 3–9 倍。
4.2 成本与长度对比
优化器 | 平均提示 token | 相对缩短 |
---|---|---|
MIPROv2 | 7 500 | 1× |
GEPA | 2 600 | 3× |
最短案例 | 2 000 | 9× |
5. 深度 FAQ:你可能想问的 10 件事
Q1:GEPA 只能改提示,不能改权重,会不会天花板很低?
A:在数据稀缺或调用昂贵的场景里,提示优化往往比全参微调更划算。论文也指出,当数据量极大时,权重微调仍可能反超——两者是互补而非替代。
Q2:每次变异都要调一次大模型写“读后感”,会不会反而更贵?
A:实验里写“读后感”用的是同尺寸 LLM,成本远低于一次完整 rollout。且因为信号密度高,通常 <100 次训练样本 就能收敛。
Q3:我怎么把 GEPA 塞进已有系统?
A:把现有提示当“种子”,按论文伪代码实现遗传循环即可。下面给出最小可运行示例(Python-like 伪代码):
# 1. 定义系统调用
def run_system(prompt_dict, task_input):
# 返回轨迹 trace 和得分 score
...
# 2. 初始化
pool = [{'prompts': init_prompts, 'parent': None}]
# 3. 主循环
for budget in range(MAX_ROLLOUTS):
parent = select_pareto(pool) # 算法 2
child = reflective_mutate(parent) # 章节 3.2
if child_score > parent_score:
pool.append(child)
Q4:提示越改越长怎么办?
A:GEPA 的“读后感”里会主动删减无效指令,实验结果反而是提示越来越短(图 15)。
Q5:可以优化 few-shot 示例吗?
A:目前版本只动指令,不动示例。论文把示例优化列为未来工作,但指出指令优化已能取得更强泛化。
Q6:系统里有多模块怎么办?
A:把每个模块的提示当成独立基因,交叉时按模块粒度互换即可(附录 F 的 Merge 算法)。
Q7:会不会陷入“提示过拟合”?
A:帕累托采样 + minibatch 验证正是为了防过拟合;实验显示验证-测试差距与 MIPROv2 持平或更小(图 14)。
Q8:能否在推理阶段继续进化?
A:可以。把待解决问题当训练集,让 GEPA 在推理时“过拟合”这批任务即可。第 6 章展示了在 NPUEval、KernelBench 上的实时搜索效果。
Q9:用闭源 API 会不会泄露隐私?
A:PUPA 任务专门测试了“隐私-性能”平衡,GEPA 生成的隐私改写策略在 94+ 分的同时零泄露(图 13)。
Q10:代码在哪里?
A:论文为 pre-print,官方仓库尚未放出,但算法 1–4 已给出完整伪代码,复现难度不高。
6. 快速上手:把 GEPA 装进自己的系统
6.1 环境准备
-
Python ≥ 3.9 -
OpenAI API key(或本地同尺寸开源模型) -
任务评估脚本(HotpotQA、IFBench 等官方 repo 均可下载)
6.2 三步走
步骤 | 动作 | 关键参数 |
---|---|---|
① 准备种子提示 | 用 1–2 句话描述模块职责 | 越简单越好 |
② 实现 feedback 函数 | 把系统输出转成自然语言批评 | 附参考实现片段 |
③ 启动遗传循环 | 每轮 3–10 个样本做 minibatch | 预算用 MIPROv2 的 1/10 即可 |
参考代码片段(以 HotpotQA 第二跳查询为例):
def feedback_fn(trace, gold):
if not gold['docs'] <= set(trace['retrieved']):
return "第二跳查询没召回缺失文档,请把问题拆解为实体+关系再检索"
return "召回正确,无需修改"
7. 小结与展望
-
GEPA 的核心启发:语言模型不仅能做任务,还能读日志、写改进方案、再自我升级。 -
成本收益:在昂贵 rollout 场景下,把“暴力采样”换成“读后感式反思”,可节省 90% 以上的调用量。 -
下一步:把提示进化与权重微调混合,或让系统在推理时持续改写自身提示,都值得探索。
如果你正在维护一个需要频繁调用外部工具的多模块 AI 系统,而又被训练成本困扰,不妨让 GEPA 帮你用更少的样本、更短的提示,做更聪明的优化。