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 a SupplierContext object used to get access to the dependant beans from the Spring context (e.g. OllamaApi bean needed to instantiate an OllamaChatModel). 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, the Environment instance provided to the BeanRegistry can be used to build a Binder 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