Skip to content

Commit e46d239

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: 953393863
1 parent a16fc0d commit e46d239

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
@@ -3095,7 +3095,25 @@ def create_evaluation_run(
30953095
if isinstance(config, dict):
30963096
config = types.CreateEvaluationRunConfig.model_validate(config)
30973097

3098-
if agent_info and not inference_configs:
3098+
# Auto-construct inference_configs when agent_info is explicitly
3099+
# provided (existing behavior) OR an agent resource is provided
3100+
# (allows omitting agent_info for both Gemini Agents and Agent
3101+
# Engine). The server skips inference per-item when a
3102+
# CandidateResponse with a matching candidate name already exists,
3103+
# so it is safe to always send inference_configs.
3104+
_should_auto_infer = not inference_configs and (agent_info or agent)
3105+
if _should_auto_infer:
3106+
if not parsed_agent_info.name:
3107+
# Prefer the dataset's candidate_name (set by run_inference)
3108+
# so the inference_configs key matches the CandidateResponse
3109+
# and the server correctly skips already-completed items.
3110+
if (
3111+
isinstance(dataset, types.EvaluationDataset)
3112+
and dataset.candidate_name
3113+
):
3114+
parsed_agent_info.name = dataset.candidate_name
3115+
else:
3116+
parsed_agent_info.name = _evals_common._DEFAULT_CANDIDATE_NAME
30993117
parsed_user_simulator_config = (
31003118
evals_types.UserSimulatorConfig.model_validate(user_simulator_config)
31013119
if isinstance(user_simulator_config, dict)
@@ -3104,7 +3122,9 @@ def create_evaluation_run(
31043122
if getattr(parsed_user_simulator_config, "max_turn", None) is None:
31053123
parsed_user_simulator_config.max_turn = 5
31063124

3107-
candidate_name = parsed_agent_info.name or "candidate-1"
3125+
candidate_name = (
3126+
parsed_agent_info.name or _evals_common._DEFAULT_CANDIDATE_NAME
3127+
)
31083128
if agent and _evals_common._is_gemini_agent_resource(agent):
31093129
agent_run_config = types.AgentRunConfig(
31103130
gemini_agent_config=types.GeminiAgentConfig(gemini_agent=agent),
@@ -5163,7 +5183,25 @@ async def create_evaluation_run(
51635183
if isinstance(config, dict):
51645184
config = types.CreateEvaluationRunConfig.model_validate(config)
51655185

5166-
if agent_info and not inference_configs:
5186+
# Auto-construct inference_configs when agent_info is explicitly
5187+
# provided (existing behavior) OR an agent resource is provided
5188+
# (allows omitting agent_info for both Gemini Agents and Agent
5189+
# Engine). The server skips inference per-item when a
5190+
# CandidateResponse with a matching candidate name already exists,
5191+
# so it is safe to always send inference_configs.
5192+
_should_auto_infer = not inference_configs and (agent_info or agent)
5193+
if _should_auto_infer:
5194+
if not parsed_agent_info.name:
5195+
# Prefer the dataset's candidate_name (set by run_inference)
5196+
# so the inference_configs key matches the CandidateResponse
5197+
# and the server correctly skips already-completed items.
5198+
if (
5199+
isinstance(dataset, types.EvaluationDataset)
5200+
and dataset.candidate_name
5201+
):
5202+
parsed_agent_info.name = dataset.candidate_name
5203+
else:
5204+
parsed_agent_info.name = _evals_common._DEFAULT_CANDIDATE_NAME
51675205
parsed_user_simulator_config = (
51685206
evals_types.UserSimulatorConfig.model_validate(user_simulator_config)
51695207
if isinstance(user_simulator_config, dict)
@@ -5172,7 +5210,9 @@ async def create_evaluation_run(
51725210
if getattr(parsed_user_simulator_config, "max_turn", None) is None:
51735211
parsed_user_simulator_config.max_turn = 5
51745212

5175-
candidate_name = parsed_agent_info.name or "candidate-1"
5213+
candidate_name = (
5214+
parsed_agent_info.name or _evals_common._DEFAULT_CANDIDATE_NAME
5215+
)
51765216
if agent and _evals_common._is_gemini_agent_resource(agent):
51775217
agent_run_config = types.AgentRunConfig(
51785218
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
@@ -10869,6 +10869,10 @@ def test_create_evaluation_run_builds_gemini_agent_config(self):
1086910869
== _TEST_GEMINI_AGENT
1087010870
)
1087110871
assert "agent_engine" not in agent_run_config
10872+
# agent_info.name overrides the default candidate name.
10873+
inference_configs = request_body["inferenceConfigs"]
10874+
assert "gemini-agent" in inference_configs
10875+
assert _evals_common._DEFAULT_CANDIDATE_NAME not in inference_configs
1087210876

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

1090011038

1090111039
class TestResolveInteractionsForDisplay:

0 commit comments

Comments
 (0)