2026/4/17 2:06:14
网站建设
项目流程
自建网站推广方式,昌吉网站建设公司,怎么申请自媒体平台账号,网站建设人员需求分析一、前言
上一篇文章#xff08;[从原理到落地#xff1a;MCP在Spring AI中的工程实践]#xff09;介绍了 MCP 在 LLM 中的作用#xff0c;其中提到 MCP 让 LLM “看起来”具备了调用外部程序的能力#xff0c;进而能够完成一些自动化工作#xff0c;如自动获取上下文、…一、前言上一篇文章[从原理到落地MCP在Spring AI中的工程实践]介绍了 MCP 在 LLM 中的作用其中提到 MCP 让 LLM “看起来”具备了调用外部程序的能力进而能够完成一些自动化工作如自动获取上下文、操作文件系统等。而本篇文章主要介绍 RAG 在 LLM 中的作用与 MCP 相同的是RAG 也能够让 LLM “看起来”可以自动获取外部信息进而增强其上下文不同的是MCP 更偏向于工具调用由于可以调用各种不同的工具因此其用途会更加广泛。而 RAG 更偏向于知识检索可以从数据库中检索出与问题相关联的知识来增强 LLM 的上下文信息相当于一个增强知识的工具。本篇文章将基于 RAG 的背景、原理以及其在 Spring AI 框架下的实践展开介绍。二、概述2.1 背景目前 LLM 生成的内容都是基于其训练时已知的信息其无法访问外部的信息因此无法回答训练数据以外的内容。例如我们提出了一个问题而这个问题是关于某个内部文档的那么 LLM 就很有可能一本正经的胡说八道这种情况称为大模型的幻觉。针对幻觉问题我们可以把文档的内容和问题一起发送给 LLM这样 LLM 就具有充足的上下文来回答问题。但是当文档十分庞大时与问题有关联的上下文可能只是文档中的某一小段话这时候 LLM 就很可能无法准确找到重点于是又胡乱地回答问题。那此时我们可能又想到一种解决方案就是不把整个文档都发送给 LLM而只发送与问题相关联的几段话给它这个动作由我们人工来完成会显得很低效因此需要一个具备“检索”能力的工具来帮我们找出与问题相关度最高的上下文并将其交给 LLM实际上 RAG 解决的正是这个问题。2.2 RAGRAGRetrieval Augmented Generation即检索增强生成其核心思想是在 LLM 回答之前先通过检索系统从外部知识库找出与问题相关的内容然后将这些内容与原始问题一起输入到 LLM 中。结合了 RAG 的 LLM 在回答内容时的大致流程如下所示1用户提出问题。2检索系统搜索知识库中与问题相关联的内容。3知识库返回相关知识给检索系统。4检索系统将问题、相关知识都发送给 LLM。5LLM 生成回答内容并展示给用户。2.3 Embedding基于上面的流程我们不难发现这里会存在几个关键的问题1如何高效地检索出与问题相关联的知识内容2知识库采用何种方式存储知识是采用关系型数据库直接存储还是采取其他方式针对第一个问题RAG 引入一种新的模型称为Embedding模型其输入是一段文字而输出是一个固定长度的浮点型数组例如 OpenAI 的 text-embedding-3-small 模型其输出的数组长度为 1536而 text-embedding-3-large 模型输出的数组长度为 3072。内容越相似其经过 Embedding 模型生成的数组则也会越相似因此我们可以通过数组之间的距离来判断两段文字的相似程度。这就类似于我们以往在学校中学习过的坐标系输出的数组也可以映射在一个很大维数的坐标系中的某个点例如 1536 维坐标系中的某个点而我们可以通过两个点的距离来判断其相似程度相关计算方式在原理部分会介绍这里以三维坐标系举例如下图所示可以看到越接近的文字其映射的点也会越接近。针对第二个问题传统的关系型数据库存储的是结构化数据适合于检索精确匹配的数据而 RAG 中需要进行语义相似度检索非精确匹配所以不适用于传统的关系型数据库因此RAG 引入向量数据库作为知识库。向量数据库是一种专门用于存储和检索高维向量数据的数据库主要用于处理相似性搜索的任务其可以存储非结构化数据如文本、音频、视频等经过 Embedding 模型后生成的向量并可以通过一个给定的向量来迅速找到最相似的若干个向量。向量数据库在存储向量时不仅会存储向量本身还会存储其原始文本和元信息如时间、语言等来方便通过向量找到其原始文本。目前市面上常用的向量数据库有 Pinecone、Chroma、PostgreSQL PGVector 等。三、原理3.1 工作流程RAG 的工作流程可以分为离线和在线两个部分离线部分指的是知识准备的过程。我们可以提前上传文档资料这些文档会经过 Embedding 模型转换为高维向量然后存储进向量数据库。在线部分指的是实时问答的过程。用户提出问题后问题文本会经过 Embedding 模型转换为高维向量然后依据这个向量在知识库中找寻最相似的若干个知识片段之后将知识和问题一起传入 LLM最后由 LLM 生成答案。RAG 的完整流程如下图所示。后续也会介绍关键部分的技术原理细节。3.2 ChunkingChunking即分块指的是将文档分割成若干个片段文档分割的质量将直接决定了后续检索的准确性和 LLM 回答的效果。在 RAG 中做 Chunking 操作的原因正如前面提到过的有时与问题相关联的知识片段可能只是文档中的一小部分如果将所有的文档都交给 LLM它可能无法马上理解到重点因此需要先将文档切分成若干个片段再将每个片段转换成各自的向量。常见的 Chunking 策略有名字描述优点缺点固定大小拆分按指定字数或 token 数来切分实现简单、速度块可能会割裂语句打断语义完整性结构拆分基于文档格式如 Html、Markdown拆分本质上是借助这些文档特有的格式来拆分语句可以保留原始文档的结构逻辑语义完整度高依赖于结构清晰、规范的文档对于无结构的语句如纯文本无法使用语义拆分根据语义边界如段落、句子、主题变化等拆分可以采用 NLP 方法如如分句、主题检测或 Embedding 聚类最符合人类理解可保留语义一致性实现复杂需要依赖 NLP 模型、Embedding 计算或聚类等且计算开销大效率低递归拆分先按大分隔符如段落拆分再按句子等进行拆分直到拆分得到的块满足长度限制在语义完整性和长度控制两个度量之间保持平衡设计较复杂需要合适的层级和递归停止条件这些策略可以组合使用即一类文档可以使用多种策略但目前没有一种策略适用于所有的文档因此需要根据情况来选择合适的策略。3.3 Indexing在 RAG 中需要对向量构建索引以便能够高效地计算向量之间的相似程度。向量索引是一种用于高效索引和检索高维向量的数据结构能帮助我们高效筛选与查询向量最接近的少量数据。目前常用的构建向量索引的方法是 ANNApproximate Nearest Neighbor近似最近邻搜索算法其能够在牺牲少量准确性的同时显著提高搜索速度和计算性能常见的几种实现方式如下1LSHLSHLocality Sensitive Hashing局部敏感哈希算法是一种基于哈希结构的算法其通过设计一种哈希函数族使得相似的向量被映射到相同哈希桶的概率高而不相似的概率低。在查询时只会搜索同一个桶或若干相似的痛中的数据进而能够避免全表扫描。2AnnoyAnnoy算法是一种基于树结构的算法其核心思想是构建一棵“随机投影二叉树”每一棵树就是向量空间划分后的小区域。算法核心流程如下① 在所有向量中随机挑选两个向量用它们的方向生成超平面进而来切割向量空间。② 将所有的向量都投影到这个方向上得到每个向量在这个方向上的数值。③ 根据投影值的中位数把向量空间分成左右两部分类似于左侧数值小右侧数值大④ 对左右两个空间继续重复上面的过程直到每个空间的向量数量小于指定阈值就不再进行划分。⑤ 每个节点的父节点就是切割前的空间子节点就是当前空间切割后的左右子空间。在搜索时会在每棵树中递归查找与查询向量最接近的叶结点然后将这些叶结点表示的向量作为候选向量并计算所有的候选向量与查询向量的实际距离最后选择距离最近的 k 个向量作为近似最近邻。3HNSWHNSWHierarchical Navigable Small World分层导航小世界算法是一种基于图结构的算法该算法会构建一个分层图的结构每一层都是一个由相互连接的节点组成的可导航小世界网络图的高层用于快速定位跳跃大量的无关节点低层则用于精细搜索近似节点有点类似于跳表。4IVFIVFInverted File Index倒排文件索引是一种基于聚类的算法通过 k-means 聚类把向量分为多个簇然后对每个簇建立一个倒排表存放簇内的所有向量。查询时会首先找到最近的几个簇之后就只在这些簇中找到最近邻的向量进而避免了全局搜索。从以上四种算法可以看出ANN 本质上并不保证找出真正最相近的向量而是找到一个足够接近的向量以换取更快的搜索速度。原因在于 ANN 中并不是全局搜索而是在部分候选区域中查找这样就有概率漏掉实际上最近的向量。而每种算法都有其独特的优势和局限性目前还不存在一种适用于所有场景的算法需要权衡性能、准确性和计算资源三个方面。3.4 Similarity Search在 RAG 中需要通过计算向量之间的距离来判断两个向量的相似程度常见的计算方式有以下几种1欧几里得距离用于计算两个向量之间的直线距离其公式如下其优点是简单直观适合表示距离感的任务如定位或聚类但缺点是对长度比较敏感不适合语义相似的向量因为有时两个语义相似的向量在长度上会有所差别。2点积用于直接计算两个向量的乘积之和其公式如下其优点是简单高效适合于含有权重意义的 Embedding 模型如推荐场景原因是它的计算公式的组成如下因此点积不仅可以衡量语义相似性方向也可以根据向量的长度进行加权。3余弦相似度用于计算两个向量之间夹角的余弦值其公式如下其优点是度量与语义方向一致即两段语义相近的文本即使它们的长度不同也会有较高的余弦相似度因此这种方式在自然语言处理领域很常用。余弦相似度的取值范围为 [-1, 1]越接近 1 表示两个向量越相似。3.5 Re-ranking前面介绍了向量索引构建的几种常用算法而这些算法虽然计算速度快但牺牲了一些准确性即最终检索出来的文档虽然相似度高但实际并不是真正相关因为“相似度”不等于“相关性”相似度只是衡量语义是否相似而不一定对问题有帮助。这里举个例子查询“介绍一下李清照的文学风格”此时向量相似度高的文档可能有1文档 A“李清照是宋代著名女词人擅长婉约词情感细腻……”真正相关2文档 B“杜甫是唐代伟大诗人以沉郁顿挫著称写了许多反映民生疾苦的诗……”不相关向量模型可能会觉得李清照和杜甫都是古代诗人属于语义相似的场景因此文档 B 的相似度也会很高但这与问题并不相关。因此这里需要做Re-ranking的操作即重排序假如我们最终要交给 LLM 的文档数量为 5那么一般在初步检索阶段也就是从向量数据库查询相似性靠前的文档时会检索出数量比 5 大的候选文档集合如 top-20然后再进行重排序此时会使用其他模型对候选文档与查询条件更精细的匹配选出最相关的 5 个文档。其中重排序模型在文档相关性排序上会更加准确但计算代价会更高因此通常只在 top-20 或 top-50 上运行。3.6 Prompt Template在 RAG 中Prompt Template会将检索到的文档context和用户的问题User Query组合成一个格式化的 prompt最终交给 LLM。其最大的好处在于能够让 LLM 更聚焦于上下文减少幻觉问题让回答更加稳定和专业。我们可以根据任务的类型来自定义模板常见的模板如下You are a helpful assistant. Based on the following context, answer the question. Context: {retrieved_documents} Question: {user_query} Answer:3.7 总结在介绍完 RAG 工作流程中关键部分的技术细节后再回看一下流程图整个流程的详细描述如下。离线部分1对上传的文档进行分块Chunking将文档分割成若干个片段。2使用 Embedding 模型将切分后的片段转换为向量。3将向量存储到向量数据库中并建立索引Indexing。在线部分1使用 Embedding 模型将用户问题转换为向量。2在向量数据库中检索出与查询向量最相似的 top-k 个知识片段Similarity Search。3对检索出的片段进行重排序保留最相关的 top-n 个片段Re-ranking。4将知识片段与问题组合成一个格式化的 promptPrompt Template。5将 prompt 提交给 LLM最终得到生成的答案。四、实践这里主要讲述使用 Spring AI 框架完成基于 RAG 的应用开发的方式。4.1 环境说明环境名说明JDK17SpringBoot3.5.0Spring AI1.0.0构建工具MavenLLMQwen2.5-72B-InstructEmbeddingtext-embedding-ada-002向量数据库PostgreSQL PGVector4.2 Embedding本篇文章使用 OpenAI 的 Embedding 模型完成向量化操作。pom 依赖dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId /dependency配置文件spring: ai: openai: base-url: [这里填url] api-key: [这里填密钥] embedding: options: model:text-embedding-ada-002之后就可以注入 EmbeddingModel 的 Bean并调用相应的 API 完成向量化代码示例如下Autowired privateEmbeddingModel embeddingModel; GetMapping(/embedding) publicvoidembedding(String input) { System.out.println(input input); float[] embeddings1 embeddingModel.embed(input); System.out.println(length embeddings1.length , array Arrays.toString(embeddings1)); }测试结果如下可以看到文本被转换为了一个 1536 维的向量。4.3 向量数据库本篇文章使用 PostgreSQL 配合 PGVector 插件作为向量数据库插件安装方式可以参考 PGVector-github。pom 依赖dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-vector-store-pgvector/artifactId /dependency 配置文件 spring: ai: vectorstore: pgvector: initialize-schema:true index-type:HNSW distance-type:COSINE_DISTANCE dimensions:1536 max-document-batch-size:10000 datasource: url:jdbc:postgresql://localhost/postgres username: [这里填用户名] password: [这里填密码]当initialize-schema为 true 时Spring AI 会自动初始化向量数据库上面的配置相当于如下的 sql 脚本CREATE TABLE IF NOT EXISTS vector_store ( id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, content text, metadata json, embedding vector(1536) ); CREATE INDEX ON vector_store USING HNSW (embedding vector_cosine_ops);然后就可以注入 VectorStore 的 Bean并调用相应的 API 完成存储向量和寻找最近相似度向量的操作代码示例如下Autowired private VectorStore vectorStore; GetMapping(/storeVector) public void storeVector(RequestParam ListString input) { ListDocument documents input.stream().map(Document::new).collect(Collectors.toList()); vectorStore.add(documents); } GetMapping(/similaritySearch) publicvoidsimilarSearch(String input) { SearchRequestquery SearchRequest.builder().query(input).topK(2).build(); ListDocument similarDocuments vectorStore.similaritySearch(query); Stringresult similarDocuments.stream() .map(Document::getText) .collect(Collectors.joining(System.lineSeparator())); System.out.println(result\n result); }注意在调用 VectorStore 的 add 方法时时无需自己调用上面提到的 Embedding API因为 add 方法底层会去调用 Embedding API 将文本转换为向量因此无需我们手动转换但是这里一定要提前在 pom 依赖和配置文件中对 Embedding 模型进行配置否则启动时会报错缺少 EmbeddingModel 的 Bean如下所示这里先调用/storeVector存储一些向量结果如下然后再调用/similaritySearch搜索最相似的文本问题是“小璐的职业是什么”结果如下可以看到这里成功搜索出了 2 条最相似的文本。4.4 ETLETL即Extract提取、Transform转换、Load加载用于将数据从不同的来源中提取出来并经过清洗、格式转换等处理后加载到目标数据库中。在 RAG 中ETL 的作用就是对数据进行预处理是从原始数据源到结构化向量存储的流程。在 Spring AI 中也提供了 ETL 相关的 API主要包含三个组件DocumentReader完成 Extract 操作实现了 Supplier DocumentReader常用的实现类有 TextReader处理纯文本文件、JsoupDocumentReader处理 HTML 文件、MarkdownDocumentReader处理 MarkDown 文件、PagePdfDocumentReader处理 PDF 文件 等。DocumentTransformer完成 Transform 操作实现了 FunctionList, List。常用的实现类有 TokenTextSplitter、ContentFormatTransformer 等。DocumentWriter完成 Load 操作实现了 Consumer。常用的实现类有 FileDocumentWriter、各种 VectorStore 类如本篇文章使用的 PgVectorStore。三个组件共同完成 ETL 的流程如下图所示。这里演示 TextReader、TokenTextSplitter、PgVectorStore 的组合代码如下所示。Autowired private VectorStore vectorStore; Value(classpath:/file.txt) private Resource resource; GetMapping(/etl) publicvoidetl() { TextReadertextReadernewTextReader(this.resource); ListDocument extractedDoc textReader.read(); System.out.println(extract result: extractedDoc); TokenTextSplittersplitternewTokenTextSplitter(200, 200, 5, 10000, true); ListDocument transformedDoc splitter.apply(extractedDoc); System.out.println(transform length transformedDoc.size() , result: transformedDoc); vectorStore.add(transformedDoc); }这里解释一下 TokenTextSplitter 的几个细节TokenTextSplitter 使用 CL100K_BASE 编码根据标记计数将文本拆分成块即按 token 对文档进行切分tokenizer 编码的标准是 CL100K_BASE对应于前面 3.2 节讲述的 Chunking。其构造函数的几个参数如下chunkSize每个文本块的目标 token 数量用于控制 chunk 的最大长度默认 800。minChunkSizeChars每个文本块中最少必须包含的字符数不是 token用于防止生成非常短、碎片化的文本块默认 350。minChunkLengthToEmbed对每个 chunk只有在长度超过这个值时才会包含进最终的结果比如用于 Embedding 向量生成用于避免处理无意义的超短段默认 5。maxNumChunks从一段文本中最多能切出多少个 chunk默认 1000keepSeparator是否在分割后保留原始文本中的分隔符如 \n、空格、句号等默认 true。这里由于我的文本内容只包含了 652 个字符因此这里对参数进行了相应的调整防止只生成一个文本块对于不同的文本内容你可以自行设定这些参数。生成的结果如下所示。可以看到最终这一个文件的内容被分成了 4 个文本块然后再看向量数据库中对应的结果如下所示。4.5 RAG前面的部分大多数都是对数据的处理对应于 RAG 的离线部分还没有涉及到 LLM 的交互这里讲述 RAG 的在线部分。pom 依赖dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-advisors-vector-store/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-rag/artifactId /dependency这里为了显示 LLM 交互时的日志在配置文件中声明了日志级别如下所示spring: ai: openai: base-url: [这里填url] api-key: [这里填密钥] chat: options: model:Qwen/Qwen2.5-72B-Instruct logging: level: org: springframework: ai: chat: client: advisor: DEBUGLLM Bean 的配置Bean publicChatClientchatClient(ChatClient.Builder chatClientBuilder) { return chatClientBuilder .defaultAdvisors(newSimpleLoggerAdvisor()) .build(); }实现 RAG 流程代码Autowired private ChatClient chatClient; Autowired private VectorStore vectorStore; GetMapping(/rag) public void chatWithRag(String input) { System.out.println(input: input); Advisor retrievalAugmentationAdvisor RetrievalAugmentationAdvisor.builder() .documentRetriever(VectorStoreDocumentRetriever.builder() .similarityThreshold(0.5) .vectorStore(vectorStore) .build()) .queryAugmenter(ContextualQueryAugmenter.builder() .allowEmptyContext(true) .build()) .build(); String result chatClient.prompt() .advisors(retrievalAugmentationAdvisor) .user(input) .call() .content(); System.out.println(result: result); }测试结果如下所示这里由于开启了日志因此整个整个交互流程都会显示在上面。从结果中还能够看出Spring AI 在 RAG 中也设置了 Prompt Template对应于 3.6 节它不仅将检索到的文档和用户提的问题组合成一个格式化的 prompt还告诉了 LLM 两条回答的规则即“如果答案不在上下文中就说你不知道”、“避免使用“根据上下文……”或“提供的信息……”之类的说法”。input: 小璐是谁他是干什么的 2025-06-12T16:00:04.14308:00 DEBUG 1183 小璐的职业是做Java开发的 小璐的职业是计算机相关的 小璐男/女一名专注于Java开发的计算机从业者自大学起便对编程与软件工程抱有浓厚兴趣。凭借对技术的热爱与不断钻研的精神他逐步走上了专业的开发之路。 大学期间小璐主修计算机科学与技术系统学习了数据结构、操作系统、计算机网络、数据库原理、Java编程语言等核心课程。在课程之外他积极参与各类编程实践与项目开发多次参加编程竞赛与开发挑战积累了 力。 除了日常开发工作小璐也不断关注新技术的发展积极学习微服务架构、分布式系统、容器化部署如Docker、Kubernetes等前沿知识。他相信技术永无止境持续学习和思考是保持竞争力的关键。 作为一名开发者小璐不仅追求技术上的成长也重视团队协作与沟通效率。他乐于帮助他人愿意分享自己的经验同时也虚心接受他人的建议。在工作中他秉持认真负责、追求完美 Given the context information andno prior knowledge, answer the query. Follow these rules: 1. If the answer isnotin the context, just say that you dont know. 2. Avoid statements like Based on the context... or The provided information.... Query: 小璐是谁他是干什么的 Answer: , properties{messageTypeUSER}, messageTypeUSER}], modelOptionsOpenAiChatOptions: {streamUsage:false,model:Qwen/Qwen2.5-72B-Instruct,temperature:0.7}}, context{rag_document_context[Document{id8d730d2c-5d35-4ff2-89c8-6bbacc642dde, text小璐的职业是做Java开发的, medianull, metadata{distance0.113830574}, score0.8861694261431694}, Document{id768fd0ba-c853-48dd-ad95-01bd0ababce4, text小璐的职业是计算机相关的, medianull, metadata{distance0.11950535}, score0.8804946467280388}, Document{idb6d0b193-c852-4e8a-9929-2918932a31c0, text小璐男/女一名专注于Java开发的计算机从业者自大学起便对编程与软件工程抱有浓厚兴趣。凭借对技术的热爱与不断钻研的精神他逐步走上了专业的开发之路。 大学期间小璐主修计算机科学与技术系统学习了数据结构、操作系统、计算机网络、数据库原理、Java编程语言等核心课程。在课程之外他积极参与各类编程实践与项目开发多次参加编程竞赛与开发挑战积累了, medianull, metadata{charsetUTF-8, sourcefile.txt, distance0.16311505}, score0.8368849456310272}, Document{ide3578e33-00f7-4e0a-a046-00ae0bdc8482, text力。 除了日常开发工作小璐也不断关注新技术的发展积极学习微服务架构、分布式系统、容器化部署如Docker、Kubernetes等前沿知识。他相信技术永无止境持续学习和思考是保持竞争力的关键。 作为一名开发者小璐不仅追求技术上的成长也重视团队协作与沟通效率。他乐于帮助他人愿意分享自己的经验同时也虚心接受他人的建议。在工作中他秉持认真负责、追求完美, medianull, metadata{charsetUTF-8, sourcefile.txt, distance0.17335716}, score0.8266428411006927}]}] 2025-06-12T16:00:11.58708:00 DEBUG 1183 result : { metadata : { finishReason : STOP, contentFilters : [ ], empty : true }, output : { messageType : ASSISTANT, metadata : { role : ASSISTANT, messageType : ASSISTANT, refusal : , finishReason : STOP, index : 0, annotations : [ ], id : 0197632746fcc873321a1dc9b0fabbcb }, toolCalls : [ ], media : [ ], text : 小璐是一名专注于Java开发的计算机从业者。他在大学期间主修计算机科学与技术系统学习了数据结构、操作系统、计算机网络、数据库原理、Java编程语言等核心课程并积极参与编程实践与项目开发。在工作中他不仅专注于技术成长还重视团队协作与沟通效率。 } }, metadata : { id : 0197632746fcc873321a1dc9b0fabbcb, model : Qwen/Qwen2.5-72B-Instruct, rateLimit : { requestsLimit : null, requestsRemaining : null, requestsReset : null, tokensLimit : null, tokensRemaining : null, tokensReset : null }, usage : { promptTokens : 330, completionTokens : 65, totalTokens : 395, nativeUsage : { completion_tokens : 65, prompt_tokens : 330, total_tokens : 395 } }, promptMetadata : [ ], empty : false }, results : [ { metadata : { finishReason : STOP, contentFilters : [ ], empty : true }, output : { messageType : ASSISTANT, metadata : { role : ASSISTANT, messageType : ASSISTANT, refusal : , finishReason : STOP, index : 0, annotations : [ ], id : 0197632746fcc873321a1dc9b0fabbcb }, toolCalls : [ ], media : [ ], text : 小璐是一名专注于Java开发的计算机从业者。他在大学期间主修计算机科学与技术系统学习了数据结构、操作系统、计算机网络、数据库原理、Java编程语言等核心课程并积极参与编程实践与项目开发。在工作中他不仅专注于技术成长还重视团队协作与沟通效率。 } } ] } result: 小璐是一名专注于Java开发的计算机从业者。他在大学期间主修计算机科学与技术系统学习了数据结构、操作系统、计算机网络、数据库原理、Java编程语言等核心课程并积极参与编程实践与项目开发。在工作中他不仅专注于技术成长还重视团队协作与沟通效率。4.6 完整代码pom 依赖dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-advisors-vector-store/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-rag/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-vector-store-pgvector/artifactId /dependency /dependencies dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version1.0.0/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement配置文件spring: ai: openai: base-url: [这里填url] api-key: [这里填密钥] chat: options: model:Qwen/Qwen2.5-72B-Instruct embedding: options: model:text-embedding-ada-002 vectorstore: pgvector: initialize-schema:true index-type:HNSW distance-type:COSINE_DISTANCE dimensions:1536 max-document-batch-size:10000 datasource: url:jdbc:postgresql://localhost/postgres username: [这里填用户名] password: [这里填密码] logging: level: org: springframework: ai: chat: client: advisor: DEBUGJava 代码import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration publicclassAIConfig { Bean public ChatClient chatClient(ChatClient.Builder chatClientBuilder) { return chatClientBuilder .defaultAdvisors(new SimpleLoggerAdvisor()) .build(); } } import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.api.Advisor; import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.rag.advisor.RetrievalAugmentationAdvisor; import org.springframework.ai.rag.generation.augmentation.ContextualQueryAugmenter; import org.springframework.ai.rag.retrieval.search.VectorStoreDocumentRetriever; import org.springframework.ai.reader.TextReader; import org.springframework.ai.transformer.splitter.TokenTextSplitter; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; RestController publicclassQwenController { Autowired private ChatClient chatClient; Autowired private EmbeddingModel embeddingModel; Autowired private VectorStore vectorStore; Value(classpath:/file.txt) private Resource resource; GetMapping(/embedding) publicvoidembedding(String input) { System.out.println(input input); float[] embeddings1 embeddingModel.embed(input); System.out.println(length embeddings1.length , array Arrays.toString(embeddings1)); } GetMapping(/storeVector) publicvoidstoreVector(RequestParam ListString input) { ListDocument documents input.stream().map(Document::new).collect(Collectors.toList()); vectorStore.add(documents); } GetMapping(/similaritySearch) publicvoidsimilarSearch(String input) { SearchRequestquery SearchRequest.builder().query(input).topK(2).build(); ListDocument similarDocuments vectorStore.similaritySearch(query); Stringresult similarDocuments.stream() .map(Document::getText) .collect(Collectors.joining(System.lineSeparator())); System.out.println(result\n result); } GetMapping(/etl) publicvoidetl() { TextReadertextReadernewTextReader(this.resource); ListDocument extractedDoc textReader.read(); System.out.println(extract result: extractedDoc); TokenTextSplittersplitternewTokenTextSplitter(200, 200, 5, 10000, true); ListDocument transformedDoc splitter.apply(extractedDoc); System.out.println(transform length transformedDoc.size() , result: transformedDoc); vectorStore.add(transformedDoc); } GetMapping(/rag) publicvoidchatWithRag(String input) { System.out.println(input: input); AdvisorretrievalAugmentationAdvisor RetrievalAugmentationAdvisor.builder() .documentRetriever(VectorStoreDocumentRetriever.builder() .similarityThreshold(0.5) .vectorStore(vectorStore) .build()) .queryAugmenter(ContextualQueryAugmenter.builder() .allowEmptyContext(true) .build()) .build(); Stringresult chatClient.prompt() .advisors(retrievalAugmentationAdvisor) .user(input) .call() .content(); System.out.println(result: result); } }五、展望RAG 作为一种融合外部知识与 LLM 强大生成能力的技术路径正在成为企业内各种 AI 应用的解决方案它在增强 LLM 的专业性、个性化能力上展现出了巨大潜力我相信随着技术的不断演进以及框架能力的不断完善RAG 将在更多真实场景中发挥重要的作用。如何学习大模型 AI 由于新岗位的生产效率要优于被取代岗位的生产效率所以实际上整个社会的生产效率是提升的。但是具体到个人只能说是“最先掌握AI的人将会比较晚掌握AI的人有竞争优势”。这句话放在计算机、互联网、移动互联网的开局时期都是一样的道理。我在一线互联网企业工作十余年里指导过不少同行后辈。帮助很多人得到了学习和成长。我意识到有很多经验和知识值得分享给大家也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限很多互联网行业朋友无法获得正确的资料得到学习提升故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。第一阶段10天初阶应用该阶段让大家对大模型 AI有一个最前沿的认识对大模型 AI 的理解超过 95% 的人可以在相关讨论时发表高级、不跟风、又接地气的见解别人只会和 AI 聊天而你能调教 AI并能用代码将大模型和业务衔接。大模型 AI 能干什么大模型是怎样获得「智能」的用好 AI 的核心心法大模型应用业务架构大模型应用技术架构代码示例向 GPT-3.5 灌入新知识提示工程的意义和核心思想Prompt 典型构成指令调优方法论思维链和思维树Prompt 攻击和防范…第二阶段30天高阶应用该阶段我们正式进入大模型 AI 进阶实战学习学会构造私有知识库扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架抓住最新的技术进展适合 Python 和 JavaScript 程序员。为什么要做 RAG搭建一个简单的 ChatPDF检索的基础概念什么是向量表示Embeddings向量数据库与向量检索基于向量检索的 RAG搭建 RAG 系统的扩展知识混合检索与 RAG-Fusion 简介向量模型本地部署…第三阶段30天模型训练恭喜你如果学到这里你基本可以找到一份大模型 AI相关的工作自己也能训练 GPT 了通过微调训练自己的垂直大模型能独立训练开源多模态大模型掌握更多技术方案。到此为止大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗为什么要做 RAG什么是模型什么是模型训练求解器 损失函数简介小实验2手写一个简单的神经网络并训练它什么是训练/预训练/微调/轻量化微调Transformer结构简介轻量化微调实验数据集的构建…第四阶段20天商业闭环对全球大模型从性能、吞吐量、成本等方面有一定的认知可以在云端和本地等多种环境下部署大模型找到适合自己的项目/创业方向做一名被 AI 武装的产品经理。硬件选型带你了解全球大模型使用国产大模型服务搭建 OpenAI 代理热身基于阿里云 PAI 部署 Stable Diffusion在本地计算机运行大模型大模型的私有化部署基于 vLLM 部署大模型案例如何优雅地在阿里云私有部署开源大模型部署一套开源 LLM 项目内容安全互联网信息服务算法备案…学习是一个过程只要学习就会有挑战。天道酬勤你越努力就会成为越优秀的自己。如果你能在15天内完成所有的任务那你堪称天才。然而如果你能完成 60-70% 的内容你就已经开始具备成为一名大模型 AI 的正确特征了。这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】