ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

第二篇:多 ChatClient Bean 的注册与选择

第二篇:多 ChatClient Bean 的注册与选择 一、问题起源上一篇我写了一个简单的ChatApiController直接在构造器里用ChatClient.Builder构建了一个ChatClientpublic ChatApiController(ChatClient.Builder chatClientBuilder) { this.chatClient chatClientBuilder.build(); }这样用没问题因为当时容器里只有一个隐式的ChatClient。但当我想要多个不同行为的 ChatClient​ 时问题就来了。二、需求两个不同性格的 AI我想做一个「卖萌版」的 AI让它用懒羊羊的语气回答问题。于是我在 config 包下新增了一个配置类package com.yoyo.demo.config; import org.springframework.ai.chat.client.ChatClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class ChatClientConfig { Bean ChatClient defaultChatClient(ChatClient.Builder builder) { return builder.build(); } Bean ChatClient cuteChatClient(ChatClient.Builder builder) { return builder.defaultSystem(你是一只懒羊羊).build(); } }这里我定义了两个 BeandefaultChatClient默认行为没有预设提示词cuteChatClient带有系统提示词「你是一只懒羊羊」三、启动报错重启应用后控制台报错Field chatClient in com.yoyo.demo.controller.ChatApiController required a single bean, but 2 were found: - defaultChatClient: defined by method defaultChatClient in class path resource [com/yoyo/demo/config/ChatClientConfig.class] - cuteChatClient: defined by method cuteChatClient in class path resource [com/yoyo/demo/config/ChatClientConfig.class]翻译一下Spring 说——你要注入ChatClient但我找到了两个我不知道你想要哪一个。四、原因分析4.1 Spring 的自动注入规则当一个类型只有一个 Bean 时Spring 直接注入没有问题。当一个类型有多个 Bean 时Spring 不知道选哪个就会报NoUniqueBeanDefinitionException。4.2 为什么之前没报错上一篇我直接在ChatApiController的构造器里写this.chatClient chatClientBuilder.build();这里注入的是ChatClient.Builder不是ChatClient。Builder 在容器里只有一个由 Spring AI 自动配置提供所以不会冲突。而我新增的两个Bean方法返回的都是ChatClient类型这就导致容器里有了两个ChatClient实例。五、解决方案方案一用Qualifier指定 Bean 名称推荐在注入点指明要用哪个 BeanRestController public class ChatApiController { private final ChatClient chatClient; public ChatApiController(Qualifier(cuteChatClient) ChatClient chatClient) { this.chatClient chatClient; } GetMapping(/ai) String generation(String userInput) { return this.chatClient.prompt() .user(userInput) .call() .content(); } }Qualifier(cuteChatClient)中的名称默认就是Bean的方法名。如果想用默认的那个就写Qualifier(defaultChatClient)。方案二用Primary标记默认 Bean在其中一个Bean上加Primary表示优先使用它Configuration public class ChatClientConfig { Bean Primary ChatClient defaultChatClient(ChatClient.Builder builder) { return builder.build(); } Bean ChatClient cuteChatClient(ChatClient.Builder builder) { return builder.defaultSystem(你是一只懒羊羊).build(); } }这样不加Qualifier时会注入defaultChatClient另一个需要通过Qualifier显式指定。方案三用Resource(name ...)RestController public class ChatApiController { private final ChatClient chatClient; public ChatApiController(Resource(name cuteChatClient) ChatClient chatClient) { this.chatClient chatClient; } // ... }Resource是 Java 原生注解按名称查找不依赖 Spring 特有的Qualifier。六、我选的方案我选择了方案一用Qualifier(cuteChatClient)注入那个带懒羊羊提示词的 ChatClient。修改后的 Controllerpackage com.yoyo.demo.controller; import org.springframework.ai.chat.client.ChatClient; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; RestController public class ChatApiController { private final ChatClient chatClient; public ChatApiController(Qualifier(cuteChatClient) ChatClient chatClient) { this.chatClient chatClient; } GetMapping(/ai) String generation(String userInput) { return this.chatClient.prompt() .user(userInput) .call() .content(); } }七、验证结果启动后访问http://localhost:8080/ai?userInput你叫什么名字返回咩~我叫懒羊羊最爱睡觉和吃零食啦你找我有什么事咩要是找我玩我可是很乐意的哦~眯眼笑成功了。系统提示词生效了ChatClient 确实用了cuteChatClient的配置。八、踩坑总结问题原因解决多 ChatClient 时报 NoUniqueBeanDefinitionException容器中有多个同类型 BeanSpring 无法确定注入哪个用 Qualifier / Primary / Resource 指定构造器注入时直接注入 ChatClient 而非 Builder想省事直接拿成品但遇到多 Bean 场景就会冲突要么用 Builder 现场 build要么用 Qualifier 指定系统提示词不生效忘记在 Builder 上调用 .defaultSystem()在 Bean 方法里通过 builder.defaultSystem(...) 设置九、关于 Builder 模式的补充理解你可能注意到我上一篇的写法是注入ChatClient.Builder然后在构造器里调用.build()。这一篇改成了直接注入ChatClient。这两种方式的区别注入 Builder 手动 build灵活可以在构造时做额外配置比如根据不同条件构建不同的 Client注入已 build 好的 ChatClient省事直接把配置类里定义好的成品拿来用如果你的 ChatClient 配置比较简单用第二种更干净。如果你需要在运行时动态决定配置用第一种。十、参考链接Spring Framework Autowired 文档Spring AI ChatClient.Builder APISpring Primary 注解说明
返回列表