3. ChatClient你与 AI 对话的终极武器3.1 为什么需要 ChatClient直接调ChatModel也可以但很啰嗦。看看对比只用 ChatModel啰嗦版AutowiredprivateChatModelchatModel;// 构建一个 Prompt手动处理各种细节PromptpromptnewPrompt(List.of(newUserMessage(讲个笑话)),OpenAiChatOptions.builder().temperature(0.7).build());ChatResponseresponsechatModel.call(prompt);Stringtextresponse.getResult().getOutput().getText();用 ChatClient简洁版StringtextchatClient.prompt().user(讲个笑话).call().content();ChatClient用流式 API 把常见的操作都串联起来了读起来像自然语言。3.2 创建 ChatClient有三种方式方式一自动注入最常用RestControllerclassMyController{privatefinalChatClientchatClient;publicMyController(ChatClient.Builderbuilder){this.chatClientbuilder.build();}GetMapping(/ai)Stringchat(RequestParamStringinput){returnchatClient.prompt().user(input).call().content();}}Spring Boot 自动配置了一个ChatClient.Builder的 prototype Bean。注入它.build()一下就完事了。方式二手动创建ChatClientchatClientChatClient.create(chatModel);方式三带默认配置的 BuilderBeanChatClientchatClient(ChatClient.Builderbuilder){returnbuilder.defaultSystem(你是一个有帮助的助手回答简洁明了。).defaultOptions(OpenAiChatOptions.builder().temperature(0.3).build()).build();}3.3 三种 prompt() 方式// 方式 1无参后面慢慢拼chatClient.prompt().user(你好).system(你是一个助手).call().content();// 方式 2直接传字符串最简chatClient.prompt(你好).call().content();// 方式 3传一个完整的 Prompt 对象PromptpromptnewPrompt(newUserMessage(你好));chatClient.prompt(prompt).call().content();3.4 call() 的返回值call()之后你有四种选择// 1. 只要文本StringcontentchatClient.prompt().user(讲个笑话).call().content();// 2. 要完整的 ChatResponse含元数据ChatResponsechatResponsechatClient.prompt().user(讲个笑话).call().chatResponse();// 可以拿到 token 用量、模型名称等System.out.println(用了 chatResponse.getMetadata().getUsage().getTotalTokens() 个 token);// 3. 要 ChatClientResponse含执行上下文RAG 场景有用ChatClientResponseclientResponsechatClient.prompt().user(讲个笑话).call().chatClientResponse();// 4. 映射成 Java 对象ActorFilmsresultchatClient.prompt().user(生成一个随机演员的电影作品列表).call().entity(ActorFilms.class);3.5 流式响应Streaming不想等 AI 一句话说完才显示用stream()FluxStringfluxchatClient.prompt().user(用中文讲一个关于程序员的长笑话).stream().content();flux.subscribe(chunk-System.out.print(chunk),// 一个字一个字出来error-System.err.println(出错了: error),()-System.out.println(\n--- 讲完了 ---));效果你会看到文字像打字机一样一个字一个字准确说是 token by token地输出。什么时候用call()什么时候用stream()简短问答、结构化输出、Tool Calling →call()简单直接长文本生成、聊天界面、需要打字机效果 →stream()用户体验更好流式响应需要额外引入spring-boot-starter-webflux依赖关于 FluxFlux是 Spring WebFlux 提供的响应式流类型用来表示随时间推移陆续到达的多个数据。如果你在 Spring MVC 环境做演示需要调用.subscribe()来触发流开始执行如果你在 WebFlux 环境直接把Flux返回给浏览器框架会自动处理不需要手动 subscribe。流式响应需要额外引入spring-boot-starter-webflux依赖。3.6 同时使用多个 Chat Model现实场景中你可能需要一个便宜模型处理简单任务一个贵模型处理复杂推理针对不同用户提供不同模型选择A/B 测试两个模型ConfigurationpublicclassChatClientConfig{BeanPrimarypublicChatClientopenAiChatClient(OpenAiChatModelopenAiModel){returnChatClient.create(openAiModel);}BeanpublicChatClientanthropicChatClient(AnthropicChatModelanthropicModel){returnChatClient.create(anthropicModel);}}// 使用时注入ServicepublicclassMultiModelService{AutowiredQualifier(openAiChatClient)privateChatClientopenAiClient;AutowiredQualifier(anthropicChatClient)privateChatClientanthropicClient;publicStringrouteToModel(Stringtask,Stringinput){if(task.equals(code)){returnanthropicClient.prompt(input).call().content();// Claude 擅长代码}else{returnopenAiClient.prompt(input).call().content();// GPT 做通用}}}3.7 使用不同的 OpenAI 兼容端点很多服务Groq、DeepSeek、通义千问都兼容 OpenAI API 格式。Spring AI 允许你派生一个 API 实例ServicepublicclassMultiEndpointService{AutowiredprivateOpenAiApibaseApi;AutowiredprivateOpenAiChatModelbaseModel;publicStringcallGroq(Stringprompt){// 派生一个指向 Groq 的 APIOpenAiApigroqApibaseApi.mutate().baseUrl(https://api.groq.com/openai).apiKey(System.getenv(GROQ_API_KEY)).build();OpenAiChatModelgroqModelbaseModel.mutate().openAiApi(groqApi).defaultOptions(OpenAiChatOptions.builder().model(llama3-70b-8192).temperature(0.5).build()).build();returnChatClient.create(groqModel).prompt(prompt).call().content();}}3.8 完整 Demo一个带 Web 界面的聊天机器人RestControllerRequestMapping(/api/chat)publicclassChatController{privatefinalChatClientchatClient;publicChatController(ChatClient.Builderbuilder){this.chatClientbuilder.defaultSystem(你是一个友好的助手回答简洁不超过 100 字。).build();}// 同步接口PostMappingpublicMapString,Stringchat(RequestBodyChatRequestrequest){StringreplychatClient.prompt().user(request.message()).call().content();returnMap.of(reply,reply);}// 流式接口SSEPostMapping(value/stream,producesMediaType.TEXT_EVENT_STREAM_VALUE)publicFluxStringchatStream(RequestBodyChatRequestrequest){returnchatClient.prompt().user(request.message()).stream().content();}}recordChatRequest(Stringmessage){}
Spring AI 从入门到精通-ChatClient你与 AI 对话的终极武器
发布时间:2026/6/8 0:42:23
3. ChatClient你与 AI 对话的终极武器3.1 为什么需要 ChatClient直接调ChatModel也可以但很啰嗦。看看对比只用 ChatModel啰嗦版AutowiredprivateChatModelchatModel;// 构建一个 Prompt手动处理各种细节PromptpromptnewPrompt(List.of(newUserMessage(讲个笑话)),OpenAiChatOptions.builder().temperature(0.7).build());ChatResponseresponsechatModel.call(prompt);Stringtextresponse.getResult().getOutput().getText();用 ChatClient简洁版StringtextchatClient.prompt().user(讲个笑话).call().content();ChatClient用流式 API 把常见的操作都串联起来了读起来像自然语言。3.2 创建 ChatClient有三种方式方式一自动注入最常用RestControllerclassMyController{privatefinalChatClientchatClient;publicMyController(ChatClient.Builderbuilder){this.chatClientbuilder.build();}GetMapping(/ai)Stringchat(RequestParamStringinput){returnchatClient.prompt().user(input).call().content();}}Spring Boot 自动配置了一个ChatClient.Builder的 prototype Bean。注入它.build()一下就完事了。方式二手动创建ChatClientchatClientChatClient.create(chatModel);方式三带默认配置的 BuilderBeanChatClientchatClient(ChatClient.Builderbuilder){returnbuilder.defaultSystem(你是一个有帮助的助手回答简洁明了。).defaultOptions(OpenAiChatOptions.builder().temperature(0.3).build()).build();}3.3 三种 prompt() 方式// 方式 1无参后面慢慢拼chatClient.prompt().user(你好).system(你是一个助手).call().content();// 方式 2直接传字符串最简chatClient.prompt(你好).call().content();// 方式 3传一个完整的 Prompt 对象PromptpromptnewPrompt(newUserMessage(你好));chatClient.prompt(prompt).call().content();3.4 call() 的返回值call()之后你有四种选择// 1. 只要文本StringcontentchatClient.prompt().user(讲个笑话).call().content();// 2. 要完整的 ChatResponse含元数据ChatResponsechatResponsechatClient.prompt().user(讲个笑话).call().chatResponse();// 可以拿到 token 用量、模型名称等System.out.println(用了 chatResponse.getMetadata().getUsage().getTotalTokens() 个 token);// 3. 要 ChatClientResponse含执行上下文RAG 场景有用ChatClientResponseclientResponsechatClient.prompt().user(讲个笑话).call().chatClientResponse();// 4. 映射成 Java 对象ActorFilmsresultchatClient.prompt().user(生成一个随机演员的电影作品列表).call().entity(ActorFilms.class);3.5 流式响应Streaming不想等 AI 一句话说完才显示用stream()FluxStringfluxchatClient.prompt().user(用中文讲一个关于程序员的长笑话).stream().content();flux.subscribe(chunk-System.out.print(chunk),// 一个字一个字出来error-System.err.println(出错了: error),()-System.out.println(\n--- 讲完了 ---));效果你会看到文字像打字机一样一个字一个字准确说是 token by token地输出。什么时候用call()什么时候用stream()简短问答、结构化输出、Tool Calling →call()简单直接长文本生成、聊天界面、需要打字机效果 →stream()用户体验更好流式响应需要额外引入spring-boot-starter-webflux依赖关于 FluxFlux是 Spring WebFlux 提供的响应式流类型用来表示随时间推移陆续到达的多个数据。如果你在 Spring MVC 环境做演示需要调用.subscribe()来触发流开始执行如果你在 WebFlux 环境直接把Flux返回给浏览器框架会自动处理不需要手动 subscribe。流式响应需要额外引入spring-boot-starter-webflux依赖。3.6 同时使用多个 Chat Model现实场景中你可能需要一个便宜模型处理简单任务一个贵模型处理复杂推理针对不同用户提供不同模型选择A/B 测试两个模型ConfigurationpublicclassChatClientConfig{BeanPrimarypublicChatClientopenAiChatClient(OpenAiChatModelopenAiModel){returnChatClient.create(openAiModel);}BeanpublicChatClientanthropicChatClient(AnthropicChatModelanthropicModel){returnChatClient.create(anthropicModel);}}// 使用时注入ServicepublicclassMultiModelService{AutowiredQualifier(openAiChatClient)privateChatClientopenAiClient;AutowiredQualifier(anthropicChatClient)privateChatClientanthropicClient;publicStringrouteToModel(Stringtask,Stringinput){if(task.equals(code)){returnanthropicClient.prompt(input).call().content();// Claude 擅长代码}else{returnopenAiClient.prompt(input).call().content();// GPT 做通用}}}3.7 使用不同的 OpenAI 兼容端点很多服务Groq、DeepSeek、通义千问都兼容 OpenAI API 格式。Spring AI 允许你派生一个 API 实例ServicepublicclassMultiEndpointService{AutowiredprivateOpenAiApibaseApi;AutowiredprivateOpenAiChatModelbaseModel;publicStringcallGroq(Stringprompt){// 派生一个指向 Groq 的 APIOpenAiApigroqApibaseApi.mutate().baseUrl(https://api.groq.com/openai).apiKey(System.getenv(GROQ_API_KEY)).build();OpenAiChatModelgroqModelbaseModel.mutate().openAiApi(groqApi).defaultOptions(OpenAiChatOptions.builder().model(llama3-70b-8192).temperature(0.5).build()).build();returnChatClient.create(groqModel).prompt(prompt).call().content();}}3.8 完整 Demo一个带 Web 界面的聊天机器人RestControllerRequestMapping(/api/chat)publicclassChatController{privatefinalChatClientchatClient;publicChatController(ChatClient.Builderbuilder){this.chatClientbuilder.defaultSystem(你是一个友好的助手回答简洁不超过 100 字。).build();}// 同步接口PostMappingpublicMapString,Stringchat(RequestBodyChatRequestrequest){StringreplychatClient.prompt().user(request.message()).call().content();returnMap.of(reply,reply);}// 流式接口SSEPostMapping(value/stream,producesMediaType.TEXT_EVENT_STREAM_VALUE)publicFluxStringchatStream(RequestBodyChatRequestrequest){returnchatClient.prompt().user(request.message()).stream().content();}}recordChatRequest(Stringmessage){}