Agent Platform 评估 SDK 模式实战:从单轮评测到托管 Agent 评估的 8 大代码范式
【免费下载链接】skillsAgent Skills for Google products and technologies项目地址: https://gitcode.com/GitHub_Trending/skills29/skills
本篇技术指南围绕 Google Cloud Agent Platform GenAI 评估 SDK(agentplatform)的常用编码模式展开,系统梳理了单轮评测、多轮 Agent 轨迹评测、冷启动合成数据生成、自定义 LLM 裁判、代码执行度量、成对模型对比与结果解析等 8 大实战范式,并覆盖初始化、错误处理等关键环节。读完本文,你将能够基于 sdk_patterns.md 所定义的 API 形态,独立搭建从数据集构造到评估结果落盘的完整评测流程,并接入 Quality Flywheel(质量飞轮)的迭代优化闭环。
前置准备:SDK 初始化与依赖安装
安装依赖
评估脚本依赖agentplatform(基于google-cloud-aiplatform[evaluation])、google-genai、pandas和requests。仓库 SKILL.md 建议不要创建虚拟环境——空虚拟环境会隐藏环境中已装好的包,导致冗余安装。正确做法是先探测再补装缺失的包:
python3 -c "import vertexai, google.genai, pandas, requests" \ || pip install 'google-cloud-aiplatform[evaluation]>=1.163.0' 'google-genai>=1.0.0'注意:版本号约束必须加引号,未加引号时 bash 会把>=1.163.0当作重定向,静默写出一个空文件而非约束安装版本。
客户端初始化
import agentplatform from agentplatform import types from google.genai import types as genai_types client = agentplatform.Client(project="{PROJECT_ID}", location="{LOCATION}")初始化前需确认环境变量GOOGLE_CLOUD_PROJECT与GOOGLE_CLOUD_LOCATION已配置;对于 Gemini 3+ 模型,应使用location="global"。新版本的 Gemini 模型通常也建议location="global"。
一个极易踩坑的关键约定
EvalCase的prompt/reference/response值都是Content 对象,而非纯字符串。必须使用genai_types.UserContent(str)/genai_types.ModelContent(str)包装——它们会把字符串包进一个 Part 并设置正确的角色。直接传字符串会触发pydantic.ValidationError(快速失败),这是构造数据集时最常见的错误之一(详见 dataset_schema.md 的 Core Types 说明)。
SDK 入口的正确形态
评估相关操作统一挂在client.evals下:
client.evals.run_inference(model=..., src=...) client.evals.evaluate(dataset=..., metrics=...) client.evals.generate_conversation_scenarios(...)两个看起来合理但不可用的导入形态(来自 SKILL.md):
from agentplatform.types import evals——会抛ModuleNotFoundError。types是模块而非包,应使用from agentplatform import types;from vertexai.evaluation import PointwiseMetric, EvalTask——这是已被取代的旧 SDK,其类参数不同(如PointwiseMetric没有system_instruction),按旧 API 写的代码会以TypeError而非导入错误失败。
Pattern 1:单轮评测——最简单的起点
单轮评测适用于 QA、摘要等 prompt/response 对评估。构造EvaluationDataset并在metrics中同时混用预定义 rubric 度量与计算型度量:
dataset = types.EvaluationDataset(eval_cases=[ types.EvalCase( prompt=genai_types.UserContent("What causes rain?"), responses=[types.ResponseCandidate( response=genai_types.ModelContent( "Rain is caused by water evaporating..."))], reference=types.ResponseCandidate( response=genai_types.ModelContent( "Rain forms when water vapor condenses...")), ), ]) result = client.evals.evaluate( dataset=dataset, metrics=[ types.RubricMetric.GENERAL_QUALITY, types.Metric(name="rouge_l_sum"), ], )注意三点细节:
responses是复数列表,不存在单数的response=参数。由于EvalCase设置了extra="allow",误写response=不会报错,而是被静默存储、永不读取,候选响应按缺失计分——这是典型的"静默失败"陷阱;reference是ResponseCandidate对象而非字符串;types.Metric(name="rouge_l_sum")走的是确定性计算路径,无需 LLM 裁判。
如果觉得直接构造EvalCase过于冗长易错,可以改用 pandas DataFrame 形式,转换器会自动用字符串列包装成 Content 对象(推荐):
import pandas as pd from agentplatform import types df = pd.DataFrame({ "prompt": ["What is 2+2?", "Capital of France?"], "response": ["4", "Paris"], "reference": ["4", "Paris"], }) dataset = types.EvaluationDataset(eval_dataset_df=df)这一推荐路径在 dataset_schema.md 中有完整说明。
Pattern 2:多轮 Agent 评测——带工具调用的完整轨迹
要评估一个完整的多轮 Agent 对话轨迹(含工具调用),需要使用AgentData类型层级:AgentData→ConversationTurn→AgentEvent。每个AgentEvent通过author区分发言者,content按角色区分消息类型:
agent_data = types.evals.AgentData( agents={ "my_agent": types.evals.AgentConfig( agent_id="my_agent", instruction="You are a helpful assistant.", tools=[genai_types.Tool(function_declarations=[ genai_types.FunctionDeclaration( name="search", description="Search the web", parameters=genai_types.Schema( type="OBJECT", properties={"query": genai_types.Schema(type="STRING")}, ), ), ])], ), }, turns=[ types.evals.ConversationTurn(turn_index=0, events=[ types.evals.AgentEvent( author="user", content=genai_types.Content(role="user", parts=[genai_types.Part(text="Find me the weather in NYC")]), ), types.evals.AgentEvent( author="my_agent", content=genai_types.Content(role="model", parts=[genai_types.Part(function_call=genai_types.FunctionCall( name="search", args={"query": "NYC weather"}))]), ), types.evals.AgentEvent( author="my_agent", content=genai_types.Content(role="tool", parts=[genai_types.Part(function_response=genai_types.FunctionResponse( name="search", response={"result": "72F, sunny"}))]), ), types.evals.AgentEvent( author="my_agent", content=genai_types.Content(role="model", parts=[genai_types.Part(text="It's 72F and sunny in NYC.")]), ), ]), ], ) result = client.evals.evaluate( dataset=types.EvaluationDataset(eval_cases=[ types.EvalCase(agent_data=agent_data), ]), metrics=[ types.RubricMetric.MULTI_TURN_TRAJECTORY_QUALITY, types.RubricMetric.MULTI_TURN_TASK_SUCCESS, ], )轨迹构造的硬性约定
仓库中的 validate_dataset.py 脚本会对这些约束做自动化校验,其校验逻辑揭示了以下规则:
- 角色必须是
user/model/tool,使用role="assistant"会被判为错误(Agent Platform 约定用model); turn_index必须是从 0 开始连续递增的序号,非顺序索引会触发 WARNING;- 工具响应必须用
genai_types.FunctionResponse包装,且parts不能为空; - 每个
EvalCase只能使用prompt(单轮)或agent_data(多轮)二选一,混用会被标记。
另外,若你的轨迹来自 ADK(Agent Development Kit)会话导出,无需手写转换逻辑,直接使用仓库脚本python scripts/parse_adk_traces.py --input session.json --output dataset.json(详见 parse_adk_traces.py)。
Pattern 3:冷启动合成数据生成——没有评估数据时怎么办
当评估数据集为空、无从谈起评测时,可以用"生成场景 → 模拟推理 → 评估"三步走的冷启动流程:
# Step 1: Generate scenarios scenarios = client.evals.generate_conversation_scenarios( agents={ "agent": types.evals.AgentConfig( agent_id="agent", instruction="You are a customer support agent for an airline.", ), }, root_agent_id="agent", user_scenario_generation_config=types.evals.UserScenarioGenerationConfig( user_scenario_count=10, simulation_instruction="Simulate customers with flight booking issues.", environment_data="Flights available: NYC-LAX, NYC-SFO. Cancellation policy: free within 24h.", model_name="gemini-2.5-flash", ), ) # Step 2: Run inference with user simulation dataset_with_responses = client.evals.run_inference( agent=my_agent, # Your callable agent src=scenarios, config={ "user_simulator_config": { "model_name": "gemini-2.5-flash", "max_turn": 5, }, }, ) # Step 3: Evaluate result = client.evals.evaluate( dataset=dataset_with_responses, metrics=[types.RubricMetric.MULTI_TURN_GENERAL_QUALITY, types.RubricMetric.SAFETY], )冷启动 API 的三个易错点
SKILL.md 明确标注了该 API 的坑:
- 参数名是
agent或agent_info,不是agents(Pattern 2 构造数据集时才是agents),且config为必填; - 配置类全名是
types.evals.UserScenarioGenerationConfig,不是types.UserScenarioGenerationConfig; - 必须设置
user_scenario_count(取值范围 1–100)。它默认是None,客户端会照单全收,然后服务端以400 INVALID_ARGUMENT拒绝调用;注意count是另一个独立字段,不能替代它。
在推理阶段,run_inference对不同类型的被评测对象形态不同(SKILL.md Stage 2):
- Agent 评测:传
model=agent_callable(包装用户 ADK Agent/App 的可调用对象); - 模型评测:直接传模型 ID,如
model="gemini-2.5-flash"; - 合成场景:让模拟器驱动,加
user_simulator_config=UserSimulatorConfig(max_turn=10); - DataFrame 也可直接作为
src=,无需包EvalCase。
Pattern 4:用 MetricPromptBuilder 构建自定义 LLM 裁判
领域特定评估(如医疗、金融、客服质量)没有现成的内置度量时,可以用LLMMetric+MetricPromptBuilder构建结构化评分裁判。与手写prompt_template字符串相比,MetricPromptBuilder更适合复杂评分卡:
metric = types.LLMMetric( name="domain_expertise", prompt_template=types.MetricPromptBuilder( metric_definition="Evaluates domain expertise in the response.", criteria={ "Accuracy": "Claims are factually correct for the domain", "Depth": "Response shows understanding beyond surface level", "Actionability": "Advice is specific and actionable", }, rating_scores={ "1": "Incorrect or misleading information", "2": "Partially correct but superficial", "3": "Correct and shows reasonable understanding", "4": "Accurate with good depth", "5": "Expert-level accuracy, depth, and actionability", }, ), judge_model="gemini-2.5-flash", judge_model_sampling_count=3, )使用 LLM 裁判的硬性规则
criteria和rating_scores两者都必填,只提供一个会抛ValidationError: Both 'criteria' and 'rating_scores' are required to construct the LLM-based metric prompt template text(见 metric_registry.md);- 必须显式设置
judge_model。它默认是None,此时每个评测用例都会以400 INVALID_ARGUMENT: Error parsing JSON失败; judge_model_sampling_count默认 1、上限 32,值过高会导致评测超时(见 failure_patterns.md)。
若只是基于固定 prompt 模板而非结构化评分卡,也可以直接使用types.LLMMetric(name=..., prompt_template="...", judge_model=...)形态,甚至支持从 YAML/JSON 文件加载(types.LLMMetric.load("path/to/metric_config.yaml"))。
Pattern 5:CodeExecutionMetric 结构化校验——超越文本对比
当需要程序化校验(如 JSON 结构、正则、字段完整性)时,用CodeExecutionMetric在远程沙箱中执行 Python 函数。函数必须命名为evaluate(instance: dict) -> dict,返回{"score": ..., "explanation": ...}:
# Validate JSON output structure json_validator = types.CodeExecutionMetric( name="json_structure_check", custom_function=''' import json def evaluate(instance: dict) -> dict: try: data = json.loads(instance.get("response", "")) required_keys = {"name", "status", "result"} missing = required_keys - set(data.keys()) if missing: return {"score": 0.0, "explanation": f"Missing keys: {missing}"} return {"score": 1.0, "explanation": "All required keys present"} except json.JSONDecodeError as e: return {"score": 0.0, "explanation": f"Invalid JSON: {e}"} ''', )本地函数与远程沙箱的选择
metric_registry.md 区分了两种自定义代码度量:
- 本地自定义函数(
types.Metric(name=..., custom_function=<callable>)):客户端执行、迭代最快、无 API 调用,但以调用进程的权限运行,只可用于可信代码; - 远程沙箱执行(
CodeExecutionMetric的custom_function字符串):在 Agent Platform 沙箱中运行,适合不可信代码。
SDK 内部的度量处理器按固定顺序分派(Handler Dispatch Order):先匹配CodeExecutionMetric的字符串函数,再匹配本地Callable、注册度量资源名、计算型度量(bleu/rouge_1等)、翻译度量(comet/metricx)、API 预定义度量,最后才是LLMMetric的prompt_template。理解这个顺序有助于排查"自定义度量没生效"的问题。
注意:在 Agent 轨迹数据集的instance字典里,顶层标准字段是agent_data(结构化的 turns/events 对象),最终回复嵌在其中;扁平占位符{response}只在 DataFrame 评测路径下可用。自定义函数应始终用.get()带默认值(见 failure_patterns.md 的 KeyError 故障说明)。
Pattern 6:成对模型对比——用 calculate_win_rates 计算胜率
对比两个模型时,SDK 没有PairwiseMetric类。正确做法是:对同一数据集分别跑两个模型的评估,再用calculate_win_rates()计算胜率:
# Same dataset, two different model responses dataset_a = types.EvaluationDataset(eval_cases=[ types.EvalCase(prompt=genai_types.UserContent("Explain quantum computing"), responses=[types.ResponseCandidate( response=genai_types.ModelContent( "Model A response..."))]), ]) dataset_b = types.EvaluationDataset(eval_cases=[ types.EvalCase(prompt=genai_types.UserContent("Explain quantum computing"), responses=[types.ResponseCandidate( response=genai_types.ModelContent( "Model B response..."))]), ]) result_a = client.evals.evaluate(dataset=dataset_a, metrics=[types.RubricMetric.GENERAL_QUALITY]) result_b = client.evals.evaluate(dataset=dataset_b, metrics=[types.RubricMetric.GENERAL_QUALITY]) # Compare from agentplatform._genai._evals_metric_handlers import calculate_win_rates win_rates = calculate_win_rates(result_a, result_b)该方法与 metric_registry.md 中 "Pairwise Comparison" 一节的用法一致。注意calculate_win_rates来自 SDK 内部模块_evals_metric_handlers,这是文档中唯一出现的内部导入路径,其余场景应尽量使用公开 API。
Pattern 7:结果解析——从摘要到逐条 rubric 判定
evaluate()返回的结果对象有清晰的层级,可按三种粒度解析:
result = client.evals.evaluate(dataset=dataset, metrics=metrics) # Interactive HTML report (recommended) result.show() # Summary level for summary in result.summary_metrics: print(f"{summary.metric_name}: mean={summary.mean_score}, pass_rate={summary.pass_rate}") # Per-case level for case in result.eval_case_results: for candidate in case.response_candidate_results: for metric_name, metric_result in candidate.metric_results.items(): print(f" {metric_name}: score={metric_result.score}") print(f" explanation: {metric_result.explanation}") # Rubric verdicts (for rubric-based metrics) if metric_result.rubric_verdicts: for v in metric_result.rubric_verdicts: print(f" rubric {v.evaluated_rubric.rubric_id}: " f"{'PASS' if v.verdict else 'FAIL'} - {v.reasoning}")持久化结果:JSON + HTML 双份落盘
结果字段路径很深(eval_case_results[].response_candidate_results),建议落盘保存供后续分析与对比。仓库 SKILL.md Stage 3 给出了标准做法——JSON(机器可读、可 diff)与 HTML(人类可读、可分享)各存一份:
import datetime from pathlib import Path from agentplatform._genai import _evals_visualization out_dir = Path("artifacts/grade_results") out_dir.mkdir(parents=True, exist_ok=True) ts = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") # fallback=str, or a DataFrame-backed dataset raises PydanticSerializationError. result_json = result.model_dump_json(fallback=str) (out_dir / f"results_{ts}.json").write_text(result_json) html = _evals_visualization.get_evaluation_html(result_json) (out_dir / f"results_{ts}.html").write_text(str(html))之后可以用仓库配套脚本快速渲染与筛选(inspect_results.py):
python scripts/inspect_results.py --result result.json # 摘要 + 逐用例分数 python scripts/inspect_results.py --result result.json --failing-only # 只看失败用例 (score < 1.0) python scripts/inspect_results.py --result result.json --metric multi_turn_task_success python scripts/inspect_results.py --result result.json --save-html report.html在迭代优化阶段,用 compare_results.py 对比修复前后两个结果文件,确认目标指标提升且无回归:
python scripts/compare_results.py --baseline baseline.json --candidate candidate.json python scripts/compare_results.py -b baseline.json -c candidate.json --threshold 0.05 --json该脚本按metric_name对齐两文件的summary_metrics,输出均值与通过率的增量;任一指标下降超过阈值(默认 0.0,即任何下降都算回归)时退出码为 1。
Pattern 8:托管 Agent 评估(Gemini Agents API)
对于使用 Managed Agents API 构建的 Agent,可以只凭其资源名完成"生成场景 → 推理 → 评估"的完整工作流,无需自己包装可调用对象:
import agentplatform from agentplatform import types client = agentplatform.Client(project="PROJECT_ID", location="global") AGENT_RESOURCE = "projects/PROJECT_ID/locations/global/agents/AGENT_ID" # Step 1: Generate conversation scenarios from the agent's configuration. scenarios = client.evals.generate_conversation_scenarios( agent=AGENT_RESOURCE, config={ "user_scenario_count": 5, "simulation_instruction": "Create agent scenarios", }, ) scenarios.show() # Step 2: Run inference, execute the agent against each scenario. inference_results = client.evals.run_inference( agent=AGENT_RESOURCE, src=scenarios, config={"user_simulator_config": {"max_turn": 3}}, ) inference_results.show() # Step 3: Evaluate the conversation traces. result = client.evals.evaluate( dataset=inference_results, metrics=[types.RubricMetric.MULTI_TURN_TASK_SUCCESS], agent=AGENT_RESOURCE, ) result.show()注意这里generate_conversation_scenarios与run_inference的agent参数直接接受资源名(形如projects/.../locations/global/agents/...),并且location固定为global。
评估已记录的交互(Interactions API)
如果交互已通过 Interactions API 记录,可以跳过推理直接评估,避免重复运行:
interactions_dataset = types.EvaluationDataset( eval_cases=[ types.EvalCase( interactions_data_source=types.InteractionsDataSource( interaction="projects/PROJECT_ID/locations/global/interactions/INTERACTION_ID", gemini_agent_config=types.GeminiAgentConfig( gemini_agent=AGENT_RESOURCE, ), ), ), ] ) result = client.evals.evaluate( dataset=interactions_dataset, metrics=[types.RubricMetric.MULTI_TURN_TASK_SUCCESS], agent=AGENT_RESOURCE, ) result.show()错误处理:区分权限、参数与配额问题
evaluate()调用失败时,根据异常类型快速定位问题类别:
try: result = client.evals.evaluate(dataset=dataset, metrics=metrics) except Exception as e: error_type = type(e).__name__ if "PermissionDenied" in error_type: print("Check: GCP project permissions, API enabled, billing active") elif "InvalidArgument" in error_type: print("Check: dataset format, metric compatibility with data type") elif "ResourceExhausted" in error_type: print("Check: API quota, reduce dataset size or add delay") else: raise结合 failure_patterns.md 的故障排查清单,这三类错误的常见根因分别是:
- PermissionDenied:GCP 项目权限不足、API 未启用、结算未激活;
- InvalidArgument:数据集格式错误(如
prompt传了字符串)、度量与数据类型不匹配(如对单轮数据用了multi_turn_*度量)、judge_model未设置; - ResourceExhausted:API 配额耗尽,可减小数据集或增加延迟。
另需留意is_infra_error: true的结构性失败(配额、超时、端点不可用)与评测超时问题——超时通常源于数据集过大、自定义度量代码过慢或judge_model_sampling_count过高,可分批评测并降低采样数。
接入 Quality Flywheel:五个阶段如何落地
以上模式是 agent-platform-eval-flywheel 这套 Skill 的技术底座。在实战中,它们服务于"质量飞轮"的五个阶段:
- 准备数据(Prepare Data):按 Pattern 1/2 构造数据集(
EvalCase、DataFrame 或agent_data),或用 Pattern 3 冷启动生成,提交前用scripts/validate_dataset.py校验; - 运行推理(Run Inference):用
run_inference填充响应,已有完整轨迹(如生产日志回放)时跳过; - 评分(Grade,必做):按 Pattern 1/4/5 选择度量并执行
evaluate(),按 Pattern 7 落盘 JSON + HTML;度量选择参考 metric_registry.md 的分类(Agent 度量优先multi_turn_task_success/multi_turn_trajectory_quality/multi_turn_tool_use_quality,静态 rubric 关注hallucination/grounding/safety); - 分析失败(Analyze Failures):用 Pattern 7 解析 rubric verdicts,配合
scripts/inspect_results.py --failing-only定位失败用例;同一指标 10+ 失败时可用 Error Analysis 服务(client.evals.generate_loss_clusters)聚类失败主题; - 优化迭代(Optimize & Iterate):针对失败指标修复 Agent 或提示词,重跑后用
scripts/compare_results.py确认目标提升且无回归。
每个失败用例通常需要 5–10+ 次迭代。需要特别提醒的是:评测结果必须来自真实的result对象,绝不可编造分数;无法产出证据(SDK 调用失败、结果截断、度量不支持)时应当明确说明,而不是掩盖缺口——这是该 Skill 反复强调的"Proving your work"原则。
延伸阅读
- sdk_patterns.md:本文所依据的模式定义原文
- dataset_schema.md:
EvaluationDataset/EvalCase/AgentData完整类型层级与字段说明 - metric_registry.md:全部预定义、计算型、翻译、多模态与自定义度量的目录与选择指南
- failure_patterns.md:常见失败模式到根因与修复方案的映射
- SKILL.md:Quality Flywheel 完整方法论与安全确认层级
- validate_dataset.py:评测数据集结构校验脚本
- parse_adk_traces.py:ADK 会话轨迹转规范数据集脚本
- inspect_results.py:结果摘要与逐用例分数渲染脚本
- compare_results.py:基线 vs 候选结果对比与回归检测脚本
【免费下载链接】skillsAgent Skills for Google products and technologies项目地址: https://gitcode.com/GitHub_Trending/skills29/skills
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考