轻松上手大模型:基于Spring AI实现RAG知识库问答机器人(收藏版)

轻松上手大模型:基于Spring AI实现RAG知识库问答机器人(收藏版) 本文将带领大家从零开始使用Spring AI框架构建一个支持文档上传的知识库问答机器人帮助大家深入理解RAG技术的核心原理和实践应用。通过一个最小成本的方案我们实现了一个完整的RAG知识库问答机器人适合对大模型应用开发感兴趣的小伙伴学习和体验。一、引言随着大语言模型的快速发展RAGRetrieval-Augmented Generation技术已成为构建知识库问答系统的核心技术之一。本文将带领大家从零开始使用Spring AI框架构建一个支持文档上传的知识库问答机器人帮助大家深入理解RAG技术的核心原理和实践应用。1.1 什么是RAGRAG检索增强生成是一种结合了信息检索和文本生成的技术。它的基本工作流程是用户提出问题系统从知识库中检索相关信息大语言模型基于检索到的信息生成答案从系统设计角度触发RAG 的核心作用可以被描述为在LLM调用生成响应之前由系统动态构造一个“最小且相关的知识上下文”。请注意两个关键词动态每次问题都不同检索的知识也不同比如用户问 A 产品时找 A 的文档问 B 产品时找 B 的文档最小只注入必要信息比如用户问 “A 产品的定价”就只塞定价相关的片段而非整份产品手册RAG可以有效的弥补上下文窗口的先天不足不再需要把所有知识塞进窗口而是只在需要时 “临时调取” 相关部分既避免了窗口溢出又减少了注意力竞争。1.2 RAG在交互链路中的位置接下来我们以RAG的经典应用场景——企业知识库为例来看一下RAG在这个流程中所处的位置在这个结构中RAG主要就是在用户提问与向LLM发起请求这个中间段用于检索关联的文档构建上下文1.3 RAG工作原理我们以一张图来介绍RAG的工作原理具体的RAG详细介绍请参照文末引用二、核心实现2.1 项目结构概览项目结构如下D05-rag-qa-bot/ ├── src/main/java/com/git/hui/springai/app/ │ ├── D05Application.java # 启动类 │ ├── mvc/ │ │ ├── QaApiController.java # API控制器 │ │ └── QaController.java # 页面控制器 │ ├── qa/QaBoltService.java # 问答服务 │ └── vectorstore/ │ ├── DocumentChunker.java # 文档分块工具 │ ├── DocumentQuantizer.java # 文档量化器 │ └── TextBasedVectorStore.java # 文本向量存储 ├── src/main/resources/ │ ├── application.yml # 配置文件 │ ├── prompts/qa-prompts.pt # 提示词模板 │ └── templates/chat.html # 前端页面 └── pom.xml # 依赖配置2.2 项目初始化2.2.1 Maven依赖配置首先我们需要在pom.xml中配置必要的依赖其中关于向量数据库、tika的文档解析属于核心依赖项hanlp适用于无法直接使用EmbeddingModel的场景在我们的示例中会实现一个基础的文档向量化方案其中会采用Hanlp来做中文分词使用智谱的免费大模型来体验我们的RAG知识库问答当然也可以基于OpenAI-Starter来切换其他的大模型使用层面并没有改变只需要替换依赖、api配置即可dependencies !-- 向量数据库 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-advisors-vector-store/artifactId /dependency !-- 文档提取使用apache-tika来实现 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-tika-document-reader/artifactId /dependency !-- pdf文档提取实际也可以用上面的tika来实现 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-pdf-document-reader/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-rag/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- 使用智谱大模型 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-zhipuai/artifactId /dependency !-- 用于前端页面的支持 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-thymeleaf/artifactId /dependency !-- 中文分词用在文档向量化 -- dependency groupIdcom.hankcs/groupId artifactIdhanlp/artifactId versionportable-1.8.4/version /dependency /dependencies这里我们引入了Spring AI的核心依赖以及用于文档处理的Tika和PDF读取器还特别加入了HanLP中文分词库来优化中文处理效果。2.2.2 应用配置在application.yml中配置API密钥和相关参数spring: ai: zhipuai: api-key:${zhipuai-api-key} chat: options: model:GLM-4-Flash temperature:0.1 thymeleaf: cache:false servlet: multipart: max-file-size:10MB max-request-size:50MB logging: level: org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor:debug org.springframework.ai.chat.client:DEBUG server: port:80802.3 自定义向量存储实现通常RAG会使用一些成熟的向量数据库如Pinecone、weaviate、qdrant、milvus或者es、redis等但是考虑到安装、环境配置等成本我们接下来会实现一个基础的自定义的文本向量库TextBasedVectorStore基于内存实现无需额外的外部依赖单纯的用来体验RAG并没有太大问题SpringAI原生提供了一个基于内存的向量数据库SimpleVectorStore在它的实现中向量数据写入依赖向量模型因此如果有额度使用大模型厂家提供的EmbeddingModel时直接用它进行测试即可当然如果你现在并没有渠道()使用向量模型的那也没关系接下来我们将参照SpringAI的SimpleVectorStore实现的一个自定义的向量库TextBasedVectorStore提供一套不依赖向量模型的解决方案特别适合快速原型开发核心实现如下当然你也完全可以忽略它它不是我们的重点2.3.1 TextBasedVectorStore - 文本匹配向量存储在下面的实现中重点体现了两个方法doAdd: 将文档保存到向量数据库中文档分片 - 向量化 - 存储doSimilaritySearch: 基于相似度的搜索需要注意一点文档的向量化与搜索时传入文本的向量化需要采用同一套向量化方案why?public classTextBasedVectorStoreextendsAbstractObservationVectorStore { Getter protected MapString, SimpleVectorStoreContent store newConcurrentHashMap(); / * 已经存储到向量库的document用于幂等 */ private SetString persistMd5 newCopyOnWriteArraySet(); / * 添加文档到向量数据库 * * param documents */ Override publicvoiddoAdd(ListDocument documents) { if (CollectionUtils.isEmpty(documents)) { return; } // 创建一个新的可变列表副本 ListDocument mutableDocuments newArrayList(); for (Document document : documents) { // 过滤掉重复的文档避免二次写入浪费空间 if (!persistMd5.contains((String) document.getMetadata().get(md5))) { mutableDocuments.add(document); } } if (CollectionUtils.isEmpty(mutableDocuments)) { return; } // 文档分片 ListDocument chunkers DocumentChunker.DEFAULT_CHUNKER.chunkDocuments(mutableDocuments); // 存储本地向量库 chunkers.forEach(document - { float[] embedding DocumentQuantizer.quantizeDocument(document); if (embedding.length 0) { return; } SimpleVectorStoreContentstoreContentnewSimpleVectorStoreContent( document.getId(), document.getText(), document.getMetadata(), embedding ); this.store.put(document.getId(), storeContent); }); mutableDocuments.forEach(document - persistMd5.add((String) document.getMetadata().get(md5))); } / * 搜索向量数据库根据相似度返回相关文档 * * param request * return */ Override public ListDocument doSimilaritySearch(SearchRequest request) { PredicateSimpleVectorStoreContent documentFilterPredicate this.doFilterPredicate(request); finalfloat[] userQueryEmbedding this.getUserQueryEmbedding(request.getQuery()); returnthis.store.values().stream() .filter(documentFilterPredicate) .map((content) - content.toDocument( DocumentQuantizer.calculateCosineSimilarity(userQueryEmbedding, content.getEmbedding()) )) .filter((document) - document.getScore() request.getSimilarityThreshold()) .sorted(Comparator.comparing(Document::getScore).reversed()) .limit((long) request.getTopK()) .toList(); } privatefloat[] getUserQueryEmbedding(String query) { return DocumentQuantizer.quantizeQuery(query); } }2.3.2 DocumentChunker - 文档分块器合理地将长文档分块是RAG系统的关键环节合理的分块大小可以有效的增加检索效率、提高准确率、减少上下文长度在真实的RAG应用中这一块具体的方案挺多的比如固定尺寸下面的方案、地柜拆分、语义拆分、结构化拆分如结构化的markdown文档就很适合、延迟拆分、自适应拆分、层级拆分、LLM驱动拆分、智能体拆分等具体这一块我也没有深入学习有兴趣的小伙伴问下AI吧~public classDocumentChunker{privatefinalint maxChunkSize;privatefinalint overlapSize;publicDocumentChunker(){this(500,50);// 默认值最大块大小500个字符重叠50个字符}public ListDocumentchunkDocument(Document document){Stringcontentdocument.getText();if(contentnull||content.trim().isEmpty()){returnList.of(document);}ListStringchunkssplitText(content);ListDocumentchunkedDocumentsnewArrayList();for(inti0;ichunks.size();i){Stringchunkchunks.get(i);StringchunkIddocument.getId()_chunk_ i;DocumentchunkDocnewDocument(chunkId, chunk, newHashMap(document.getMetadata()));chunkDoc.getMetadata().put(chunk_index, i);chunkDoc.getMetadata().put(total_chunks, chunks.size());chunkDoc.getMetadata().put(original_document_id, document.getId());chunkedDocuments.add(chunkDoc);}returnchunkedDocuments;}private ListStringsplitText(String text){ListStringchunksnewArrayList();// 按多种分隔符分割优先在语义边界处分割 String[]sentencestext.split((?。)|(?)|(?!)|(?)|(?\\?)|(?\\n\\n));StringBuildercurrentChunknewStringBuilder();for(String sentence:sentences){if(sentence.trim().isEmpty()){continue;// 跳过空句子}if(currentChunk.length() sentence.length()maxChunkSize){// 如果当前块加上新句子不超过最大大小就添加到当前块if(currentChunk.length()0){currentChunk.append(sentence);}else{currentChunk.append(sentence);}}else{// 如果当前块为空但是单个句子太长需要强制分割if(currentChunk.length()0){ListStringsubChunksforceSplit(sentence, maxChunkSize);for(inti0;isubChunks.size();i){StringsubChunksubChunks.get(i);if(isubChunks.size()-1){chunks.add(subChunk);}else{currentChunk.append(subChunk);}}}else{chunks.add(currentChunk.toString());currentChunknewStringBuilder();// 添加重叠部分如果句子长度大于重叠大小则只取末尾部分if(sentence.length()overlapSize){Stringoverlapsentence.substring(Math.max(0, sentence.length()- overlapSize));currentChunk.append(overlap);currentChunk.append(sentence);}else{currentChunk.append(sentence);}}}}if(currentChunk.length()0){chunks.add(currentChunk.toString());}returnchunks;}}2.3.3 DocumentQuantizer - 文档量化器使用HanLP进行中文分词实现了一个简单的文档向量化工具类同样的你也完全可以忽略它的具体实现因为它的效果显然比使用EmbedingModel要差很多很多但用于学习体验RAG也基本够用public classDocumentQuantizer { privatestaticfinalSegmentSEGMENT HanLP.newSegment(); publicstaticfloat[] quantizeText(String text) { if (text null || text.trim().isEmpty()) { returnnewfloat[0]; } String[] words preprocessText(text); MapString, Integer wordFreq countWordFrequency(words); // 生成固定长度的向量表示这里使用前128个高频词 return generateFixedLengthVector(wordFreq, 128); } / * 将文本转换为数值向量表示简化版 使用TF-IDF的基本思想但简化为词频统计 * * param text 输入文本 return 数值向量 */ privatestatic String[] preprocessText(String text) { ListTerm termList SEGMENT.seg(text); return termList.stream() .filter(term - !isStopWord(term.word)) // 过滤停用词 .filter(term - !term.nature.toString().startsWith(w)) // 过滤标点符号 .map(term - term.word.toLowerCase()) // 转换为小写 .toArray(String[]::new); } / * 生成固定长度的向量表示 * param wordFreq 词频映射 param length 向量长度 * return 固定长度的向量 / privatestaticfloat[] generateFixedLengthVector(MapString, Integer wordFreq, int length) { float[] vector newfloat[length]; // 获取频率最高的词汇 ListMap.EntryString, Integer sortedEntries wordFreq.entrySet() .stream() .sorted(Map.Entry.String, IntegercomparingByValue().reversed()) .limit(length) .collect(Collectors.toList()); // 将词频填入向量 for (inti0; i Math.min(sortedEntries.size(), length); i) { vector[i] sortedEntries.get(i).getValue(); } return vector; } publicstaticdoublecalculateCosineSimilarity(float[] vectorA, float[] vectorB) { if (vectorA null || vectorB null || vectorA.length 0 || vectorB.length 0) { return0.0; } intminLength Math.min(vectorA.length, vectorB.length); float[] adjustedA Arrays.copyOf(vectorA, minLength); float[] adjustedB Arrays.copyOf(vectorB, minLength); doubledotProduct0.0; doublenormA0.0; doublenormB0.0; for (inti0; i minLength; i) { dotProduct adjustedA[i] * adjustedB[i]; normA Math.pow(adjustedA[i], 2); normB Math.pow(adjustedB[i], 2); } normA Math.sqrt(normA); normB Math.sqrt(normB); if (normA 0 || normB 0) { return0.0; } return dotProduct / (normA * normB); } }2.3.4 注册向量库接下来就是注册使用这个向量库在配置类or启动类中添加下面这个声明即可Bean public VectorStore vectorStore() { return TextBasedVectorStore.builder().build(); }2.4 SpringAI向量存储上面2.3适用于无法直接使用大模型厂家的向量模型的场景如果可以直接使用那么上面的全部可以直接忽略掉直接使用下面的方式进行声明向量库即可Bean public VectorStore vectorStore(EmbeddingModel embeddingModel) { return SimpleVectorStore.builder(embeddingModel).build(); }2.5 问答服务实现接下来我们进入核心的基于RAG的QA问答机器人的实现2.5.1 QaBoltService - 核心问答服务Pre. 问答服务流程我们先从时序的角度来看一下这个问答服务的核心交互流程在这个时序过程中为了简化大家的理解我们将文档的向量化存储与问答进行了拆分第一步文档向量化这一部分包含RAG应用数据准备阶段的完整过程数据提取文本分割向量化第二步问答应用层响应用户提问从向量数据库检索相似度高的文档信息注入提示词访问大模型获取答案Impl. 核心实现接下来我们看一下具体的实现上面的步骤分割得很清楚但是实际使用时用户可以在问答中上传附件这个附件也会作为我们知识库的一部分因此具体的实现中你会发现这两部耦合在一起了请不要惊讶step1: 初始化ChatClient在开始之前我们首先参照SpringAI的官方教程通过Advisor来初始化支持RAG的ChatClient官方文档https://docs.spring.io/spring-ai/reference/api/retrieval-augmented-generation.html[2]Service publicclassQaBoltService { privatefinal ChatClient chatClient; privatefinal ChatMemory chatMemory; privatefinal VectorStore vectorStore; Value(classpath:/prompts/qa-prompts.pt) private Resource boltPrompts; publicQaBoltService(ChatClient.Builder builder, VectorStore vectorStore, ChatMemory chatMemory) { this.vectorStore vectorStore; this.chatMemory chatMemory; this.chatClient builder.defaultAdvisors( newSimpleLoggerAdvisor(ModelOptionsUtils::toJsonStringPrettyPrinter, ModelOptionsUtils::toJsonStringPrettyPrinter, 0), // 用于支持多轮对话 MessageChatMemoryAdvisor.builder(chatMemory).build(), // 用于支持RAG RetrievalAugmentationAdvisor.builder() .queryTransformers( // 使用大型语言模型重写用户查询以便在查询目标系统时提供更好的结果。 RewriteQueryTransformer.builder().chatClientBuilder(builder.build().mutate()).build() ) .queryAugmenter( // ContextualQueryAugmenter 使用来自所提供文档内容的上下文数据来增强用户查询。 // 默认不支持上下文为空的场景出现之后大模型会不返回用户查询这里调整为支持为空 ContextualQueryAugmenter.builder().allowEmptyContext(true).build() ) .documentRetriever( VectorStoreDocumentRetriever.builder() .similarityThreshold(0.50) .vectorStore(vectorStore) .build() ) .build() ).build(); } }接下来就是响应问答的实现这里分两步step2: 文档处理处理用户上传的附件即上面时序图中的第一步解析文档、切分、向量化、保存到向量库;下面的实现中主要体现的是基于SpringAI封装的tika与pdf文档解析starter来提取上传的文档生成供向量数据库使用的ListDocument; 而具体的文档切分、向量化等则是在上面的TextBasedVectorStore实现注为了一个文档重复进行数据处理我们在元数据中维护了文档的 md5这样当添加到向量库中时就可以基于这个md5来进行去重了一个工程化实现方面的小技巧~private ProceedInfo processFiles(String chatId, CollectionMultipartFile files) { StringBuildercontextnewStringBuilder(/n/n); ListMedia mediaList newArrayList(); files.forEach(file - { try { vardatanewByteArrayResource(file.getBytes()); varmd5 calculateHash(chatId, file.getBytes()); MimeTypemime MimeType.valueOf(file.getContentType()); if (mime.equalsTypeAndSubtype(MediaType.APPLICATION_PDF)) { PagePdfDocumentReaderpdfReadernewPagePdfDocumentReader(data, PdfDocumentReaderConfig.builder() .withPageTopMargin(0) .withPageExtractedTextFormatter(ExtractedTextFormatter.builder() .withNumberOfTopTextLinesToDelete(0) .build()) .withPagesPerDocument(1) .build()); ListDocument documents pdfReader.read(); documents.forEach(document - { document.getMetadata().put(md5, md5); if (document.getMetadata().containsKey(file_name) document.getMetadata().get(file_name) null) { document.getMetadata().put(file_name, file.getName()); } }); vectorStore.add(documents); varcontent String.join(/n, documents.stream().map(Document::getText).toList()); context.append(String.format(ATTACHMENT_TEMPLATE, file.getName(), content)); } elseif (text.equalsIgnoreCase(mime.getType())) { ListDocument documents newTikaDocumentReader(data).read(); documents.forEach(document - document.getMetadata().put(md5, md5)); vectorStore.add(documents); varcontent String.join(/n, documents.stream().map(Document::getText).toList()); context.append(String.format(ATTACHMENT_TEMPLATE, file.getName(), content)); } } catch (IOException e) { thrownewRuntimeException(e); } }); returnnewProceedInfo(context.toString(), mediaList); }step3: 问答实现然后就是具体的问答实现这里主要是借助QuestionAnswerAdvisor来封装RAG相关的信息说明在下面的实现中使用了自定义的提示词模板当然也可以直接使用SpringAI默认的方案public FluxString ask(String chatId, String question, CollectionMultipartFile files) { processFiles(chatId, files); // 自定义的提示词模板替换默认的检索参考资料的提示词模板 // 其中 query 对应的是用户的提问 question // question_answer_context 对应的是增强检索的document即检索到的参考资料 PromptTemplatecustomPromptTemplate PromptTemplate.builder() .renderer(StTemplateRenderer.builder().startDelimiterToken().endDelimiterToken().build()) .template( query Context information is below. --------------------- question_answer_context --------------------- Given the context information and no prior knowledge, answer the query. Follow these rules: 1. If the answer is not in the context, just say that you dont know. statements like Based on the context... or The provided information.... ).build(); varqaAdvisor QuestionAnswerAdvisor.builder(vectorStore) .searchRequest(SearchRequest.builder().similarityThreshold(0.5d).topK(3).build()) .promptTemplate(customPromptTemplate) .build(); varrequestSpec chatClient.prompt() .system(boltPrompts) .user(question) .advisors(qaAdvisor) .advisors(a - a.param(ChatMemory.CONVERSATION_ID, chatId)); return requestSpec.stream().content().map(s - s.replaceAll(/n, br/)); }到这里一个基于RAG的问答机器人的核心逻辑已经全部完成接下来我们进入体验阶段2.5.2 控制器实现QaApiController - API控制器RestController RequestMapping(/api) publicclassQaApiController { Autowired private QaBoltService qaBolt; GetMapping(path /chat/{chatId}, produces MediaType.TEXT_EVENT_STREAM_VALUE) public FluxString qaGet(PathVariable(chatId) String chatId, RequestParam(question) String question) { return qaBolt.ask(chatId, question, Collections.emptyList()); } PostMapping(path /chat/{chatId}, produces MediaType.TEXT_EVENT_STREAM_VALUE) public FluxString qaPost(PathVariable(chatId) String chatId, RequestParam(question) String question, RequestParam(value files, required false) CollectionMultipartFile files) { if (files null) { files Collections.emptyList(); } return qaBolt.ask(chatId, question, files); } }2.6 前端界面交互式聊天界面前端界面提供了文件上传和问答交互功能具体的代码实现请参考文末的项目源码地址这里就不贴了主要是太长了~三、体验与小结3.1 启动类SpringBootApplication publicclassD05Application { Bean public VectorStore vectorStore() { return TextBasedVectorStore.builder().build(); } publicstaticvoidmain(String[] args) { SpringApplication.run(D05Application.class, args); System.out.println(启动成功前端测试访问地址 http://localhost:8080/chat); } }3.2 问答提示词在resources/prompts/qa-prompts.pt中维护我们的qa机器人的系统提示词DeepSeek生成的## 角色设定 你是一个智能问答助手专门负责根据用户提供的文档内容进行准确的回答和信息提取。 ## 核心任务 - 仔细阅读并理解用户上传的文档内容 - 基于文档中的信息回答用户的问题 - 提供准确、相关且基于文档的答案 - 当问题超出文档范围时明确告知用户该信息未在文档中提及 ## 工作流程 1. **首先分析用户上传的文档提取关键信息** 2. **理解用户提出的问题** 3. **在文档中查找与问题相关的信息** 4. **整合相关信息并形成结构化答案** 5. **如无法从文档中找到相关信息则说明情况** ## 回答规范 - 严格基于文档内容作答不得编造信息 - 引用文档中的具体信息时请保持原文准确性 - 如果问题涉及多个知识点在答案中清晰分点说明 - 对于不确定的内容应诚实表达不确定性而非猜测 - 保持回答简洁明了同时确保信息完整 ## 注意事项 - 不得脱离文档内容进行回答 - 遇到模糊或不明确的问题时可以请求用户提供更详细的信息 - 如果文档中没有相关内容必须明确告知用户 - 保持专业、礼貌的沟通态度3.3 运行与测试启动应用运行D05Application主类2.访问页面打开http://localhost:8080/chat3.上传文档选择PDF、Word或文本文件4.提问测试在输入框中输入关于文档的问题当然在启动时可以在启动参数中指定大模型的ApiKey也可以直接修改applicatino.yml直接维护上apiKey也可以哦在上面这个示意图中我上传的是宣传文档显然是没有被大模型检索、训练过的从问答来看效果还是不错的但是请注意这个只是给大家用来体验RAG的用来学习验证还是不错的但是真实场景显然比我们提到的内容还多很多比如安全隐私不同用户的知识库文件需要隔离存储优化上下文窗口的管理、对话历史的管理检索优化多路召回、查询语义理解、查询改写等模型优化成本、效率的权衡监控体系链路追踪、日志分析、告警等DevOps: CI/CD容器编排体验、性能等3.4 核心技术要点小结1. RAG工作流程检索阶段当用户提问时系统首先将问题转换为向量然后在文档向量库中查找相似的文档片段生成阶段将检索到的相关文档内容与用户问题一起输入大语言模型生成最终答案2. 文档处理优化中文分词使用HanLP进行精确的中文分词提高语义理解准确性文档分块将长文档合理分块保持语义完整性的同时便于检索去重机制通过MD5哈希避免重复上传相同的文档3. 性能优化相似度计算使用余弦相似度算法计算文本相似度缓存机制对已处理的文档进行缓存避免重复处理流式响应使用SSE实现答案的流式返回提升用户体验本文通过一个最小成本技术和资金成本都很小的方案我们实现了一个完整的RAG知识库问答机器人。通过这个项目相信对RAG感兴趣想快速体验一下完成流程的小伙伴可以有一个动手实操的机会。如何学习大模型 AI 由于新岗位的生产效率要优于被取代岗位的生产效率所以实际上整个社会的生产效率是提升的。但是具体到个人只能说是“最先掌握AI的人将会比较晚掌握AI的人有竞争优势”。这句话放在计算机、互联网、移动互联网的开局时期都是一样的道理。我在一线科技企业深耕十二载见证过太多因技术卡位而跃迁的案例。那些率先拥抱 AI 的同事早已在效率与薪资上形成代际优势我意识到有很多经验和知识值得分享给大家也可以通过我们的能力和经验解答大家在大模型的学习中的很多困惑。我们整理出这套AI 大模型突围资料包✅ 从零到一的 AI 学习路径图✅ 大模型调优实战手册附医疗/金融等大厂真实案例✅ 百度/阿里专家闭门录播课✅ 大模型当下最新行业报告✅ 真实大厂面试真题✅ 2026 最新岗位需求图谱所有资料 ⚡️ 朋友们如果有需要《AI大模型入门进阶学习资源包》下方扫码获取~① 全套AI大模型应用开发视频教程包含提示工程、RAG、LangChain、Agent、模型微调与部署、DeepSeek等技术点② 大模型系统化学习路线作为学习AI大模型技术的新手方向至关重要。 正确的学习路线可以为你节省时间少走弯路方向不对努力白费。这里我给大家准备了一份最科学最系统的学习成长路线图和学习规划带你从零基础入门到精通③ 大模型学习书籍文档学习AI大模型离不开书籍文档我精选了一系列大模型技术的书籍和学习文档电子版它们由领域内的顶尖专家撰写内容全面、深入、详尽为你学习大模型提供坚实的理论基础。④ AI大模型最新行业报告2025最新行业报告针对不同行业的现状、趋势、问题、机会等进行系统地调研和评估以了解哪些行业更适合引入大模型的技术和应用以及在哪些方面可以发挥大模型的优势。⑤ 大模型项目实战配套源码学以致用在项目实战中检验和巩固你所学到的知识同时为你找工作就业和职业发展打下坚实的基础。⑥ 大模型大厂面试真题面试不仅是技术的较量更需要充分的准备。在你已经掌握了大模型技术之后就需要开始准备面试我精心整理了一份大模型面试题库涵盖当前面试中可能遇到的各种技术问题让你在面试中游刃有余。以上资料如何领取为什么大家都在学大模型最近科技巨头英特尔宣布裁员2万人传统岗位不断缩减但AI相关技术岗疯狂扩招有3-5年经验大厂薪资就能给到50K*20薪不出1年“有AI项目经验”将成为投递简历的门槛。风口之下与其像“温水煮青蛙”一样坐等被行业淘汰不如先人一步掌握AI大模型原理应用技术项目实操经验“顺风”翻盘这些资料真的有用吗这份资料由我和鲁为民博士(北京清华大学学士和美国加州理工学院博士)共同整理现任上海殷泊信息科技CEO其创立的MoPaaS云平台获Forrester全球’强劲表现者’认证服务航天科工、国家电网等1000企业以第一作者在IEEE Transactions发表论文50篇获NASA JPL火星探测系统强化学习专利等35项中美专利。本套AI大模型课程由清华大学-加州理工双料博士、吴文俊人工智能奖得主鲁为民教授领衔研发。资料内容涵盖了从入门到进阶的各类视频教程和实战项目无论你是小白还是有些技术基础的技术人员这份资料都绝对能帮助你提升薪资待遇转行大模型岗位。以上全套大模型资料如何领取