用自然语言反思,而不是暴力调参:GEPA 如何让大模型少跑 35 倍数据就学得更好

如果你只想知道结论:把每一次实验轨迹变成一段“读后感”,再让模型像遗传算法一样交叉、变异,就能在 4 个任务上平均提升 10–20%,同时把训练采样量压到原来的 1/35。下文会逐步拆解背后的原理、实验与落地步骤。


目录

  1. 背景:为什么传统 RL 越来越贵
  2. 核心问题:语言本身就是信号
  3. GEPA 三步曲:遗传 + 反思 + 帕累托
  4. 实验速览:4 个任务、2 个模型、3 个基线
  5. 深度 FAQ:你可能想问的 10 件事
  6. 快速上手:把 GEPA 装进自己的系统
  7. 小结与展望

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 遗传:把提示当成“基因”

  • 初始种群:每个模块给一条最简单的提示。
  • 变异算子

    1. Reflective Prompt Mutation——用 LLM 读轨迹、写批评、再重写提示。
    2. 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
GEPA 2 600
最短案例 2 000

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 帮你用更少的样本、更短的提示,做更聪明的优化