ADK AgentEvaluator 实战指南在 pytest 中用回放对话为 AI Agent 建立质量回归测试【免费下载链接】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-pythonAgentEvaluator是 google-adk-python 中google.adk.evaluation模块唯一对外导出的类它以回放已录制的对话 按指标评分 阈值断言的方式把 Agent 质量验证无缝嵌入 pytest 套件。本文基于 docs/guides/evaluation/agent_evaluator/index.md 展开结合 src/google/adk/evaluation/ 下的源码与 contributing/samples/evaluation 示例完整讲解它的目录约定、test_config.json配置、evaluate/evaluate_eval_set两个入口、底层五阶段执行流程与全部参数并给出无法用文件承载场景代码生成用例、旧数据迁移的进阶用法。为什么 Agent 质量不能用普通单元测试断言模型每次运行都会换一种措辞assert response ...这种等价断言会在无害的措辞变化上失败而且它完全无法回答Agent 是否用对了工具、传对了参数这一更关键的问题。AgentEvaluator用带评分的比较取代这种断言你先把一次对话录制下来包含用户轮次、期望的最终回复、期望的工具调用评估器回放这段对话让真实 Agent 逐轮作答并产出实际结果工具调用做结构化比较回复文本用ROUGE-1 词重叠分数比较从而容忍改写每个指标都有一个阈值方法以assert收尾所以整个评估就是测试函数里的一行await。阈值是把一个数字变成一个回归测试的关键单独跑一次只得到一个数字数字本身不说明 Agent 好不好而把它与你信任的那次运行得到的阈值比较就能得出最新改动让质量向哪个方向移动这一可行动的结论。正因如此选择分数含义符合你预期的指标是绝大部分工作量——下面 Get started 会详细解释两个默认指标。从零开始三个磁盘要素与两个默认指标评估器在磁盘上需要三样东西一个可被导入的 agent 包、一个名为*.test.json的已录制对话文件、以及紧挨着该文件的test_config.jsonmy_agents/ home_automation/ __init__.py # from . import agent agent.py # defines root_agent tests/ eval/ home_automation/ simple.test.json test_config.json test_home_automation.pytest_config.json为每个指标命名并给出阈值。绝大多数套件从下面这两个指标起步因为它们恰好覆盖一轮回复的两半——Agent做了什么和说了什么{ criteria: { tool_trajectory_avg_score: 1.0, response_match_score: 0.6 } }指标一tool_trajectory_avg_score做了什么对每个用户轮次把 Agent 实际发出的工具调用与录制中期望的工具调用做比较工具名和参数都要匹配整轮完全匹配记 1.0否则记 0.0。名字里的avg是对轮次求平均而不是在一轮内部给部分分得 0.5 意味着有一半轮次完全正确而不是每一轮都答对了一半。这就是为什么1.0是常见阈值——任何更低的数字都是在声明你愿意容忍多少轮出错。该指标的误导场景Agent 用多条路径到达同一答案时一次无害的多余查询就会让这轮得 0.0。正确的解法是调整match_type见 eval config 指南而不是调低阈值。源码层面ToolTrajectoryCriterioneval_metrics.py支持三种MatchTypeEXACT默认实际与期望工具调用序列完全一致才算匹配IN_ORDER要求实际调用按与期望相同的顺序发生允许中间夹杂额外调用。例如期望[T1, T2, T3]、实际[T1, T1.1, T2, T2.1, T2.2, T3, T3.1]即满足但期望里出现过的T4缺失则不满足ANY_ORDER只要求期望的工具都出现过、顺序不限同样允许额外调用适合发了 5 次搜索、但不在乎先后这类场景。此外ignore_argsTrue可让指标只比较工具名、忽略参数。分支实现在 trajectory_evaluator.py而真实示例见 basic_criteria/eval_config.json它把match_type显式写成了EXACT。指标二response_match_score说了什么这是 ROUGE-1 比较把两段文本都还原为词干统计共有的单词数返回精确率与召回率的调和结果f-measure见 final_response_match_v1.py 的_calculate_rouge_1_scores。因此词序无关紧要而往回答里注水和漏掉要点都会拉低分数改写过的答案仍能得高分——这正是优先用它而非等价断言的全部理由。它的误导场景在于语义the light is on 与 the light is off 几乎共享所有单词。请把它当作Agent 谈到了正确主题的检查当你要断言的确实是正确性时改用final_response_match_v2——它会请一个 judge 模型来判断两个答案是否意思一致LlmAsAJudgeCriterion默认 judge 模型为gemini-2.5-flash默认采样num_samples5见 eval_metrics.py。0.6 只是起点不是推荐值先对你已信任的 Agent跑一次 eval看它产出的分数再把每个阈值设到最低分数略低的位置让测试只在回归时失败、而不是在正常波动时失败。一行代码的测试import pytest from google.adk.evaluation import AgentEvaluator pytest.mark.asyncio async def test_home_automation_agent(): await AgentEvaluator.evaluate( agent_modulemy_agents.home_automation, eval_dataset_file_path_or_dirtests/eval/home_automation/simple.test.json, num_runs2, )这个调用里有两个决定成败的细节agent_module是可导入的点分模块路径不是文件系统路径。指定包名后加载器会导入它、寻找名为agent的成员再从那个内层模块读取root_agent。这就是为什么约定俗成的包要在__init__.py里写from . import agent见 home_automation_agent/init.py。直接指定内层模块如my_agents.home_automation.agent也可以如果模块暴露的是异步的get_agent_async()而不是root_agent加载器会 await 它并取其第一个返回值。这些逻辑对应 agent_evaluator.py 的_get_agent_for_eval模块必须带有agent成员或以.agent结尾否则抛ValueError。eval_dataset_file_path_or_dir是相对进程工作目录解析的你写的是相对启动 pytest 的目录的路径而不是相对测试文件的路径。如果传目录而非单文件目录下所有以.test.json结尾的文件都会被运行各自使用旁边的test_config.json。它是怎么工作的五阶段执行流程一次evaluate调用按顺序走完五个阶段对应 agent_evaluator.py 的evaluate与_get_eval_results_by_eval_id收集 eval 数据。目录参数会递归遍历*.test.json文件参数原样使用。每个文件被解析成一个EvalSeteval_set.py 定义了eval_set_id、name、description、eval_cases字段。若文件是EvalSet之前的旧 schema仍可加载但会打出一条指向AgentEvaluator.migrate_eval_data_to_new_schema的警告。寻找配置。对每个测试文件find_config_for_test_file在同目录下找test_config.jsonagent_evaluator.py。若缺失评估不会报错而是回退到内置默认值tool_trajectory_avg_score阈值1.0、response_match_score阈值0.8见 eval_config.py 的_DEFAULT_EVAL_CONFIG。这是很严苛的标准首次运行常常会因为与 Agent 本身无关的原因失败。解析 Agent。按上文方式导入模块并定位root_agent。若模块还暴露名为app的App实例它也会被拾取使其插件和上下文缓存配置参与运行。真实运行 Agent。第一阶段是真实推理LocalEvalService对 eval set 中的每个用户轮次实际执行你的 Agent共执行num_runs次。即使你配置的所有指标都是确定性的也需要模型凭据因为产出待评分的输出本身就是一次模型调用。多次运行是串行的所以墙上时间随num_runs线性增长——代码里通过[InferenceRequest(...)] * num_runs构造重复请求并逐个消费agent_evaluator.py。评分并断言。第二阶段对录制输出评分每个指标把每次运行的逐调用分数平均成一个数均值 ≥ 阈值即通过agent_evaluator.py 使用statistics.mean。每个失败指标贡献一行输出response_match_score for my_agents.home_automation Failed. Expected 0.6, but got 0.41.方法以assert not failures收尾这些行于是成为 pytest 的失败消息。如果某次运行完全没有产出任何指标结果比如推理本身抛异常会被单独报告保证崩溃不会伪装成干净通过对应_get_failures_from_final_eval_statusagent_evaluator.py。当print_detailed_results保持默认的True时失败指标还会打印一张期望 vs 实际的逐调用对照表格包含 prompt、期望/实际回复、期望/实际工具调用等列_print_detailsagent_evaluator.py。该表格依赖pandas与tabulate缺少时会抛出带安装提示的ModuleNotFoundError。配置选项全表以下是evaluate的参数。evaluate_eval_set除eval_dataset_file_path_or_dir与initial_session_file外参数相同——这两个被eval_set与eval_config取代。选项类型默认值说明agent_modulestr必填Agent 包的点分模块路径。eval_dataset_file_path_or_dirstr必填单个 eval 文件或递归搜索*.test.json的目录。num_runsint2整个 eval set 在被平均前运行多少次。agent_namestr \| NoneNone评估命名子 Agent 而非根 Agent。initial_session_filestr \| NoneNone初始会话状态仅用于EvalSet之前的旧数据。print_detailed_resultsboolTrue为失败指标打印期望 vs 实际表格。artifact_serviceBaseArtifactService \| NoneNone运行读取的 Artifact 服务默认用内存版。output_filestr \| NoneNone以 CSV 把逐调用结果写入该路径。app_namestr \| NoneNone持久化结果时使用的 App 名。eval_set_results_managerEvalSetResultsManager \| NoneNone把结果持久化为*.evalset_result.json。各参数的源码级细节num_runs的存在是因为单次运行真实模型有噪声。平均两次是默认值源码常量NUM_RUNS 2ADK 集成测试对已知易波动的用例用四次。测试波动而非错误时提高它是第一件该试的事代价是模型调用数线性增长。agent_name从已加载根 Agent 的树中按名字选中一个子 Agent从而可以单独给某个专家打分。名字不匹配会抛ValueError_get_agent_for_eval中的root_agent.find_agent(agent_name)。initial_session_file只适用于旧 schema 数据。与新版EvalSet文件一起传会导致加载失败并提示初始会话应属于 eval set 文件内部agent_evaluator.py 的断言逻辑。artifact_service在用例依赖运行开始前就必须存在的 artifact 时如 Agent 要总结的 PDF有用把 artifact 预载入服务并传入再通过SessionInput.session_id把 eval case 固定到某个会话 id查找即可命中——EvalCase.session_input的注释说明 artifact 按(app_name, user_id, session_id)键控eval_case.py。eval_set_results_manager把运行产物持久化从而把 CI 任务变成可对比的历史。它要求app_name只传 manager 不传app_name会在任何运行之前抛ValueErroragent_evaluator.py。LocalEvalSetResultsManager(agents_dir...)会在agents_dir/app_name/.adk/eval_history/下为每个被评估的 eval set 写一个*.evalset_result.json内含num_runs次运行各自的EvalCaseResult。output_file是扁平替代方案每个指标每调用一行 CSV携带阈值、分数、状态、prompt 以及期望/实际的回复与工具调用。行是追加的所以多个测试文件可以累积进同一张表_write_results_to_csv用modea且只在文件不存在时写表头agent_evaluator.py。进阶应用脱离文件驱动的两种场景不用文件评估evaluate_eval_set当用例是代码生成而非检入的静态文件例如覆盖输入矩阵、或从数据库读出的用例直接用evaluate_eval_set传入EvalSet与EvalConfig对象from google.adk.evaluation import AgentEvaluator from google.adk.evaluation.eval_case import EvalCase from google.adk.evaluation.eval_case import Invocation from google.adk.evaluation.eval_config import EvalConfig from google.adk.evaluation.eval_set import EvalSet from google.genai import types eval_set EvalSet( eval_set_idgenerated, eval_cases[ EvalCase( eval_idturn_off_bedroom_light, conversation[ Invocation( user_contenttypes.Content( roleuser, parts[types.Part(textTurn off the bedroom light.)], ), final_responsetypes.Content( rolemodel, parts[types.Part(textThe bedroom light is off.)], ), ) ], ) ], ) await AgentEvaluator.evaluate_eval_set( agent_modulemy_agents.home_automation, eval_seteval_set, eval_configEvalConfig(criteria{response_match_score: 0.6}), num_runs1, )注意EvalCase校验conversation与conversation_scenario必须且只能提供一个eval_case.py 的ensure_conversation_xor_conversation_scenario。evaluate_eval_set也接受criteria字典但已废弃。它不只是旧当criteria非空时它会替换你传入的eval_config所以同时提供两者的调用会静默丢失配置agent_evaluator.py。请只用eval_config。迁移旧 eval 数据AgentEvaluator.migrate_eval_data_to_new_schema(old_file, new_file)把EvalSet之前的旧 JSON 文件重写为当前 schema指标取自旧文件旁的test_config.json。它是一次性工具不要在测试里调用agent_evaluator.py。局限与注意点需要 evaluation extra且失败信息几乎不提示原因。安装pip install google-adk[eval]。没有它时from google.adk.evaluation import AgentEvaluator会报ImportError: cannot import name AgentEvaluator from google.adk.evaluation仅此而已不会点名真正缺失的依赖init.py 捕获了ImportError。想定位缺失依赖直接导入google.adk.evaluation.agent_evaluator基础安装下会报No module named vertexai它来自google-cloud-aiplatform[evaluation]。底层统一抛出的MISSING_EVAL_DEPENDENCIES_MESSAGE也给出了同样的安装提示constants.py。评估不是离线的。每次运行都会执行 Agent因此即使指标全是确定性的也需要凭据与模型配额。失败是AssertionError。没有类型化异常也没有返回给调用方的结果对象要程序化查看分数请传eval_set_results_manager或output_file。缺失配置是静默的。eval 文件旁没有test_config.json意味着采用严格的默认值只打一条信息级日志说明。相关示例Evaluation samples围绕同一个共享 Agent 的六种评估变体附有对比各技术的 README。Test file vs. eval set.test.json与.evalset.json的含义以及为何两者以相同方式加载。共享的家居自动化 Agent所有评估示例打分的确定性 Agent——所有工具由内存字典支撑reset_data()被adk eval拾取以在每个 eval case 之间重置状态。【免费下载链接】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),仅供参考