google / google/adk-java

[google-adk-spring-ai] SpringAI beans are never auto-configured: @ConditionalOnBean(ChatModel) is evaluated before Spring AI model auto-configurations (missing ordering declaration)

Offen
#1,501 2 Kommentare 0 Reaktionen 1 zugewiesene Person Beansprucht von @hemasekhar-p Auf GitHub ansehen
needs review
Vorherrschende Sprache
Java
Sterne
1.7k
Forks
420
Ø Merge
4 T. 12 Std.
Gemergte PRs (30 T.)
31

Beschreibung

# Environment

| Component | Version |
|---|---|
| google-adk / google-adk-spring-ai | 1.9.0 |
| Spring AI (BOM) | 2.0.1 |
| Spring Boot | 4.0.2 |
| Java | 25 |

## Minimal reproduction

**pom.xml** (relevant parts):

```xml

org.springframework.boot
spring-boot-starter-parent
4.0.2

25
2.0.1
1.9.0


org.springframework.boot
spring-boot-starter


com.google.adk
google-adk
${adk.version}


com.google.adk
google-adk-spring-ai
${adk.version}


org.springframework.ai
spring-ai-starter-model-openai



org.springframework.ai
spring-ai-bom
${spring-ai.version}
pom
import

```

**Application.java:**

```java
@SpringBootApplication
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

@Bean
LlmAgent agent(SpringAI springAI) {
return LlmAgent.builder()
.name("demo-agent")
.model(springAI)
.instruction("You are a helpful assistant.")
.build();
}
}
```

**application.yaml** (dummy values are enough — the failure happens at bean-definition processing, before any remote call):

```yaml
spring:
ai:
openai:
base-url: https://api.openai.com
api-key: dummy
chat:
model: gpt-4o-mini
```

Run: `mvn spring-boot:run`

## Actual behavior

Application fails to start:

```
***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method agent in com.example.demo.DemoApplication required a bean
of type 'com.google.adk.models.springai.SpringAI' that could not be found.

Action:

Consider defining a bean of type 'com.google.adk.models.springai.SpringAI' in your configuration.
```

Running with `--debug` shows the root cause — the OpenAI `ChatModel` bean definition **is** registered, but `SpringAIAutoConfiguration` is processed **before** it, so all three `SpringAI` `@Bean` methods are skipped:

```
OpenAiChatAutoConfiguration matched:
- @ConditionalOnProperty (spring.ai.model.chat=openai) matched
OpenAiChatAutoConfiguration#openAiChatModel matched:
- @ConditionalOnMissingBean ... did not find any beans (OnBeanCondition)

SpringAIAutoConfiguration#springAIWithBothModels:
Did not match:
- @ConditionalOnBean (types: ...ChatModel, ...StreamingChatModel) did not find any beans
SpringAIAutoConfiguration#springAIWithChatModel:
Did not match:
- @ConditionalOnBean (types: ...ChatModel) did not find any beans of type ...ChatModel (OnBeanCondition)
SpringAIAutoConfiguration#springAIWithStreamingModel:
Did not match:
- @ConditionalOnBean (types: ...StreamingChatModel) did not find any beans
```

Note `springAIEmbedding` has the same problem (`@ConditionalOnBean(EmbeddingModel.class)`) — it fails **silently** (no bean, no error), which makes it even harder to notice.

## Expected behavior
`SpringAIAutoConfiguration` registers a `SpringAI` bean whenever a `ChatModel` (and/or `StreamingChatModel`) is defined by Spring AI model auto-configurations, regardless of which provider starter is used.
## Root cause
`SpringAIAutoConfiguration` guards its `@Bean` methods with `@ConditionalOnBean(...)`, but declares no ordering relative to the auto-configurations that may provide those beans. Per the Spring Boot reference documentation, the result of `@ConditionalOnBean` depends on what has been processed so far, so an auto-configuration relying on it must be ordered after the configurations that register the matched beans.

`google-adk-spring-ai` 1.9.0 is built against Spring AI 2.x / Boot 4 (its POM depends on `spring-ai-model:2.0.1` and `spring-boot-autoconfigure:4.0.2`), and since it compiles only against `spring-ai-model` (no provider modules), the Class-based `after = ...` attribute is not usable here — the string-based `afterName` attribute exists exactly for this case (non-existent class names are silently ignored by the sorter).

## Suggested fix

Add an `afterName` list covering the Spring AI model auto-configurations, mirroring what Spring AI 1.x's own `ChatClientAutoConfiguration` did for the identical scenario (`@ConditionalOnBean(ChatModel)` with an unpredictable provider):

```diff
-@AutoConfiguration
+@AutoConfiguration(afterName = {
+ "org.springframework.ai.model.openai.autoconfigure.OpenAiChatAutoConfiguration",
+ "org.springframework.ai.model.openai.autoconfigure.OpenAiEmbeddingAutoConfiguration",
+ // remaining Spring AI 2.x model auto-configurations, e.g.:
+ // org.springframework.ai.model.anthropic.autoconfigure.AnthropicChatAutoConfiguration
+ // org.springframework.ai.model.ollama.autoconfigure.OllamaChatAutoConfiguration
+ // ... (package pattern: org.springframework.ai.model..autoconfigure.*)
+})
@ConditionalOnClass({SpringAI.class, ChatModel.class})
@ConditionalOnProperty(prefix = "adk.spring-ai.auto-configuration", name = "enabled",
havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties({SpringAIProperties.class})
public class SpringAIAutoConfiguration {
```

(Verified against Spring AI 2.0.1: `org.springframework.ai.model.openai.autoconfigure.OpenAiChatAutoConfiguration` / `OpenAiEmbeddingAutoConfiguration`. The other provider names above follow the 2.x package pattern and should be double-checked against the current source.)

An alternative design — the one Spring AI 2.0 itself adopted — is to drop the `@ConditionalOnBean` guards entirely and take `ChatModel`/`StreamingChatModel` as `@Bean` method parameters, which removes the ordering sensitivity altogether. The `afterName` fix is the smaller, backward-compatible change, though.

## Workaround (for users on 1.9.0)

Define the `SpringAI` bean in application code — user-defined beans are processed before auto-configurations, and ADK's `@ConditionalOnMissingBean(SpringAI.class)` then backs off:

```java
@Bean
SpringAI springAI(ChatModel chatModel) {
return new SpringAI(chatModel, "gpt-4o-mini");
}
```

This works with any provider (it consumes the `ChatModel` abstraction), but every project using ADK + Spring AI has to copy it, so it is not a substitute for the upstream fix.

## References

- Spring Boot reference — [Creating your own auto-configuration / condition annotations](https://docs.spring.io/spring-boot/reference/features/developing-auto-configuration.html): ordering matters for `@ConditionalOnBean`
- Spring AI 1.x `ChatClientAutoConfiguration`: same pattern solved with `afterName` over all provider auto-configurations
- Spring AI 2.0.1 `ChatClientAutoConfiguration`: same problem avoided via `@Bean` parameter injection instead of `@ConditionalOnBean`

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.