AI 开发入门之 RAG 技术

目录

    • 一、从一个简单的问题开始
    • 二、语言模型“闭卷考试”的困境
    • 三、RAG 是什么—LLM 的现实世界“外挂”
    • 四、RAG 的七步流程
      • 第一步:加载数据(Load)
      • 第二步:切分文本(Chunking)
      • 第三步:向量化(Embedding)
        • 向量化:把句子变成“可以计算距离”的坐标点
        • 向量化模型做了啥?
        • 相似度怎么计算?
        • 总结一下
      • 第四步:存入向量数据库(Vector Store)
      • 第五步:接收用户问题(Query)
      • 第六步:检索相关文段(Retrieve)
      • 第七步:组织 Prompt,交给大模型生成回答(Generate)
    • 总结

如果关注 AI 领域,那么 RAG 这个名词你肯定不陌生,这篇文章,我们就来揭开它的神秘面纱。为什么需要 RAG,它到底是什么,能解决什么问题。

一、从一个简单的问题开始

假设你在和一个 AI 聊天助手对话,你问它:

“北京到上海高铁多久?”

这看起来像个非常简单的问题,但它考验的却是 AI 模型的知识广度知识时效性

你希望它能回答类似这样:

“大约 4.5 到 6 小时,具体取决于车次。”

但是,假设这个 AI 模型训练得比较早,它可能回答是——

“我不知道。”

或者:

“我认为北京和上海之间目前没有高铁。”(因为它只看到了 2010 年以前的数据)

这就暴露出一个大语言模型的通病

训练完就定格了,它不会自己更新知识。


二、语言模型“闭卷考试”的困境

所有的大语言模型(如 GPT、Claude、Gemini)在训练时都要读取大量文本,比如:

  • 维基百科
  • 新闻网站
  • Reddit 论坛
  • Github 代码
  • 开放书籍、论文

训练结束后,它就像一个“背书高手”,记住了大量的知识。但这也意味着一但遇到新知识实时内容你私有的数据,它就歇菜了。

所以问题就来了:怎么让模型既有“语言能力”,又能随时“看资料再回答”呢?

这时候就该 RAG 登场了!


三、RAG 是什么—LLM 的现实世界“外挂”

RAG,全称是 Retrieval-Augmented Generation,翻译为“检索增强生成”。

通过字面意思也能看出来它的核心作用,通过检索来增强生成(废话)

用通俗话来讲:
它让 AI 在回答之前,先“查资料”,再用大模型来“组织语言”。

就像你考试的时候如果不确定答案,那就翻课本,然后用自己的话组织一段回答。

想象一个真实的场景,比如你在一家 SaaS 公司,客户经常问你:

  • “你们的产品怎么绑定企业微信?”
  • “有没有 API 文档?”
  • “怎么开具发票?”

这些内容,可能都写在:

  • 帮助中心文档
  • FAQ 文档
  • 客服聊天记录
  • 内部知识库

而传统的 ChatGPT 模型对这些你们内部的这些专属知识一无所知

这时候你就可以用 RAG,它的基本流程是:

  1. 用户提问
  2. 在你的知识库里“检索”相关文档段落(比如找到 API 文档那一段)检索
  3. 把这些内容和用户问题一起送进语言模型 增强
  4. 生成一个有针对性的、个性化的回答。生成

这样的系统既懂你公司,又能写好回答

所以 RAG 的核心优势显而易见:

优点解释
实时更新你改了文档,模型就能学会新内容,不需要重新训练
私有知识可以在不暴露给外部模型的前提下使用公司内部数据
可控性强检索什么,传给模型什么,你可以干预整个过程
更少幻觉模型参考真实资料后,不容易瞎编

所以,总的来说,大语言模型就像是通用的大脑,RAG 则让它接入你自己的知识RAG 不是让模型更“聪明”,而是让它更“有见识”。

通过上面的描述,RAG 听起来很简单嘛。

但真正的 RAG 系统背后可是有很多技术细节:

  • 文档如何分段(chunking)
  • 怎样计算用户问题和文档的“语义相似度”(向量检索)
  • 检索出几条内容?怎么拼接 Prompt?
  • 模型是否支持多轮记忆和上下文压缩?
  • 如何缓存和优化响应速度?

等等,这些都会影响最终效果。

四、RAG 的七步流程

我们已经大致了解了 RAG 的原理,现在我们就从宏观视角来看看 RAG 的全流程是怎么样的。

第一步:加载数据(Load)

RAG 的第一步,就是从你现有的资料中**“把内容读进来”**。比如我们加载一份 FAQ 文档:

import { TextLoader } from "langchain/document_loaders/fs/text";const loader = new TextLoader("docs/faq.txt");
const rawDocs = await loader.load();

输出结果是一个标准格式:

[{pageContent: "退订说明:用户如需退订,请登录控制台,点击账户管理。",metadata: { source: "faq.txt" }},...
]

这就像是把原始文档清洗成结构化文本,供后续使用。

第二步:切分文本(Chunking)

为什么要切分?因为文档太大了,大模型一次吃不下。

我们需要把文档拆成段落级别的小块(chunk),通常每块控制在几百字以内。

切分工具(在 langchain.js 中):

import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";const splitter = new RecursiveCharacterTextSplitter({chunkSize: 500,chunkOverlap: 50
});
const docs = await splitter.splitDocuments(rawDocs);

第三步:向量化(Embedding)

现在我们已经把文档切分了,但是有一个问题:

计算机如何知道,两个句子意思相近?

比如下面这两个问法:

  • “怎么取消订阅?”
  • “我不想继续用了,怎么退?”

我们人类一看就知道是同一个意思。可对计算机来说,它只看到一串字符,完全不懂“语义”。

那怎么办?

我们需要给它一种能“看出意思相似”的方式,这就是向量化。

向量化:把句子变成“可以计算距离”的坐标点

你可以把“向量化”想象成这样的过程:

我们给每个句子分配一个“坐标点”,让相近意思的句子靠得近,差很多的句子离得远。

比如:

句子向量(简化表示)
“怎么退订服务?”[0.9, 0.1, 0.4]
“不想用了怎么办?”[0.88, 0.12, 0.45]
“产品价格是多少?”[0.1, 0.8, 0.9]

你可以把每个向量想象成一个坐标点在三维空间中:

  • 第一个句子和第二个句子很靠近(表示意思差不多)
  • 第三个句子在远处(表示是完全不同的问题)

于是我们就可以计算两个句子之间的“距离”,这个距离越近,它们的意思就越像。

这就是所谓的**“语义相似度计算”**。


向量化模型做了啥?

现在的语言模型已经很强大,它们会从大量语料中学会如何把意思相近的词语、句子放到更接近的坐标位置上

你只要给它一句话,它就会返回一个长长的向量,比如:

[0.12, -0.03, 0.77, ..., 0.01]  // 长度可能是 1536 维

虽然我们看不懂这个向量长啥样,但这没关系——我们只需要知道:它可以拿来计算“相似度”


相似度怎么计算?

最常用的方式就是:

计算两个向量的夹角是否接近(余弦相似度)

可以理解为:

  • 两个方向完全一样的箭头,表示“非常相似”
  • 两个方向差很多,说明“几乎没关系”

总结一下
概念通俗理解
向量把一个句子的意思表示成一组数字坐标
向量化把句子转成向量(embedding 模型来做)
相似度比较两个向量距离近不近,距离越近意思越相近

所以,向量化的本质就是:把语言变成“可以比较距离的东西”,让计算机能看出语义像不像。


第四步:存入向量数据库(Vector Store)

我们把每段文本 + 它的向量都存到一个数据库里,方便后续检索。

可用的数据库有:

  • FAISS(本地)
  • Pinecone / Weaviate / Chroma(云服务)
  • Milvus(工业级)

示例(用 FAISS):

import { FaissStore } from "langchain/vectorstores/faiss";const store = await FaissStore.fromDocuments(docs, embeddings);

现在,你就有了一个可以按语义相似度查内容的数据库了。


第五步:接收用户问题(Query)

终于轮到用户提问了,比如:

“怎么退订你们的服务?”

这个问题会经过同样的向量化过程,再去数据库中查最接近的问题片段。


第六步:检索相关文段(Retrieve)

将用户问题的向量丢进数据库,找出前几段最相似的内容(通常是 top-3 或 top-5):

const results = await store.similaritySearch("怎么退订服务?", 3);

返回类似:

["退订说明:请登录控制台,点击账户管理页面...","退订功能位于控制台左侧菜单栏...",...
]

这就是查资料的部分。


第七步:组织 Prompt,交给大模型生成回答(Generate)

最后,我们把:

  • 用户问题
  • 检索到的文档片段

组织成一个 Prompt,交给 LLM:

const prompt = `
你是一个客服助手,请参考以下内容回答用户问题:资料:
---
1. ${results[0]}
2. ${results[1]}
3. ${results[2]}
---用户提问:
怎么退订服务?请根据资料,用简洁的语言回答:
`;

然后喂给 OpenAI 或其他模型:

const res = await llm.call(prompt);

得到最终回答:

“您好,您可以登录控制台,进入‘账户管理’,点击‘退订管理’即可操作退订。”

至此,一个完整的 RAG 流程就完成了。

当然这只是最简单笼统的流程介绍,具体的每个环节都是很复杂的,比如算法的选取以及参数的调整等等等等…


总结

RAG = 查文档 + 用大模型答题,RAG 本质上让 LLM 具备了实时访问企业知识库的能力,既规避了幻觉,又能针对性回答个性化问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/78228.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决yarn install 报错 error \node_modules\electron: Command failed.

在电脑重装系统后,重新安装项目依赖,遇到这一报错 完整报错信息如下: error D:\xxxxx\xxxxxx\node_modules\electron: Command failed. Exit code: 1 Command: node install.js Arguments: Directory: D:\xxxxx\xxxxx\node_modules\electron Output: HTTPError: Response cod…

2025年3月电子学会青少年机器人技术(五级)等级考试试卷-理论综合

青少年机器人技术等级考试理论综合试卷(五级) 分数:100 题数:30 一、单选题(共20题,共80分) 1. 2025年初,中国科技初创公司深度求索在大模型领域迅速崛起,其开源的大模型成为全球AI领域的焦…

23种设计模式-行为型模式之模版方法模式(Java版本)

Java 模板方法模式(Template Method Pattern)详解 🧠 什么是模板方法模式? 模板方法模式是一种行为型设计模式,在一个方法中定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在…

长城杯铁人三项初赛-REVERSE复现

前言 记录记录 1.LoginToMe int __fastcall main(int argc, const char **argv, const char **envp) {unsigned int v3; // eaxchar s[96]; // [rsp10h] [rbp-70h] BYREFint v6; // [rsp70h] [rbp-10h]int v7; // [rsp78h] [rbp-8h]int i; // [rsp7Ch] [rbp-4h]memset(s, 0, s…

DNS实验

DNS原理 客户端发起请求:客户端向本地 DNS 服务器发送域名解析请求,这是流程的起始点。本地 DNS 服务器查询根域名服务器:若本地 DNS 服务器缓存中无对应记录,它向根域名服务器发起查询,根域名服务器是 DNS 系统顶层&a…

SQLMesh 通知系统深度解析:构建自动化监控体系

SQLMesh 是一款强大的数据编排工具,其内置的灵活通知系统可显著提升团队协作效率。本文将系统解读 SQLMesh 的通知机制,涵盖配置方法、事件触发逻辑及高级定制技巧。 一、通知系统的核心架构 1. 通知目标(Notification Targets) …

精益数据分析(20/126):解析经典数据分析框架,助力创业增长

精益数据分析(20/126):解析经典数据分析框架,助力创业增长 在创业和数据分析的学习道路上,每一次深入探索都可能为我们带来新的启发。今天,依旧带着和大家共同进步的想法,我们一起深入研读《精…

【OSG学习笔记】Day 8: 纹理贴图——赋予模型细节

在 OSG(Open Scene Graph)中,纹理贴图是为模型添加细节的关键技术,主要涉及纹理加载、UV 映射和多重纹理叠加三部分。 基础理论 纹理加载 纹理的作用,就是将2D图像映射到3D模型表面,增强视觉细节。 纹理类型与格式支持: OSG 支持多种图像格式,包括常见的 .jpg/.jpe…

基于事件驱动的云原生后端架构设计:从理念到落地

📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:微服务之后,事件驱动正在成为新范式 随着业务复杂度的提升,传统同步式微服务调用模式逐渐暴露出瓶颈:服务间耦合度高、并发能力有限、出错链路复杂。而在互联网业务、金融交易、物联网等场景中…

vue3:十一、主页面布局(修改顶部导航栏样式-右侧:用户信息+退出登录+全屏显示)

一、效果 完成效果,增加顶部导航栏,右侧用户信息(其中个人中心需要后续进行页面开发,这里只写了退出登录功能),以及全屏功能 二、搭建并引入右侧组件 将右侧内容封装到单独的组件,直接引入(像左侧导航条等内容也是可以做成这种形式) 1、新建右侧组件的页面 在layout中…

沁恒CHV203中断嵌套导致修改线程栈-韦东山

调试专题bug实例 2025年01月09日20点场 处理办法1:就是关闭中断嵌套 处理办法2: 使用原来的栈

Qt本地化 - installTranslator不生效

bool QCoreApplication::installTranslator(QTranslator *translationFile)注意这里输入的是QTranslator对象指针,如果QTranslator是局部变量,一旦离开其作用域就会导致翻译失效 错误代码示范: void ApplyTranslator(const QString& qmf…

Qt UDP组播实现与调试指南

在Qt中使用UDP组播(Multicast)可以实现高效的一对多网络通信。以下是关键步骤和示例代码: 一、UDP组播核心机制 组播地址:使用D类地址(224.0.0.0 - 239.255.255.255)TTL设置:控制数据包传播范围(默认1,同一网段)网络接口:指定发送/接收的物理接口二、发送端实现 /…

PCB封装主要组成元素

PCB(Printed Circuit Board,印刷电路板)封装是指将电子元件固定在 PCB 上,并实现电气连接的方式。主要包括以下几类。 1. 焊盘(Pad) 作用:焊盘是 PCB 封装中最重要的元素之一,它是…

前端基础之《Vue(8)—内置组件》

一、Vue2.0中的内置组件 1、<slot> 插槽 2、<keep-alive> 动态组件 被keep-alive所包裹的组件&#xff1a; &#xff08;1&#xff09;不会被销毁。 &#xff08;2&#xff09;还会多两个生命周期钩子&#xff1a;activated()、deactivated()。 &#xff08;3&a…

某大型电解铝厂电解系统谐波治理装置改造沃伦森电气

电解铝行业谐波治理解决方案——无源滤波装置优化升级&#xff0c;保障稳定运行 在电解铝生产过程中&#xff0c;谐波污染问题严重影响电网电能质量&#xff0c;甚至可能导致滤波装置损坏&#xff0c;引发群爆事故。河南登封某大型电解铝厂通过无源滤波装置智能化改造&#xff…

在 Ubuntu 环境为 Elasticsearch 引入 `icu_tokenizer

1. 为什么需要 ICU 分析插件 Elasticsearch 默认的 standard tokenizer 遵循 UAX #29 规则&#xff0c;但在 CJK&#xff08;中、日、韩&#xff09;等亚洲语言上仅能按字符切分&#xff0c;无法识别词边界&#xff1b;对包含重音符号、大小写或多脚本混排的文本也缺乏统一归一…

避免事件“穿透”——Vue 中事件冒泡的理解与解决方案

一、事件冒泡是什么&#xff1f; 事件冒泡指的是&#xff1a;当某个元素上的事件被触发后&#xff0c;事件会从该元素向其父级、祖先元素一直“冒泡”传递&#xff0c;直到 document。这意味着&#xff0c;如果父元素绑定了点击事件&#xff0c;子元素触发点击时也可能顺带触发…

【Java面试笔记:进阶】17.一个线程两次调用start()方法会出现什么情况?

1. 线程启动与异常 线程启动:Java 线程只能启动一次,通过调用 Thread 对象的 start() 方法。多次启动的后果:如果尝试第二次调用 start() 方法,会抛出 IllegalThreadStateException 运行时异常。(1) 代码示例 public class ThreadStartDemo {public static void main(Stri…

Flask + ajax上传文件(一)

一、概述 本教程将教你如何使用Flask后端和AJAX前端实现文件上传功能,包含完整的代码实现和详细解释。 二、环境准备 1. 所需工具和库 Python 3.xFlask框架jQuery库Bootstrap(可选,用于美化界面)2. 安装Flask pip install flask三、项目结构 upload_project/ ├── a…