# User simulation
Supported in ADKPython v1.18.0
When evaluating conversational agents, it is not always practical to use a fixed
set of user prompts, as the conversation can proceed in unexpected ways.
For example, if the agent needs the user to supply two values to perform a task,
it may ask for those values one at a time or both at once.
To resolve this issue, ADK can dynamically generate user prompts using a
generative AI model.
To use this feature, you must specify a [`ConversationScenario`](https://github.com/google/adk-python/blob/main/src/google/adk/evaluation/conversation_scenarios.py) which dictates the user's goals in their conversation with the agent. You may also specify a user persona that you expect the user to adhere to.
A `ConversationScenario` consists of the following components:
* `starting_prompt`: A fixed initial prompt that the user should use to start
the conversation with the agent.
* `conversation_plan`: A high-level guideline for the goals the user must
achieve.
* `user_persona`: A definition of the user's traits, such as technical
expertise or linguistic style.
A sample conversation scenario for the
[`hello_world`](https://github.com/google/adk-python/tree/main/contributing/samples/core/hello_world)
agent is shown below:
```json
{
"starting_prompt": "What can you do for me?",
"conversation_plan": "Ask the agent to roll a 20-sided die. After you get the result, ask the agent to check if it is prime."
}
```
The LLM uses the `conversation_plan`, along with the conversation history, to
dynamically generate user prompts.
You can also specify a pre-built `user_persona` in the following manner:
```json
{
"starting_prompt": "What can you do for me?",
"conversation_plan": "Ask the agent to roll a 20-sided die. After you get the result, ask the agent to check if it is prime.",
"user_persona": "NOVICE"
}
```
While the conversation plan dictates what must be accomplished, the persona dictates how the model phrases its queries and reacts to the agent's responses.
## User personas
Supported in ADKPython v1.26.0
A User Persona is a role that the simulated user adopts during the conversation.
It is defined by a set of **behaviors** that dictate how the user interacts with
the agent, such as their communication style, how they provide information, and
how they react to errors.
A `UserPersona` consists of the following fields:
* `id`: A unique identifier for the persona.
* `description`: A high-level description of who the user is and how they
interact with the agent.
* `behaviors`: A list of `UserBehavior` objects that define specific traits.
Each `UserBehavior` includes:
* `name`: The name of the behavior.
* `description`: A summary of the expected behavior.
* `behavior_instructions`: Specific instructions given to the simulated user
(LLM) on how to act.
* `violation_rubrics`: Used by evaluators to determine whether the user is
following this behavior. If **any** of these rubrics are **satisfied**, the
evaluator should determine the behavior was **not** followed.
## Pre-built Personas
ADK provides a set of pre-built personas composed of common behaviors. The table
below summarizes the behaviors for each persona:
| Behavior | **EXPERT** persona | **NOVICE** persona | **EVALUATOR** persona |
| :--- | :--- | :--- | :--- |
| **Advance** | Detail oriented (proactively provides details) | Goal oriented (waits to be asked for details) | Detail oriented |
| **Answer** | Relevant questions only | Answer all questions | Relevant questions only |
| **Correct Agent Inaccuracies** | Yes | No | No |
| **Troubleshoot Agent Errors** | Once | Never | Never |
| **Tone** | Professional | Conversational | Conversational |
## Example: Evaluate the [`hello_world`](https://github.com/google/adk-python/tree/main/contributing/samples/core/hello_world) agent with conversation scenarios
To add evaluation cases containing conversation scenarios to a new or existing
[`EvalSet`](https://github.com/google/adk-python/blob/main/src/google/adk/evaluation/eval_set.py),
you need to first create a list of conversation scenarios to test the agent in.
Try saving the following to
`contributing/samples/core/hello_world/conversation_scenarios.json`:
```json
{
"scenarios": [
{
"starting_prompt": "What can you do for me?",
"conversation_plan": "Ask the agent to roll a 20-sided die. After you get the result, ask the agent to check if it is prime.",
"user_persona": "NOVICE"
},
{
"starting_prompt": "Hi, I'm running a tabletop RPG in which prime numbers are bad!",
"conversation_plan": "Say that you don't care about the value; you just want the agent to tell you if a roll is good or bad. Once the agent agrees, ask it to roll a 6-sided die. Finally, ask the agent to do the same with 2 20-sided dice.",
"user_persona": "EXPERT"
}
]
}
```
You will also need a session input file containing information used during
evaluation.
Try saving the following to
`contributing/samples/core/hello_world/session_input.json`:
```json
{
"app_name": "hello_world",
"user_id": "user"
}
```
Then, you can add the conversation scenarios to an `EvalSet`:
```bash
# (optional) create a new EvalSet
adk eval_set create \
contributing/samples/core/hello_world \
eval_set_with_scenarios
# add conversation scenarios to the EvalSet as new eval cases
adk eval_set add_eval_case \
contributing/samples/core/hello_world \
eval_set_with_scenarios \
--scenarios_file contributing/samples/core/hello_world/conversation_scenarios.json \
--session_input_file contributing/samples/core/hello_world/session_input.json
```
By default, ADK runs evaluations with metrics that require the agent's expected
response to be specified.
Since that is not the case for a dynamic conversation scenario, we will use an
[`EvalConfig`](https://github.com/google/adk-python/blob/main/src/google/adk/evaluation/eval_config.py)
with some alternate supported metrics.
Try saving the following to
`contributing/samples/core/hello_world/eval_config.json`:
```json
{
"criteria": {
"hallucinations_v1": {
"threshold": 0.5,
"evaluate_intermediate_nl_responses": true
},
"safety_v1": {
"threshold": 0.8
}
}
}
```
Finally, you can use the `adk eval` command to run the evaluation:
```bash
adk eval \
contributing/samples/core/hello_world \
--config_file_path contributing/samples/core/hello_world/eval_config.json \
eval_set_with_scenarios \
--print_detailed_results
```
## User simulator configuration
You can override the default user simulator configuration to change the model,
internal model behavior, and the maximum number of user-agent interactions.
The below `EvalConfig` shows the default user simulator configuration:
```json
{
"criteria": {
# same as before
},
"user_simulator_config": {
"model": "gemini-flash-latest",
"model_configuration": {
"thinking_config": {
"include_thoughts": true,
"thinking_budget": 10240
}
},
"max_allowed_invocations": 20
}
}
```
* `model`: The model backing the user simulator.
* `model_configuration`: A
[`GenerateContentConfig`](https://github.com/googleapis/python-genai/blob/6196b1b4251007e33661bb5d7dc27bafee3feefe/google/genai/types.py#L4295)
which controls the model behavior.
* `max_allowed_invocations`: The maximum user-agent interactions allowed
before the conversation is forcefully terminated. This should be set to be
greater than the longest reasonable user-agent interaction in your
`EvalSet`.
* `custom_instructions`: Optional. Overrides the default instructions for the
user simulator. The instruction string must contain the following formatting
placeholders using
[Jinja](https://jinja.palletsprojects.com/en/stable/templates/#) syntax (*do
not substitute values in advance!*):
* `{{ stop_signal }}` : text to be generated when the user simulator
decides that the conversation is over.
* `{{ conversation_plan }}` : the overall plan for the conversation that
the user simulator must follow.
* `{{ conversation_history }}` : the conversation between the user and the
agent so far.
* You can also access the `UserPersona` object through the `{{ persona }}`
placeholder.
## Custom personas
You can define your own custom persona by providing a `UserPersona` object in
the `ConversationScenario`.
Example of a custom persona definition:
```json
{
"starting_prompt": "I need help with my account.",
"conversation_plan": "Ask the agent to reset your password.",
"user_persona": {
"id": "IMPATIENT_USER",
"description": "A user who is in a rush and gets easily frustrated.",
"behaviors": [
{
"name": "Short responses",
"description": "The user should provide very short, sometimes incomplete responses.",
"behavior_instructions": [
"Keep your responses under 10 words.",
"Omit polite phrases."
],
"violation_rubrics": [
"The user response is over 10 words.",
"The user response is overly polite."
]
}
]
}
}
```
## Generate evaluation cases via user simulation
Writing evaluation cases manually can be time-consuming and may not cover all potential failure modes. ADK provides a command to automatically generate diverse and realistic conversation scenarios based on your agent's definition using the Agent Platform Eval SDK.
!!! warning "Prerequisites: Agent Platform Credentials"
Generating evaluation cases uses the [Vertex Gen AI Evaluation Service API](https://docs.cloud.google.com/vertex-ai/generative-ai/docs/models/evaluation-overview). You must have a Google Cloud project with the Agent Platform API enabled and valid Application Default Credentials (ADC) configured in your environment.
### Command Syntax
```bash
adk eval_set generate_eval_cases \
\
\
--user_simulation_config_file=
```
### Configuration File Format
The `--user_simulation_config_file` expects a JSON file matching the `ConversationGenerationConfig` schema:
```json
{
"count": 5,
"generation_instruction": "Generate scenarios where the user asks to control home devices under different conditions.",
"environment_context": "Available devices: device_1 (Light), device_2 (Thermostat).",
"model_name": "gemini-flash-latest"
}
```
### Configuration Fields
* **`count`** (required): The number of conversation scenarios to generate.
* **`generation_instruction`** (optional): A natural language prompt guiding the specific types of scenarios or goals you want to test.
* **`environment_context`** (optional): Context describing the backend data or state accessible to the agent's tools. This helps the generator create queries that are grounded in realistic data (e.g., valid device IDs).
* **`model_name`** (required): The Gemini model used for generation (e.g., `gemini-flash-latest`).