达州做淘宝网站,建湖网站建设,网站建设工作情况,网站建设及维护流程图在大模型快速演进的今天#xff0c;Java 开发者同样希望“开箱即用”地接入各类模型服务。Spring 官方推出的 Spring AI#xff0c;已经为 Java / Spring Boot 应用提供了一套统一、优雅的 AI 抽象#xff1b;而在国内模型生态中#xff0c;如何更好地对接阿里云通义#…在大模型快速演进的今天Java 开发者同样希望“开箱即用”地接入各类模型服务。Spring 官方推出的 Spring AI已经为 Java / Spring Boot 应用提供了一套统一、优雅的 AI 抽象而在国内模型生态中如何更好地对接阿里云通义Qwen与灵积平台DashScope则是 Spring AI Alibaba 重点解决的问题。本文基于仓库中的spring_ai_alibaba-demo子项目从真实代码出发带你一起拆解如何用 Spring AI Spring AI Alibaba 的生态在本地通过Ollama 跑 Qwen3 模型并逐步扩展到 RAG、工具调用和 Graph 工作流。GitHub 项目地址https://github.com/zhouByte-hub/java-ai/tree/main/spring_ai_alibaba-demo欢迎 Star、Fork 和关注文中所有代码都可以在该子项目中找到更适合边读边跑。面向读者已有 Spring Boot 基础希望快速接入大模型的后端开发计划在本地或内网环境使用 Qwen3 等模型通过 Ollama但又希望未来平滑切到阿里云 DashScope想了解 Spring AI Alibaba 在 Graph、RAG、工具调用等场景中的作用和优势。一、项目概览Spring AI Spring AI Alibaba 在这个 Demo 里的分工spring_ai_alibaba-demo是一个多模块示例工程核心模块包括根模块spring_ai_alibaba-demo使用Spring AI的spring-ai-starter-model-ollama接入本地 Ollama 服务使用spring-ai-starter-vector-store-pgvector集成 PostgreSQL PgVector 做向量检索通过ChatModel/ChatClient演示基础对话、RAG、工具调用和记忆通过依赖管理引入spring-ai-alibaba-bom为后续接入阿里云生态包括 DashScope、Graph 等奠定基础。子模块alibaba-graph使用spring-ai-alibaba-graph-core演示基于大模型的有状态流程StateGraph依然以 Ollama 的 Qwen3 作为底层模型子模块alibaba-mcp-server/alibaba-mcp-client使用 Spring AI 的 MCP 能力演示模型调用外部工具 / 资源的模式。换句话说当前 Demo没有直接连阿里云 DashScope而是选择在本地通过Ollama 运行 Qwen3 模型但项目在依赖管理和结构设计上已经完全站在Spring AI Alibaba 生态之上随时可以切换到阿里云在线服务。接下来我们按“从简单到复杂”的顺序依次看看各个模块是怎么搭建的。二、依赖与环境本地 Qwen3 PgVector先看根模块spring_ai_alibaba-demo/pom.xml中的关键部分properties!-- 项目使用的 JDK 版本 --java.version17/java.version!-- Spring AI Alibaba 相关依赖统一使用的版本 --spring-ai-alibaba.version1.1.0.0-M5/spring-ai-alibaba.version!-- Spring AI 核心依赖统一使用的版本 --spring-ai.version1.1.0/spring-ai.version/propertiesdependencies!-- 基础 Web 能力提供 Spring MVC / 内嵌容器等 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!-- 通过 Spring AI 访问本地 Ollama 大模型服务 --dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-model-ollama/artifactId/dependency!-- 向量数据库Spring AI 对 PgVector 的封装 --dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-vector-store-pgvector/artifactId/dependency!-- PostgreSQL JDBC 驱动用于访问数据库 --dependencygroupIdorg.postgresql/groupIdartifactIdpostgresql/artifactId/dependency/dependenciesdependencyManagementdependencies!-- Spring AI Alibaba 统一版本管理国内生态相关依赖 --dependencygroupIdcom.alibaba.cloud.ai/groupIdartifactIdspring-ai-alibaba-bom/artifactIdversion${spring-ai-alibaba.version}/versiontypepom/typescopeimport/scope/dependency!-- Spring AI 官方 BOM核心抽象与 Starter 的版本对齐 --dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-bom/artifactIdversion${spring-ai.version}/versiontypepom/typescopeimport/scope/dependency/dependencies/dependencyManagement这里体现了几个核心设计理念通过BOMspring-ai-alibaba-bomspring-ai-bom统一版本管理避免各个 Starter 之间的版本地狱实际运行时模型选择Ollama既方便本地开发调试又可以在网络受限场景下顺畅运行未来如果要切到阿里云 DashScope只需要打开已经写好的但当前被注释掉的spring-ai-alibaba-starter-dashscope依赖在配置文件里增加spring.ai.dashscope.*对应配置不需要改业务代码。环境配置Ollama Qwen3 PgVectorspring_ai_alibaba-demo/src/main/resources/application.yaml中server:port:8081# 应用监听端口servlet:context-path:/alibaba-ai# 统一的服务前缀spring:ai:ollama:base-url:http://localhost:11434# 本地 Ollama 服务地址chat:options:model:qwen3:0.6b# 聊天用的 Qwen3 模型名称temperature:0.8# 采样温度越高回答越发散embedding:options:model:qwen3-embedding:0.6b# 用于向量化的 embedding 模型vectorstore:pgvector:dimensions:1024# 向量维度需要与 embedding 模型输出一致distance-type:cosine_distance# 相似度度量方式initialize-schema:true# 启动时自动创建 PgVector 表结构datasource:url:jdbc:postgresql://your-host:5432/postgres?serverTimezoneAsia/Shanghai# PostgreSQL 连接串username:postgrespassword:****# 建议通过环境变量或配置中心注入Ollama 在本机 11434 端口提供服务加载的是qwen3:0.6b模型本质上仍然是阿里云通义家族的模型只是以本地方式运行Embedding 使用qwen3-embedding:0.6bPgVector 存储维度设置为 1024采用余弦相似度数据源配置指向 PostgreSQL用于向量存储和可选对话记忆持久化。三、基础对话从 ChatModel 到 ChatClientDemo 中提供了两种对话方式直接使用ChatModel以及通过ChatClient封装后的高级用法。3.1 使用 ChatModel 流式返回ChatModelControllerRestControllerRequestMapping(/chatModel)publicclassChatModelController{// 注入由 Spring AI 自动装配的 Ollama ChatModelprivatefinalChatModelollamaChatModel;publicChatModelController(ChatModelollamaChatModel){this.ollamaChatModelollamaChatModel;}GetMapping(/chat)publicFluxStringchat(RequestParam(message)Stringmessage){// message用户输入的自然语言问题returnollamaChatModel.stream(newPrompt(message))// 以流式方式调用大模型.map(ChatResponse::getResult)// 提取每个增量响应的结果对象.mapNotNull(result-result.getOutput().getText());// 只保留最终输出的文本内容}}ChatModel由spring-ai-starter-model-ollama自动装配底层指向本地 Qwen3 模型.stream(...)返回的是一个响应式 Flux可以在前端按 token/片段逐步渲染控制器本身和普通 Spring Web 控制器没有本质差别学习成本非常低。3.2 使用 ChatClient 提升可用性ChatClientControllerRestControllerRequestMapping(/chatClient)publicclassChatClientController{// 基于 ChatModel 封装的高级客户端后续可以挂接 Adviser、工具等能力privatefinalChatClientollamaChatClient;publicChatClientController(ChatClientollamaChatClient){this.ollamaChatClientollamaChatClient;}GetMapping(/chat)publicFluxStringstream(RequestParam(message)Stringmessage){// 使用最简单的 Prompt直接将用户输入交给大模型并以流式方式返回结果returnollamaChatClient.prompt(newPrompt(message))// 构造 Prompt 对象.stream()// 流式调用.content();// 提取文本内容}GetMapping(/prompt)publicFluxStringprompt(){PromptTemplatetemplatePromptTemplate.builder().template(请用简短中文回答{question})// 模板中定义占位符 {question}.variables(Map.of())// 这里可以预先声明变量也可以在 create 时传入.build();// 使用实际问题填充模板变量Promptprompttemplate.create(Map.of(question,Spring AI Alibaba 有什么特点));returnollamaChatClient.prompt(prompt).stream().content();}}和ChatModel相比ChatClient的优势在于提供链式 API.prompt().call()/stream()更易读更容易挂接 Adviser记忆、RAG、工具等形成统一调用入口在需要多轮交互、上下文管理时更易扩展。在OllamaConfig中Demo 还展示了如何为ChatClient挂接记忆 Adviser后面章节会展开。四、对话记忆内存版与可扩展版实际业务中一个“傻傻忘记前文”的大模型体验非常差。Demo 中给出了两种记忆实现方式。4.1 简单内存记忆SimpleMemoriesComponentpublicclassSimpleMemoriesimplementsChatMemory{privatestaticfinalMapString,ListMessageMEMORIES_CACHEnewHashMap();Overridepublicvoidadd(StringconversationId,ListMessagemessages){// conversationId会话标识messages本轮新增的消息列表ListMessagememoriesMEMORIES_CACHE.getOrDefault(conversationId,newArrayList());if(messages!null!messages.isEmpty()){memories.addAll(messages);}MEMORIES_CACHE.put(conversationId,memories);}OverridepublicListMessageget(StringconversationId){// 根据会话 ID 取出该会话的历史消息returnMEMORIES_CACHE.getOrDefault(conversationId,newArrayList());}Overridepublicvoidclear(StringconversationId){// 清空某个会话的记忆ListMessagemessagesMEMORIES_CACHE.get(conversationId);if(messages!null){messages.clear();}}}通过conversationId区分不同会话适合 Demo、PoC 或对可靠性要求不高的场景结合MessageChatMemoryAdvisor可以自动把历史消息注入到当前 Prompt 中。4.2 Adviser 方式MemoriesAdviserComponentpublicclassMemoriesAdviserimplementsBaseAdvisor{privatestaticfinalMapString,ListMessageMEMORIESnewHashMap();// 用于在 ChatClient 的上下文中标识当前会话 ID 的 keyprivatestaticfinalStringCHAT_MEMORIES_SESSION_IDchat_memories_session_id;OverridepublicChatClientRequestbefore(ChatClientRequestrequest,AdvisorChainchain){// 从上下文中读取会话 ID并取出其历史消息StringsessionIdrequest.context().get(CHAT_MEMORIES_SESSION_ID).toString();ListMessagemessagesMEMORIES.getOrDefault(sessionId,newArrayList());// 当前请求的消息放到历史消息后面一起交给大模型messages.addAll(request.prompt().getInstructions());Promptpromptrequest.prompt().mutate().messages(messages).build();returnrequest.mutate().prompt(prompt).build();}OverridepublicChatClientResponseafter(ChatClientResponseresponse,AdvisorChainchain){// 把本次大模型回复写回到对应会话的记忆中AssistantMessageoutputresponse.chatResponse().getResult().getOutput();StringsessionIdresponse.context().get(CHAT_MEMORIES_SESSION_ID).toString();ListMessagemessagesMEMORIES.getOrDefault(sessionId,newArrayList());messages.add(output);MEMORIES.put(sessionId,messages);returnresponse;}}在before中把历史消息 当前消息拼成一个新的 Prompt在after中把模型回复写回内存通过在ChatClient构建时添加defaultAdvisors(memoriesAdvisor)即可对所有请求启用记忆能力。进一步你可以把DataBaseChatMemoryRepository补充完整将消息写入数据库实现持久化对话记忆。五、RAGQwen3 PgVector 的检索增强RAGRetrieval Augmented Generation是典型的企业级能力本 Demo 通过RagChatClientController进行演示。5.1 向量入库TokenTextSplitter PgVectorStoreRestControllerRequestMapping(/rag)publicclassRagChatClientController{privatefinalChatClientragChatClient;privatefinalPgVectorStorepgVectorStore;publicRagChatClientController(ChatClientragChatClient,PgVectorStorepgVectorStore){this.ragChatClientragChatClient;this.pgVectorStorepgVectorStore;}GetMapping(/embedding)publicvoidembeddingContent(RequestParam(message)Stringmessage){// message待向量化的原始文本内容TokenTextSplittersplitterTokenTextSplitter.builder().withChunkSize(50)// 每个分片的最大 token 数.withKeepSeparator(true)// 是否保留分隔符如换行符.withMaxNumChunks(1024)// 单次允许生成的最大分片数.withMinChunkLengthToEmbed(20)// 小于该长度的分片不入库避免噪声.withMinChunkSizeChars(10)// 切分时的最小字符数避免切得过碎.build();ListDocumentdocssplitter.split(Document.builder().text(message).build());// 将文本切分为多个 DocumentpgVectorStore.add(docs);// 写入 PgVector 向量库}}TokenTextSplitter基于 token 切分文档避免切得过碎或过长PgVectorStore.add将切分后的文档写入 PostgreSQL PgVector真实项目中可把/embedding换成异步批处理任务。5.2 RAG 对话RetrievalAugmentationAdvisorConfigurationpublicclassVectorChatClientConfig{Bean(ragChatClient)publicChatClientragChatClient(ChatModelchatModel,VectorStorevectorStore){VectorStoreDocumentRetrieverretrieverVectorStoreDocumentRetriever.builder().vectorStore(vectorStore)// 具体使用的向量库实现这里是 PgVector.topK(3)// 每次检索返回相似度最高的前 3 条文档.similarityThreshold(0.5)// 相似度阈值小于该值的文档会被过滤掉.build();RetrievalAugmentationAdvisoradvisorRetrievalAugmentationAdvisor.builder().documentRetriever(retriever)// 指定文档检索器.order(0)// Adviser 执行顺序越小越先执行.build();returnChatClient.builder(chatModel).defaultAdvisors(advisor)// 默认启用 RAG 能力.build();}}RetrievalAugmentationAdvisor会在每次请求前先到向量库检索相关文档然后把检索结果作为“系统提示词”或“上下文”塞给 Qwen3 模型对你来说只需调用ragChatClient.prompt().user(question).call()就能得到“带知识库”的回答。六、工具调用用 Tool 让模型调用你的 Java 方法在很多场景中大模型需要调用业务系统的 API 才能完成任务。Spring AI 提供了Tool注解Demo 中的ZoomTool便是一个简单示例。6.1 定义工具ZoomToolComponentpublicclassZoomTool{Tool(description通过时区 ID 获取当前时间)publicStringgetTimeByZone(ToolParam(description时区 ID比如 Asia/Shanghai)Stringzone){// zone时区 ID示例Asia/Shanghai、Europe/BerlinZoneIdzoneIdZoneId.of(zone);ZonedDateTimenowZonedDateTime.now(zoneId);returnDateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss).format(now);// 返回格式化后的时间字符串}}6.2 将工具挂到 ChatClient 上ConfigurationpublicclassToolChatClientConfig{Bean(toolChatClient)publicChatClienttoolChatClient(ChatModelollamaChatModel,ZoomToolzoomTool){// ollamaChatModel底层使用的 Qwen3 模型zoomTool提供获取时间的业务工具returnChatClient.builder(ollamaChatModel).defaultSystem(this.systemPrompt())// 设置默认的系统提示词统一咖啡馆背景.defaultTools(zoomTool)// 将 ZoomTool 注册为可调用的工具.build();}privateStringsystemPrompt(){MapString,ObjectvarsnewHashMap();vars.put(AMERICAN,1-3);// 美式咖啡制作时间分钟vars.put(LATTE,2);// 拿铁咖啡制作时间分钟vars.put(TIME_ZONE,Asia/Shanghai);// 默认时区 IDSystemPromptTemplatetplSystemPromptTemplate.builder().template(欢迎光临 ZhouByte咖啡馆... 默认时区{TIME_ZONE})// 系统提示词模板.variables(vars)// 绑定上面的变量.build();returntpl.render();// 渲染出包含具体变量值的系统提示词}}对应的 ControllerRestControllerRequestMapping(/tool)publicclassToolChatController{privatefinalChatClienttoolChatClient;publicToolChatController(ChatClienttoolChatClient){this.toolChatClienttoolChatClient;}GetMapping(/chat)publicFluxStringchat(RequestParam(message)Stringmessage){returntoolChatClient.prompt()// 创建一次新的对话请求.user(message)// 添加一条用户消息.stream()// 流式调用大模型.content();// 只提取文本内容返回}}模型可以在需要时自动调用getTimeByZone返回指定时区时间你只需要编写普通的 Java 方法剩下的交给 Spring AI 的工具调用机制。七、Alibaba Graph 子项目有状态工作流编排spring_ai_alibaba-demo/alibaba-graph子项目使用spring-ai-alibaba-graph-core演示了如何构建大模型工作流。7.1 定义 GraphStateGraph CompiledGraphGraphConfig中ConfigurationpublicclassGraphConfig{Bean(quickStartGraph)publicCompiledGraphquickStartGraph()throwsGraphStateException{// quickStartGraph图名称后面的 Map 用于定义状态 key 的合并策略StateGraphgraphnewStateGraph(quickStartGraph,()-Map.of(input,newReplaceStrategy(),// 多次写入时后写入的值覆盖之前的值output,newReplaceStrategy()));graph.addNode(node1,AsyncNodeAction.node_async(state-{// node1设置初始 input 和 outputreturnMap.of(input,graphConfig_addNode,output,graphConfig_output);}));graph.addNode(node2,AsyncNodeAction.node_async(state-{// node2模拟业务处理将 input 改为 ZhouBytereturnMap.of(input,ZhouByte,output,EMPTY);}));// 定义执行顺序START - node1 - node2 - ENDgraph.addEdge(StateGraph.START,node1).addEdge(node1,node2).addEdge(node2,StateGraph.END);returngraph.compile();}}StateGraph描述节点、边和状态合并策略AsyncNodeAction封装每个节点的执行逻辑compile()得到可执行的CompiledGraph。7.2 调用 GraphWebFlux 流式输出GraphControllerRestControllerRequestMapping(/v1)publicclassGraphController{ResourceprivateCompiledGraphquickStartGraph;GetMapping(/graph)publicFluxStringstartGraph(){// 这里传入空的初始状态 Map按定义好的 StateGraph 顺序执行returnquickStartGraph.stream(Map.of()).map(NodeOutput::toString);// 将每个节点的输出对象转换为字符串返回}}使用 WebFlux FluxNodeOutput将节点执行结果流式返回通过RunnableConfig.builder().threadId(conversationId)还可以实现“带会话 ID 的工作流”类似有状态 Agent。7.3 quickStartGraph 执行流程图结合上面的GraphConfig和GraphController/v1/graph接口整体执行流程可以用下面这张流程图来表示以 GitHub 为例可以直接渲染 MermaidHTTP 请求GET /alibaba-graph/v1/graphGraphController.startGraph()CompiledGraph.stream(Map.of())StateGraph.START节点 node1input graphConfig_addNodeoutput graphConfig_output节点 node2input ZhouByteoutput EMPTYStateGraph.ENDFlux 流式返回从GraphController.startGraph()开始调用CompiledGraph.stream(Map.of())启动图的执行图从StateGraph.START出发依次流经node1、node2最终到达StateGraph.END每个节点都会向全局状态写入input/output等字段并以FluxNodeOutput的形式逐步返回给调用方。7.4 多条件分支 Graph 示例addConditionalEdges在实际业务中Graph 往往不只是线性顺序还会根据状态进行分支判断。spring-ai-alibaba-graph-core提供了addConditionalEdges可以基于当前OverAllState计算「条件标签」再根据标签跳转到不同节点。下面是一个简化的「评分决策」示例根据score分数分别走向通过 / 复核 / 拒绝三条路径ConfigurationpublicclassConditionalGraphConfig{Bean(scoreDecisionGraph)publicCompiledGraphscoreDecisionGraph()throwsGraphStateException{StateGraphgraphnewStateGraph(scoreDecisionGraph,()-Map.of(score,newReplaceStrategy(),// 保存当前评分result,newReplaceStrategy()// 保存决策结果));// 读取或设置评分示例中从 state 中读取实际可由外部请求传入graph.addNode(checkScore,AsyncNodeAction.node_async(state-{Integerscore(Integer)state.value(score).orElse(75);// 默认 75 分returnMap.of(score,score);}));// 三个业务分支节点通过 / 复核 / 拒绝graph.addNode(pass,AsyncNodeAction.node_async(state-Map.of(result,PASS)));graph.addNode(review,AsyncNodeAction.node_async(state-Map.of(result,REVIEW)));graph.addNode(reject,AsyncNodeAction.node_async(state-Map.of(result,REJECT)));// 起点先进入评分检查节点graph.addEdge(StateGraph.START,checkScore);// 多条件边根据 score 返回不同的“标签”再由 mappings 决定下一跳节点graph.addConditionalEdges(checkScore,AsyncEdgeAction.edge_async(state-{intscore(Integer)state.value(score).orElse(0);if(score80){returnPASS;}if(score60){returnREVIEW;}returnREJECT;}),Map.of(PASS,pass,REVIEW,review,REJECT,reject));// 三个结果节点最终都指向 ENDgraph.addEdge(pass,StateGraph.END);graph.addEdge(review,StateGraph.END);graph.addEdge(reject,StateGraph.END);returngraph.compile();}}这段代码中addConditionalEdges的三个参数含义是sourceId条件边的源节点 ID这里是checkScoreAsyncEdgeAction根据当前OverAllState计算条件标签这里返回PASS/REVIEW/REJECTmappings标签与目标节点 ID 的映射例如PASS - pass即当标签为PASS时跳到pass节点。对应的执行流程可以画成如下多分支流程图在真实项目中你可以把score换成「风控评分」「召回结果命中情况」「用户画像标签」等任意业务信号通过addConditionalEdges把复杂分支逻辑从代码 if/else 中抽离出来统一放在 Graph 层管理。在这个子项目中Graph 本身是“流程层”可以在节点里调用 Spring AI / Spring AI Alibaba 的各种模型与工具实现复杂的多步推理与业务编排。八、如何从本地 Ollama 平滑切到阿里云 DashScope虽然当前 Demo 主要跑在本地 Ollama 上但由于使用了 Spring AI Spring AI Alibaba 的统一抽象切换到阿里云 DashScope 十分简单在pom.xml中启用 DashScope Starter示例中已给出注释代码dependencygroupIdcom.alibaba.cloud.ai/groupIdartifactIdspring-ai-alibaba-starter-dashscope/artifactIdversion1.1.0.0-M5/version/dependency在配置文件中增加 DashScope 的配置示例spring:ai:dashscope:api-key:${DASHSCOPE_API_KEY}# 从环境变量或配置中心读取 DashScope 的 API Keyendpoint:https://dashscope.aliyuncs.comchat:options:model:qwen-plus# 使用的通义千问在线模型temperature:0.8# 采样温度max-tokens:2048# 单次回答的最大 token 数将原来的ChatModel注入点从 Ollama 替换为 DashScope 对应的 Bean通常只需要调整配置不改业务代码。凭借 Spring AI 的抽象层你可以开发阶段本地跑 Qwen3Ollama成本低、调试快生产阶段切到云上 DashScopeQwen-Max / Qwen-Plus 等享受更强算力和更高可用性中长期在 Spring AI Alibaba 的生态内同时兼容多家国内模型厂商。九、实践建议与最佳实践配置管理API Key 使用环境变量或配置中心Nacos、KMS 等避免硬编码Ollama、DashScope 的模型名称、温度等参数尽量抽到配置文件中。错误处理与重试针对网络异常、超时、限流等场景做兜底和重试策略对外暴露的接口统一封装错误返回避免直接把底层错误抛给前端。性能与成本在高并发场景建议优先使用流式输出 前端增量渲染RAG 中控制 TopK、相似度阈值和切分策略避免向量库“爆炸”。代码结构将ChatClient配置、Graph 配置等放在独立的config包中业务层只关心接口调用工具方法使用Tool暴露便于模型统一管理和调用。版本与升级Spring AI Alibaba 当前仍以 Milestone 版本为主如1.1.0.0-M5升级前建议阅读 release notes保持对spring-ai-bom/spring-ai-alibaba-bom的依赖让升级尽量在 BOM 层完成。十、总结与展望基于spring_ai_alibaba-demo子项目我们实际体验了一次如何用Spring AISpring AI Alibaba BOM快速接入本地 Qwen3Ollama如何在同一套抽象下串联起对话、记忆、RAG、工具调用如何通过spring-ai-alibaba-graph-core构建基于大模型的有状态工作流以及如何在不改业务代码的前提下为未来切换到阿里云 DashScope 留出空间。对 Spring 开发者来说这套体系最大的价值在于统一抽象不同模型供应商之间切换成本极低生态完善兼容 Spring Boot、WebFlux、向量库、MCP、Graph 等丰富组件本地 云端双模既能在本地快速迭代又能无缝迁移到云上生产环境。再次附上示例子项目 GitHub 地址欢迎你亲手跑一跑代码、提 Issue、点 StarGitHub 项目地址https://github.com/zhouByte-hub/java-ai/tree/main/spring_ai_alibaba-demo