DeepEval 如何用 GEPA 运行提示词优化并解读 optimization_report
【免费下载链接】deepevalThe LLM Evaluation Framework项目地址: https://gitcode.com/GitHub_Trending/de/deepeval
如果你有几十个 golden 用例,但不确定当前 prompt 模板该往哪个方向改,DeepEval(The LLM Evaluation Framework)里的PromptOptimizer可以用 GEPA 算法自动完成这件事:你提供 prompt、golden 列表、评分指标和一个调用你 LLM 应用的model_callback,它会自动搜索得分更高的 prompt,并返回优化结果和一份optimization_report。本文基于 Prompt Optimization Introduction 和 GEPA 算法页/prompt-optimization-gepa.mdx),给出一条可以直接照做的执行路径,以及 report 各字段的读法。
准备条件:Prompt、Golden 与 model_callback
在跑优化之前,先确认三类东西齐了:
- Prompt:
deepeval.prompt.Prompt实例,包含 prompt 模板(text_template)。 - Goldens:一组
Golden或ConversationalGolden实例,作为优化的对照数据。 - model_callback:包住你 LLM 应用的回调。优化过程中
deepeval会把当前候选Prompt和一条Golden传进来,你用prompt.interpolate(input=golden.input)把 golden 的输入填进模板,再调用你的应用,必须返回str——这个字符串会作为 test case 的actual_output交给 metrics 打分。
from deepeval.dataset import Golden from deepeval.metrics import AnswerRelevancyMetric from deepeval.prompt import Prompt from deepeval.optimizer import PromptOptimizer # 你要优化的 prompt prompt = Prompt(text_template="Respond to the query.") # 包住你的 LLM 应用 async def model_callback(prompt: Prompt, golden: Golden) -> str: interpolated_prompt = prompt.interpolate(input=golden.input) res = await YourApp(interpolated_prompt) # 按你应用的实际调用方式 return res optimizer = PromptOptimizer(metrics=[AnswerRelevancyMetric()], model_callback=model_callback)两个必填参数是metrics(用于打分和反馈的 deepeval 指标列表)和model_callback。可选参数包括algorithm(默认就是GEPA())、async_config、display_config、mutation_config。
执行步骤:用 GEPA 运行一次优化
GEPA 是PromptOptimizer的默认算法(algorithm默认值为GEPA()),所以不传algorithm就已经在用 GEPA。只有想调整它的行为时才需要显式构造:
optimized_prompt = optimizer.optimize( prompt=prompt, goldens=[ Golden(input="What is Saturn?", expected_output="Saturn is a car brand."), Golden(input="What is Mercury?", expected_output="Mercury is a planet."), ], ) # 查看优化结果 print("Optimized prompt:", optimized_prompt.text_template) print("Optimization report:", optimizer.optimization_report)optimize()有两个必填参数:prompt和goldens。注意metrics是在构造PromptOptimizer时传入的(见 PromptOptimizer 源码),GEPA 页面示例里把metrics写在optimize()调用参数里的写法与当前源码签名不一致,以构造函数传参为准。
在 Python 环境中执行:
python main.pyoptimize()返回最优Prompt。如果想并发运行而不阻塞主线程,文档提供了异步入口a_optimize():在 async 函数里await optimizer.a_optimize(...),再用asyncio.run驱动。
可选:自定义 GEPA 参数
需要控制搜索行为时,构造GEPA实例并传给algorithm:
from deepeval.optimizer.algorithms import GEPA gepa = GEPA( iterations=10, pareto_size=5, minibatch_size=4, patience=4, random_seed=42, ) optimizer = PromptOptimizer(algorithm=gepa, metrics=[...], model_callback=model_callback)文档列出的可选参数及默认值:
| 参数 | 默认值 | 文档说明 |
|---|---|---|
iterations | 5 | 变异尝试总次数 |
pareto_size | 3 | 验证集D_pareto中的 golden 数,每个候选都会在这批 golden 上评分以保证公平比较 |
minibatch_size | 8 | 每次迭代从D_feedback抽取的 golden 数,自动按可用数据截断 |
patience | 3 | 连续拒绝该次数子代后提前停止 |
random_seed | time.time_ns() | 控制 golden 切分、minibatch 抽样、Pareto 父代选择与平局判定;固定如42才能复现 |
tie_breaker | PREFER_CHILD | 平局策略,另有PREFER_ROOT、RANDOM |
aggregate_instances | mean_of_all | 把单个 prompt 的 per-golden Pareto 分数聚合成标量 |
reflection_model | "gpt-4o-mini" | 生成诊断/反馈的 LLM |
mutation_model | "gpt-4o" | 重写 prompt 的 LLM |
scorer | — | 自定义 scorer,通常由PromptOptimizer注入 |
默认random_seed是time.time_ns(),即不固定种子时每次运行结果都会不同;需要可复现的运行就固定random_seed。
可选:限流配置
如果你的评测模型或 LLM 应用会触发 rate limit,给PromptOptimizer传AsyncConfig:
from deepeval.optimizer.configs import AsyncConfig optimizer = PromptOptimizer( metrics=[AnswerRelevancyMetric()], model_callback=model_callback, async_config=AsyncConfig(throttle_value=2, max_concurrent=5), )throttle_value(每个 test case 的节流秒数,默认 0)和max_concurrent(并行 test case 数上限,默认 20)只在run_async为True(默认)时生效。降低max_concurrent、调高throttle_value是文档推荐的限流手段。
GEPA 做了什么:理解 report 之前先懂流程
GEPA(Genetic-Pareto)不是收敛到单个“最好”的 prompt,而是维护一个多样化候选池,流程分五步:
- Golden 切分:把 goldens 切成互不相交的两部分——固定的验证集
D_pareto(大小pareto_size)和反馈集D_feedback。prompt 基于D_feedback的反馈变异,但按D_pareto上的表现挑选,避免过拟合。 - Pareto 父代选择:一个 prompt 若在
D_pareto上所有 golden 都不劣、至少一个更优,就“支配”另一个 prompt;不被任何 prompt 支配的构成 Pareto 前沿。父代按各 prompt“赢得最高分”的频率加权抽样,而不是总是选平均分最高的。 - 反馈与重写:从
D_feedback抽一个 minibatch,收集诊断反馈,基线打分,再用 rewriter 生成子代 prompt。 - 双门验收:子代必须先在同一个 minibatch 上严格超过父代(minibatch gate),再在
D_pareto上相对父代和存档内所有配置都非支配(Pareto gate)。被拒会累加连续拒绝计数,达到patience就提前结束。 - 终选:按聚合分数(默认均值)排名,平局由
tie_breaker决定,返回获胜 prompt。
结果验证与解读 optimization_report
优化跑完后,验证路径有两条:
- 拿到新 prompt:
optimized_prompt.text_template(LIST 风格 prompt 是messages_template)就是可以直接替换线上模板的结果;DisplayConfig.show_indicator默认为True,控制台还会打印算法生成的 summary 表格。 - 读
optimization_report:它挂在PromptOptimizer实例上(优化结束后赋值,见 prompt_optimizer.py):
print(optimizer.optimization_report) print(optimizer.optimization_report.optimization_id)report 共暴露六个顶层字段(定义见 gepa.py 中 report 的组装):
| 字段 | 类型 | 怎么解读 |
|---|---|---|
optimization_id | str | 本次运行的唯一标识,文档建议在多数工作流中把它记录进日志,方便回溯 |
best_id | str | 最终获胜 prompt 配置的内部 id |
accepted_iterations | List[AcceptedIteration] | 每个被接受的子代一条记录:parent/child的 id、moduleid,以及标量化的before/after分数——这是判断“哪一步改进有效”的直接依据 |
pareto_scores | Dict[str, List[float]] | 每个配置 id 到D_pareto上逐 golden 分数列表的映射,即 GEPA 维持 Pareto 前沿所用的分数表 |
parents | Dict[str, Optional[str]] | 每个配置 id 到其父 id 的映射,根配置对应None,构成所有被探索变体的祖先树 |
prompt_configurations | Dict[str, PromptConfigSnapshot] | 每个配置 id 到该节点 prompt 快照的映射,含父 id 和逐模块的 TEXT/LIST prompt 内容 |
实际读法:大多数时候直接取optimized_prompt.text_template并使用即可。需要深入时,用best_id在prompt_configurations里找到获胜节点的完整 prompt 文本;用parents沿祖先链回溯它的演化路径;用accepted_iterations里各条记录的before/after确认每一步被接受时分数确实提升了;pareto_scores则告诉你获胜 prompt 是在哪些 golden 上强、哪些上弱。文档明确说这些字段适合“重建搜索树、可视化 prompt 跨迭代演化、调试某个配置为何被选为best_id”这类场景。
早停与其他运行现象
- 若某轮子代被 Pareto gate 拒绝,会累计连续拒绝计数;计数达到
patience(默认 3)时搜索提前停止,不会跑满全部iterations(默认 5)。运行中如果看到类似early stop (patience=3)的状态说明,即触发了这条路径。 DisplayConfig.announce_ties默认为False;设为True后,GEPA 检测到配置间平局时会打印一行提示。- 优化开始前如果发生错误(如
model_callback内部抛错),PromptOptimizer会以DeepEvalError中断并在状态行给出[GEPA] ... halted形式的信息(见 错误处理逻辑),此时检查你的 callback 是否正确调用了 LLM 应用并返回字符串。
限制与注意事项
- 文档只覆盖了
PromptOptimizer的 Python 用法,未提供命令行或离线批处理入口,主路径就是上述脚本形式。 - 两个 LLM 分工不同:
reflection_model(默认gpt-4o-mini)负责诊断,mutation_model(默认gpt-4o)负责重写,两者都可以在GEPA(...)构造时覆盖。 - goldens 会被切成
D_pareto和D_feedback两份互斥集合,minibatch_size超出D_feedback可用量时会自动截断;因此 golden 数量太少时反馈信号会受限。 a_optimize()与optimize()是同步/异步两种入口,二选一即可,不要在同步上下文里嵌套再调asyncio.run。
跑通一次后,optimized_prompt与optimization_report就是本次任务的完整产出:前者用于替换模板,后者(尤其optimization_id、best_id、accepted_iterations)用于归档和复盘这次搜索为什么收敛到该 prompt。
【免费下载链接】deepevalThe LLM Evaluation Framework项目地址: https://gitcode.com/GitHub_Trending/de/deepeval
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考