Expected Behavior
It should be possible to auto-configure multiple beans of the same type, including ChatClient
, ChatModel
, and McpClient
.
I expect to be able to specify a configuration like the following:
spring:
ai:
chat:
models:
instance1:
model: smollm2:360m
temperature: 0.7
instance2:
model: smollm2:135m
temperature: 0.3
and then be able to autowire them as follows:
@RestController
class DemoController {
private final ChatModel instance1;
private final ChatModel instance2;
DemoController(@Qualifier("instance1") ChatModel instance1, @Qualifier("instance2") ChatModel instance2) {
this.instance1= instance1;
this.instance2= instance2;
}
}
Spring AI could even introduce meta-annotations for @Qualifier
as suggested in the Spring Framework documentation.
@RestController
class DemoController {
DemoController(@ChatClient("ragClient") ChatClient ragClient) {
...
}
}
Current Behavior
Spring Boot doesn't support multiple bean registration and there's no plan to add this capability, so Spring AI doesn't provide this capability for ChatClient
and ChatModel
.
About McpClient
, there is a woarkound to register a collection of McpClients
, but the logic is fragile and doesn't support users defining their own McpClient
beans. If they do, the autoconfiguration will ignore those beans.
Context
In a real-world scenario, most of the times an application will need more than one ChatClient
/ChatModel
/McpClient
. For example, I might need a ChatModel
tailored for more precise tasks like structured data extraction and another one for tool calling. Or I might want to define two McpClient
beans in my application, one to call a search engine and another one to call the GitHub API.
Other Java frameworks support registering multiple beans of the same type, and this capability is assumed to be in place even in standards like Microprofile, which provides standard ways to define configuration properties and map the config to beans via unique keys (e.g. Microprofile Rest Client).
Spring Boot doesn't have this support. And the underlying Spring Framework doesn't provide the necessary primitives to build this capability. The BeanRegistrar
API added to Spring Framework 7, similar to other APIs for processing bean definitions and bean factories (e.g. BeanFactoryPostProcessor
), is not suitable to register beans programmatically if those beans have dependencies (no autowiring possible), which is almost always the case in every scenario where multiple beans of the same type are useful (including all the use cases in Spring AI). I might be missing out on other strategies, so please correct me if I got things wrong.
Future
Solving the problem described in this issue would provide the foundation to support a declarative model for ChatClient, similar to how Spring Data repositories work (you define an interface, and the framework provides the implementation).
Comment From: ThomasVitale
I managed to get a working POC using the Programmatic Bean Registration introduced in Spring Framework 7.
Some key aspects that enabled the implementation:
- The
BeanRegistry
API gives access to aSupplierContext
object used to get access to the dependant beans from the Spring context (e.g.OllamaApi
bean needed to instantiate anOllamaChatModel
). I had missed this capability in my previous attempts. - Since the
SupplierContext
is only available within the context of a single bean registration, it's not possible to use it for getting configuration properties beans. Instead, theEnvironment
instance provided to theBeanRegistry
can be used to build aBinder
and bind the configuration properties from the environment to the@ConfigurationProperties
bean.
I haven't still figured out how to make co-exist in the same @ConfigurationProperties
both a default instance config and a map of named instances without requiring extra nesting.
Here's the POC: https://github.com/ThomasVitale/spring-ai-multiple-beans-demo