Class SpringAiSupport
This class provides bridge methods to use Spring AI components with the Dokimos evaluation framework.
Using Spring AI ChatClient as a Judge
ChatClient.Builder clientBuilder = ChatClient.builder(chatModel);
JudgeLM judge = SpringAiSupport.asJudge(clientBuilder);
var evaluator = FaithfulnessEvaluator.builder()
.judge(judge)
.build();
Converting Spring AI Evaluation Objects
// Convert Spring AI EvaluationRequest to Dokimos EvalTestCase
EvaluationRequest request = ...;
EvalTestCase testCase = SpringAiSupport.toTestCase(request);
// Run Dokimos evaluation
EvalResult result = evaluator.evaluate(testCase);
// Convert back to Spring AI EvaluationResponse
EvaluationResponse response = SpringAiSupport.toEvaluationResponse(result);
-
Field Summary
Fields -
Method Summary
Modifier and TypeMethodDescriptionstatic JudgeLMasJudge(org.springframework.ai.chat.client.ChatClient.Builder builder) Creates aJudgeLMfrom a Spring AIChatClient.Builder.static JudgeLMasJudge(org.springframework.ai.chat.model.ChatModel model) Creates aJudgeLMfrom a Spring AIChatModel.static AsyncTaskasyncTask(org.springframework.ai.chat.client.ChatClient client) Creates anAsyncTaskthat calls a Spring AIChatClientoff the calling thread and writes the response under thedefault output key.static AsyncTaskCreates anAsyncTaskthat calls a Spring AIChatClientoff the calling thread using caller-chosen input and output keys.static AsyncTaskasyncTask(org.springframework.ai.chat.client.ChatClient client, String inputKey, String outputKey, Executor executor) Creates anAsyncTaskthat calls a Spring AIChatClientusing caller-chosen input and output keys, dispatching each blocking call on the suppliedExecutor(or the commonForkJoinPoolwhenexecutorisnull).static AsyncTaskstatic AsyncTaskmeasuredAsyncTask(org.springframework.ai.chat.client.ChatClient client, String modelId, PriceTable prices) Creates a measuredAsyncTaskthat calls a Spring AIChatClientand captures token usage, latency, and (when aPriceTableis supplied) cost, lighting up the run's metrics cards.static AsyncTaskmeasuredAsyncTask(org.springframework.ai.chat.client.ChatClient client, String modelId, PriceTable prices, Executor executor) static AsyncTaskmeasuredAsyncTask(org.springframework.ai.chat.client.ChatClient client, String inputKey, String outputKey, String modelId, PriceTable prices, Executor executor) Creates a measuredAsyncTaskwith caller-chosen input and output keys, dispatching each blocking call on the suppliedExecutor(or the commonForkJoinPoolwhenexecutorisnull).static AsyncTaskreactiveStringTask(Function<Example, reactor.core.publisher.Mono<String>> taskFunction) Adapts a ReactorMonoofStringoutput to anAsyncTask, wrapping the emitted string under thedefault output key.static AsyncTaskreactiveTask(Function<Example, reactor.core.publisher.Mono<TaskResult>> taskFunction) static AgentTracetoAgentTrace(org.springframework.ai.chat.messages.AssistantMessage message) Builds anAgentTracefrom a Spring AIAssistantMessage.static AgentTracetoAgentTrace(org.springframework.ai.chat.messages.AssistantMessage message, List<org.springframework.ai.chat.messages.ToolResponseMessage> toolResponses) Builds anAgentTracefrom a Spring AIAssistantMessageand the tool responses produced for it.static org.springframework.ai.evaluation.EvaluationResponsetoEvaluationResponse(EvalResult result) Converts a DokimosEvalResultto a Spring AIEvaluationResponse.static EvalTestCasetoTestCase(org.springframework.ai.evaluation.EvaluationRequest request) Converts a Spring AIEvaluationRequestto a DokimosEvalTestCase.toToolCalls(org.springframework.ai.chat.messages.AssistantMessage message) ExtractsToolCalls from a Spring AIAssistantMessagewithout results.toToolCalls(org.springframework.ai.chat.messages.AssistantMessage message, List<org.springframework.ai.chat.messages.ToolResponseMessage> toolResponses) ExtractsToolCalls from a Spring AIAssistantMessage, attaching results from the supplied tool responses by tool-call id.static List<ToolDefinition> toToolDefinitions(List<org.springframework.ai.tool.definition.ToolDefinition> toolDefinitions) Converts Spring AIToolDefinitions to DokimosToolDefinitions so tool calls can be evaluated against the tools the agent was given.
-
Field Details
-
OUTPUT_KEY
Default key for the model output in evaluation results.- See Also:
-
CONTEXT_KEY
Default key for additional context in evaluation results.- See Also:
-
INPUT_KEY
Default key for reading input from dataset examples.- See Also:
-
-
Method Details
-
asJudge
Creates aJudgeLMfrom a Spring AIChatClient.Builder.Use this to create judges for LLM-based evaluators like
LLMJudgeEvaluator,FaithfulnessEvaluator, etc.Example:
ChatClient.Builder clientBuilder = ChatClient.builder(chatModel); JudgeLM judge = SpringAiSupport.asJudge(clientBuilder); var evaluator = LLMJudgeEvaluator.builder() .judge(judge) .criteria("Is the response helpful?") .build();- Parameters:
builder- the ChatClient.Builder to use as judge- Returns:
- a JudgeLM that delegates to the ChatClient
-
asJudge
Creates aJudgeLMfrom a Spring AIChatModel.This is a convenience overload that accepts a ChatModel directly instead of a
ChatClient.Builder.Example:
ChatModel chatModel = OpenAiChatModel.builder()...build(); JudgeLM judge = SpringAiSupport.asJudge(chatModel); var evaluator = FaithfulnessEvaluator.builder() .judge(judge) .build();- Parameters:
model- the ChatModel to use as judge- Returns:
- a JudgeLM that delegates to the ChatModel
-
toTestCase
Converts a Spring AIEvaluationRequestto a DokimosEvalTestCase.Maps the following fields:
getUserText()→ inputgetResponseContent()→ actual outputgetDataList()→ context (list of document contents)
Example:
EvaluationRequest request = new EvaluationRequest( userText, retrievedDocuments, responseContent); EvalTestCase testCase = SpringAiSupport.toTestCase(request); EvalResult result = faithfulnessEvaluator.evaluate(testCase);- Parameters:
request- the Spring AI evaluation request- Returns:
- an EvalTestCase containing the request data
-
toEvaluationResponse
public static org.springframework.ai.evaluation.EvaluationResponse toEvaluationResponse(EvalResult result) Converts a DokimosEvalResultto a Spring AIEvaluationResponse.Maps the following fields:
score-> metadata["score"] (as float)success-> pass/fail statusreason-> the reasoning textmetadata-> preserved in response metadata
Example:
EvalResult result = evaluator.evaluate(testCase); EvaluationResponse response = SpringAiSupport.toEvaluationResponse(result); System.out.println("Score: " + response.getMetadata().get("score")); System.out.println("Passed: " + response.isPass()); System.out.println("Feedback: " + response.getFeedback());- Parameters:
result- the Dokimos evaluation result- Returns:
- an EvaluationResponse containing the result data
-
asyncTask
Creates anAsyncTaskthat calls a Spring AIChatClientoff the calling thread and writes the response under thedefault output key.The example's
inputis sent as the user message. TheChatClient.prompt()call is dispatched on the commonForkJoinPoolviaCompletableFuture.supplyAsync(java.util.function.Supplier)so the experiment's async execution path can keep many calls in flight without a blocked thread per example.Note: because the call blocks on the common pool, the experiment's
parallelismbounds how many invocations are launched, but the effective concurrency of the blocking HTTP call is also limited by the common pool (~one less than the CPU count), which is shared process-wide. For higher, isolated concurrency useasyncTask(ChatClient, java.util.concurrent.Executor)(or the four-arg overload) to run calls on a pool you control.Example:
ChatClient client = ChatClient.builder(chatModel).build(); AsyncTask task = SpringAiSupport.asyncTask(client); Experiment.builder() .asyncTask(task) .parallelism(8) .evaluators(List.of(evaluator)) .build() .run();- Parameters:
client- the ChatClient to call, never null- Returns:
- an AsyncTask suitable for
Experiment.builder().asyncTask(...) - Throws:
IllegalArgumentException- ifclientis null
-
asyncTask
public static AsyncTask asyncTask(org.springframework.ai.chat.client.ChatClient client, String inputKey, String outputKey) Creates anAsyncTaskthat calls a Spring AIChatClientoff the calling thread using caller-chosen input and output keys.Behaves like
asyncTask(ChatClient)but reads the user message frominputKeyand writes the response underoutputKey, for datasets or evaluators that use different key names.- Parameters:
client- the ChatClient to call, never nullinputKey- the key to read the user message from the example inputs, never nulloutputKey- the key the response is written under in the result, never null- Returns:
- an AsyncTask suitable for
Experiment.builder().asyncTask(...) - Throws:
IllegalArgumentException- if any argument is null
-
asyncTask
public static AsyncTask asyncTask(org.springframework.ai.chat.client.ChatClient client, Executor executor) Creates anAsyncTaskthat calls a Spring AIChatClienton the suppliedExecutor, with default input and output keys.Use this when you want the blocking call to run on a pool you control (sized to your desired concurrency) rather than the shared common
ForkJoinPool. Pair the executor's size with the experiment'sparallelismfor predictable throughput.- Parameters:
client- the ChatClient to call, never nullexecutor- the executor each blocking call runs on, never null- Returns:
- an AsyncTask suitable for
Experiment.builder().asyncTask(...) - Throws:
IllegalArgumentException- ifclientorexecutoris null
-
asyncTask
public static AsyncTask asyncTask(org.springframework.ai.chat.client.ChatClient client, String inputKey, String outputKey, Executor executor) Creates anAsyncTaskthat calls a Spring AIChatClientusing caller-chosen input and output keys, dispatching each blocking call on the suppliedExecutor(or the commonForkJoinPoolwhenexecutorisnull).Supplying an executor lets you control and isolate concurrency: the experiment's
parallelismbounds in-flight invocations, and a pool sized to match gives true parallel blocking calls instead of the common pool's ~CPU-count, process-wide ceiling.- Parameters:
client- the ChatClient to call, never nullinputKey- the key to read the user message from the example inputs, never nulloutputKey- the key the response is written under in the result, never nullexecutor- the executor each blocking call runs on, ornullfor the common pool- Returns:
- an AsyncTask suitable for
Experiment.builder().asyncTask(...) - Throws:
IllegalArgumentException- ifclient,inputKey, oroutputKeyis null
-
reactiveTask
public static AsyncTask reactiveTask(Function<Example, reactor.core.publisher.Mono<TaskResult>> taskFunction) Adapts a ReactorMonoofTaskResultto anAsyncTask.For reactive Spring AI pipelines: supply a function that produces a
Mono<TaskResult>for an example, and the resulting task converts each Mono to aCompletableFutureviaMono.toFuture().Example:
AsyncTask task = SpringAiSupport.reactiveTask(example -> reactiveChatClient.prompt() .user(example.input()) .stream() .content() .collectList() .map(parts -> TaskResult.of(Map.of("output", String.join("", parts)))));- Parameters:
taskFunction- a function producing aMono<TaskResult>for an example, never null- Returns:
- an AsyncTask backed by the supplied Mono
- Throws:
IllegalArgumentException- iftaskFunctionis null
-
reactiveStringTask
public static AsyncTask reactiveStringTask(Function<Example, reactor.core.publisher.Mono<String>> taskFunction) Adapts a ReactorMonoofStringoutput to anAsyncTask, wrapping the emitted string under thedefault output key.Convenience over
reactiveTask(Function)for the common case where the reactive pipeline yields the model's textual response directly. Anullemission is stored as an empty string.Example:
AsyncTask task = SpringAiSupport.reactiveStringTask(example -> reactiveChatClient.prompt().user(example.input()).stream().content().last());- Parameters:
taskFunction- a function producing aMono<String>response for an example, never null- Returns:
- an AsyncTask that writes the emitted string under the default output key
- Throws:
IllegalArgumentException- iftaskFunctionis null
-
measuredAsyncTask
public static AsyncTask measuredAsyncTask(org.springframework.ai.chat.client.ChatClient client, String modelId, PriceTable prices) Creates a measuredAsyncTaskthat calls a Spring AIChatClientand captures token usage, latency, and (when aPriceTableis supplied) cost, lighting up the run's metrics cards.Counterpart to
asyncTask(ChatClient): instead of reading only.call().content(), it reads.call().chatResponse()so theUsage(prompt/completion tokens) is available, times the call, and composes cost viaprices. The blocking call runs on the commonForkJoinPool; for isolated, true concurrency usemeasuredAsyncTask(ChatClient, String, PriceTable, Executor)with a pool you size to the experiment'sparallelism(the common pool's ceiling is ~CPU-count, process-wide).Missing usage leaves the token fields null; a null
prices(or a null lookup result) leaves cost null so only the Tokens and Latency cards light. Never throws on missing metrics.- Parameters:
client- the ChatClient to call, never nullmodelId- the model id used as thePriceTablelookup key, or null to skip pricingprices- the price lookup, or null to capture tokens and latency only- Returns:
- an AsyncTask suitable for
Experiment.builder().asyncTask(...) - Throws:
IllegalArgumentException- ifclientis null
-
measuredAsyncTask
public static AsyncTask measuredAsyncTask(org.springframework.ai.chat.client.ChatClient client, String modelId, PriceTable prices, Executor executor) Creates a measuredAsyncTaskthat dispatches each blocking call on the suppliedExecutorso you control and isolate concurrency.- Parameters:
client- the ChatClient to call, never nullmodelId- the model id used as thePriceTablelookup key, or null to skip pricingprices- the price lookup, or null to capture tokens and latency onlyexecutor- the executor each blocking call runs on, never null- Returns:
- an AsyncTask suitable for
Experiment.builder().asyncTask(...) - Throws:
IllegalArgumentException- ifclientorexecutoris null
-
measuredAsyncTask
public static AsyncTask measuredAsyncTask(org.springframework.ai.chat.client.ChatClient client, String inputKey, String outputKey, String modelId, PriceTable prices, Executor executor) Creates a measuredAsyncTaskwith caller-chosen input and output keys, dispatching each blocking call on the suppliedExecutor(or the commonForkJoinPoolwhenexecutorisnull).- Parameters:
client- the ChatClient to call, never nullinputKey- the key to read the user message from the example inputs, never nulloutputKey- the key the response is written under in the result, never nullmodelId- the model id used as thePriceTablelookup key, or null to skip pricingprices- the price lookup, or null to capture tokens and latency onlyexecutor- the executor each blocking call runs on, ornullfor the common pool- Returns:
- an AsyncTask suitable for
Experiment.builder().asyncTask(...) - Throws:
IllegalArgumentException- ifclient,inputKey, oroutputKeyis null
-
toAgentTrace
public static AgentTrace toAgentTrace(org.springframework.ai.chat.messages.AssistantMessage message) Builds anAgentTracefrom a Spring AIAssistantMessage.The message's text becomes the final response and its
getToolCalls()becomeToolCalls with parsed arguments. Tool results are not part of anAssistantMessage; usetoAgentTrace(AssistantMessage, List)to attach them.- Parameters:
message- the assistant message (may be null)- Returns:
- an agent trace, never null
-
toAgentTrace
public static AgentTrace toAgentTrace(org.springframework.ai.chat.messages.AssistantMessage message, List<org.springframework.ai.chat.messages.ToolResponseMessage> toolResponses) Builds anAgentTracefrom a Spring AIAssistantMessageand the tool responses produced for it.Each tool call is matched to its result by tool-call id from the supplied
ToolResponseMessages, so the resulting trace carries both the agent's tool calls and what those tools returned.AgentTrace trace = SpringAiSupport.toAgentTrace(assistantMessage, toolResponseMessages); EvalTestCase testCase = trace.toTestCase(userMessage, tools);- Parameters:
message- the assistant message (may be null)toolResponses- the tool response messages whose responses carry results (may be null)- Returns:
- an agent trace, never null
-
toToolCalls
public static List<ToolCall> toToolCalls(org.springframework.ai.chat.messages.AssistantMessage message) ExtractsToolCalls from a Spring AIAssistantMessagewithout results.- Parameters:
message- the assistant message (may be null)- Returns:
- the tool calls in order, or an empty list
-
toToolCalls
public static List<ToolCall> toToolCalls(org.springframework.ai.chat.messages.AssistantMessage message, List<org.springframework.ai.chat.messages.ToolResponseMessage> toolResponses) ExtractsToolCalls from a Spring AIAssistantMessage, attaching results from the supplied tool responses by tool-call id.- Parameters:
message- the assistant message (may be null)toolResponses- the tool response messages (may be null)- Returns:
- the tool calls in order, or an empty list
-
toToolDefinitions
public static List<ToolDefinition> toToolDefinitions(List<org.springframework.ai.tool.definition.ToolDefinition> toolDefinitions) Converts Spring AIToolDefinitions to DokimosToolDefinitions so tool calls can be evaluated against the tools the agent was given.- Parameters:
toolDefinitions- the Spring AI tool definitions (may be null)- Returns:
- the Dokimos tool definitions, or an empty list
-