Spring AI系列之RAG(检索增强生成)从原理到实战指南

Spring AI系列之RAG(检索增强生成)从原理到实战指南

Spring AI系列之RAG(检索增强生成)从原理到实战指南

在LLM(大语言模型)时代,如何让AI既拥有通用能力又具备专业知识?RAG技术给出了完美答案。本文将基于Spring AI生态,深入剖析RAG的核心原理、实现细节与优化策略。

一、为什么需要RAG?

在深入了解RAG之前,我们需要先认识传统LLM的局限性:

缺陷类型具体表现RAG解决方案
知识截止模型知识有截止日期,无法获取最新信息实时检索外部知识库
幻觉问题自信地生成看似合理但实际错误的内容基于检索到的真实信息生成
上下文限制长文本处理能力有限只检索最相关的上下文片段
领域专业度通用模型缺乏垂直领域深度知识外挂专业领域知识库

比喻理解:如果将LLM比作一个"高中毕业生",那么:

  • Fine-tuning(微调) = 让他花7年时间去医学院学习,然后成为医生
  • RAG = 给他配备了一群专业主任医师作为顾问,遇到问题时先咨询专家再作答

二、RAG核心架构解析

2.1 整体工作流程

RAG的工作流程可以分为两大阶段:离线索引(Indexing)在线检索生成(Retrieval & Generation)

RAG论⽂:https://arxiv.org/pdf/2312.10997

在这里插入图片描述


中文版本:

在这里插入图片描述

详细流程说明

  1. 索引阶段(离线)
    • 文档加载:从PDF、Word、Excel等格式中提取文本
    • 文本分割(Chunking):将长文档切分为适当大小的片段
    • 向量化(Embedding):使用Embedding模型将文本转为向量
    • 存储:存入Milvus、Redis等向量数据库
  2. 检索阶段(在线)
    • 查询向量化:将用户问题转换为向量
    • 相似度匹配:在向量空间中查找最相似的Top-K个片段
    • 重排序(Reranking):(可选)对检索结果进行精排
  3. 生成阶段
    • 上下文组装:将检索到的片段作为"已知信息"注入Prompt
    • LLM推理:模型基于提供的上下文生成答案

2.2 关键技术:Embedding与相似度计算

什么是Embedding?
Embedding是将文本、图像等转换为高维向量的技术。语义相似的文本在向量空间中的距离更近。

例如,⼆维空间中的向量可以表示为 (𝑥,𝑦),即表示从原点 (0,0) 到点 (𝑥,𝑦) 的有向线段

在这里插入图片描述
  1. 将⽂本转成⼀组浮点数:每个下标 i ,对应⼀个维度
  2. 整个数组对应⼀个 n 维空间的⼀个点,即⽂本向量叫 Embeddings
  3. 向量之间可以计算距离,距离远近对应语义相似度⼤⼩
"这个多少钱" → [0.1, 0.5, -0.7, ..., 0.25] "这个什么价格" → [0.12, 0.4, -0.3, ..., 0.3] ← 距离近(语义相似) "给我报个价" → [0.15, 0.3, -0.2, ..., 0.3] ← 距离近(语义相似) "我想要这个" → [0.8, -0.1, 0.4, ..., -0.1] ← 距离远(语义不同) 
在这里插入图片描述

相似度计算方法

  1. 余弦相似度(Cosine Similarity)
    • 衡量两个向量方向的相似性,值域[-1, 1]
    • 适合文本语义匹配,不受向量长度影响
    • 公式: s i m i l a r i t y ( A , B ) = A ⋅ B ∥ A ∥ ∥ B ∥ similarity(A,B) = \frac{A \cdot B}{\|A\| \|B\|} similarity(A,B)=∥A∥∥B∥A⋅B​
  2. 欧氏距离(Euclidean Distance)
    • 衡量向量空间的实际距离
    • 公式: d ( A , B ) = ∑ i = 1 n ( a i − b i ) 2 d(A,B) = \sqrt{\sum_{i=1}^{n}(a_i - b_i)^2} d(A,B)=∑i=1n​(ai​−bi​)2​
    • 值越小越相似

具体选哪种方法?

  • 欧式距离:如果更侧重于向量的实际距离,且向量的尺度相对一致时,更适合用欧式距离

余弦相似度:更适用于比较文本、关键词向量等场景。因为这些场景向量的方向比他们的模长更重要

在这里插入图片描述

三、实战:基于Spring AI + Milvus实现RAG

3.1 环境准备

依赖配置(Maven)

<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-openai</artifactId></dependency><dependency><groupId>io.milvus</groupId><artifactId>milvus-sdk-java</artifactId><version>2.2.10</version></dependency>

配置信息

# OpenAI配置(用于Embedding和Chat) spring.ai.openai.api-key=your-api-key spring.ai.openai.embedding.api-key=your-api-key spring.ai.openai.embedding.base-url=https://api.openai-hk.com # Milvus配置 milvus.host=localhost milvus.port=19530 

3.2 核心代码实现

步骤1:创建向量集合
publicvoidcreateCollection(){List<FieldType> fieldTypes =Arrays.asList(// 主键IDFieldType.newBuilder().withName("id").withDataType(DataType.Int64).withPrimaryKey(true).withAutoID(true).build(),// 向量字段(1536维,对应text-embedding-3-small)FieldType.newBuilder().withName("feature").withDataType(DataType.FloatVector).withDimension(1536).build(),// 原始文本FieldType.newBuilder().withName("instruction").withDataType(DataType.VarChar).withMaxLength(65535).build(),// 答案内容FieldType.newBuilder().withName("output").withDataType(DataType.VarChar).withMaxLength(65535).build());CreateCollectionParam createParam =CreateCollectionParam.newBuilder().withCollectionName("springai_rag").withFieldTypes(fieldTypes).build(); client.createCollection(createParam);// 创建IVF_FLAT索引,加速检索CreateIndexParam indexParam =CreateIndexParam.newBuilder().withCollectionName("springai_rag").withFieldName("feature").withIndexType(IndexType.IVF_FLAT).withMetricType(MetricType.L2).build(); client.createIndex(indexParam);}
步骤2:数据向量化与存储
@AutowiredprivateEmbeddingModel embeddingModel;publicvoidinsertData(List<FaqItem> items){for(FaqItem item : items){// 1. 文本向量化float[] embeddings = embeddingModel.embed(item.getInstruction());// 2. 构建插入参数List<InsertParam.Field> fields =newArrayList<>(); fields.add(newInsertParam.Field("feature",Collections.singletonList(embeddings))); fields.add(newInsertParam.Field("instruction",Collections.singletonList(item.getInstruction()))); fields.add(newInsertParam.Field("output",Collections.singletonList(item.getOutput())));// 3. 插入MilvusInsertParam insertParam =InsertParam.newBuilder().withCollectionName("springai_rag").withFields(fields).build(); client.insert(insertParam);}}
步骤3:RAG检索与生成
@TestvoidragTest(){String userQuestion ="预算8000元以内,适合深度学习的笔记本电脑推荐";// 1. 向量化查询float[] queryEmbedding = embeddingModel.embed(userQuestion);// 2. 向量检索Top-3SearchParam searchParam =SearchParam.newBuilder().withCollectionName("springai_rag").withMetricType(MetricType.L2).withTopK(3).withVectors(Collections.singletonList(queryEmbedding)).withVectorFieldName("feature").withOutFields(Arrays.asList("instruction","output")).build();SearchResults results = client.search(searchParam).getData();List<RowRecord> records =newSearchResultsWrapper(results).getRowRecords();// 3. 构建上下文StringBuilder context =newStringBuilder();for(RowRecordrecord: records){ context.append("Q: ").append(record.get("instruction")).append("\n"); context.append("A: ").append(record.get("output")).append("\n\n");}// 4. 构建增强PromptString enhancedPrompt =String.format(""" # 角色设定 你是资深数码产品顾问,擅长根据用户需求推荐笔记本电脑。 请严格基于以下商品库信息回答,不要推荐库中不存在的商品。 # 商品库信息(Top-3匹配结果): %s # 用户需求: %s # 回答要求: 1. 先分析用户需求(用途、预算、性能要求) 2. 从商品库中推荐1-2款最合适的,说明理由 3. 如果商品库中没有匹配项,请明确告知"暂无符合要求的商品" 4. 最后可简要补充选购建议(非强制) """, context, userQuestion);// 5. 调用LLM生成String answer = chatClient.prompt(enhancedPrompt).call().content();System.out.println(answer);}

四、RAG优化策略与痛点解决

4.1 文本分割的艺术(Chunking Strategy)

文本分割是影响RAG效果的关键因素,常用策略对比:

分割策略实现方式优点缺点适用场景
固定字符数每N个字符切分简单高效可能切断语义对上下文连续性要求不高的场景
滑动窗口固定大小+重叠部分保留上下文衔接数据冗余,存储增加需要连贯性的长文档
递归字符按标点优先级切分(先句号→逗号→空格)保持语义完整实现复杂专业文档、论文
基于语义使用NLP模型判断语义边界最优语义保留计算成本高高精度要求的知识库

最佳实践

  • 结合文档结构(Markdown标题、PDF段落)进行分层切分
  • chunk大小建议:256-512 tokens(根据embedding模型调整)
  • 设置适当的重叠(overlap)保持上下文连贯

4.2 检索优化的进阶技巧

1. 混合检索(Hybrid Search)
结合关键词检索(BM25)和向量检索,兼顾精确匹配和语义理解:

// 伪代码示例List<Document> keywordResults =keywordSearch(query);List<Document> vectorResults =vectorSearch(query);List<Document> hybridResults =rerank(merge(keywordResults, vectorResults));

2. 重排序(Reranking)
使用专门的交叉编码器(Cross-Encoder)模型对Top-K结果进行精排:

  • 先使用向量检索召回Top-20
  • 使用重排模型计算问题与文档的相关性分数
  • 取Top-3作为最终上下文

3. 查询重写(Query Rewriting)
对用户的模糊查询进行扩展和澄清:

  • 原查询:“这个多少钱?”
  • 重写后:“iPhone 15 Pro Max 256GB 官方售价是多少?”

4.3 RAG痛点与解决方案

基于《Seven Failure Points When Engineering a Retrieval Augmented Generation System》的总结:

痛点类别具体表现解决方案
Missing Content知识库中没有答案设置兜底回复;持续扩充知识库
Missed Top Ranked正确答案未进入Top-K调整similarity阈值;引入重排序
Not in Context检索到内容但与问题无关优化文本分割;提升向量模型质量
Wrong Format需要JSON但返回了文本Prompt中明确输出格式示例;使用结构化输出
Incomplete答案只覆盖问题部分引导模型逐步思考(CoT);拆分复杂问题
Not Extracted上下文中有答案但模型未提取优化Prompt模板;增强上下文标识

五、RAG效果评估(RAGAS)

RAGAS(Retrieval-Augmented Generation Assessment)是评估RAG系统的标准框架,核心指标:

5.1 检索质量指标

  1. Context Relevancy(上下文相关性)
    • 衡量检索到的上下文与问题的相关程度
    • 计算公式:相关句子数 / 总句子数
  2. Context Recall(上下文召回率)
    • 衡量检索结果是否包含回答问题所需的所有信息
    • 基于标准答案(Ground Truth)进行判断

5.2 生成质量指标

  1. Faithfulness(忠实性)
    • 评估生成答案是否基于检索到的上下文,而非幻觉
    • 值越高,模型"编造"内容越少
  2. Answer Relevancy(答案相关性)
    • 衡量答案与问题的直接相关程度

评估数据集格式

{"question":"预算8000元以内,适合深度学习的笔记本电脑推荐","contexts":["机械革命翼龙15 Pro配备RTX4060显卡,支持CUDA加速,售价7499元","联想拯救者Y7000P 2024款搭载i7-14650HX和RTX4060,售价8499元超出预算","轻薄本不适合深度学习,缺乏独立显卡"],"answer":"推荐机械革命翼龙15 Pro,配备RTX4060显卡支持CUDA加速,价格7499元符合预算","ground_truths":["机械革命翼龙15 Pro,RTX4060,7499元"]}

六、总结与展望

RAG vs Fine-tuning 选择指南

选择RAG的场景

  • 需要实时更新的知识(如新闻、股价)
  • 数据量庞大且频繁变动
  • 需要解释性强的应用场景(可溯源到具体文档)
  • 预算有限,无法承担微调成本

选择Fine-tuning的场景

  • 需要改变模型行为风格(如特定语气、格式)
  • 领域知识非常固定且通用模型表现极差
  • 对延迟敏感(RAG需要额外检索时间)

未来趋势

  1. Agentic RAG:结合ReAct模式,让模型自主决定何时检索、检索什么
  2. 多模态RAG:支持图片、音频、视频的检索增强
  3. Graph RAG:结合知识图谱,处理复杂的多跳推理问题

参考资料

  • Spring AI官方文档
  • 《Seven Failure Points When Engineering a Retrieval Augmented Generation System》
  • Milvus向量数据库最佳实践

通过本文,你应该已经掌握了RAG技术的完整链路:从文档切分、向量化存储,到相似度检索和Prompt增强。在实际项目中,建议先从简单的关键字检索+向量混合方案开始,逐步引入重排序、查询重写等优化策略。

Read more

程序员的自我修养:用 AR 眼镜管理健康

程序员的自我修养:用 AR 眼镜管理健康

欢迎文末添加好友交流,共同进步! “ 俺はモンキー・D・ルフィ。海贼王になる男だ!” * 一、从一次体检说起 * 二、为什么是 AR 眼镜? * 三、技术选型:CXR-M SDK vs 灵珠平台 * 四、项目架构设计 * 五、从配置开始:Gradle 和权限 * 5.1 添加 SDK 依赖 * 5.2 权限配置 * 六、数据层实现 * 6.1 数据模型 * 6.2 数据仓库 * 七、SDK 封装层 * 7.1 发送提醒到眼镜 * 7.2 TTS 语音播报

Cesium(二) 实现无人机巡检、无人机扫描地面动画效果、无人机喷洒农药、低空经济效果

Cesium(二) 实现无人机巡检、无人机扫描地面动画效果、无人机喷洒农药、低空经济效果

随着低空经济的快速崛起和智慧农业的普及,无人机在农田巡检、农药喷洒、地面扫描等场景中的应用越来越广泛。Cesium 作为一款强大的 3D 地理空间可视化引擎,能够完美还原无人机作业的真实场景,为智慧农业、低空经济相关系统提供直观的可视化支撑。 本文将基于 Vue3 + Cesium,通过核心代码片段快速实现无人机沿指定区域飞行、喷洒农药可视化、已喷洒区域标记等核心效果,打造完整的智慧农业无人机作业 3D 场景。 一、场景需求与核心技术栈 1. 核心需求 1. 加载天地图卫星底图,构建真实地理空间环境 2. 加载无人机 3D 模型,实现沿农田区域匀速飞行 3. 可视化无人机喷洒锥,同步跟随无人机移动 4. 实时标记已喷洒区域,提供开始 / 暂停交互控制 5. 优化性能,避免内存泄漏 2. 核心技术栈 * 前端框架:Vue3(<script setup>

无人机 5.8G 模拟图传电路设计方案及性能分析

一、什么是 5.8G 模拟图传? 简单说,5.8G 模拟图传就是无人机的 “千里眼”,能把天上拍的画面实时传到地面。你在遥控器上看到的无人机视角,全靠它来实现。 为啥是 5.8G?因为这个频段干扰少,就像高速路上车少,信号跑起来更顺畅。而且模拟信号传输快,延迟低,特别适合 FPV 竞速这种需要快速反应的场景 —— 总不能无人机都撞墙了,你才在屏幕上看到障碍物吧? 二、工作原理:信号的 “旅行记” 2.1 信号采集:无人机的 “眼睛” 无人机上的摄像头就像手机相机,能把看到的景象变成电信号。但这时候的信号很弱,还带着 “杂音”,就像说话含着口水,听不清。 这时候会经过两步处理: * 过滤杂音:用低通滤波器 “过滤” 掉高频噪音,就像用滤网把水里的沙子去掉。 * 信号放大:放大器把信号变强,

格拉姆角场(Gramian Angular Field, GAF)详解

格拉姆角场(Gramian Angular Field, GAF)详解

格拉姆角场(Gramian Angular Field, GAF)是一种于2015年被提出的时间序列可视化与特征编码技术。其核心思想是将一维时间序列转换为二维图像,并在此过程中保留原始序列的时间依赖关系与数值特征。目前,GAF已在故障诊断、生物电信号分析、射频信号识别等多个领域得到广泛应用。 GAF的实质是借助极坐标变换与格拉姆矩阵的结构,将一维序列中的“时间–数值”映射为图像中的像素关联信息。生成的图像矩阵的行列索引直接对应时间顺序,使其能够兼容主流图像识别模型(如CNN),从而挖掘出时间序列中的深层特征。 一、GAF 的核心设计逻辑 传统的一维时间序列包含两类基本信息:数值大小(如振幅)和时间顺序(如信号随时间的变化趋势)。折线图等常规方法虽能展示趋势,却难以显式表达不同时刻之间的数值关联。GAF 通过以下三步逻辑实现信息的结构化编码: 1. 数值归一化:将原始序列缩放至[-1, 1]区间,消除量纲与异常值影响,为极坐标变换提供基础; 2. 极坐标转换:将时间索引映射为半径,数值大小映射为角度,建立 时间-数值 在极坐标系统中的对应关系; 3. 格拉姆矩阵构建: