Skip to content

Commit 6a2951f

Browse files
vertex-sdk-botcopybara-github
authored andcommitted
chore: Auto-construct inference_configs for create_evaluation_run with agent parameter without requiring agent_info
PiperOrigin-RevId: 951079941
1 parent 06a9089 commit 6a2951f

4 files changed

Lines changed: 188 additions & 8 deletions

File tree

agentplatform/_genai/_evals_common.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
PARTS = _evals_constant.PARTS
8989
USER_AUTHOR = _evals_constant.USER_AUTHOR
9090
AGENT_DATA = _evals_constant.AGENT_DATA
91+
_DEFAULT_CANDIDATE_NAME = _evals_constant.DEFAULT_CANDIDATE_NAME
9192

9293

9394
@contextlib.contextmanager
@@ -528,11 +529,11 @@ def _resolve_inference_configs(
528529
if inference_configs is None:
529530
inference_configs = {}
530531

531-
# We might have used "candidate-1" as a placeholder key in the caller,
532-
# let's migrate it to the agent name, or if it doesn't exist, just create it.
533-
if "candidate-1" in inference_configs:
532+
# We might have used the default candidate name as a placeholder key
533+
# in the caller; migrate it to the agent name.
534+
if _DEFAULT_CANDIDATE_NAME in inference_configs:
534535
inference_configs[parsed_agent_info.name] = inference_configs.pop(
535-
"candidate-1"
536+
_DEFAULT_CANDIDATE_NAME
536537
)
537538

538539
if parsed_agent_info.name not in inference_configs:

agentplatform/_genai/_evals_constant.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
CONVERSATION_PLAN = "conversation_plan"
6464
HISTORY = "history"
6565
CONVERSATION_HISTORY = "conversation_history"
66+
DEFAULT_CANDIDATE_NAME = "candidate-1"
6667

6768
COMMON_DATASET_COLUMNS = frozenset(
6869
{

agentplatform/_genai/evals.py

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2746,7 +2746,25 @@ def create_evaluation_run(
27462746
if isinstance(config, dict):
27472747
config = types.CreateEvaluationRunConfig.model_validate(config)
27482748

2749-
if agent_info and not inference_configs:
2749+
# Auto-construct inference_configs when agent_info is explicitly
2750+
# provided (existing behavior) OR an agent resource is provided
2751+
# (allows omitting agent_info for both Gemini Agents and Agent
2752+
# Engine). The server skips inference per-item when a
2753+
# CandidateResponse with a matching candidate name already exists,
2754+
# so it is safe to always send inference_configs.
2755+
_should_auto_infer = not inference_configs and (agent_info or agent)
2756+
if _should_auto_infer:
2757+
if not parsed_agent_info.name:
2758+
# Prefer the dataset's candidate_name (set by run_inference)
2759+
# so the inference_configs key matches the CandidateResponse
2760+
# and the server correctly skips already-completed items.
2761+
if (
2762+
isinstance(dataset, types.EvaluationDataset)
2763+
and dataset.candidate_name
2764+
):
2765+
parsed_agent_info.name = dataset.candidate_name
2766+
else:
2767+
parsed_agent_info.name = _evals_common._DEFAULT_CANDIDATE_NAME
27502768
parsed_user_simulator_config = (
27512769
evals_types.UserSimulatorConfig.model_validate(user_simulator_config)
27522770
if isinstance(user_simulator_config, dict)
@@ -2755,7 +2773,9 @@ def create_evaluation_run(
27552773
if getattr(parsed_user_simulator_config, "max_turn", None) is None:
27562774
parsed_user_simulator_config.max_turn = 5
27572775

2758-
candidate_name = parsed_agent_info.name or "candidate-1"
2776+
candidate_name = (
2777+
parsed_agent_info.name or _evals_common._DEFAULT_CANDIDATE_NAME
2778+
)
27592779
if agent and _evals_common._is_gemini_agent_resource(agent):
27602780
agent_run_config = types.AgentRunConfig(
27612781
gemini_agent_config=types.GeminiAgentConfig(gemini_agent=agent),
@@ -4534,7 +4554,25 @@ async def create_evaluation_run(
45344554
if isinstance(config, dict):
45354555
config = types.CreateEvaluationRunConfig.model_validate(config)
45364556

4537-
if agent_info and not inference_configs:
4557+
# Auto-construct inference_configs when agent_info is explicitly
4558+
# provided (existing behavior) OR an agent resource is provided
4559+
# (allows omitting agent_info for both Gemini Agents and Agent
4560+
# Engine). The server skips inference per-item when a
4561+
# CandidateResponse with a matching candidate name already exists,
4562+
# so it is safe to always send inference_configs.
4563+
_should_auto_infer = not inference_configs and (agent_info or agent)
4564+
if _should_auto_infer:
4565+
if not parsed_agent_info.name:
4566+
# Prefer the dataset's candidate_name (set by run_inference)
4567+
# so the inference_configs key matches the CandidateResponse
4568+
# and the server correctly skips already-completed items.
4569+
if (
4570+
isinstance(dataset, types.EvaluationDataset)
4571+
and dataset.candidate_name
4572+
):
4573+
parsed_agent_info.name = dataset.candidate_name
4574+
else:
4575+
parsed_agent_info.name = _evals_common._DEFAULT_CANDIDATE_NAME
45384576
parsed_user_simulator_config = (
45394577
evals_types.UserSimulatorConfig.model_validate(user_simulator_config)
45404578
if isinstance(user_simulator_config, dict)
@@ -4543,7 +4581,9 @@ async def create_evaluation_run(
45434581
if getattr(parsed_user_simulator_config, "max_turn", None) is None:
45444582
parsed_user_simulator_config.max_turn = 5
45454583

4546-
candidate_name = parsed_agent_info.name or "candidate-1"
4584+
candidate_name = (
4585+
parsed_agent_info.name or _evals_common._DEFAULT_CANDIDATE_NAME
4586+
)
45474587
if agent and _evals_common._is_gemini_agent_resource(agent):
45484588
agent_run_config = types.AgentRunConfig(
45494589
gemini_agent_config=types.GeminiAgentConfig(gemini_agent=agent),

tests/unit/agentplatform/genai/test_evals.py

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10873,6 +10873,10 @@ def test_create_evaluation_run_builds_gemini_agent_config(self):
1087310873
== _TEST_GEMINI_AGENT
1087410874
)
1087510875
assert "agent_engine" not in agent_run_config
10876+
# agent_info.name overrides the default candidate name.
10877+
inference_configs = request_body["inferenceConfigs"]
10878+
assert "gemini-agent" in inference_configs
10879+
assert _evals_common._DEFAULT_CANDIDATE_NAME not in inference_configs
1087610880

1087710881
def test_create_evaluation_run_agent_engine_does_not_set_gemini(self):
1087810882
evals_module = evals.Evals(api_client_=self.mock_api_client)
@@ -10900,6 +10904,140 @@ def test_create_evaluation_run_agent_engine_does_not_set_gemini(self):
1090010904
agent_run_config = self._agent_run_config(request_body)
1090110905
assert "gemini_agent_config" not in agent_run_config
1090210906
assert agent_run_config["agent_engine"] == _TEST_AGENT_ENGINE
10907+
# agent_info.name overrides the default candidate name.
10908+
inference_configs = request_body["inferenceConfigs"]
10909+
assert "ae-agent" in inference_configs
10910+
assert _evals_common._DEFAULT_CANDIDATE_NAME not in inference_configs
10911+
10912+
def test_create_evaluation_run_gemini_agent_without_agent_info(self):
10913+
"""Gemini agent resource alone triggers inference_configs auto-construction."""
10914+
evals_module = evals.Evals(api_client_=self.mock_api_client)
10915+
10916+
evals_module.create_evaluation_run(
10917+
dataset=agentplatform_genai_types.EvaluationRunDataSource(
10918+
evaluation_set="projects/123/locations/us-central1/evaluationSets/789"
10919+
),
10920+
metrics=[
10921+
agentplatform_genai_types.EvaluationRunMetric(
10922+
metric="multi_turn_task_success_v1",
10923+
metric_config=agentplatform_genai_types.UnifiedMetric(
10924+
predefined_metric_spec=genai_types.PredefinedMetricSpec(
10925+
metric_spec_name="multi_turn_task_success_v1",
10926+
)
10927+
),
10928+
)
10929+
],
10930+
dest="gs://test-bucket/output",
10931+
agent=_TEST_GEMINI_AGENT,
10932+
# No agent_info provided.
10933+
)
10934+
10935+
request_body = self._get_create_run_body()
10936+
agent_run_config = self._agent_run_config(request_body)
10937+
assert (
10938+
agent_run_config["gemini_agent_config"]["gemini_agent"]
10939+
== _TEST_GEMINI_AGENT
10940+
)
10941+
assert "agent_engine" not in agent_run_config
10942+
# Default candidate name should match the constant.
10943+
inference_configs = request_body["inferenceConfigs"]
10944+
assert _evals_common._DEFAULT_CANDIDATE_NAME in inference_configs
10945+
10946+
def test_create_evaluation_run_no_agent_no_agent_info_no_inference(self):
10947+
"""Without agent or agent_info, no inference_configs are auto-constructed."""
10948+
evals_module = evals.Evals(api_client_=self.mock_api_client)
10949+
10950+
evals_module.create_evaluation_run(
10951+
dataset=agentplatform_genai_types.EvaluationRunDataSource(
10952+
evaluation_set="projects/123/locations/us-central1/evaluationSets/789"
10953+
),
10954+
metrics=[
10955+
agentplatform_genai_types.EvaluationRunMetric(
10956+
metric="multi_turn_task_success_v1",
10957+
metric_config=agentplatform_genai_types.UnifiedMetric(
10958+
predefined_metric_spec=genai_types.PredefinedMetricSpec(
10959+
metric_spec_name="multi_turn_task_success_v1",
10960+
)
10961+
),
10962+
)
10963+
],
10964+
dest="gs://test-bucket/output",
10965+
# No agent, no agent_info.
10966+
)
10967+
10968+
request_body = self._get_create_run_body()
10969+
assert "inferenceConfigs" not in request_body or not request_body.get(
10970+
"inferenceConfigs"
10971+
)
10972+
10973+
def test_create_evaluation_run_agent_engine_without_agent_info(self):
10974+
"""Agent Engine resource alone triggers inference_configs auto-construction."""
10975+
evals_module = evals.Evals(api_client_=self.mock_api_client)
10976+
10977+
evals_module.create_evaluation_run(
10978+
dataset=agentplatform_genai_types.EvaluationRunDataSource(
10979+
evaluation_set="projects/123/locations/us-central1/evaluationSets/789"
10980+
),
10981+
metrics=[
10982+
agentplatform_genai_types.EvaluationRunMetric(
10983+
metric="multi_turn_task_success_v1",
10984+
metric_config=agentplatform_genai_types.UnifiedMetric(
10985+
predefined_metric_spec=genai_types.PredefinedMetricSpec(
10986+
metric_spec_name="multi_turn_task_success_v1",
10987+
)
10988+
),
10989+
)
10990+
],
10991+
dest="gs://test-bucket/output",
10992+
agent=_TEST_AGENT_ENGINE,
10993+
# No agent_info provided.
10994+
)
10995+
10996+
request_body = self._get_create_run_body()
10997+
agent_run_config = self._agent_run_config(request_body)
10998+
assert agent_run_config["agent_engine"] == _TEST_AGENT_ENGINE
10999+
assert "gemini_agent_config" not in agent_run_config
11000+
# Default candidate name should match the constant.
11001+
inference_configs = request_body["inferenceConfigs"]
11002+
assert _evals_common._DEFAULT_CANDIDATE_NAME in inference_configs
11003+
11004+
@mock.patch.object(_evals_common, "_resolve_dataset")
11005+
def test_create_evaluation_run_uses_dataset_candidate_name(
11006+
self, mock_resolve_dataset
11007+
):
11008+
"""When dataset.candidate_name is set (e.g. from run_inference), the
11009+
inference_configs key should match it instead of using the default."""
11010+
mock_resolve_dataset.return_value = (
11011+
agentplatform_genai_types.EvaluationRunDataSource(
11012+
evaluation_set="projects/123/locations/us-central1/evaluationSets/789"
11013+
)
11014+
)
11015+
evals_module = evals.Evals(api_client_=self.mock_api_client)
11016+
11017+
evals_module.create_evaluation_run(
11018+
dataset=agentplatform_genai_types.EvaluationDataset(
11019+
eval_dataset_df=pd.DataFrame({"prompt": ["hello"]}),
11020+
candidate_name="my-agent-v2",
11021+
),
11022+
metrics=[
11023+
agentplatform_genai_types.EvaluationRunMetric(
11024+
metric="multi_turn_task_success_v1",
11025+
metric_config=agentplatform_genai_types.UnifiedMetric(
11026+
predefined_metric_spec=genai_types.PredefinedMetricSpec(
11027+
metric_spec_name="multi_turn_task_success_v1",
11028+
)
11029+
),
11030+
)
11031+
],
11032+
dest="gs://test-bucket/output",
11033+
agent=_TEST_GEMINI_AGENT,
11034+
# No agent_info -- candidate name should come from dataset.
11035+
)
11036+
11037+
request_body = self._get_create_run_body()
11038+
inference_configs = request_body["inferenceConfigs"]
11039+
assert "my-agent-v2" in inference_configs
11040+
assert _evals_common._DEFAULT_CANDIDATE_NAME not in inference_configs
1090311041

1090411042

1090511043
class TestResolveInteractionsForDisplay:

0 commit comments

Comments
 (0)