Skip to main content

Test Case Model

AgentTestCase is the core data container that represents a single agent interaction to be evaluated.

AgentTestCase

All fields use an immutable builder. Only input and actualOutput are required.

var testCase = AgentTestCase.builder()
.input("What is our refund policy?")
.actualOutput(agent.run("What is our refund policy?"))
.expectedOutput("Full refund within 30 days of purchase.")
.retrievalContext(List.of(
"Customers may request a full refund within 30 days.",
"Refunds are processed within 5–7 business days."
))
.context(List.of(
"Full refund within 30 days of purchase." // ground truth — what SHOULD have been retrieved
))
.toolCalls(agent.getLastToolCalls())
.expectedToolCalls(List.of(
ToolCall.of("SearchKnowledgeBase", Map.of("query", "refund policy"))
))
.latencyMs(342)
.tokenUsage(TokenUsage.of(120, 85, 205))
.metadata(Map.of("category", "refund", "difficulty", "easy"))
.build();

Field Reference

FieldTypeRequiredDescription
inputStringYesUser query or prompt sent to the agent
actualOutputStringYesThe agent's actual response
expectedOutputStringNoGround truth / ideal response
retrievalContextList<String>NoDocuments retrieved by the RAG pipeline
contextList<String>NoGround truth context (should have been retrieved)
toolCallsList<ToolCall>NoTools actually invoked during execution
expectedToolCallsList<ToolCall>NoExpected tool invocations
reasoningTraceList<ReasoningStep>NoChain-of-thought / planning steps
latencyMslongNoEnd-to-end execution time in milliseconds
tokenUsageTokenUsageNoInput/output/total token counts
costBigDecimalNoEstimated cost of the interaction
metadataMap<String, Object>NoArbitrary key-value pairs for filtering

ConversationTestCase

For multi-turn conversations, use ConversationTestCase:

var conversation = ConversationTestCase.builder()
.conversationId("session-42")
.systemPrompt("You are a helpful customer support agent.")
.turn(AgentTestCase.builder()
.input("Hi, I want to return something.")
.actualOutput(agent.chat("Hi, I want to return something."))
.build())
.turn(AgentTestCase.builder()
.input("It's order #5678.")
.actualOutput(agent.chat("It's order #5678."))
.build())
.build();

Supporting Types

ToolCall

// Simple tool call (no result)
ToolCall.of("SearchOrders", Map.of("orderId", "12345"));

// With result
ToolCall toolCall = ToolCall.builder()
.name("SearchOrders")
.arguments(Map.of("orderId", "12345"))
.result("{\"status\": \"delivered\", \"date\": \"2026-01-15\"}")
.durationMs(143)
.build();

ReasoningStep

ReasoningStep step = ReasoningStep.builder()
.type(StepType.THOUGHT)
.content("I need to look up the order status before proceeding.")
.build();

ReasoningStep action = ReasoningStep.builder()
.type(StepType.ACTION)
.content("Calling SearchOrders tool")
.toolCall(ToolCall.of("SearchOrders", Map.of("orderId", "12345")))
.build();

StepType values: PLAN, THOUGHT, OBSERVATION, ACTION

TokenUsage

TokenUsage usage = TokenUsage.of(120, 85, 205);  // input, output, total

// Or:
TokenUsage usage = new TokenUsage(120, 85, 205);

Which Fields to Populate

Different metrics require different fields:

Metric CategoryRequired Fields
Response quality (AnswerRelevancy, Correctness)input, actualOutput
RAG metrics (Faithfulness, ContextualPrecision)input, actualOutput, retrievalContext
Tool metricstoolCalls, expectedToolCalls
Plan metricsreasoningTrace
Conversation metricsUse ConversationTestCase