大模型 RAG 应用开发基础及入门


什么是大语言模型的幻觉?

大语言模型在处理自然语言时,有时候会出现”幻觉“现象。所谓幻觉,就是模型生成的内容与事实或上下文不一致的问题。这些问题会严重影响AI应用的可靠性和实用性。

幻觉的两大类型

事实性幻觉

指模型生成的内容与实际事实不匹配。比如在回答”第一个登上月球的人是谁?”这个问题时:

  • 错误回答: “Charles Lindbergh在1951年月球任务中第一个登上月球”
  • 正确事实: Neil Armstrong才是第一个登上月球的人(1969年阿波罗11号任务)

这种幻觉之所以危险,是因为模型生成的内容看起来很可信,但实际上完全错误。

忠实性幻觉

指模型生成的内容与提供的上下文不一致。这种幻觉可以分为三类:

  • 输出与原文不一致(编出原文中没有的信息)
  • 上下文之间不一致(前后矛盾)
  • 逻辑链不一致(推理过程存在漏洞)

比如在总结新闻时,模型可能会添加原文中不存在的细节,或者前后描述矛盾。

为什么会产生幻觉?

大语言模型产生幻觉的原因主要来自三个方面:

  1. 数据源导致的幻觉
    • 训练数据中的质量问题
    • 数据中存在的错误信息
    • 数据覆盖范围有限
  2. 训练过程导致的幻觉
    • 架构限制:无法准确理解长文本的上下文关联
    • 累积错误:生成过程中的错误会逐步传递和放大
  3. 推理相关的幻觉
    • 回答过于简略
    • 生成过程中的不完整推理

如何评估幻觉问题

为了客观评估模型的幻觉问题,我们可以使用多种方法:

  1. 事实一致性评估:将生成内容与权威来源进行比对
  2. 分类器评估:使用专门训练的模型来检测是否存在幻觉
  3. 问答测量:通过问答来验证生成内容的一致性
  4. 不确定度分析:评估模型对自身输出的确信程度
  5. 提示测量:让模型自我评估,通过特定提示策略来评估生成内容

RAG解决方案

RAG是什么?

RAG(Retrieval-Augmented Generation)也叫检索增强生成,是指对大语言模型输出进行优化,使其能够参考并利用数据源之外的权威知识。简单来说,RAG就是从外部检索对应的知识内容,和用户的提问一起构成Prompt发给大模型,再让大模型生成内容。

它的核心思想是:

  1. 从外部知识库检索相关信息
  2. 将检索到的信息作为上下文提供给模型
  3. 让模型基于这些上下文生成回答

简单来说:RAG = 外部知识检索 + Prompt构建 + LLM 生成

image

为什么需要RAG?

LLM虽然是一个强大的工具,但它本身拒绝了解任何时事,且它给出的答案总是非常流畅,内容却不一定靠谱。这存在几个主要的问题:

  1. LLM的训练数据量有限且无法更新到最新知识。
  2. 当用户需要专业或领域特定的数据时,LLM往往缺乏相应的知识
  3. 对于答案的问答内容很难从源创进行溯源
  4. 由于技术限制,不同的训练源使用相同的大语言技术,可能会产生不确信的响应

而RAG为解决这些问题带来了以下优势:

  • 经济高效:预训练和微调模型的成本很高,而RAG是一种经济高效的新方法
  • 信息时效:使用RAG可以为LLM提供最新的研究、统计数据或新闻
  • 增强用户信任度:RAG允许LLM通过来源归属来呈现具体的信息,输出可以包括对来源的引文或参考,这可以增加对对话的生成式人工智能解决方案的任何信心

RAG是如何工作的?

RAG采用三种主要的检索方式:

  1. 一次性检索
    • 从单次检索中获取相关知识
    • 直接预置到大模型的提示词中
    • 不会收集反馈信息
  2. 迭代检索
    • 允许在对话过程中多次检索
    • 每一轮都可能有新的检索
    • 支持多轮对话优化
  3. 事后检索
    • 先生成答案
    • 然后检索验证
    • 对答案进行修正

image

RAG实战示例

以一个简单的问答场景为例,展示RAG的实际应用流程:

  1. 用户提问:”公司有销售什么产品?”
  2. 系统处理流程:
    • 使用检索器获取产品相关文档
    • 将文档内容与问题组合成提示词
    • 通过LLM生成回答
    • 确保回答基于检索到的事实信息
  3. 最终输出:包含准确的产品信息,并且所有信息都可以溯源。

AI应用开发利器:向量数据库详解

什么是向量数据库?

向量数据库(Vector Database)是一种专门用于存储和处理向量数据的数据库系统。它不同于传统的关系型数据库,因为它需要将所有数据映射为特定的向量格式,并采用相似性搜索作为主要的检索方式。

一个生动的例子:识别猫咪

让我们通过一个识别猫咪的例子来理解向量数据库。假设我们有一组不同品种的猫咪图片:

  • 波斯猫
  • 英国短毛猫
  • 暹罗猫
  • 布偶猫
  • 无毛猫

每张猫咪图片都可以用一组数字向量来表示其特征,如:


波斯猫: [0.4, 0.3, 0.4, 0.5, 0.3, 0.4, 0.5, ...]
英国短毛猫: [0.7, 0.2, 0.5, 0.5, 0.5, 0.5, 0.5, ...]
暹罗猫: [0.5, 0.3, 0.4, 0.5, 0.3, 0.4, 0.5, ...]

这些数字代表了猫咪的各种特征,比如:

  • 毛发长度
  • 体型大小
  • 面部特征
  • 耳朵形状等等

向量数据库的优势

与传统的数据库相比,向量数据库有以下特点:

  1. 数据类型
    • 传统数据库:数值、字符串、时间等结构化数据
    • 向量数据库:向量数据(不存储原始数据,有的也支持)
  2. 数据规模
    • 传统数据库:小,1亿条数据对关系型数据库来说规模很大
    • 向量数据库:大,最少千亿数据是基线
  3. 数据组织方式
    • 传统数据库:基于表格、按照行和列组织
    • 向量数据库:基于向量、按向量维度组织
  4. 查找方式
    • 传统数据库:精确查找/范围查找
    • 向量数据库:近似查找,查询结果是与输入向量最相似的向量

相似性搜索算法

在向量数据库中,支持通过多种方式来计算两个向量的相似度:

余弦相似度:主要是用于衡量向量在方向上的相似性,特别适用于文本、图像和高维空间中的向量。它不受向量长度的影响,只考虑方向的相似程度,计算公式如下(计算两个向量间的夹角的余弦值,取值范围为[-1, 1]):


similarity(A,B) = (A·B)/(||A||·||B||)

欧式距离:主要是用于衡量向量之间的直线距离,得到的值可能很大,最小为0,通常用于低维空间或需要考虑向量各个维度之间差异的情况。欧式距离较小的向量被认为更相似,计算公式如下:


distance(A,B) = √∑(Ai-Bi)²

例如下图:左侧就是欧式距离,右侧就是余弦相似度

image

实际应用场景

向量数据库的主要应用场景包括:

  1. 人脸识别
  2. 图像搜索
  3. 音频识别
  4. 智能推荐系统

这些场景的共同特点是:需要对非结构化数据(如图片、文本、音频)进行相似度搜索。

在RAG中,我们会将文档的知识按特定规则分成小块,转换成向量存储到向量数据库中。当人类提问时,我们将问题转换为向量,在数据库中找到最相似的文本块,这些文本块可以成为Prompt的补充内容。

深入理解Embedding嵌入技术

Embedding 是什么?

Embedding(嵌入)是一种在机器学习中广泛使用的技术,它能将文本、图片、视频等非结构化数据映射到向量空间中。一个Embedding向量通常是一个包含N个浮点数的数组,这个向量不仅表示了数据的特征,更重要的是通过学习可以表达它们的内在语义。简而言之,Embedding就是一个模型生成方法,可以将非结构化的数据,例如文本/图片/视频等数据映射成有意义的向量数据。比如一段文本、一张图片、一段视频,警告Embedding模型处理后都会变成类似这样的向量:


[0.5, 0.8, 0.7, 0.5, 0.8, 0.7, 0.5, 0.8, 0.7, 0.5]

image

主流的Embedding模型

目前主要有这几类Embedding模型:

  1. Word2Vec(词嵌入模型)
    • 通过学习词语转化为连续的向量表示
    • 基于两种主要算法:CBOWSkip-gram
    • 能够捕捉词语之间的语义关系
  2. 1GloVe
    • 类似Word2Vec但采用不同的训练方式
    • 同时考虑全局共现信息
    • 能较好地保存词语间的语义关系
    • 适用于多种自然语言处理任务
  3. FastText
    • 考虑了单词的子词信息
    • 能处理训练集中未出现的生词
    • 支持多语言处理
  4. 大模型Embeddings
    • 如OpenAI的text-embedding-ada-002
    • 输入维度8191个tokens
    • 输出维度1536维向量

Embedding的神奇之处

Embedding最有趣的特性是它能够捕捉语义关系。让我们看一个著名的例子


King - Man + Woman ≈ Queen
(国王 - 男人 + 女人 ≈ 女王)

这个公式展示了Embedding不仅仅是把词语转换成数字,它还能:

  1. 保留词语之间的关系
  2. 支持向量运算
  3. 产生有意义的结果

我们可以通过可视化的方式看到这些词语在向量空间中的分布:

  • woman和girl的向量位置接近
  • man和boy的向量位置接近
  • king和queen虽然性别不同,但都位于表示”统治者”的维度上

Embedding的重要价值

  1. 降维:将高维数据映射到低维空间,大大降低了计算复杂度
  2. 捕捉语义信息:不仅能记录表面的词频信息,还能捕捉深层的语义关联
  3. 泛化性:Embedding学习到的是通用的语言表达方式,可以应用到新的场景
  4. 泛化能力:对于未见过的数据,也能基于已学习的语义特征给出合理的向量表示
  5. 可视化支持:虽然Embedding本身很复杂,但我们可以使用t-SNE等工具将其可视化,帮助理解数据的内在结构。

在RAG中的应用

在RAG系统中,Embedding主要用于两个场景:

  1. 文档向量化:将知识库中的文档转换为向量
  2. 查询向量化:将用户的问题转换为向量

通过比较这些向量的相似度,我们可以找到与用户问题最相关的文档片段,从而提供更准确的答案。

RAG应用实战:OpenAI Embedding与LangChain的结合

OpenAI Embedding接口简介

OpenAI提供了多个Embedding模型选择,以下是几个主要模型的对比:

模型 Token数(每个文档800个) 性能评估 最大输入 向量维度
text-embedding-3-small 62,500 62.3% 8191 1536
text-embedding-3-large 9,615 64.6% 8191 3072
text-embedding-ada-002 12,500 61.0% 8191 1536

LangChain中的Embedding组件使用

在LangChain中,Embedding类提供了统一的接口来使用各种嵌入模型:


class Embeddings(ABC):
    """Interface for embedding models."""
    
    @abstractmethod
    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        """Embed search docs."""
        
    @abstractmethod
    def embed_query(self, text: str) -> List[float]:
        """Embed query text."""

使用示例:


import dotenv
import numpy as np
from langchain_openai import OpenAIEmbeddings
from numpy.linalg import norm

# 初始化Embedding模型
embeddings = OpenAIEmbeddings()

# 进行文本嵌入
query_vector = embeddings.embed_query("你好, 我是小潘")
documents_vector = embeddings.embed_documents([
    "你好, 我是小潘",
    "这个自然语言处理的人叫小潘",
    "来知若惘, 既心若旷"
])

# 计算相似度
def cosine_similarity(vector1, vector2):
    dot_product = np.dot(vector1, vector2)
    norm1 = norm(vector1)
    norm2 = norm(vector2)
    return dot_product / (norm1 * norm2)

CacheBackEmbedding的使用

为了提高性能,LangChain提供了缓存功能:


from langchain.embeddings import CacheBackedEmbeddings
from langchain.storage import LocalFileStore

embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
embeddings_with_cache = CacheBackedEmbeddings.from_bytes_store(
    embeddings,
    LocalFileStore("./cache/"),
    namespace=embeddings.model,
    query_embedding_cache=True
)

使用缓存时需要注意:

  1. underlying_embedder: 使用的基础嵌入模型
  2. document_embedding_cache: 用于缓存文档的存储结构
  3. batch_size: 可选参数,默认None
  4. namespace: 用于文档缓存的命名空间
  5. query_embedding_cache: 是否缓存查询向量

运行流程分析

一个完整的RAG应用运行流程如下:

  1. 文档预处理
    • 分割文档
    • 生成向量
    • 存入向量数据库
  2. 查询处理
    • 将用户问题转为向量
    • 在向量数据库中检索
    • 组合上下文生成回答
  3. 缓存优化
    • 缓存常见文档的向量
    • 缓存常见查询的向量
    • 提供响应速度

注意事项

  1. 向量维度的选择
    • 需要平衡精度和效率
    • 维度越高,表达能力越强,但计算成本也越高
  2. 缓存策略
    • 合理设置缓存大小
    • 选择适当的缓存淘汰策略
    • 定期更新缓存
  3. 性能优化
    • 使用批处理提高效率
    • 合理使用多线程
    • 监控资源使用情况

  目录