当前位置: 首页 > news >正文

Spring AI 从入门到精通-ChatClient你与 AI 对话的终极武器

3. ChatClient:你与 AI 对话的终极武器

3.1 为什么需要 ChatClient?

直接调ChatModel也可以,但很啰嗦。看看对比:

只用 ChatModel(啰嗦版):

@AutowiredprivateChatModelchatModel;// 构建一个 Prompt,手动处理各种细节Promptprompt=newPrompt(List.of(newUserMessage("讲个笑话")),OpenAiChatOptions.builder().temperature(0.7).build());ChatResponseresponse=chatModel.call(prompt);Stringtext=response.getResult().getOutput().getText();

用 ChatClient(简洁版):

Stringtext=chatClient.prompt().user("讲个笑话").call().content();

ChatClient用流式 API 把常见的操作都串联起来了,读起来像自然语言。

3.2 创建 ChatClient

有三种方式:

方式一:自动注入(最常用)

@RestControllerclassMyController{privatefinalChatClientchatClient;publicMyController(ChatClient.Builderbuilder){this.chatClient=builder.build();}@GetMapping("/ai")Stringchat(@RequestParamStringinput){returnchatClient.prompt().user(input).call().content();}}

Spring Boot 自动配置了一个ChatClient.Builder的 prototype Bean。注入它,.build()一下就完事了。

方式二:手动创建

ChatClientchatClient=ChatClient.create(chatModel);

方式三:带默认配置的 Builder

@BeanChatClientchatClient(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 对象Promptprompt=newPrompt(newUserMessage("你好"));chatClient.prompt(prompt).call().content();

3.4 call() 的返回值

call()之后,你有四种选择:

// 1. 只要文本Stringcontent=chatClient.prompt().user("讲个笑话").call().content();// 2. 要完整的 ChatResponse(含元数据)ChatResponsechatResponse=chatClient.prompt().user("讲个笑话").call().chatResponse();// 可以拿到 token 用量、模型名称等System.out.println("用了 "+chatResponse.getMetadata().getUsage().getTotalTokens()+" 个 token");// 3. 要 ChatClientResponse(含执行上下文,RAG 场景有用)ChatClientResponseclientResponse=chatClient.prompt().user("讲个笑话").call().chatClientResponse();// 4. 映射成 Java 对象ActorFilmsresult=chatClient.prompt().user("生成一个随机演员的电影作品列表").call().entity(ActorFilms.class);

3.5 流式响应(Streaming)

不想等 AI 一句话说完才显示?用stream()

Flux<String>flux=chatClient.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依赖

💡关于 Flux:Flux是 Spring WebFlux 提供的响应式流类型,用来表示"随时间推移陆续到达的多个数据"。如果你在 Spring MVC 环境做演示,需要调用.subscribe()来触发流开始执行;如果你在 WebFlux 环境直接把Flux返回给浏览器,框架会自动处理,不需要手动 subscribe。流式响应需要额外引入spring-boot-starter-webflux依赖。

3.6 同时使用多个 Chat Model

现实场景中,你可能需要:

  • 一个便宜模型处理简单任务,一个贵模型处理复杂推理
  • 针对不同用户提供不同模型选择
  • A/B 测试两个模型
@ConfigurationpublicclassChatClientConfig{@Bean@PrimarypublicChatClientopenAiChatClient(OpenAiChatModelopenAiModel){returnChatClient.create(openAiModel);}@BeanpublicChatClientanthropicChatClient(AnthropicChatModelanthropicModel){returnChatClient.create(anthropicModel);}}// 使用时注入@ServicepublicclassMultiModelService{@Autowired@Qualifier("openAiChatClient")privateChatClientopenAiClient;@Autowired@Qualifier("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 的 APIOpenAiApigroqApi=baseApi.mutate().baseUrl("https://api.groq.com/openai").apiKey(System.getenv("GROQ_API_KEY")).build();OpenAiChatModelgroqModel=baseModel.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 界面的聊天机器人

@RestController@RequestMapping("/api/chat")publicclassChatController{privatefinalChatClientchatClient;publicChatController(ChatClient.Builderbuilder){this.chatClient=builder.defaultSystem("你是一个友好的助手,回答简洁,不超过 100 字。").build();}// 同步接口@PostMappingpublicMap<String,String>chat(@RequestBodyChatRequestrequest){Stringreply=chatClient.prompt().user(request.message()).call().content();returnMap.of("reply",reply);}// 流式接口(SSE)@PostMapping(value="/stream",produces=MediaType.TEXT_EVENT_STREAM_VALUE)publicFlux<String>chatStream(@RequestBodyChatRequestrequest){returnchatClient.prompt().user(request.message()).stream().content();}}recordChatRequest(Stringmessage){}

http://www.cnnetsun.cn/news/2814921.html

相关文章:

  • 神经渲染:重塑室内设计的“造梦引擎”——从原理到落地全解析
  • 深度解析Jsxer:JSXBIN二进制反编译引擎的架构设计与实现原理
  • 终极macOS清理指南:使用Pearcleaner彻底告别应用残留文件
  • 3步掌握OBS多平台推流:免费插件让直播效率提升300%
  • 小米智能家居接入HomeAssistant的终极解决方案:Xiaomi Miot插件深度解析
  • Notepad-- 终极使用指南:跨平台文本编辑器的完整掌握手册
  • AI编程15-重构与AI辅助代码改进:让AI帮你还技术债,代码可维护性提升200%
  • AI驱动的内容获客革命(2024最新成本模型验证)
  • BAT 窗口不输出日志:三种静默方案,从半隐藏到完全消失
  • 5分钟学会使用免费在线法线贴图生成器,让3D模型细节飙升300%!
  • 镜像视界低延迟实景同步技术,实现通关现场实时视频孪生调度
  • Redis/MySQL 中间件深度优化与生产选型
  • B站视频下载器技术指南:基于异步架构的高效离线解决方案
  • GDA安卓逆向分析平台:无需Java虚拟机的原生逆向工程利器
  • SMUDebugTool深度解析:AMD Ryzen处理器硬件调试的技术实践
  • 书匠策AI官网www.shujiangce.com:揭秘一个让导师都查不出来的期刊论文“流水线“,附完整拆解
  • 从垂直整合到水平分工:手机产业如何降低门槛让跨界者入局
  • Java全栈面试进阶宝典(2026最新版)
  • 3个步骤,让你的Mac拥有Windows超能力:Whisky完全指南
  • 【字节跳动】该文摘揭示了计算机底层系统的核心配置参数与运行机制,涵盖六大关键领域:1)段寄存器固化配置与权限管理;2)浮点运算异常处理机制;3)存储设备扇区读写控制;4)实时时钟校准与校验;5)内存动
  • Warcraft Helper终极指南:5分钟解决魔兽争霸III所有兼容性问题
  • 终极Discord消息清理指南:如何一键删除数千条聊天记录
  • 如何快速掌握冒险岛游戏编辑器:面向新手的完整指南
  • Redis 有序集合(sorted set)
  • 别再死磕公式了!用Python实战模拟TDOA定位(附Chan‘s和Fang‘s算法对比代码)
  • 蚂蚁二面:怎么省Claude Code缓存,我说了四点:用Subagent、一次性装好MCP、配好claude.md、开1小时TTL。面试官点头,说我有工程深度.
  • 从Pycharm到VSCode:不同IDE下Python环境与pip命令的联动配置避坑
  • PVZ Toolkit终极指南:3分钟掌握植物大战僵尸无限资源修改器
  • 如何用Montserrat字体让你的设计作品瞬间提升专业感?
  • 图灵机:什么是计算的本质?