Repository navigation
test(eval): add the harness and Gradle task for LLM tool-selection evals - #264
Open
adityamparikh wants to merge 1 commit into
Open
adityamparikh wants to merge 1 commit into
adityamparikh wants to merge 1 commit into
Conversation
adityamparikh
force-pushed
the
test/eval-harness
branch
5 times, most recently
from
October 14, 2026 15:45
37c0362 to
51d0077
Compare
adityamparikh
force-pushed
the
test/eval-harness
branch
from
October 14, 2026 19:09
51d0077 to
1e9c4db
Compare
This was referenced Oct 23, 2026
First part of apache#256. `./gradlew eval` runs tests tagged `llm-eval`; every other Test task excludes the tag, so `./gradlew build` never calls a model. The eval context is Spring Boot auto-configuration, set up by properties: - spring-ai-starter-model-openai is the agent, on Spring AI's defaults with OPENAI_API_KEY; nothing is configured. - spring-ai-starter-mcp-client starts the built jar over STDIO against a Testcontainers Solr (stdio connection in application-integration-test.properties). - The ChatClient bean gets the server's instructions, its tools and ToolCallAuditAdvisor, which observes the tool-calling loop from inside (ordered after ToolCallingAdvisor, as the Spring AI reference describes under "Observing the tool-calling loop"). When the model gives its answer, that iteration's request holds every tool call and its ToolResponseMessage; the advisor records them as spring-ai-typesafe JevJudgeInput.ToolCall (name, arguments, result). An ApplicationRunner loads the DevNexus 2026 sessions through the server's own tools. ToolCallAuditAdvisorTest runs a real ChatClient tool loop over a scripted model in ./gradlew build. The first scenario follows in the next change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
adityamparikh
force-pushed
the
test/eval-harness
branch
from
October 26, 2026 19:41
1e9c4db to
e9b2d68
Compare
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Part of #256. Adds the harness for the opt-in LLM tool-selection evals and the
./gradlew evaltask. The first scenario is #265.Stacked on #269 (
./gradlew buildrunsbuildSrc's tests) and #266 (google-java-format): the first two commits here are those PRs, and only the top commit (test(eval): add the harness and Gradle task for LLM tool-selection evals) is new.How it works
A Spring AI
ChatClienton OpenAI, set up as an MCP client of solr-mcp, gets natural-language prompts and calls the server's tools. An advisor records every tool call so a scenario can check which tools were called and with what arguments../gradlew evalruns tests taggedllm-eval. Every otherTesttask excludes that tag, so./gradlew buildnever calls a model.evalis never up to date, doesn't finalizejacocoTestReport(which would pull intest), and passes the bootJar path assolr.mcp.jar.EvalConfigurationis a@TestConfigurationwith@EnableAutoConfiguration, soMain's component scan never picks it up. Auto-configuration provides everything else:spring-ai-starter-model-openaiwith Spring AI's defaults (gpt-5-mini, key fromOPENAI_API_KEY). Nothing is configured.spring-ai-starter-mcp-clientstarts the built jar over STDIO. The connection is inapplication-integration-test.properties:${java.home}/bin/java,-jar ${solr.mcp.jar}, andSOLR_URL=${solr.url}fromTestcontainersConfiguration. The profile also setsspring.ai.mcp.server.enabled=false, so auto-configuration doesn't start an MCP server on the test JVM's stdin and stdout.ChatClientbean: the server's instructions (defaultSystem), its tools (defaultTools), andToolCallAuditAdvisor(defaultAdvisors).ApplicationRunnerloadsmydata/devnexus-2026.json(116 sessions) intodevnexusthrough the server's own tools.ToolCallAuditAdvisorobserves the tool-calling loop from inside, as the Spring AI reference describes under Observing the tool-calling loop. Ordered afterToolCallingAdvisor, it runs on every iteration, and each iteration's request carries the turn so far. When the model answers without asking for another tool, that request holds every tool call and theToolResponseMessagethat answered it. The advisor records them as spring-ai-typesafeJevJudgeInput.ToolCall(name, arguments, result), andToolCallAuditAdvisor.toolCalls(response)reads them back. No tool is wrapped.ToolCallAuditAdvisorTest(inbuild) runs a realChatClienttool loop over a scriptedChatModeland checks what the advisor recorded.The three new dependencies are test-only. The shipped classpath, the SBOM (141 components) and the generated LICENSE are unaffected.
Verification
./gradlew build: 467 tests, 0 skipped, 0 failed (with JDK 25 first onPATHforMcpClientStdioIntegrationTest), plusbuildSrc's 12 tests, which run in the same build via build: run buildSrc's tests as part of the build #269../gradlew nativeTest -Pnative: 306 passed, 0 failed.🤖 Generated with Claude Code