大家好我是Java1234_小锋老师最近更新《2027版本 Spring AI 2.0 开发Java Agent智能体 视频教程》专辑感谢大家支持。本课程主要介绍和讲解Spring AI 2.0简介Spring AI 2.0 HelloWorld搭建Advisors — 拦截器模式增强AI能力对话与提示词工程Prompt工具调用 (Function Calling / Tools) RAG (检索增强生成)MCP(模型 上下文协议)和多模态支持。等这个Spring AI2.0基础课程录制完成接下来要发布2个 企业级Java AI实战课程RAG 企业知识库系统和AI智能客服系统。大家可以点点关注后面更精彩。视频教程课件源码打包下载链接https://pan.baidu.com/s/1o-zRfndo1HHrS_uFroOiCw?pwd1234提取码0000Spring AI 2.0 开发Java Agent智能体 - 嵌入模型(Embedding Model)与向量数据库(Vector Databases)一什么是嵌入模型1.1 什么是嵌入简单来说嵌入Embedding是一种将非数字数据如单词、句子、图像、甚至整个文档转换为计算机能够理解的数字向量的技术。向量是数学、物理学及工程科学中的基础概念指同时具有大小和方向的量与只有大小没有方向的标量如温度、质量相对。数据比如一句话“我喜欢吃苹果”。向量经过嵌入模型处理后这句话会变成一个由数百个浮点数组成的数组例如[0.125, -0.342, 0.987, ..., 0.045]。这个向量不是随机生成的它通过复杂的神经网络模型训练得出能够捕获原始数据的语义信息。1.2 嵌入模型的核心作用将“意义”映射到“向量空间”嵌入模型最关键的特性是它会把相似的语义内容映射到向量空间中的相近位置。例子句子A“我喜欢吃苹果”句子B“我爱吃香蕉”句子C“火箭发射升空”经过嵌入模型后在向量空间中句子A和句子B的距离会非常近因为都是表达对水果的喜爱。句子C与A、B的距离会非常远因为讨论的是完全不同的主题。1.3 为什么需要嵌入模型语义搜索传统的搜索引擎依赖关键词匹配比如搜索“苹果”只会返回包含“苹果”这两个字的结果。而基于嵌入的搜索是语义上的理解和匹配即使搜索“一种富含维生素的水果”也能找到关于“苹果”的文档。信息压缩与表示将一个复杂的对象图片、长文本压缩成一个固定长度的、富含语义信息的向量。作为大模型的“外部记忆”这是最广泛的应用之一。大模型的知识是静态的训练到某个时间点且上下文窗口有限。通过嵌入我们可以将海量的私有知识公司文档、产品手册向量化然后在需要时检索出最相关的部分再“喂”给大模型让它基于这些知识回答问题从而解决模型的知识局限和幻觉问题。1.4 常见嵌入模型OpenAI 的 text-embedding-3-small 和 text-embedding-3-large目前性能强大的通用文本嵌入模型。BAAI/bge-* 系列北京智源研究院开源的优秀中英文嵌入模型。sentence-transformers一个非常流行的Python库提供了大量预训练的句子、段落嵌入模型。多模态嵌入模型如CLIP可以将图片和文本嵌入到同一个向量空间实现文本搜图、图搜图等功能。阿里百炼平台的嵌入模型目前文本嵌入模型最新版本 text-embedding-v4支持64~2048维用户自定义向量维度。项目里application.yml里我们指定下嵌入模型和维度spring:application:name:helloWorldai:model:embedding:openaiopenai:api-key:${OPENAI_API_KEY}base-url:https://dashscope.aliyuncs.com/compatible-modechat:options:model:qwen3.6-plusembedding:options:model:text-embedding-v4dimensions:2048# 向量维度然后controller包下新建MyEmController以及注入openAiEmbeddingModel新建em测试方法。packagecom.java1234.controller;importorg.springframework.ai.openai.OpenAiEmbeddingModel;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.Arrays;RestControllerpublicclassMyEmController{AutowiredprivateOpenAiEmbeddingModelopenAiEmbeddingModel;RequestMapping(/em)publicStringem(){float[]textVector1openAiEmbeddingModel.embed(学java上java1234.com);System.out.println(textVector1.length:Arrays.toString(textVector1));returnOK;}}浏览器输入http://localhost:8080/em控制台返回我们在看一个示例求下欧氏距离距离越小说明越相似RequestMapping(/em)publicStringem(){float[]textVector1openAiEmbeddingModel.embed(学java上java1234.com);float[]textVector2openAiEmbeddingModel.embed(java1234.com网站教学Java质量真不错);float[]textVector3openAiEmbeddingModel.embed(我喜欢吃苹果);System.out.println(textVector1.length:Arrays.toString(textVector1));System.out.println(textVector2.length:Arrays.toString(textVector2));System.out.println(textVector3.length:Arrays.toString(textVector3));doubledist12euclideanDistance(textVector1,textVector2);doubledist13euclideanDistance(textVector1,textVector3);System.out.println(textVector1 与 textVector2 欧氏距离: dist12);System.out.println(textVector1 与 textVector3 欧氏距离: dist13);returnOK;}/** * 计算两个向量的欧氏距离 * * param a 向量1 * param b 向量2 * return 欧氏距离 */privatestaticdoubleeuclideanDistance(float[]a,float[]b){if(a.length!b.length){thrownewIllegalArgumentException(向量维度不一致);}doublesumSq0;for(inti0;ia.length;i){doubleda[i]-b[i];sumSqd*d;}returnMath.sqrt(sumSq);}运行结果二什么是向量数据库2.1 什么是向量数据库向量数据库是一种专门设计用来存储、索引和查询向量数据的数据库。传统的关系型数据库擅长存储和查询结构化数据如表格中的姓名、年龄但它们无法高效处理向量的“相似性检索”需求。2.2 向量数据库的核心功能相似性搜索向量数据库的核心能力是近似最近邻检索。任务给定一个查询向量在数据库中快速找到与之最相似的K个向量。算法它不进行暴力的一一比对而是使用专门的索引算法如 HNSW——分层可导航小世界图IVF——倒排文件索引来极大地提高搜索效率。即便数据库中有十亿个向量也能在毫秒级内返回结果。距离度量通常通过计算向量之间的“距离”来衡量相似度。余弦相似度衡量方向上的相似度最常用。欧氏距离衡量空间中的直线距离。点积衡量两个向量的投影。2.3 为什么需要向量数据库高效的检索性能专为大规模向量相似性搜索优化这是传统数据库无法做到的。元数据过滤在实际应用中向量通常还附带元数据。例如一个商品图片的向量可能还附有“商品ID”、“价格”、“类别”等信息。向量数据库允许你在进行相似性搜索时先或同时根据这些元数据进行过滤例如“找到与这件红色T恤最相似的衣服且价格低于100元”。数据管理提供增删改查、数据持久化、备份、容灾等标准的数据库功能。与嵌入模型和大模型的完美集成它们共同构成了现代AI应用如RAG——检索增强生成的数据流水线。2.4 常用的向量数据库有哪些以下是5个最常用的向量数据库对比表格数据库类型特点优点适用场景Pinecone商业SaaS全托管云服务上手最快零运维提供免费额度快速原型开发不想自己搭建维护的项目Milvus开源/商业功能最全面的专业向量数据库支持十亿级向量索引类型丰富性能强大大规模生产环境对性能要求高的场景Qdrant开源/商业Rust编写性能优异内存占用低API友好支持过滤需要高性能、资源受限的环境Chroma开源Python原生轻量级极简API与LangChain集成好本地开发友好本地开发、学习、小型项目pgvectorPostgreSQL扩展基于PostgreSQL支持ACID事务SQL语法无需引入新数据库已有PostgreSQL向量数据量百万级以内三两者的协同工作 —— RAG流程示例这是目前最经典的AI应用架构可以清晰地看到嵌入模型和向量数据库是如何配合的。场景构建一个基于公司内部知识库的智能问答机器人。第一步数据预处理与索引入库阶段准备文档收集所有公司文档PDF、Word、内部Wiki等。文本分块将长文档切分成更小的段落或“块”。生成嵌入使用嵌入模型为每一个文本块生成一个向量。存储将生成的向量连同原始的文本块和相关的元数据如文档来源、页码一起存入向量数据库。第二步用户提问与检索查询阶段用户提问用户问“我们公司的年假政策是什么”问题嵌入使用相同的嵌入模型将用户的这个问题也转换成一个向量。向量检索将这个代表问题的向量发送到向量数据库进行查询。数据库会迅速返回与问题向量最相似的K个文本块向量。获取上下文根据返回的向量ID取出对应的原始文本块内容。第三步生成答案生成阶段构建提示词将用户的问题 检索到的相关文本块作为上下文组合成一个提示词。调用大语言模型将提示词发送给大语言模型如GPT-4并指示它“请根据提供的上下文回答问题”。返回答案大模型阅读并理解上下文后生成一个准确、有据可依的答案返回给用户。Spring AI2.0支持的向量数据库还是比较多的。我们课程选用Redis。这里的Redis不是普通的Redis Server而是支持向量存储的redis-stack。我们windows跑的话一般都是跑docker里的windows平台建议大家去安装一个Docker Desktop比较方便。https://www.docker.com/products/docker-desktop/接下来 直接 运行 安装运行镜像命令docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 -v d:/redis-data:/data redis/redis-stack:latest6379端口映射的是redis-stack服务8001端口映射的是可视化服务。接下来项目里把向量存入Redis-stack向量数据库。首先第一步pom.xml加下redis的向量支持依赖以及jedis客户端。dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-vector-store-redis/artifactId/dependency!-- Spring AI RedisVectorStoreAutoConfiguration 仅在存在 JedisConnectionFactory 时生效不用 Lettuce。 因此改用 Jedis并从 starter 中排除 Lettuce。 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactIdexclusionsexclusiongroupIdio.lettuce/groupIdartifactIdlettuce-core/artifactId/exclusion/exclusions/dependencydependencygroupIdredis.clients/groupIdartifactIdjedis/artifactId/dependency接下来第二步application.yml里配置下redis连接以及redis向量配置spring:application:name:helloWorlddata:redis:client-type:jedisurl:redis://localhost:6379ai:model:embedding:openaivectorstore:redis:initialize-schema:true# 是否在启动时创建/初始化向量索引等结构index-name:java1234_ai_vector_index# RediSearch 里的 索引名prefix:java1234_# 存向量文档用的 Redis 键前缀openai:api-key:${OPENAI_API_KEY}base-url:https://dashscope.aliyuncs.com/compatible-modechat:options:model:qwen3.6-plusembedding:options:model:text-embedding-v4dimensions:2048# 向量维度最后第三步MyEmController里我们注入VectorStore以及写一个addDoc和querypackagecom.java1234.controller;importorg.springframework.ai.document.Document;importorg.springframework.ai.openai.OpenAiEmbeddingModel;importorg.springframework.ai.vectorstore.SearchRequest;importorg.springframework.ai.vectorstore.VectorStore;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.Arrays;importjava.util.List;RestControllerpublicclassMyEmController{AutowiredprivateOpenAiEmbeddingModelopenAiEmbeddingModel;AutowiredprivateVectorStorevectorStore;RequestMapping(/addDoc)publicStringaddDoc(){ListDocumentdocsList.of(newDocument(学java上java1234.com),newDocument(java1234.com是个学Java的好地方),newDocument(我喜欢打篮球));vectorStore.add(docs);returnOK;}RequestMapping(/query)publicStringquery(){ListDocumentdocsvectorStore.similaritySearch(SearchRequest.builder().query(去哪里学Java ?).topK(2).build());System.out.println(docs);returnOK;}RequestMapping(/em)publicStringem(){float[]textVector1openAiEmbeddingModel.embed(学java上java1234.com);float[]textVector2openAiEmbeddingModel.embed(java1234.com网站教学Java质量真不错);float[]textVector3openAiEmbeddingModel.embed(我喜欢吃苹果);System.out.println(textVector1.length:Arrays.toString(textVector1));System.out.println(textVector2.length:Arrays.toString(textVector2));System.out.println(textVector3.length:Arrays.toString(textVector3));doubledist12euclideanDistance(textVector1,textVector2);doubledist13euclideanDistance(textVector1,textVector3);System.out.println(textVector1 与 textVector2 欧氏距离: dist12);System.out.println(textVector1 与 textVector3 欧氏距离: dist13);returnOK;}/** * 计算两个向量的欧氏距离 * * param a 向量1 * param b 向量2 * return 欧氏距离 */privatestaticdoubleeuclideanDistance(float[]a,float[]b){if(a.length!b.length){thrownewIllegalArgumentException(向量维度不一致);}doublesumSq0;for(inti0;ia.length;i){doubleda[i]-b[i];sumSqd*d;}returnMath.sqrt(sumSq);}}我们来测试下浏览器输入http://localhost:8080/addDoc我们可以用 redis-stack可视化服务来查看redis向量数据。浏览器输入http://localhost:8001/我们在通过VectorStore的 similaritySearch 方法进行相似性搜索。浏览器输入http://localhost:8080/query返回结果[Document{id1dc1fc3c-0bd6-46ad-b857-fecb74636ea5, text学java上java1234.com, medianull, metadata{distance0.15828251838684082, vector_score0.316565096378}, score0.8417174816131592}, Document{id33ff1eb9-3ca4-4381-80e4-b1ed4670ff56, textjava1234.com是个学Java的好地方, medianull, metadata{distance0.15871202945709229, vector_score0.317424118519}, score0.8412879705429077}]找到两个最相似的结果。
Spring AI 2.0 开发Java Agent智能体 - 嵌入模型(Embedding Model)与向量数据库(Vector Databases)
大家好我是Java1234_小锋老师最近更新《2027版本 Spring AI 2.0 开发Java Agent智能体 视频教程》专辑感谢大家支持。本课程主要介绍和讲解Spring AI 2.0简介Spring AI 2.0 HelloWorld搭建Advisors — 拦截器模式增强AI能力对话与提示词工程Prompt工具调用 (Function Calling / Tools) RAG (检索增强生成)MCP(模型 上下文协议)和多模态支持。等这个Spring AI2.0基础课程录制完成接下来要发布2个 企业级Java AI实战课程RAG 企业知识库系统和AI智能客服系统。大家可以点点关注后面更精彩。视频教程课件源码打包下载链接https://pan.baidu.com/s/1o-zRfndo1HHrS_uFroOiCw?pwd1234提取码0000Spring AI 2.0 开发Java Agent智能体 - 嵌入模型(Embedding Model)与向量数据库(Vector Databases)一什么是嵌入模型1.1 什么是嵌入简单来说嵌入Embedding是一种将非数字数据如单词、句子、图像、甚至整个文档转换为计算机能够理解的数字向量的技术。向量是数学、物理学及工程科学中的基础概念指同时具有大小和方向的量与只有大小没有方向的标量如温度、质量相对。数据比如一句话“我喜欢吃苹果”。向量经过嵌入模型处理后这句话会变成一个由数百个浮点数组成的数组例如[0.125, -0.342, 0.987, ..., 0.045]。这个向量不是随机生成的它通过复杂的神经网络模型训练得出能够捕获原始数据的语义信息。1.2 嵌入模型的核心作用将“意义”映射到“向量空间”嵌入模型最关键的特性是它会把相似的语义内容映射到向量空间中的相近位置。例子句子A“我喜欢吃苹果”句子B“我爱吃香蕉”句子C“火箭发射升空”经过嵌入模型后在向量空间中句子A和句子B的距离会非常近因为都是表达对水果的喜爱。句子C与A、B的距离会非常远因为讨论的是完全不同的主题。1.3 为什么需要嵌入模型语义搜索传统的搜索引擎依赖关键词匹配比如搜索“苹果”只会返回包含“苹果”这两个字的结果。而基于嵌入的搜索是语义上的理解和匹配即使搜索“一种富含维生素的水果”也能找到关于“苹果”的文档。信息压缩与表示将一个复杂的对象图片、长文本压缩成一个固定长度的、富含语义信息的向量。作为大模型的“外部记忆”这是最广泛的应用之一。大模型的知识是静态的训练到某个时间点且上下文窗口有限。通过嵌入我们可以将海量的私有知识公司文档、产品手册向量化然后在需要时检索出最相关的部分再“喂”给大模型让它基于这些知识回答问题从而解决模型的知识局限和幻觉问题。1.4 常见嵌入模型OpenAI 的 text-embedding-3-small 和 text-embedding-3-large目前性能强大的通用文本嵌入模型。BAAI/bge-* 系列北京智源研究院开源的优秀中英文嵌入模型。sentence-transformers一个非常流行的Python库提供了大量预训练的句子、段落嵌入模型。多模态嵌入模型如CLIP可以将图片和文本嵌入到同一个向量空间实现文本搜图、图搜图等功能。阿里百炼平台的嵌入模型目前文本嵌入模型最新版本 text-embedding-v4支持64~2048维用户自定义向量维度。项目里application.yml里我们指定下嵌入模型和维度spring:application:name:helloWorldai:model:embedding:openaiopenai:api-key:${OPENAI_API_KEY}base-url:https://dashscope.aliyuncs.com/compatible-modechat:options:model:qwen3.6-plusembedding:options:model:text-embedding-v4dimensions:2048# 向量维度然后controller包下新建MyEmController以及注入openAiEmbeddingModel新建em测试方法。packagecom.java1234.controller;importorg.springframework.ai.openai.OpenAiEmbeddingModel;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.Arrays;RestControllerpublicclassMyEmController{AutowiredprivateOpenAiEmbeddingModelopenAiEmbeddingModel;RequestMapping(/em)publicStringem(){float[]textVector1openAiEmbeddingModel.embed(学java上java1234.com);System.out.println(textVector1.length:Arrays.toString(textVector1));returnOK;}}浏览器输入http://localhost:8080/em控制台返回我们在看一个示例求下欧氏距离距离越小说明越相似RequestMapping(/em)publicStringem(){float[]textVector1openAiEmbeddingModel.embed(学java上java1234.com);float[]textVector2openAiEmbeddingModel.embed(java1234.com网站教学Java质量真不错);float[]textVector3openAiEmbeddingModel.embed(我喜欢吃苹果);System.out.println(textVector1.length:Arrays.toString(textVector1));System.out.println(textVector2.length:Arrays.toString(textVector2));System.out.println(textVector3.length:Arrays.toString(textVector3));doubledist12euclideanDistance(textVector1,textVector2);doubledist13euclideanDistance(textVector1,textVector3);System.out.println(textVector1 与 textVector2 欧氏距离: dist12);System.out.println(textVector1 与 textVector3 欧氏距离: dist13);returnOK;}/** * 计算两个向量的欧氏距离 * * param a 向量1 * param b 向量2 * return 欧氏距离 */privatestaticdoubleeuclideanDistance(float[]a,float[]b){if(a.length!b.length){thrownewIllegalArgumentException(向量维度不一致);}doublesumSq0;for(inti0;ia.length;i){doubleda[i]-b[i];sumSqd*d;}returnMath.sqrt(sumSq);}运行结果二什么是向量数据库2.1 什么是向量数据库向量数据库是一种专门设计用来存储、索引和查询向量数据的数据库。传统的关系型数据库擅长存储和查询结构化数据如表格中的姓名、年龄但它们无法高效处理向量的“相似性检索”需求。2.2 向量数据库的核心功能相似性搜索向量数据库的核心能力是近似最近邻检索。任务给定一个查询向量在数据库中快速找到与之最相似的K个向量。算法它不进行暴力的一一比对而是使用专门的索引算法如 HNSW——分层可导航小世界图IVF——倒排文件索引来极大地提高搜索效率。即便数据库中有十亿个向量也能在毫秒级内返回结果。距离度量通常通过计算向量之间的“距离”来衡量相似度。余弦相似度衡量方向上的相似度最常用。欧氏距离衡量空间中的直线距离。点积衡量两个向量的投影。2.3 为什么需要向量数据库高效的检索性能专为大规模向量相似性搜索优化这是传统数据库无法做到的。元数据过滤在实际应用中向量通常还附带元数据。例如一个商品图片的向量可能还附有“商品ID”、“价格”、“类别”等信息。向量数据库允许你在进行相似性搜索时先或同时根据这些元数据进行过滤例如“找到与这件红色T恤最相似的衣服且价格低于100元”。数据管理提供增删改查、数据持久化、备份、容灾等标准的数据库功能。与嵌入模型和大模型的完美集成它们共同构成了现代AI应用如RAG——检索增强生成的数据流水线。2.4 常用的向量数据库有哪些以下是5个最常用的向量数据库对比表格数据库类型特点优点适用场景Pinecone商业SaaS全托管云服务上手最快零运维提供免费额度快速原型开发不想自己搭建维护的项目Milvus开源/商业功能最全面的专业向量数据库支持十亿级向量索引类型丰富性能强大大规模生产环境对性能要求高的场景Qdrant开源/商业Rust编写性能优异内存占用低API友好支持过滤需要高性能、资源受限的环境Chroma开源Python原生轻量级极简API与LangChain集成好本地开发友好本地开发、学习、小型项目pgvectorPostgreSQL扩展基于PostgreSQL支持ACID事务SQL语法无需引入新数据库已有PostgreSQL向量数据量百万级以内三两者的协同工作 —— RAG流程示例这是目前最经典的AI应用架构可以清晰地看到嵌入模型和向量数据库是如何配合的。场景构建一个基于公司内部知识库的智能问答机器人。第一步数据预处理与索引入库阶段准备文档收集所有公司文档PDF、Word、内部Wiki等。文本分块将长文档切分成更小的段落或“块”。生成嵌入使用嵌入模型为每一个文本块生成一个向量。存储将生成的向量连同原始的文本块和相关的元数据如文档来源、页码一起存入向量数据库。第二步用户提问与检索查询阶段用户提问用户问“我们公司的年假政策是什么”问题嵌入使用相同的嵌入模型将用户的这个问题也转换成一个向量。向量检索将这个代表问题的向量发送到向量数据库进行查询。数据库会迅速返回与问题向量最相似的K个文本块向量。获取上下文根据返回的向量ID取出对应的原始文本块内容。第三步生成答案生成阶段构建提示词将用户的问题 检索到的相关文本块作为上下文组合成一个提示词。调用大语言模型将提示词发送给大语言模型如GPT-4并指示它“请根据提供的上下文回答问题”。返回答案大模型阅读并理解上下文后生成一个准确、有据可依的答案返回给用户。Spring AI2.0支持的向量数据库还是比较多的。我们课程选用Redis。这里的Redis不是普通的Redis Server而是支持向量存储的redis-stack。我们windows跑的话一般都是跑docker里的windows平台建议大家去安装一个Docker Desktop比较方便。https://www.docker.com/products/docker-desktop/接下来 直接 运行 安装运行镜像命令docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 -v d:/redis-data:/data redis/redis-stack:latest6379端口映射的是redis-stack服务8001端口映射的是可视化服务。接下来项目里把向量存入Redis-stack向量数据库。首先第一步pom.xml加下redis的向量支持依赖以及jedis客户端。dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-vector-store-redis/artifactId/dependency!-- Spring AI RedisVectorStoreAutoConfiguration 仅在存在 JedisConnectionFactory 时生效不用 Lettuce。 因此改用 Jedis并从 starter 中排除 Lettuce。 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactIdexclusionsexclusiongroupIdio.lettuce/groupIdartifactIdlettuce-core/artifactId/exclusion/exclusions/dependencydependencygroupIdredis.clients/groupIdartifactIdjedis/artifactId/dependency接下来第二步application.yml里配置下redis连接以及redis向量配置spring:application:name:helloWorlddata:redis:client-type:jedisurl:redis://localhost:6379ai:model:embedding:openaivectorstore:redis:initialize-schema:true# 是否在启动时创建/初始化向量索引等结构index-name:java1234_ai_vector_index# RediSearch 里的 索引名prefix:java1234_# 存向量文档用的 Redis 键前缀openai:api-key:${OPENAI_API_KEY}base-url:https://dashscope.aliyuncs.com/compatible-modechat:options:model:qwen3.6-plusembedding:options:model:text-embedding-v4dimensions:2048# 向量维度最后第三步MyEmController里我们注入VectorStore以及写一个addDoc和querypackagecom.java1234.controller;importorg.springframework.ai.document.Document;importorg.springframework.ai.openai.OpenAiEmbeddingModel;importorg.springframework.ai.vectorstore.SearchRequest;importorg.springframework.ai.vectorstore.VectorStore;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.Arrays;importjava.util.List;RestControllerpublicclassMyEmController{AutowiredprivateOpenAiEmbeddingModelopenAiEmbeddingModel;AutowiredprivateVectorStorevectorStore;RequestMapping(/addDoc)publicStringaddDoc(){ListDocumentdocsList.of(newDocument(学java上java1234.com),newDocument(java1234.com是个学Java的好地方),newDocument(我喜欢打篮球));vectorStore.add(docs);returnOK;}RequestMapping(/query)publicStringquery(){ListDocumentdocsvectorStore.similaritySearch(SearchRequest.builder().query(去哪里学Java ?).topK(2).build());System.out.println(docs);returnOK;}RequestMapping(/em)publicStringem(){float[]textVector1openAiEmbeddingModel.embed(学java上java1234.com);float[]textVector2openAiEmbeddingModel.embed(java1234.com网站教学Java质量真不错);float[]textVector3openAiEmbeddingModel.embed(我喜欢吃苹果);System.out.println(textVector1.length:Arrays.toString(textVector1));System.out.println(textVector2.length:Arrays.toString(textVector2));System.out.println(textVector3.length:Arrays.toString(textVector3));doubledist12euclideanDistance(textVector1,textVector2);doubledist13euclideanDistance(textVector1,textVector3);System.out.println(textVector1 与 textVector2 欧氏距离: dist12);System.out.println(textVector1 与 textVector3 欧氏距离: dist13);returnOK;}/** * 计算两个向量的欧氏距离 * * param a 向量1 * param b 向量2 * return 欧氏距离 */privatestaticdoubleeuclideanDistance(float[]a,float[]b){if(a.length!b.length){thrownewIllegalArgumentException(向量维度不一致);}doublesumSq0;for(inti0;ia.length;i){doubleda[i]-b[i];sumSqd*d;}returnMath.sqrt(sumSq);}}我们来测试下浏览器输入http://localhost:8080/addDoc我们可以用 redis-stack可视化服务来查看redis向量数据。浏览器输入http://localhost:8001/我们在通过VectorStore的 similaritySearch 方法进行相似性搜索。浏览器输入http://localhost:8080/query返回结果[Document{id1dc1fc3c-0bd6-46ad-b857-fecb74636ea5, text学java上java1234.com, medianull, metadata{distance0.15828251838684082, vector_score0.316565096378}, score0.8417174816131592}, Document{id33ff1eb9-3ca4-4381-80e4-b1ed4670ff56, textjava1234.com是个学Java的好地方, medianull, metadata{distance0.15871202945709229, vector_score0.317424118519}, score0.8412879705429077}]找到两个最相似的结果。