ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Spring AI 2.0实战:Java开发者构建企业级AI应用全攻略

Spring AI 2.0实战:Java开发者构建企业级AI应用全攻略 1. 这篇文章真正要解决的问题如果你是一名Java开发者最近可能正被两件事困扰一是AI浪潮下自己熟悉的Spring生态似乎被Python和JavaScript抢了风头感觉快要掉队二是面试时面试官开始频繁地问起“你们项目里怎么集成大模型”、“有没有做过AI Agent”而你只能泛泛而谈缺乏一个能拿得出手的、工程化的实战项目来证明能力。这正是本文要解决的核心痛点。我们不再空谈AI概念而是聚焦于一个具体且迫切的目标如何用你最熟悉的Java技术栈特别是Spring生态构建一个符合企业级标准的AI应用。本文将以Spring AI 2.0为核心结合LangChain4j和国产优秀的DeepSeek模型带你从零到一搭建一个可运行、可扩展的AI工程化项目。读完本文你将彻底搞清楚在Java世界里AI应用开发的完整技术选型、架构设计、代码实现和避坑指南是什么。这不仅能让你在技术上跟上时代更能为你的简历增加一个极具竞争力的实战案例。2. 为什么是Spring AI 2.0 LangChain4j DeepSeek面对琳琅满目的AI框架和模型这个组合并非随意拼凑而是基于当前Java AI工程化的最佳实践考量。Spring AI 2.0这是Spring官方在AI领域的战略级项目。它的意义在于将AI能力如聊天、文生图、嵌入、函数调用抽象成一套统一的、声明式的Spring风格API。这意味着你可以像使用JdbcTemplate操作数据库、使用RestTemplate调用HTTP接口一样使用ChatClient、EmbeddingClient来调用各种大模型。它极大地降低了集成复杂度并天然与Spring Boot的自动配置、依赖注入、外部化配置等特性无缝融合是Java开发者切入AI最快、最稳的路径。LangChain4j这是LangChain的Java版本。如果说Spring AI提供了“连接器”那么LangChain4j则提供了构建复杂AI应用如Agent、RAG的“工具箱”和“设计模式”。它封装了提示词模板、记忆管理、文档加载与分割、向量存储集成、工具调用等高级范式。在Spring AI中你可以直接注入LangChain4j的组件两者互补让Spring AI如虎添翼。DeepSeek在模型选择上我们聚焦于DeepSeek。原因有三第一它是目前综合能力最强的国产开源模型之一在代码、数学、推理等多个基准测试中表现优异完全满足企业级应用需求第二其API完全开放、成本透明可控避免了使用闭源模型可能带来的数据安全和未来成本不可预测的风险第三作为国产模型在合规性和数据本地化部署方面有天然优势。通过Spring AI我们可以用同一套代码轻松切换不同的模型提供商DeepSeek是我们实战的首选。这个技术栈的组合本质上是在回答Java开发者如何在不脱离主流工程范式的前提下高效、优雅地拥抱AI。接下来我们将从环境搭建开始一步步实现它。3. 环境准备与项目初始化在开始编码前确保你的开发环境就绪。本文将基于主流的Java 17和Spring Boot 3.x进行演示。3.1 基础环境要求JDK: 17 或更高版本推荐17或21。构建工具: Maven 3.6 或 Gradle 7.x。本文使用Maven。IDE: IntelliJ IDEA推荐或 Eclipse with STS。API密钥: 你需要一个DeepSeek的API Key。前往 DeepSeek官网 注册并获取。3.2 创建Spring Boot项目使用Spring Initializr start.spring.io 快速生成项目骨架。Project: MavenLanguage: JavaSpring Boot: 3.2.x (确保 3.2.0以兼容Spring AI 2.0)Dependencies: 添加Spring Web,Spring AI(这是核心),Lombok(简化代码可选但推荐)。下载并解压后用IDE打开项目。3.3 配置Maven依赖与仓库Spring AI 2.0的依赖可能需要添加Spring的里程碑或快照仓库。打开你的pom.xml确保包含以下配置?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.2.5/version !-- 使用稳定版本 -- relativePath/ /parent groupIdcom.example/groupId artifactIdspring-ai-demo/artifactId version0.0.1-SNAPSHOT/version namespring-ai-demo/name descriptionDemo project for Spring AI with DeepSeek/description properties java.version17/java.version spring-ai.version1.0.0-M3/spring-ai.version !-- 注意Spring AI 2.0正式版前可能仍用此坐标 -- /properties dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- Spring AI Core -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-core/artifactId version${spring-ai.version}/version /dependency !-- Spring AI DeepSeek 连接器 -- !-- 注意截至撰写时Spring AI官方可能尚未提供DeepSeek的官方starter。 我们需要使用其通用OpenAI兼容的客户端因为DeepSeek的API与OpenAI兼容。 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai-spring-boot-starter/artifactId version${spring-ai.version}/version /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId configuration excludes exclude groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /exclude /excludes /configuration /plugin /plugins /build !-- 添加Spring Milestone仓库以获取Spring AI依赖 -- repositories repository idspring-milestones/id nameSpring Milestones/name urlhttps://repo.spring.io/milestone/url snapshots enabledfalse/enabled /snapshots /repository /repositories /project关键点解释由于DeepSeek的API与OpenAI API高度兼容我们使用spring-ai-openai-spring-boot-starter来连接它。你只需要在配置中指定DeepSeek的API端点即可。3.4 配置DeepSeek API密钥和端点在application.yml或application.properties中配置。这里以YAML为例# src/main/resources/application.yml spring: application: name: spring-ai-demo # Spring AI OpenAI 兼容配置 (用于连接DeepSeek) spring: ai: openai: # 这里填写你在DeepSeek平台获取的API Key api-key: ${DEEPSEEK_API_KEY:sk-your-deepseek-api-key-here} # DeepSeek的API基础地址 base-url: https://api.deepseek.com # 指定使用的模型例如 deepseek-chat chat: options: model: deepseek-chat temperature: 0.7 # 创造性0-2之间越高越随机 max-tokens: 2000 # 最大生成长度安全提醒永远不要将真实的API密钥提交到版本控制系统如Git。上述配置中的${DEEPSEEK_API_KEY:}表示优先从环境变量DEEPSEEK_API_KEY中读取如果不存在则使用冒号后的默认值你应该删除这个默认值。最佳实践是在IDE的运行配置或系统环境变量中设置。4. 核心概念与Spring AI基础使用环境配好后我们先理解几个核心对象并完成第一个AI对话。4.1 核心接口ChatClientChatClient是Spring AI中用于与大语言模型进行对话的核心接口。Spring Boot会自动为我们配置一个基于OpenAiChatClient的Bean因为我们配置了spring.ai.openai它指向了DeepSeek。4.2 第一个对话Controller让我们创建一个简单的REST端点来测试连通性。// 文件路径src/main/java/com/example/demo/controller/ChatController.java package com.example.demo.controller; import org.springframework.ai.chat.ChatClient; import org.springframework.ai.chat.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.chat.prompt.PromptTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.Map; RestController public class ChatController { private final ChatClient chatClient; Autowired // 构造器注入是推荐的方式 public ChatController(ChatClient chatClient) { this.chatClient chatClient; } /** * 最简单的对话接口 * param message 用户消息 * return AI的回复 */ GetMapping(/ai/chat) public String chat(RequestParam(value message, defaultValue 你好请介绍一下你自己。) String message) { // 方式1直接调用获取完整的ChatResponse // ChatResponse response chatClient.call(new Prompt(message)); // return response.getResult().getOutput().getContent(); // 方式2更简洁直接获取回复文本内容 return chatClient.call(message); } /** * 使用PromptTemplate进行带变量的对话 * param topic 话题 * return AI的回复 */ GetMapping(/ai/explain) public String explainTopic(RequestParam String topic) { // 定义提示词模板{topic}是占位符 String template 请用简单易懂的语言向一名有三年经验的Java开发者解释什么是{topic}。; PromptTemplate promptTemplate new PromptTemplate(template); // 将变量填入模板生成最终的Prompt对象 Prompt prompt promptTemplate.create(Map.of(topic, topic)); // 调用模型 ChatResponse response chatClient.call(prompt); return response.getResult().getOutput().getContent(); } }启动应用运行SpringAiDemoApplication主类访问http://localhost:8080/ai/chat或http://localhost:8080/ai/explain?topicSpring%20AOP你应该能收到来自DeepSeek模型的回复。4.3 理解ChatResponse和Message一次完整的交互返回的是ChatResponse对象它包含了更丰富的信息getResult().getOutput().getContent(): AI返回的文本内容。getMetadata(): 本次调用的元数据如令牌使用情况、模型名称等。getResults(): 实际上是一个列表但通常只有一个结果。在Spring AI中对话消息被抽象为Message接口其实现包括UserMessage: 用户发送的消息。AssistantMessage: AI助手的回复消息。SystemMessage: 系统指令用于设定AI的角色和行为。5. 进阶实战集成LangChain4j构建RAG应用简单的对话只是开始。企业级应用常需要让AI基于特定知识库回答问题这就是RAG检索增强生成。接下来我们结合LangChain4j实现一个基于本地文档的问答系统。5.1 添加LangChain4j依赖在pom.xml中添加LangChain4j及其与Spring AI的集成依赖。!-- 在pom.xml的dependencies部分添加 -- !-- LangChain4j Core -- dependency groupIddev.langchain4j/groupId artifactIdlangchain4j/artifactId version0.31.0/version !-- 请查看最新版本 -- /dependency !-- LangChain4j Spring AI Integration -- dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-spring-ai/artifactId version0.31.0/version /dependency !-- 文档加载器这里用Apache Tika解析多种格式 -- dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-document-parser-apache-tika/artifactId version0.31.0/version /dependency !-- 内存向量存储用于演示生产环境需用Redis、PgVector等 -- dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-embeddings-all-minilm-l6-v2/artifactId !-- 本地嵌入模型免API调用 -- version0.31.0/version /dependency dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-store-embedding-in-memory/artifactId version0.31.0/version /dependency5.2 创建文档嵌入与检索服务我们创建一个服务负责加载文档、分割文本、生成嵌入向量并存储最后执行检索。// 文件路径src/main/java/com/example/demo/service/RagService.java package com.example.demo.service; import dev.langchain4j.data.document.Document; import dev.langchain4j.data.document.DocumentParser; import dev.langchain4j.data.document.DocumentSplitter; import dev.langchain4j.data.document.parser.apache.tika.ApacheTikaDocumentParser; import dev.langchain4j.data.document.splitter.DocumentSplitters; import dev.langchain4j.data.embedding.Embedding; import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.model.embedding.EmbeddingModel; import dev.langchain4j.model.embedding.all.minilm.l6.v2.AllMiniLmL6V2EmbeddingModel; import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever; import dev.langchain4j.store.embedding.EmbeddingStore; import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.chat.ChatClient; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.chat.prompt.PromptTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Service; import java.io.IOException; import java.nio.file.Paths; import java.util.HashMap; import java.util.List; import java.util.Map; Service Slf4j public class RagService { Autowired private ChatClient chatClient; Autowired private ResourceLoader resourceLoader; // 使用本地的轻量级嵌入模型避免为文档向量化调用付费API private final EmbeddingModel embeddingModel new AllMiniLmL6V2EmbeddingModel(); private final EmbeddingStoreTextSegment embeddingStore new InMemoryEmbeddingStore(); private EmbeddingStoreContentRetriever contentRetriever; /** * 初始化加载文档并构建向量存储 */ PostConstruct public void init() throws IOException { // 1. 加载文档示例从resources目录加载一个PDF或TXT文件 Resource resource resourceLoader.getResource(classpath:knowledge_base.txt); // 请准备一个知识库文件 DocumentParser parser new ApacheTikaDocumentParser(); Document document parser.parse(resource.getFile()); // 2. 分割文档按段落或固定大小 DocumentSplitter splitter DocumentSplitters.recursive(500, 100); // 最大500字符重叠100字符 ListTextSegment segments splitter.split(document); // 3. 为每个文本段生成嵌入向量 ListEmbedding embeddings embeddingModel.embedAll(segments).content(); // 4. 存储到内存向量库 embeddingStore.addAll(embeddings, segments); log.info(已加载并向量化 {} 个文本片段。, segments.size()); // 5. 创建检索器 contentRetriever EmbeddingStoreContentRetriever.builder() .embeddingStore(embeddingStore) .embeddingModel(embeddingModel) .maxResults(2) // 每次检索最相关的2个片段 .build(); } /** * 基于知识库的问答 * param question 用户问题 * return 基于检索内容的AI回答 */ public String answerFromKnowledgeBase(String question) { // 1. 检索与问题相关的文档片段 ListTextSegment relevantSegments contentRetriever.findRelevant(question); if (relevantSegments.isEmpty()) { return 抱歉在我的知识库中没有找到相关信息。; } // 2. 构建上下文 StringBuilder contextBuilder new StringBuilder(根据以下参考信息回答问题\n\n); for (TextSegment segment : relevantSegments) { contextBuilder.append(- ).append(segment.text()).append(\n); } String context contextBuilder.toString(); // 3. 构建提示词将上下文和问题结合 String template {context} 请严格基于以上提供的参考信息回答下面的问题。如果参考信息中没有明确答案请直接说“根据已知信息无法回答此问题”。 问题{question} 答案 ; MapString, Object variables new HashMap(); variables.put(context, context); variables.put(question, question); PromptTemplate promptTemplate new PromptTemplate(template); Prompt prompt promptTemplate.create(variables); // 4. 调用AI生成答案 return chatClient.call(prompt).getResult().getOutput().getContent(); } }关键点解释PostConstruct注解的方法在Bean初始化后执行用于构建本地的知识向量库。我们使用了本地的AllMiniLmL6V2EmbeddingModel来生成文本向量这完全在本地运行不消耗API额度适合文档预处理。InMemoryEmbeddingStore是内存存储重启后数据丢失。生产环境应替换为RedisEmbeddingStore、PgVectorEmbeddingStore等持久化方案。RAG的核心流程是检索(Retrieve)相关文档 -增强(Augment)提示词 -生成(Generate)答案。5.3 创建RAG问答接口// 文件路径src/main/java/com/example/demo/controller/RagController.java package com.example.demo.controller; import com.example.demo.service.RagService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; RestController RequestMapping(/ai/rag) public class RagController { Autowired private RagService ragService; GetMapping(/ask) public String ask(RequestParam String question) { return ragService.answerFromKnowledgeBase(question); } }在src/main/resources下创建一个knowledge_base.txt文件写入一些公司产品介绍或技术文档。启动应用访问http://localhost:8080/ai/rag/ask?question你的产品有什么特点AI将基于你文档中的内容进行回答。6. 构建AI Agent让大模型使用工具Agent是大模型根据目标自主规划、调用工具完成任务的能力。Spring AI 2.0 和 LangChain4j 对此提供了强大支持。我们实现一个让AI调用“计算器”和“获取当前时间”工具的简单Agent。6.1 定义工具Tools首先定义AI可以调用的工具。工具本质上是带有Tool注解的Bean方法。// 文件路径src/main/java/com/example/demo/tools/CalculatorTool.java package com.example.demo.tools; import dev.langchain4j.agent.tool.Tool; import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; Component public class CalculatorTool { Tool(用于计算两个数字的和) public double add(double a, double b) { return a b; } Tool(用于计算两个数字的差返回 a - b 的结果) public double subtract(double a, double b) { return a - b; } Tool(用于计算两个数字的乘积) public double multiply(double a, double b) { return a * b; } Tool(用于计算两个数字的商返回 a / b 的结果。注意b不能为0。) public double divide(double a, double b) { if (b 0) { throw new IllegalArgumentException(除数不能为0); } return a / b; } }// 文件路径src/main/java/com/example/demo/tools/TimeTool.java package com.example.demo.tools; import dev.langchain4j.agent.tool.Tool; import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; Component public class TimeTool { Tool(获取当前的日期和时间可以指定格式例如yyyy-MM-dd HH:mm:ss) public String getCurrentTime(String format) { DateTimeFormatter formatter; try { formatter DateTimeFormatter.ofPattern(format); } catch (IllegalArgumentException e) { formatter DateTimeFormatter.ISO_LOCAL_DATE_TIME; } return LocalDateTime.now().format(formatter); } }6.2 配置并运行Agent我们需要配置一个AiServices它将自动把工具暴露给模型并处理模型与工具之间的交互。// 文件路径src/main/java/com/example/demo/service/AgentService.java package com.example.demo.service; import dev.langchain4j.service.AiServices; import dev.langchain4j.service.UserMessage; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.ai.chat.memory.InMemoryChatMemory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; // 定义一个Agent的接口 interface Assistant { String chat(String userMessage); } Configuration public class AgentService { // 注入ChatClient它背后连接的是DeepSeek private final ChatClient chatClient; public AgentService(ChatClient chatClient) { this.chatClient chatClient; } Bean public Assistant myAssistant() { // 使用LangChain4j的AiServices.builder来构建Agent // 它需要模型、工具列表、以及一个实现接口 return AiServices.builder(Assistant.class) .chatLanguageModel(new SpringAiChatModel(chatClient)) // 适配层将Spring AI ChatClient转为LangChain4j的ChatLanguageModel .tools(new CalculatorTool(), new TimeTool()) // 注册工具 .chatMemory(MessageChatMemoryAdvisor.defaultChatMemory()) // 简单的对话记忆 .build(); } // 适配器将Spring AI的ChatClient包装成LangChain4j所需的ChatLanguageModel // 注意这是一个简化示例实际可能需要更复杂的适配逻辑。Spring AI和LangChain4j的集成库会提供更优雅的方式。 // 这里为了概念清晰展示其原理。 static class SpringAiChatModel implements dev.langchain4j.model.chat.ChatLanguageModel { private final ChatClient chatClient; SpringAiChatModel(ChatClient chatClient) { this.chatClient chatClient; } Override public String generate(String userMessage) { return chatClient.call(userMessage); } // 其他重载方法需要根据实际情况实现... } }重要说明上述SpringAiChatModel适配器是一个原理性演示。在实际项目中应使用langchain4j-spring-ai模块提供的官方适配器或者等待Spring AI 2.0更完善的Agent支持。当前Spring AI 1.0/2.0早期版本构建复杂Agent更成熟的方式是直接使用LangChain4j的原生API配合其OpenAI客户端。但本文旨在展示Spring AI生态内的整合思路。6.3 使用Agent的Controller// 文件路径src/main/java/com/example/demo/controller/AgentController.java package com.example.demo.controller; import com.example.demo.service.AgentService.Assistant; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; RestController RequestMapping(/ai/agent) public class AgentController { Autowired private Assistant assistant; // 注入我们定义的Agent GetMapping(/talk) public String talkWithAgent(RequestParam String message) { // 将用户消息交给Agent处理Agent会自动判断是否需要以及调用哪个工具 return assistant.chat(message); } }启动应用尝试访问http://localhost:8080/ai/agent/talk?message123加上456等于多少http://localhost:8080/ai/agent/talk?message现在的时间是什么格式是yyyy年MM月dd日你会发现AI不仅回答了问题还在背后自动调用了你定义的CalculatorTool.add或TimeTool.getCurrentTime方法并将工具执行结果融入到了最终回复中。这就是AI Agent的核心能力。7. 生产环境配置、优化与常见问题将Demo运行起来只是第一步要用于生产还需考虑诸多因素。7.1 配置优化连接池与超时在application.yml中配置HTTP客户端防止因网络波动导致线程阻塞。spring: ai: openai: client: connect-timeout: 10s read-timeout: 30s重试机制对于可重试的错误如网络超时、速率限制配置重试逻辑。Spring AI或底层RestTemplate支持配置RetryTemplate。多模型与降级不要绑定单一模型。可以配置多个ChatClientBean根据策略主备、负载均衡选择。在Configuration类中定义多个ChatClient使用Qualifier区分。Bean Primary public ChatClient deepSeekChatClient(OpenAiChatClient deepSeekClient) { return deepSeekClient; } Bean public ChatClient backupChatClient(/* 配置另一个模型的连接器如通义千问 */) { // ... 返回另一个ChatClient }7.2 监控与可观测性日志记录为ChatClient的调用开启DEBUG日志记录请求和响应的元数据注意不要记录包含敏感信息的完整消息体。指标收集利用Spring Actuator和Micrometer收集每次AI调用的耗时、令牌使用量、成功率等指标并与Prometheus、Grafana集成。链路追踪在分布式系统中确保AI调用被纳入统一的Trace如SkyWalking, Jaeger中。7.3 安全与合规API密钥管理必须使用安全的密钥管理服务如HashiCorp Vault, AWS Secrets Manager, Kubernetes Secrets绝对禁止硬编码。内容审核在将用户输入发送给模型前以及将模型输出返回给用户前应加入内容安全审核层过滤有害、偏见或不合规信息。数据隐私明确告知用户数据的使用方式。对于敏感数据考虑使用模型微调或本地化部署方案而非公有云API。7.4 常见问题与排查问题现象可能原因排查方式解决方案启动报错No qualifying bean of type ChatClient1.spring-ai-openai-starter依赖缺失或版本不对。2.spring.ai.openai.api-key未配置。1. 检查pom.xml依赖和版本。2. 检查application.yml配置确保密钥有效。1. 添加正确依赖检查Spring AI版本兼容性。2. 正确设置API_KEY环境变量或配置文件。调用API返回401或403错误API密钥错误、过期或没有权限。检查控制台日志中的错误信息。在DeepSeek平台验证API密钥状态和余额。更换有效API密钥检查账号配额。响应速度非常慢1. 网络问题。2. 模型负载高。3. 提示词过长或max-tokens设置过大。1. 检查网络连通性。2. 查看DeepSeek服务状态。3. 分析日志中的请求大小。1. 优化网络或使用代理合规前提下。2. 调整temperature和max-tokens。3. 对长文本进行合理分割。Agent不调用工具1. 工具类未被Spring管理缺少Component。2. 工具方法描述不清晰模型无法理解。3. 模型能力不支持工具调用需确认DeepSeek对function calling的支持度。1. 检查工具类是否在Spring扫描路径下。2. 查看模型返回的原始信息看是否识别了工具。3. 查阅DeepSeek官方文档关于工具调用的说明。1. 确保工具类是Spring Bean。2. 优化Tool注解中的描述使其更精确。3. 考虑使用对工具调用支持更好的模型如GPT-4进行关键环节测试。RAG检索结果不相关1. 文档分割策略不合理。2. 嵌入模型Embedding Model不匹配。3. 检索数量maxResults太少。1. 检查分割后的文本片段是否保持语义完整。2. 尝试不同的嵌入模型如OpenAI的text-embedding-3-small。3. 增加maxResults但需权衡性能。1. 调整DocumentSplitters的参数大小、重叠。2. 对于中文可尝试BGE、M3E等中文优化的嵌入模型。3. 采用混合检索关键词向量提升召回率。8. 面试要点与项目复盘如果你正在准备面试基于这个项目你可以深入阐述以下要点这能极大体现你的工程化思维技术选型论证为什么选择Spring AI而不是直接调用HTTP API为什么结合LangChain4jDeepSeek相比其他模型的优势是什么考察技术视野和决策能力架构设计如何设计一个可扩展的AI服务层如何管理不同模型的客户端如何设计RAG系统的数据流考察系统设计能力性能与成本如何监控和优化AI调用的耗时与令牌消耗如何设计缓存策略例如对常见问题的嵌入向量或最终答案进行缓存以降低成本和延迟考察工程优化能力错误处理与稳定性如何实现模型的降级和熔断如何重试可恢复的失败如何记录和分析AI输出的不确定性考察高可用设计安全与合规如何管理API密钥如何对用户输入和AI输出进行内容过滤在涉及用户隐私数据的场景下如何设计系统考察安全意识Agent设计模式你如何设计工具的描述才能让模型更准确地调用如何处理工具调用的异常如何管理Agent的对话状态记忆考察对AI范式的理解这个项目为你提供了一个完整的沙盒你可以在此基础上继续深化引入向量数据库将InMemoryEmbeddingStore替换为Redis或PgVector实现持久化和分布式检索。实现流式响应使用Spring AI的ChatClient.stream()和Server-Sent Events (SSE)实现类似ChatGPT的打字机效果。复杂Agent编排利用LangChain4j的AgentExecutor实现多步骤规划、工具序列调用。模型微调针对特定领域任务收集数据对DeepSeek模型进行微调并通过Spring AI接入自定义模型端点。通过这个从零到一的项目实践你不仅掌握了Spring AI 2.0、LangChain4j和DeepSeek的具体用法更重要的是你建立了一套在Java生态中构建、评估和部署生产级AI应用的方法论。这远比单纯会调用一个API更有价值也是你在面试和实际工作中脱颖而出的关键。
返回列表