大语言模型(LLM)展现出了令人惊叹的能力——它们能够自如对话、精准翻译、编写代码、自动摘要……几乎无所不能。然而,这些强悍功能背后,离不开海量数据的预训练支撑。其核心原理是“标记预测”,即模型根据前文推测下一个词,从而学会生成流畅、富有上下文的回复。这种机制让LLM具备了令人瞩目的语言生成能力。
不过,这一机制也带来了隐忧。模型过度追求“预测最可能的下一词”,而忽略了事实校验,导致输出有时不够准确甚至具有误导性。更棘手的是,预训练数据往往停留在数月之前,LLM无法回答关于最新动态的问题。除非你亲自验证,否则很难判断其回答是否可靠。
此时,检索增强生成(RAG)便成了破解困局的关键方案。本文就来深入解析RAG的原理与应用。
01 什么是RAG
大语言模型无疑是AI领域最受关注的技术,能够解决多种自然语言处理任务。然而,它的短板也很突出——受限于训练数据的时效性。例如,GPT-4 Turbo的训练数据截止于2023年12月。如果你在此之后提问,得到的答案可能失真。这种现象被称为“LLM幻觉”——看似合理,实则完全错误。
检测幻觉是一大难题,至今仍有大量研究人员在探索。尽管可以通过困惑度等指标评估文本质量,但这并未触及核心:我们如何保障LLM的回答既准确又符合事实?
这时RAG应运而生。它的核心目标是缓解幻觉问题。流程非常简单:首先向LLM提交问题,但并非直接抛出,而是先检索能够帮助LLM给出更精准答案的相关上下文。然后将原始问题与最相关的上下文一同提供给LLM。最后,LLM基于这些信息生成回复。这样一来,LLM不再凭空编造,而是输出富含上下文的可靠答案。
02 RAG的组件
RAG主要由三大组件构成:检索、增强与生成。
检索组件
检索组件的目标是根据用户问题找到最相似的上下文候选。第一步是将输入问题转化为数值表示——即生成Embedding向量。向量的维度取决于所用Embedding模型。HuggingFace上提供了许多开源免费的Embedding模型(如SentenceTransformers)。这些向量保留了原始文本的语义信息——两段文本语义越接近,它们在向量空间中的位置就越近。通过计算任意两个向量之间的欧氏距离(L2)即可判断相似度。

理解了Embedding向量的概念后,搜索相似上下文就清晰了:计算查询向量与数据库中上下文向量之间的距离。当向量数量较少时,这种计算尚可接受;但若有数百万个向量,计算成本急剧上升,本地机器可能难以承载。此时就需要高度可扩展的向量数据库(例如Milvus)来高效处理海量向量。

Milvus提供了先进的索引算法,能够高效存储十亿级向量并执行超大规模的相似性搜索。它还与主流AI框架深度集成,极大简化了RAG应用的开发过程。
增强组件
向量相似性搜索完成后,进入增强阶段。将上一步检索到的top-k最相关上下文与用户查询组合起来,形成完整的Prompt,作为LLM的输入。
根据具体用例可以尝试不同Prompt,但基本模板通常如下:
Use the following pieces of context to answer the question at the end.
{context}
Question: {question}
Helpful Answer:
生成组件
这是RAG的最后环节。所选LLM(如GPT、Llama、Mistral、Claude等)根据包含用户查询和最相关上下文的Prompt生成回复。LLM依赖提供的上下文回答问题,而非仅凭训练数据中的知识。这种策略能显著降低幻觉风险。
下图展示了RAG应用的完整组件与工作流程:

03 Milvus Lite、Llama 3 与 LlamaIndex 简介
接下来我们将利用Milvus和LlamaIndex搭建一个RAG驱动的LLM应用。先简要介绍要用到的工具。
Milvus Lite
Milvus是开源向量数据库,能够存储十亿级向量并高效搜索。在接下来的演示中,我们用Milvus存储上下文向量并计算相似度。有多种安装方式,最简单的是Milvus Lite——轻量版,适合快速开发原型,例如测试不同的文档分块策略或Embedding模型。
安装只需一条pip命令:
pip install "pymilvus>=2.4.2"
安装完成后即可用Python初始化Milvus。需要注意,Milvus Lite最多支持存储100万条向量数据。若需更大容量,生产环境建议使用Docker或Kubernetes部署。
Llama3
除了向量数据库,RAG的另一关键组件是LLM。市面上有很多开源模型,其中Llama和Mistral备受欢迎。本文选用Meta开发的Llama3。Llama3基于比Llama2大7倍的数据集预训练,性能提升显著。它有两种规格:80亿参数和700亿参数。性能测试显示,两种规格均优于同级别模型。

本文使用80亿参数的Llama3。默认需要约32GB显存,超出免费GPU上限。但通过4-bit量化可将模型压缩至约4GB显存。加载并量化有两种方法:一是使用HuggingFace + bitsandbytes,二是安装Ollama直接加载模型(Ollama上的LLM默认已量化)。本文使用Ollama在本地运行各种LLM。安装完成后,运行以下命令下载Llama3:
ollama run llama3
LlamaIndex
LlamaIndex是协调RAG Pipeline的框架。我们已经安装好了向量数据库和LLM,现在需要将它们连接起来。LlamaIndex负责预处理多种数据源,转换为向量并存入数据库,搜索上下文,组合查询与搜索结果,最后输出LLM的回复。
安装同样简单:
pip install llama
pip install llama-index-vector-stores-milvus llama-index-llms-ollama llama-index-embeddings-huggingface
04 使用 Milvus Lite、Llama3 和 LlamaIndex 搭建 RAG 聊天机器人
现在开始动手实践!本节将搭建一个聊天机器人,回答关于《Attention is All You Need》论文的问题(即介绍Transformer的那篇)。你也可以替换为其他论文。所有代码可在notebook中找到。
首先导入库:
!pip install arxiv
import arxiv
from llama_index.core import SimpleDirectoryReader
from llama_index.vector_stores.milvus import MilvusVectorStore
from llama_index.core import VectorStoreIndex, Settings
from llama_index.llms.ollama import Ollama
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from pymilvus import MilvusClient
通过Arxiv官方Python库下载论文PDF:
dir_name = "./Documents/pdf_data/"
arxiv_client = arxiv.Client()
paper = next(arxiv.Client().results(arxiv.Search(id_list=["1706.03762"])))
# Download the PDF to a specified directory with a custom filename.
paper.download_pdf(dirpath=dir_name, filename="attention.pdf")
这里通过论文ID下载《Attention is All You Need》。Arxiv上每篇论文都有唯一ID,你可以直接替换。
接下来初始化Milvus向量数据库和Llama3模型。转换文本向量时使用HuggingFace上的BGE base模型:
vector_store = MilvusVectorStore(uri="./milvus_rag_demo.db",dim=768, overwrite=True)
embedding_model = HuggingFaceEmbedding(model_name="BAAI/bge-base-en-v1.5")
llm = Ollama(model="llama3",temperature=0.1, request_timeout=480.0)
向量维度设为768,与BGE base模型输出一致。现在加载PDF论文——使用LlamaIndex的SimpleDirectoryReader:
pdf_document = SimpleDirectoryReader(
input_files=[f"{dir_name}attention.pdf"]
).load_data()
print("Number of Input documents:", len(pdf_document))
# OR execute this command if you ha ve multiple PDFs inside the directory
pdf_document = SimpleDirectoryReader(
dir_name, recursive=True
).load_data()
"""
Output:
Number of Input documents: 15
"""
输入文档数量为15(论文共15页)。然后使用LlamaIndex的Settings将LLM和Embedding模型绑定,同时自定义分块大小与重叠:
Settings.llm = llm
Settings.embed_model = embedding_model
Settings.chunk_size = 128
Settings.chunk_overlap = 64
接下来将PDF文档导入Milvus向量数据库。PDF被分割成块,每个块由BGE base模型转换为向量,然后存入Milvus:
index = VectorStoreIndex.from_documents(pdf_document)
print("Number of nodes:", len(index.docstore.docs))
query_engine = index.as_query_engine()
"""
Output:
Number of nodes: 196
"""
向量数据库中现在有196个块。调用as_query_engine方法即可提问。以上便是使用LlamaIndex构建完整RAG Pipeline的全部步骤。现在询问一个论文相关问题:“multi-head attention相比single-head attention有什么好处?”:
query = "What is the benefit of multi-head attention instead of single-head attention?"
result = query_engine.query(query)
print(result)
"""
Output:
Multi-head attention allows the model to jointly attend to information from different representation subspaces at different positions. With a single attention head, a veraging inhibits this.
"""
答案高度相关!你也可以用RAG应用提出更复杂的问题。
05 优化 RAG Pipeline
将RAG Pipeline部署到生产环境比原型开发复杂得多。一个常见挑战是如何评估生成响应的质量。好在有几个开源工具可以派上用场,例如Ragas和TruLens-Eval。Ragas提供了测量上下文精确度的方法,以及忠实度、答案相关性等指标来评估生成组件的质量。更多信息请参考官方文档。

如果发现响应质量下降,第一步应检查这些评估指标。指标不佳则针对性改进。当然,更重要的是先评估数据质量:向量数据库中是否包含正确的上下文?分块大小是否合适?数据在分块前是否需要清洗?确认数据没问题后,可以尝试更换更优的LLM和Embedding模型。关于RAG优化,推荐阅读以下两篇文章:《走向生产:LLM应用评估与可观测性》和《RAG修炼手册|如何评估RAG应用?》。
06 总结
得益于Ollama、LlamaIndex、HuggingFace等框架,构建RAG Pipeline变得前所未有地简单。Milvus支持高效存储海量上下文向量,并与多种AI框架无缝集成。因此,仅用几行代码就能完成一个RAG应用的搭建。Milvus Lite更是通过一条简单的pip命令完成安装与配置,让你轻松开发多个RAG原型。
