사용자 시뮬레이션
사용자 시뮬레이션은 LLM 지원 액터를 사용하여 에이전트와 상호 작용하는 최종 사용자의 역할을 수행합니다. 액터의 프로필과 목표를 정의하고, 액터는 목표가 충족되거나 턴 한도에 도달할 때까지 에이전트와 멀티턴 대화를 진행합니다.
참고
사용자 시뮬레이션은 SDK 측에서 Amazon Bedrock 모델을 호출하여 액터의 응답을 생성합니다. 이러한 호출에는 표준 Amazon Bedrock 모델 호출 요금이 적용됩니다. 자세한 내용은 AgentCore 요금 페이지를
이는 다음과 같은 경우에 유용합니다.
-
사실적인 변형으로 테스트: 액터는 실행마다 다양한 문구, 후속 질문 및 대화 경로를 생성하여 수작업 작성 시나리오가 놓치는 엣지 케이스를 노출합니다.
-
개방형 대화 평가: 자유 형식 대화(고객 지원, 자습서, 자문)를 처리하는 에이전트의 경우 시뮬레이션된 시나리오는 고정 턴 시퀀스보다 실제 사용자 행동을 더 잘 반영합니다.
-
시나리오 범위 조정: 수십 개의 멀티턴 스크립트를 직접 작성하는 대신 다양한 페르소나와 목표를 가진 액터 프로파일을 정의하고 액터가 대화를 생성하도록 합니다.
-
다양성을 사용한 회귀 테스트: 동일한 액터 프로파일을 여러 번 실행하여 에이전트가 동일한 의도의 다양한 표현식을 처리하는지 확인합니다.
사용자 시뮬레이션은 온디맨드 및 배치 데이터 세트 실행기 모두에서 작동합니다.
작동 방식
실행기는 대화 루프를 통해 시뮬레이션된 각 시나리오를 처리합니다.
-
시작: 실행기가 시나리오의
input필드를 에이전트에게 첫 번째 턴으로 보냅니다. -
에이전트 응답: 에이전트가 입력을 처리하고 응답을 반환합니다.
-
액터 평가: LLM 지원 액터는 에이전트의 응답을 수신하고 프로필과 목표에 따라 다음에 수행할 작업을 결정합니다. 액터는 다음을 포함하는 구조화된 응답을 생성합니다.
-
추론: 액터의 응답에 대한 내부 추론(예: “에이전트가 항공편 옵션을 제공했지만 원하는 시간을 요청하지 않았습니다. 오전 항공편을 선호한다고 지정해야 합니다."). 이는 액터가 특정 방식으로 동작한 이유를 디버깅하는 데 유용합니다.
-
메시지: 에이전트에게 보낼 다음 메시지입니다.
-
중지 신호: 액터가 목표를 달성했다고 간주하는지 여부를 나타내는 부울입니다.
-
-
계속 또는 중지: 액터가 목표 완료(
stop: true)에 신호를 보내거나 회전 수가에 도달하면 대화max_turns가 종료됩니다. 그렇지 않으면 액터의 다음 메시지가 다음 턴의 입력이 됩니다. -
평가: 대화가 완료되면 실행기는 사전 정의된 시나리오와 마찬가지로 구성된 평가자를 사용하여 세션을 평가합니다.
액터 프로파일
시뮬레이션된 각 시나리오에는 액터가 누구이고 무엇을 달성하고 싶은지 ActorProfile 정의하는이 필요합니다.
| Field | 필수 | 설명 |
|---|---|---|
|
|
예 |
액터에 대한 배경 정보입니다. 상황과 액터가 알아야 하는 관련 세부 정보를 설명합니다. |
|
|
예 |
액터가 대화에서 달성하고자 하는 것. 액터는 목표가 충족되었다고 판단되면 완료 신호를 보냅니다. |
|
|
아니요 |
액터의 특성(예: 전문 지식 수준, 커뮤니케이션 스타일, 인내)을 설명하는 키-값 페어입니다. 기본값은 비어 있습니다. |
{ "actor_profile": { "context": "A customer who purchased a laptop last week and it arrived with a cracked screen", "goal": "Get a replacement laptop shipped within 2 business days", "traits": { "expertise": "non-technical", "tone": "frustrated but polite", "patience": "low" } } }
시뮬레이션 구성
는 액터의 동작을 SimulationConfig 제어하며 러너의 평가 구성에 설정됩니다.
| Field | 기본값 | 설명 |
|---|---|---|
|
|
기본 모델 |
액터 LLM에 사용되는 Amazon Bedrock 모델 ID입니다. 복잡한 페르소나 지침을 따를 수 있는 모델을 선택합니다. 생략하면 기본 모델이 사용됩니다. |
from bedrock_agentcore.evaluation import SimulationConfig simulation_config = SimulationConfig( model_id="<model-id>", )
데이터 세트 스키마
시뮬레이션된 시나리오는 input 대신 actor_profile 및를 사용합니다turns.
{ "scenarios": [ { "scenario_id": "geography-student", "scenario_description": "A curious student asks geography questions", "actor_profile": { "traits": {"expertise": "novice", "tone": "curious"}, "context": "A student studying world geography who wants to learn about capitals", "goal": "Find out the capital cities of at least two different countries" }, "input": "Hi! I'm studying geography. Can you help me learn about world capitals?", "max_turns": 5, "assertions": [ "Agent provides accurate capital city information", "Agent is helpful and encouraging to the student" ] } ] }
| Field | 필수 | 기본값 | 설명 |
|---|---|---|---|
|
|
예 |
— |
시나리오의 고유 식별자입니다. |
|
|
아니요 |
|
시나리오를 설명하는 선택적 메타데이터입니다. 결과에서 시나리오를 구성하고 식별하는 데 유용합니다. |
|
|
예 |
— |
액터의 자격 증명 및 목표. 액터 프로파일을(를) 참조하세요. |
|
|
예 |
— |
대화를 시작하기 위해 에이전트에게 전송된 첫 번째 메시지입니다. |
|
|
아니요 |
10 |
대화가 중지되기 전 최대 회전 수입니다. 1 이상이어야 함. |
|
|
아니요 |
— |
예상 동작에 대한 자연어 어설션입니다. 와 같은 세션 수준 평가자가 사용합니다 |
참고
시뮬레이션된 시나리오는 대화 흐름을 미리 알 수 없기 expected_response 때문에 expected_trajectory 또는 턴당을 지원하지 않습니다. 시뮬레이션된 시나리오에서 실측 정보에 assertions를 사용합니다.
FileDatasetProvider는 JSON 구조에서 시나리오 유형을 자동 감지합니다. actor_profile 필드가 있는 시나리오( turns 필드가 없는 시나리오)는 로 로드됩니다SimulatedScenario.
배치 데이터 세트 실행기와 함께 사용
다음 예제에서는 배치 데이터 세트 실행기를 사용하여 시뮬레이션된 시나리오 평가를 실행합니다. simulation_config를 설정하고 데이터 세트에 SimulatedScenario 인스턴스를 BatchEvaluationRunConfig 포함합니다.
import boto3 import json from bedrock_agentcore.evaluation import ( BatchEvaluationRunner, BatchEvaluationRunConfig, BatchEvaluatorConfig, CloudWatchDataSourceConfig, SimulationConfig, AgentInvokerInput, AgentInvokerOutput, Dataset, SimulatedScenario, ActorProfile, ) AGENT_ARN = "arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/MyAgent-abc123" # Replace with your agent runtime ARN REGION = "us-west-2" # Replace with your region RUNTIME_ID = AGENT_ARN.split("/")[-1] AGENT_NAME = RUNTIME_ID.rsplit("-", 1)[0] ENDPOINT_NAME = "DEFAULT" LOG_GROUP = f"/aws/bedrock-agentcore/runtimes/{RUNTIME_ID}-{ENDPOINT_NAME}" SERVICE_NAME = f"{AGENT_NAME}.{ENDPOINT_NAME}" ACTOR_MODEL_ID = "global.anthropic.claude-haiku-4-5-20251001-v1:0" # Replace with your preferred model # Define the dataset with simulated scenarios dataset = Dataset( scenarios=[ SimulatedScenario( scenario_id="support-frustrated-customer", scenario_description="A frustrated customer with a defective product", actor_profile=ActorProfile( traits={"expertise": "non-technical", "tone": "frustrated but polite"}, context="Purchased a laptop last week that arrived with a cracked screen", goal="Get a replacement laptop shipped within 2 business days", ), input="I received my laptop and the screen is cracked. I need help.", max_turns=8, assertions=[ "Agent acknowledges the issue and apologizes", "Agent offers a replacement or refund", "Agent provides a timeline for resolution", ], ), SimulatedScenario( scenario_id="support-billing-question", scenario_description="A customer with a billing discrepancy", actor_profile=ActorProfile( traits={"expertise": "moderate", "tone": "calm"}, context="Noticed a double charge on the last credit card statement", goal="Get the duplicate charge reversed and confirmation of the refund", ), input="I see two charges for the same order on my statement. Can you look into this?", max_turns=6, assertions=[ "Agent investigates the billing issue", "Agent confirms whether a duplicate charge exists", ], ), ] ) # Configure the evaluation config = BatchEvaluationRunConfig( batch_evaluation_name="simulated-support-eval", evaluator_config=BatchEvaluatorConfig( evaluator_ids=[ "Builtin.GoalSuccessRate", "Builtin.Helpfulness", ], ), data_source=CloudWatchDataSourceConfig( service_names=[SERVICE_NAME], log_group_names=[LOG_GROUP], ingestion_delay_seconds=180, ), simulation_config=SimulationConfig( model_id=ACTOR_MODEL_ID, ), polling_timeout_seconds=1800, polling_interval_seconds=30, ) # Define the agent invoker agentcore_client = boto3.client("bedrock-agentcore", region_name=REGION) def agent_invoker(inp: AgentInvokerInput) -> AgentInvokerOutput: payload = inp.payload if isinstance(payload, str): raw_bytes = json.dumps({"prompt": payload}).encode() elif isinstance(payload, dict): raw_bytes = json.dumps(payload).encode() else: raw_bytes = json.dumps({"prompt": str(payload)}).encode() print(f"[{inp.session_id}] > sending payload: {raw_bytes.decode()}") response = agentcore_client.invoke_agent_runtime( agentRuntimeArn=AGENT_ARN, runtimeSessionId=inp.session_id, payload=raw_bytes, ) response_body = response["response"].read() print(f"[{inp.session_id}] < received response: {response_body.decode()}") return AgentInvokerOutput(agent_output=json.loads(response_body)) # Run the evaluation runner = BatchEvaluationRunner(region=REGION) result = runner.run_dataset_evaluation( config=config, dataset=dataset, agent_invoker=agent_invoker, ) # Display results print(f"Status: {result.status}") if result.evaluation_results: er = result.evaluation_results print(f"Sessions completed: {er.number_of_sessions_completed}") print(f"Sessions failed: {er.number_of_sessions_failed}") for summary in er.evaluator_summaries or []: avg = summary.statistics.average_score if summary.statistics else None print(f" {summary.evaluator_id}: avg={avg}")
온디맨드 데이터 세트 실행기와 함께 사용
온디맨드 데이터 세트 실행기는 동일한 패턴을 따릅니다. simulation_config를 설정하고 데이터 세트에 SimulatedScenario 인스턴스를 EvaluationRunConfig 포함합니다.
참고
온디맨드 평가는 사용량에 따라 요금이 부과됩니다. 자세한 내용은 AgentCore 요금 페이지를
from bedrock_agentcore.evaluation import ( OnDemandEvaluationDatasetRunner, EvaluationRunConfig, EvaluatorConfig, CloudWatchAgentSpanCollector, SimulationConfig, FileDatasetProvider, ) AGENT_ARN = "arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/MyAgent-abc123" # Replace with your agent runtime ARN REGION = "us-west-2" # Replace with your region RUNTIME_ID = AGENT_ARN.split("/")[-1] ENDPOINT_NAME = "DEFAULT" LOG_GROUP = f"/aws/bedrock-agentcore/runtimes/{RUNTIME_ID}-{ENDPOINT_NAME}" ACTOR_MODEL_ID = "global.anthropic.claude-haiku-4-5-20251001-v1:0" # Replace with your preferred model # Load dataset (auto-detects simulated scenarios from actor_profile field) dataset = FileDatasetProvider("simulated_dataset.json").get_dataset() # Create span collector span_collector = CloudWatchAgentSpanCollector( log_group_name=LOG_GROUP, region=REGION, ) # Configure with simulation support config = EvaluationRunConfig( evaluator_config=EvaluatorConfig( evaluator_ids=["Builtin.GoalSuccessRate", "Builtin.Helpfulness"], ), evaluation_delay_seconds=180, max_concurrent_scenarios=5, simulation_config=SimulationConfig( model_id=ACTOR_MODEL_ID, ), ) # Run runner = OnDemandEvaluationDatasetRunner(region=REGION) result = runner.run( agent_invoker=agent_invoker, dataset=dataset, span_collector=span_collector, config=config, ) for scenario in result.scenario_results: print(f"Scenario: {scenario.scenario_id} ({scenario.status})") for evaluator in scenario.evaluator_results: for r in evaluator.results: print(f" {evaluator.evaluator_id}: {r.get('value')} ({r.get('label')})")
중지 조건
시뮬레이션된 대화는 다음 조건 중 하나라도 충족되면 종료됩니다.
-
목표 완료: 액터가 목표가 달성되었다고 판단하고에 신호를 보냅니다
stop: true. 이는 예상되는 결과입니다. -
최대 회전 수에 도달: 대화가
max_turns제한에 도달했습니다. 이는 안전 백스톱 역할을 합니다. 시나리오가 턴 제한에 자주 도달하는 경우 액터의 목표를 늘리max_turns거나 단순화하는 것이 좋습니다. -
메시지가 생성되지 않음: 액터가 다음 메시지를 생성하지 않지만 명시적으로 중지 신호를 보내지 않습니다. 이는 암시적 목표 완료로 취급됩니다.
효과적인 시뮬레이션 시나리오를 위한 팁
-
목표에 구체적으로 명시하세요. "대화하기"와 같은 모호한 목표는 포커스가 없는 상호 작용으로 이어집니다. "주문 #12345에 대한 환불 받기"와 같은 특정 목표는 액터에게 명확한 엔드포인트를 제공합니다.
-
특성을 사용하여 난이도 제어:가 있는 액터
"expertise": "expert"는가 있는 액터보다 더 어려운 질문을 합니다"expertise": "novice". 특성을 사용하여 다양한 사용자 세그먼트에서 에이전트를 테스트합니다. -
현실적인 턴 제한 설정: 대부분의 고객 지원 대화는 5~10차례에 걸쳐 해결됩니다.
max_turns너무 높게 설정하면 컴퓨팅이 낭비되고 너무 낮게 설정하면 목표에 도달하기 전에 대화가 중단될 수 있습니다. -
실측에 어설션 사용: 대화 흐름은 동적이므로 턴당
expected_response을 사용할 수 없습니다. 가져온 특정 경로에 관계없이 예상한 결과를 설명하는 어설션을 작성합니다. -
적절한 액터 모델 선택: 액터 모델은 차례로 일관된 페르소나를 유지할 수 있을 만큼 충분히 능력이 있어야 합니다. 작은 모델은 단순한 페르소나에 적합합니다. 미묘한 목표가 있는 복잡한 페르소나는 보다 유능한 모델의 이점을 누릴 수 있습니다.