ADK-Python 如何用 AgentOptimizer 与 LocalEvalSampler 基于评估集自动优化 Agent instruction

发布时间:2026/9/14 15:35:00
ADK-Python 如何用 AgentOptimizer 与 LocalEvalSampler 基于评估集自动优化 Agent instruction ADK-Python 如何用 AgentOptimizer 与 LocalEvalSampler 基于评估集自动优化 Agent instruction【免费下载链接】adk-pythonAn open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-python你手上已经有一个能跑的 ADK agent 和一套评估集但不想再靠手感逐句修改 instruction这时 ADK-Python 的google.adk.optimization提供了一条离线优化路径优化器提出新的 instructionLocalEvalSampler把候选 agent 在你的评估集上跑一遍打分分数高的胜出。这是一次离线批量任务不在请求时运行它的产出是一个内存中的Agent对象赢家的 instruction 需要手工复制回你的源码。两个组成部分AgentOptimizer 与 Samplergoogle.adk.optimization分成在同一个接口上会合的两半AgentOptimizer是搜索决定试哪些 prompt、按什么顺序、何时停止。自带两个实现SimplePromptOptimizer一次一个 prompt 爬山GEPARootAgentOptimizer封装 GEPA 算法返回一组 Pareto front 上的 prompt 而不是单个赢家。Sampler是打分回答“存在哪些样例”和“这个候选 agent 在上面表现如何”。LocalEvalSampler在 ADK 自己的 eval set 之上实现了它你也可以对接自己已有的任何打分方式。google/adk/optimization/__init__.py不做 re-export所有导入都按模块路径写from google.adk.optimization.data_types import AgentWithScores from google.adk.optimization.data_types import OptimizerResult from google.adk.optimization.data_types import UnstructuredSamplingResult from google.adk.optimization.local_eval_sampler import LocalEvalSampler from google.adk.optimization.local_eval_sampler import LocalEvalSamplerConfig from google.adk.optimization.simple_prompt_optimizer import SimplePromptOptimizer from google.adk.optimization.simple_prompt_optimizer import SimplePromptOptimizerConfig分数约定只有一个float越大越好数值范围由你自己定优化器只是拿你自己的两个数字互相比大小。准备依赖与前置条件安装 eval extra。导入local_eval_sampler会拉进整个 eval 栈pip install google-adk[eval]没装它时导入会直接失败报ModuleNotFoundError: No module named vertexai。模型凭据与配额。即使你计划用的指标全是确定性的凭据和配额也是必需的——因为产出被打分的那份输出本身就是一次模型调用。每一次打分都是一次完整的 agent 运行成本是真实的。现成的评估集。LocalEvalSampler指向已存在的 eval set。用LocalEvalSetsManager(agents_dir...)从 agents 目录读取*.evalset.json文件布局为agents_dir/app_name/eval_set_id.evalset.json。你还需要一个EvalConfig声明这次运行用哪些指标、阈值多少下面第 1 步处理。如果你还没有评估集LocalEvalService 指南展示了用InMemoryEvalSetsManager在 Python 里构造案例的接口create_eval_setadd_eval_case案例是EvalCase(eval_id..., conversation[...])conversation里是若干Invocation含user_content、final_response、intermediate_data.tool_uses。该指南里的示例值给set_light下发{room: bedroom, on: False}的关灯案例只是示例。要落盘给LocalEvalSetsManager读就用它构造一个 managereval set 文件会写到agents_dir/app_name/eval_set_id.evalset.json。第 1 步准备 EvalConfigEvalConfig回答“这个运行按什么方式打分、离目标多近算够”。它也是 eval config 文件解析出来的同一个对象所以你在评估流程里已经调好的指标在这里同样决定“更好”的含义。最小可用配置from google.adk.evaluation.eval_config import EvalConfig eval_config EvalConfig(criteria{ tool_trajectory_avg_score: 1.0, response_match_score: 0.6, })裸数字是阈值简写指标在所有运行上的平均分大于等于阈值时通过。指标的键可以写snake_case或camelCase任何层级都成立。指标带可选项时要写对象形式threshold必填例如{threshold: 1.0, match_type: IN_ORDER}。一个容易踩的点在adk eval/AgentEvaluator路径上如果找不到配置文件评估不会失败而是静默回退到内置默认tool_trajectory_avg_score1.0 response_match_score0.8只打一行信息日志。而LocalEvalSamplerConfig.eval_config是必填字段Python 路径必须显式给出不存在回退。13 个内置指标、criterion 类型和自定义指标的完整写法见 EvalConfig 指南。第 2 步构建 LocalEvalSamplerfrom google.adk.evaluation.local_eval_sets_manager import LocalEvalSetsManager from google.adk.optimization.local_eval_sampler import LocalEvalSampler from google.adk.optimization.local_eval_sampler import LocalEvalSamplerConfig # agents 目录包含 app_name/eval_set_id.evalset.json 的目录 eval_sets_manager LocalEvalSetsManager(agents_dir./agents) sampler LocalEvalSampler( LocalEvalSamplerConfig( eval_configeval_config, app_namemy_app, train_eval_settrain_set, validation_eval_setholdout_set, ), eval_sets_managereval_sets_manager, )字段说明app_name与train_eval_set必须指向真实存在的 eval set。LocalEvalSampler在构造时就解析该集合的 eval case ID集合不存在会直接抛ValueError: Eval set \... does not exist for app ...。单独给一个验证集。省略validation_eval_set时会复用训练集做验证报出来的分数是优化器已经拟合过的对新案例什么都说明不了。train_eval_case_ids/validation_eval_case_ids可选可以收窄到指定 case省略则用集合内全部 case。训练集与验证集应当不相交。GEPARootAgentOptimizer会检查交集并打 warningSimplePromptOptimizer不检查分离与否由你自己保证。LocalEvalSampler内部把每个候选 agent 交给LocalEvalService先perform_inference再evaluate按你传入的EvalConfig逐 case 执行。打分按状态而不是按指标值final_eval_status为PASSED的 case 得1.0其余一律0.0。所以一个 case 以 0.94 差一点没过 0.95 的阈值和一个直接报错的 case在优化器看来没有区别。第 3 步运行 SimplePromptOptimizer最短路径把上一节的sampler接到优化器上整个脚本如下check_order_status、issue_refund换成你的 agent 真实使用的工具函数import asyncio from google.adk.agents import Agent from google.adk.optimization.simple_prompt_optimizer import SimplePromptOptimizer from google.adk.optimization.simple_prompt_optimizer import SimplePromptOptimizerConfig async def main() - None: agent Agent( namesupport_agent, instructionHelp the user with their order., tools[check_order_status, issue_refund], # 替换为你 agent 的真实工具 ) optimizer SimplePromptOptimizer( SimplePromptOptimizerConfig(num_iterations5, batch_size3) ) result await optimizer.optimize(agent, sampler) best result.optimized_agents[0] print(best.overall_score) print(best.optimized_agent.instruction) if __name__ __main__: asyncio.run(main())optimize从不修改你传入的 agent每个候选都用clone(update{instruction: ...})构造所以运行结束时你构造的对象仍是原始 instruction。SimplePromptOptimizerConfig的四个选项选项类型默认说明optimizer_modelstrgemini-2.5-flash负责重写 prompt 的模型不是 agent 自己的模型。model_configurationGenerateContentConfigthinking on, budget 10240优化器模型的生成配置。num_iterationsint10尝试的候选 prompt 数量。batch_sizeint5每个候选打分的训练样例数。内部循环是无记忆的爬山在训练样例的一个随机 batch 上给初始 agent 打分这是要超越的基线每轮让优化器模型只看当前最优 instruction 和它的分数重写出一条新 instruction用它克隆出候选 agent在全新的随机训练 batch 上打分只有分数更高才保留最后一轮结束后让幸存 agent 在整个验证集上打一次分这个数就是overall_score。所以num_iterationsn的一次运行总共调用sample_and_score共n 2次1 次基线、n次候选、1 次最终验证。选择完全基于训练分数验证只在结尾测一次从不影响选哪条 prompt。由此有两个后果每次比较用的是不同的随机 batch候选可能靠 batch 噪声胜出优化器模型只见得到上一条 prompt 和一个数字它是在猜该改什么。还有两个实现细节会影响你的操作optimize发现batch_size超过训练样例数时会把它钳制到样例数而且是写回你传入的 config 对象——运行后读config.batch_size可能发现和你设的不一样。优化器模型在__init__里解析而不是在optimize里所以模型名写错在构造那一刻就失败。从日志读运行过程与结果运行中会打出这样的日志行取自源码的日志模板数值仅为示例实际取决于你的运行Evaluating initial agent to get baseline score... Initial agent baseline score: 0.600000 --- Starting optimization iteration 1/5 --- Generated new candidate prompt: ... Candidate score: 0.666667 (vs. best score: 0.600000) New candidate is better. Updating best agent. ... Optimization loop finished. Running final validation on the best agent found. Final validation score: 0.800000LocalEvalSampler每轮打分还会输出一行汇总形如Evaluation summary: 2 PASSED, 1 FAILED。运行结束后result.optimized_agents[0]是一个AgentWithScoresoverall_score是最终全量验证的平均分在LocalEvalSampler下就是验证集上 PASSED 的占比optimized_agent.instruction是赢家 instruction。把赢家 instruction 复制回源码没有任何东西被写回optimize只返回内存中的Agent。把赢家 instruction 复制进源码、再对它跑一遍你常规测试这一步是手工的文档把它明确留给你。同时注意一条文档声明的边界因为选择只看训练分数一次运行完全可能报出比初始 agent 更差的验证分数却仍然返回重写后的 prompt。验证分数不能自动证明“比原来好”保留与否请结合你自己的常规测试判断。可选分支GEPARootAgentOptimizer想要基于失败的反思而不是盲目猜测——运行候选、把低分 run 的捕获轨迹喂给反思模型、用它的诊断提出下一条 prompt——就用GEPARootAgentOptimizer。它标记为experimental构造时会打一条UserWarning内容为[EXPERIMENTAL] GEPARootAgentOptimizer: ...。额外前提算法本体在第三方gepa包里ADK 在optimize内部惰性导入。缺它时调用抛ImportError: Eval module is not installed, please install via \pip install google-adk[eval]。GEPA 样例安装完整依赖的命令是pip install google-adk absl-py gepa jinja2 litellm retry。initial_agent.instruction必须是纯字符串。instruction 是 callable provider 的 agent 会在任何评估运行前抛ValueError——这个检查位于gepa导入之后所以先装好 extra否则你看到的是ImportError。from google.adk.optimization.gepa_root_agent_optimizer import GEPARootAgentOptimizer from google.adk.optimization.gepa_root_agent_optimizer import GEPARootAgentOptimizerConfig result await GEPARootAgentOptimizer( GEPARootAgentOptimizerConfig(max_metric_calls200, run_dir/tmp/gepa_run) ).optimize(agent, sampler)配置项选项类型默认说明optimizer_modelstrgemini-3.5-flash用于反思和提出新 prompt 的模型。model_configurationGenerateContentConfigthinking levelHIGH反思模型的生成配置。max_metric_callsint100整个运行的评估总预算。reflection_minibatch_sizeint3每一步给反思模型看的样例数。run_dirstr \| NoneNonecheckpoint 目录设置它才能断点续跑。max_metric_calls是决定一次运行花多少钱的那一个旋钮文档建议从默认 100 起步认真的运行提到 500 以上。run_dir值得在任何长到可能被中断的运行里设置有它 GEPA 写中间状态并从上一个 checkpoint 恢复没有它中断后从头开始。与简单优化器的行为差异它维护 Pareto front 而不是单一冠军optimized_agents会返回多个各有所长的 agentGEPARootAgentOptimizerResult.gepa_result携带原始算法输出的 dict。优化范围是根 agent 的 instruction以及 agent 工具中经SkillToolset可达的每个Skill的instructions文本各自作为独立演化的组件sub-agent 的 prompt 不优化——initial_agent.sub_agents非空时优化器只打一条 warning 并只优化根节点。模块里还有GEPARootAgentPromptOptimizer是更早、更窄的版本只演化根 instruction、完全忽略 skills。文档建议优先用GEPARootAgentOptimizer它包含后者的全部能力。限制与陷阱没有写回。复制 instruction 回源码并对你常规测试重跑都是手工步骤。SimplePromptOptimizer内置了一段客服场景 prompt。它的优化器模板写着“the agent needs to solve customer support tasks by using tools correctly and following policies”且没有选项可以替换。对其它领域这句话是每次迭代都发给重写模型的误导。SimplePromptOptimizer只返回一个 agent尽管OptimizerResult.optimized_agents是文档写作 Pareto front 的列表只有 GEPA 会填多个。LocalEvalSampler丢掉指标精度。只有过与不过优化器看不到一个从 0.4 涨到 0.9 但没越过阈值的候选。成本不受包约束。每次打分都是一次对 live 模型的完整 agent 运行max_metric_calls只约束 GEPA自定义 sampler 没有上限。导入data_types会打 Pydantic deprecation warning模型传了 Pydantic v2 不再识别的requiredTrue关键字。字段本来就是必填的这个警告是噪声。延伸阅读AgentOptimizer and Sampler 指南优化器与 sampler 的完整契约、自定义Sampler的接口形状EvalConfig 与 eval config 文件指标、criterion 类型与自定义指标BaseEvalService 与 LocalEvalService推理与打分两阶段、eval set 的三种来源Evaluator编写 sampler 所打分的指标GEPA 集成样例直接对第三方gepa包在 Tau-bench retail 上优化 ADK agent 的 prompt它早于google.adk.optimization出现、自带 GEPA 适配器适合读“一个Sampler封装的评估工作长什么样”而不是当 API 示例源码入口local_eval_sampler.py、simple_prompt_optimizer.py、gepa_root_agent_optimizer.py【免费下载链接】adk-pythonAn open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-python创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考