@@ -1064,6 +1064,7 @@ def cli_optimize(
10641064 from .cli_eval import _collect_eval_results
10651065 from .cli_eval import _collect_inferences
10661066 from .cli_eval import get_root_agent
1067+
10671068 except ModuleNotFoundError as mnf :
10681069 raise click .ClickException (MISSING_EVAL_DEPENDENCIES_MESSAGE ) from mnf
10691070
@@ -1199,6 +1200,7 @@ def cli_add_eval_case(
11991200 from ..evaluation .eval_case import EvalCase
12001201 from ..evaluation .eval_case import SessionInput
12011202 from .cli_eval import get_eval_sets_manager
1203+
12021204 except ModuleNotFoundError as mnf :
12031205 raise click .ClickException (MISSING_EVAL_DEPENDENCIES_MESSAGE ) from mnf
12041206
@@ -1247,6 +1249,127 @@ def cli_add_eval_case(
12471249 raise click .ClickException (f"Failed to add eval case(s): { e } " ) from e
12481250
12491251
1252+ @eval_set .command ("generate_eval_cases" , cls = HelpfulCommand )
1253+ @click .argument (
1254+ "agent_module_file_path" ,
1255+ type = click .Path (
1256+ exists = True , dir_okay = True , file_okay = False , resolve_path = True
1257+ ),
1258+ )
1259+ @click .argument ("eval_set_id" , type = str , required = True )
1260+ @click .option (
1261+ "--user_simulation_config_file" ,
1262+ type = click .Path (
1263+ exists = True , dir_okay = False , file_okay = True , resolve_path = True
1264+ ),
1265+ help = (
1266+ "A path to file containing JSON serialized "
1267+ "UserScenarioGenerationConfig dict."
1268+ ),
1269+ required = True ,
1270+ )
1271+ @eval_options ()
1272+ def cli_generate_eval_cases (
1273+ agent_module_file_path : str ,
1274+ eval_set_id : str ,
1275+ user_simulation_config_file : str ,
1276+ eval_storage_uri : Optional [str ] = None ,
1277+ log_level : str = "INFO" ,
1278+ ):
1279+ """Generates eval cases dynamically and adds them to the given eval set.
1280+
1281+ Uses Vertex AI Eval SDK to generate conversation scenarios based on an
1282+ Agent's info and definitions. It will automatically create the empty eval_set
1283+ if it has not been created in advance.
1284+
1285+ Args:
1286+ agent_module_file_path: The path to the agent module file.
1287+ eval_set_id: The id of the eval set to generate cases for.
1288+ user_simulation_config_file: The path to the user simulation config file.
1289+ eval_storage_uri: The eval storage uri.
1290+ log_level: The log level.
1291+ """
1292+ logs .setup_adk_logger (getattr (logging , log_level .upper ()))
1293+ try :
1294+ from ..evaluation ._vertex_ai_scenario_generation_facade import ScenarioGenerator
1295+ from ..evaluation .conversation_scenarios import ConversationGenerationConfig
1296+ from ..evaluation .eval_case import EvalCase
1297+ from ..evaluation .eval_case import SessionInput
1298+ from .cli_eval import get_eval_sets_manager
1299+ from .cli_eval import get_root_agent
1300+ from .utils .state import create_empty_state
1301+
1302+ except ModuleNotFoundError as mnf :
1303+ raise click .ClickException (MISSING_EVAL_DEPENDENCIES_MESSAGE ) from mnf
1304+
1305+ app_name = os .path .basename (agent_module_file_path )
1306+ agents_dir = os .path .dirname (agent_module_file_path )
1307+
1308+ try :
1309+ eval_sets_manager = get_eval_sets_manager (eval_storage_uri , agents_dir )
1310+ root_agent = get_root_agent (agent_module_file_path )
1311+
1312+ # Try to create if it doesn't already exist.
1313+ if (
1314+ eval_sets_manager .get_eval_set (
1315+ app_name = app_name , eval_set_id = eval_set_id
1316+ )
1317+ is None
1318+ ):
1319+ eval_sets_manager .create_eval_set (
1320+ app_name = app_name , eval_set_id = eval_set_id
1321+ )
1322+ click .echo (f"Eval set '{ eval_set_id } ' created for app '{ app_name } '." )
1323+ else :
1324+ click .echo (f"Eval set '{ eval_set_id } ' already exists." )
1325+
1326+ with open (user_simulation_config_file , "r" ) as f :
1327+ config = ConversationGenerationConfig .model_validate_json (f .read ())
1328+
1329+ generator = ScenarioGenerator ()
1330+ click .echo ("Generating scenarios utilizing Vertex AI Eval SDK..." )
1331+ scenarios = generator .generate_scenarios (root_agent , config )
1332+
1333+ # TODO(pthodoroff): Expose initial session state when simulation library
1334+ # supports it.
1335+ initial_session_state = create_empty_state (root_agent )
1336+
1337+ session_input = SessionInput (
1338+ app_name = app_name , user_id = "test_user_id" , state = initial_session_state
1339+ )
1340+
1341+ for scenario in scenarios :
1342+ scenario_str = json .dumps (scenario .model_dump (), sort_keys = True )
1343+ eval_id = hashlib .sha256 (scenario_str .encode ("utf-8" )).hexdigest ()[:8 ]
1344+ eval_case = EvalCase (
1345+ eval_id = eval_id ,
1346+ conversation_scenario = scenario ,
1347+ session_input = session_input ,
1348+ creation_timestamp = datetime .now ().timestamp (),
1349+ )
1350+
1351+ if (
1352+ eval_sets_manager .get_eval_case (
1353+ app_name = app_name , eval_set_id = eval_set_id , eval_case_id = eval_id
1354+ )
1355+ is None
1356+ ):
1357+ eval_sets_manager .add_eval_case (
1358+ app_name = app_name , eval_set_id = eval_set_id , eval_case = eval_case
1359+ )
1360+ click .echo (
1361+ f"Eval case '{ eval_case .eval_id } ' added to eval set"
1362+ f" '{ eval_set_id } '."
1363+ )
1364+ else :
1365+ click .echo (
1366+ f"Eval case '{ eval_case .eval_id } ' already exists in eval set"
1367+ f" '{ eval_set_id } ', skipped adding."
1368+ )
1369+ except Exception as e :
1370+ raise click .ClickException (f"Failed to generate eval case(s): { e } " ) from e
1371+
1372+
12501373def web_options ():
12511374 """Decorator to add web UI options to click commands."""
12521375
0 commit comments