Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 35 additions & 7 deletions contrib/spring-ai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,9 @@ adk:
observability:
enabled: true
metrics-enabled: true
tool-execution:
# Default: ADK executes tool calls with its InvocationContext-backed ToolContext.
mode: ADK_MANAGED
```

## Architecture
Expand Down Expand Up @@ -399,15 +402,16 @@ Converts between ADK tools and Spring AI function calling format.
**Key Features:**
- Converts ADK `BaseTool` to Spring AI `ToolCallback`
- Schema conversion from ADK format to Spring AI JSON schema
- Intelligent argument processing for different provider formats
- **Function Schema Registration:** Properly registers JSON schemas with Spring AI using `inputSchema()` method
- Configurable tool execution ownership: `ADK_MANAGED` (default) or `SPRING_AI_MANAGED`
- Never executes an ADK tool with a hard-coded `null` `ToolContext`
- Debug logging for troubleshooting function calling issues

**Function Calling Flow:**
1. ADK `FunctionDeclaration` → Spring AI `FunctionToolCallback`
2. ADK schema → JSON schema string
3. Runtime argument conversion and validation
4. Tool execution and result serialization
3. In `ADK_MANAGED` mode, Spring AI returns the function call and ADK executes it with the current invocation context
4. In `SPRING_AI_MANAGED` mode, Spring AI executes the callback using an application-provided `AdkToolContextResolver`

#### 4. SpringAIEmbedding (SpringAIEmbedding.java)

Expand Down Expand Up @@ -482,7 +486,9 @@ Flowable<LlmResponse> stream = springAI.generateContent(llmRequest, true);

### Function Calling

The library supports function calling through ADK tools:
The library supports function calling through ADK tools. Tool execution is owned by ADK by
default, preserving ADK's tool callbacks, confirmation flow, state changes, and
`InvocationContext`-backed `ToolContext`:

```java
// Create agent with tools
Expand All @@ -495,6 +501,25 @@ LlmAgent agent = LlmAgent.builder()
// Tools are automatically converted to Spring AI format
```

Applications that intentionally want Spring AI to own the tool-calling loop can opt in explicitly:

```java
AdkToolContextResolver resolver = (tool, arguments, springAiContext) ->
resolveToolContextForTheCurrentRequest();

SpringAI springAI = new SpringAI(
chatModel,
"gpt-4o-mini",
ToolExecutionMode.SPRING_AI_MANAGED,
resolver);
```

The resolver must return a non-null ADK `ToolContext` for every call. Spring Boot applications can
select the same mode with `adk.spring-ai.tool-execution.mode=SPRING_AI_MANAGED` and must provide a
single `AdkToolContextResolver` bean. Configuration fails fast when that bean is missing. In this
mode, each streaming model turn is buffered so tool calls can be detected safely; chunks from the
final model turn are emitted after that turn completes.

### Embedding Generation

```java
Expand Down Expand Up @@ -594,6 +619,8 @@ adk:
enabled: true
metrics-enabled: true
include-content: false
tool-execution:
mode: ADK_MANAGED
```

### Auto-Configuration Beans
Expand Down Expand Up @@ -679,8 +706,9 @@ The library provides comprehensive error handling through `SpringAIErrorMapper`:
### Function Calling
1. Ensure function schemas are properly defined in ADK tools
2. Test function calling with each provider separately
3. Handle provider-specific argument format differences
4. Use debug logging to troubleshoot function calling issues
3. Keep `ADK_MANAGED` unless the application deliberately supplies ADK context for Spring AI-managed execution
4. Never return `null` from an `AdkToolContextResolver`
5. Use debug logging to troubleshoot function calling issues

### Performance
1. Use streaming for long responses
Expand Down Expand Up @@ -745,4 +773,4 @@ The library provides comprehensive error handling through `SpringAIErrorMapper`:
- Java: 17+
- ADK: 0.3.1+

This library provides a robust foundation for integrating Spring AI models with the ADK framework, offering enterprise-grade features like observability, error handling, and multi-provider support while maintaining the flexibility and power of both frameworks.
This library provides a robust foundation for integrating Spring AI models with the ADK framework, offering enterprise-grade features like observability, error handling, and multi-provider support while maintaining the flexibility and power of both frameworks.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.adk.models.springai;

import com.google.adk.tools.BaseTool;
import com.google.adk.tools.ToolContext;
import java.util.Map;

/**
* Resolves the ADK {@link ToolContext} used when Spring AI owns tool execution.
*
* <p>Spring AI's tool context does not contain ADK's invocation state. Applications opting into
* {@link ToolExecutionMode#SPRING_AI_MANAGED} must therefore supply this resolver explicitly.
*/
@FunctionalInterface
public interface AdkToolContextResolver {

/**
* Resolves a non-null ADK tool context for one tool invocation.
*
* @param tool the ADK tool being called
* @param arguments the decoded tool arguments
* @param springAiToolContext the context supplied by Spring AI; it may be {@code null} when a
* callback is invoked directly without a context
* @return the ADK context to pass to the tool; must not be {@code null}
*/
ToolContext resolve(
BaseTool tool,
Map<String, Object> arguments,
org.springframework.ai.chat.model.ToolContext springAiToolContext);
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,14 @@ public class MessageConverter {
private final ConfigMapper configMapper;

public MessageConverter(ObjectMapper objectMapper) {
this(
objectMapper,
new ToolConverter(objectMapper, ToolExecutionMode.ADK_MANAGED, /* resolver= */ null));
}

public MessageConverter(ObjectMapper objectMapper, ToolConverter toolConverter) {
this.objectMapper = objectMapper;
this.toolConverter = new ToolConverter();
this.toolConverter = toolConverter;
this.configMapper = new ConfigMapper();
}

Expand Down
Loading