Files
spring-ai/README.md
T
Claude fff9f52116 Add tool-calling module: @Tool, ToolCallingAdvisor, returnDirect, ToolContext, and Tool Search Advisor
Every test drives the real Spring AI advisor classes (ToolCallingAdvisor,
ToolSearchToolCallingAdvisor) against a hand-written ScriptedChatModel that queues
real ChatResponse objects instead of calling a live LLM -- confirmed viable because
ChatModel has exactly one abstract method, call(Prompt) (checked with javap).

Covers:
- The plain call/execute/recall loop (WeatherTools, an ordinary @Tool method)
- @Tool(returnDirect = true) skipping the second model round trip entirely
  (ServerStatusTools)
- ToolContext: excluded from the model-facing JSON schema (verified against the
  real generated schema), still delivered to the tool from caller-supplied data
  (UserContextTools)
- A 230-tool synthetic library across six fake domains, generated via
  FunctionToolCallback.builder(...) (LargeToolLibrary)
- ToolSearchToolCallingAdvisor + RegexToolIndex: one tool ("toolSearchTool")
  offered on the first call instead of 230, with real tool-count and
  character-footprint measurements taken off the actual outgoing prompts

Findings recorded in the module's Javadoc rather than silently worked around:
- ToolCallingAdvisor only engages when the request's Prompt carries
  ToolCallingChatOptions, built from ChatModel.getOptions().mutate() (not
  getDefaultOptions(), a separate default method the request-building path never
  calls) -- confirmed by disassembling ToolCallingAdvisor.adviseCall and
  DefaultChatClientUtils
- The Tool Search Advisor's own tool is named "toolSearchTool" (camelCase), not
  "tool_search_tool" -- confirmed via @Tool(name=...) in the decompiled class
- Its session ID comes from ChatClientRequest.context() (AdvisorSpec.param), not
  from ChatClient.toolContext(Map) -- confirmed by disassembling
  ToolSearchToolCallingAdvisor.initializeSession
- RegexToolIndex matches on verb/noun substrings, not semantic relevance -- a
  real captured search for "look up an invoice" returned 5 lookup_-named tools
  across three unrelated domains alongside the one actually wanted

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FtpJvZfg4nvLvtzgJTDWpB
2026-09-23 17:03:41 +00:00

15 lines
2.8 KiB
Markdown

# spring-ai
Runnable companion code for the Spring AI articles on [ankurm.com](https://ankurm.com). One directory per module; each module is one commit and carries its own README, tests and captured output.
| Module | What it is | Article |
|---|---|---|
| [`getting-started/`](getting-started) | One `ChatClient` bean, three endpoints (plain call, templated system prompt, streaming), and a test proving `spring.ai.model.chat` switches providers with zero code change. Spring Boot 4.1.1, Spring AI 2.0.1, Java 25. | [Spring AI 2.0 in 10 Minutes: ChatClient on Spring Boot 4.1](https://ankurm.com/spring-ai-2-0-chatclient-boot-4-1/) |
| [`rag/`](rag) | Ingest PDFs, chunk, retrieve from pgvector, rerank, answer, check the answer. Spring Boot 4.1.1, Spring AI 2.0.1, Java 25. | [Production-grade RAG with Spring AI](https://ankurm.com/production-rag-spring-ai-java/) and [the complete example](https://ankurm.com/spring-ai-rag-complete-example/) |
| [`mcp-server/`](mcp-server) | An order-lookup service exposed as MCP tools, a resource, and a prompt with `@McpTool`/`@McpResource`/`@McpPrompt`, served over Streamable HTTP (Spring AI 2.0's default MCP server transport). Spring Boot 4.1.1, Spring AI 2.0.1, Java 25. | [Build an MCP Server with Spring AI 2.0](https://ankurm.com/spring-ai-2-0-mcp-server-streamable-http/) |
| [`mcp-client/`](mcp-client) | `ChatClient` calling tools from two real external MCP servers (filesystem, git) over stdio via `defaultToolCallbacks(ToolCallbackProvider...)`, contrasted with a local `@Tool` method, with every call logged through one Micrometer `ObservationHandler`. Spring Boot 4.1.1, Spring AI 2.0.1, Java 25. | [Spring AI MCP Client: Calling External MCP Servers from ChatClient](https://ankurm.com/spring-ai-2-0-mcp-client/) |
| [`mcp-secure/`](mcp-secure) | The mcp-server article's order-lookup tools behind a real OAuth2 resource server: JWT validation, one scope per tool via `@PreAuthorize`, unauthenticated tool discovery rejected outright, and every call audit-logged through MDC -- denials included. Spring Boot 4.1.1, Spring AI 2.0.1, Spring Security 7.1.1, Java 25. | [Securing an MCP Server with Spring Security 7](https://ankurm.com/spring-ai-2-0-mcp-server-security/) |
| [`tool-calling/`](tool-calling) | `@Tool` methods, `ToolCallingAdvisor` (the advisor-layer replacement for Spring AI 1.x's per-model tool loop), `returnDirect`, `ToolContext`, and `ToolSearchToolCallingAdvisor` for progressive disclosure across a 230-tool synthetic library -- every test driven by a hand-written `ScriptedChatModel`, no live model anywhere. Spring Boot 4.1.1, Spring AI 2.0.1, Java 25. | [Tool Calling in Spring AI 2.0](https://ankurm.com/spring-ai-2-0-tool-calling/) |
Upgrading from Spring AI 1.x: [migration guide](https://ankurm.com/spring-ai-1-to-2-migration-guide/).