免费POC, 零成本试错
AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


从零实现一个简单的 RAG 系统

发布日期:2025-11-12 20:38:15 浏览次数: 1535
作者:图灵编辑部

微信搜一搜,关注“图灵编辑部”

推荐语

RAG技术如何让AI更懂你?手把手教你从零搭建智能问答系统。

核心内容:
1. RAG系统的工作原理与核心组件解析
2. 基于Python和ollama的极简RAG系统搭建实战
3. 不同RAG实现方式的对比与应用场景探讨

杨芳贤
53AI创始人/腾讯云(TVP)最具价值专家

最近,检索增强生成(Retrieval-Augmented Generation,简称 RAG)在人工智能和大模型领域中崭露头角,成为一种极具潜力的新范式。

RAG 将信息检索与文本生成相结合,通过引入外部知识源来提升大模型的表现。这种方法已在问答系统、对话系统以及内容生成等多种应用中展现出令人期待的成果。

在这篇文章中,作者将带你深入了解 RAG 的工作原理,并使用 Python 和 Ollama 从零构建一个简单的 RAG 系统。通过这个项目,你将掌握 RAG 系统的核心组成部分,并学会如何利用基础的编程概念实现它。可以说实用满满。

什么是RAG

我们先从一个没有使用 RAG 的简单聊天机器人说起:

这个聊天机器人可以根据训练数据回答常见问题,但它无法访问最新的信息特定领域的知识

举个现实例子:你问 ChatGPT——“我妈妈叫什么名字?”

它当然回答不了,因为它无法访问外部信息,比如你的家庭成员资料。

要解决这个问题,我们需要给模型补充外部知识比如在这个例子里,我们可以提供一份“家庭成员名单”作为外部知识来源。

RAG 系统的两个核心组成部分:

  • 检索模型(Retrieval Model):从外部知识源(例如数据库、搜索引擎或知识库)中找出与问题最相关的信息。

  • 生成模型(Language Model):在检索到的信息基础上,生成最终的自然语言回答。

RAG 的实现方式有多种,比如 Graph RAGHybrid RAGHierarchical RAG 等,我们会在文章结尾简单介绍。

构建一个极简的RAG系统

下面我们来搭建一个简单的 RAG 系统,它能从预定义的数据集中检索信息,并基于检索结果生成回答。这个系统包括三个主要部分:

  • Embedding 模型:一种预训练语言模型,用来把输入文本转换成向量,即能表示语义的数值形式。这些向量可以用来在数据集中查找相似内容。

  • 向量数据库:用来存储知识及其对应的向量。常见的向量数据库包括 Qdrant、Pinecone、pgvector 等,但这里我们将从零实现一个简单的内存版数据库。

  • 聊天机器人:根据检索结果生成回答的语言模型,可以是 Llama、Gemma 或 GPT 等。

索引阶段

构建 RAG 系统的第一步是索引。在这个阶段,我们需要把数据集(或文档)拆分成更小的片段(chunks),并为每个片段计算一个向量表示,方便后续快速检索。

不同应用场景下,片段大小会有所不同:

  • 文档检索系统中,一个片段可以是一段文字或一句话;

  • 对话系统中,一个片段可以是一轮对话。

索引完成后,每个片段和它对应的向量都会被存入向量数据库中。下图展示了索引阶段后,数据库中数据的大致结构示例:

文本片段
向量表示
意大利和法国生产了全球超过40%的葡萄酒
\[0.1, 0.04, -0.34, 0.21, ...\]
印度的泰姬陵完全由大理石建成
\[-0.12, 0.03, 0.9, -0.1, ...\]
全球90%的淡水储备在南极洲 
\[-0.02, 0.6, -0.54, 0.03, ...\]
...
...
这些向量表示之后可以用来根据用户的查询检索相关信息。
你可以把它想象成 SQL 语句里的 WHERE 条件但不同的是,这里不是精确匹配文本,而是根据向量之间的语义相似度查找最相关的片段。

为了比较两个向量的相似度,我们可以使用余弦相似度(cosine similarity)欧几里得距离(Euclidean distance) 或其他距离度量方法。

在这个示例中,我们将使用余弦相似度。下面是向量 A 和向量 B 之间的余弦相似度公式:

如果你对上面的公式还不太熟悉,也不用担心——我们会在下一节中亲手实现它。

检索阶段

如下图所示,当用户Input Query 时,系统会先将这个查询转换成一个 Query Vector,然后将其与向量数据库中的所有向量进行比较,以找到最相关的文本片段(chunks)。

Vector Database 返回的结果会包含与查询最相关的前 N 个片段,接下来 Chatbot 会基于这些片段生成最终的回答。

开始写代码吧

在这个示例中,我们将用 Python 实现一个简单版本的 RAG 系统。

为了运行模型,我们会使用 ollama —— 一款命令行工具,可以直接运行来自 Hugging Face 的模型。

使用 ollama,你不需要连接服务器或云服务,就能在自己的电脑上本地运行模型。

我们将使用以下两个模型:

  • Embedding 模型hf.co/CompendiumLabs/bge-base-en-v1.5-gguf

  • 语言模型(Language Model)hf.co/bartowski/Llama-3.2-1B-Instruct-GGUF

至于数据集,我们会用一份关于 cat 的简单事实列表。在索引阶段,每一条事实都会被当作一个独立的文本片段。

下载 ollama 和模型

首先,从官方网站 ollama.com 安装 ollama

安装完成后,打开终端,运行以下命令来下载所需的模型:

ollama pull hf.co/CompendiumLabs/bge-base-en-v1.5-ggufollama pull hf.co/bartowski/Llama-3.2-1B-Instruct-GGUF

如果你看到下面这个输出结果,那说明你的安装成功了:

pulling manifest...verifying sha256 digestwriting manifestsuccess

在继续之前,为了在 Python 中使用 ollama,我们还需要安装 ollama 的 Python 包:

pip install ollama

加载数据集

接下来,创建一个 Python 脚本,并将数据集加载到内存中。这个数据集包含了一系列关于 cat 的事实,每条事实将在索引阶段作为一个片段使用。

你可以从这里下载示例数据集。下面是一个加载数据集的示例代码:

dataset = []with open('cat-facts.txt''r'as file:  dataset = file.readlines()  print(f'Loaded {len(dataset)} entries')

实现向量数据库

现在,我们来实现向量数据库。

我们将使用 ollama 的 embedding 模型,将每个片段转换为向量表示,然后将片段及其对应的向量存入到一个列表中。

下面是一个计算给定文本向量表示的示例函数:

import ollamaEMBEDDING_MODEL = 'hf.co/CompendiumLabs/bge-base-en-v1.5-gguf'LANGUAGE_MODEL = 'hf.co/bartowski/Llama-3.2-1B-Instruct-GGUF'# Each element in the VECTOR_DB will be a tuple (chunk, embedding)# The embedding is a list of floats, for example: [0.1, 0.04, -0.34, 0.21, ...]VECTOR_DB = []def add_chunk_to_database(chunk):  embedding = ollama.embed(model=EMBEDDING_MODEL, input=chunk)['embeddings'][0]  VECTOR_DB.append((chunk, embedding))

在这个示例中,为了简单起见,我们将数据集中的每一行都视为一个片段。

for i, chunk in enumerate(dataset):  add_chunk_to_database(chunk)  print(f'Added chunk {i+1}/{len(dataset)} to the database')

实现检索函数

接下来,我们来实现检索函数该函数接收一个查询,并根据余弦相似度返回与查询最相关的前 N 个片段。

可以理解为:两个向量的余弦相似度越高,它们在向量空间中就越接近,也就意味着它们在语义上越相似。

下面是一个计算两个向量余弦相似度的示例函数:

def cosine_similarity(a, b):  dot_product = sum([x * y for x, y in zip(a, b)])  norm_a = sum([x ** 2 for x in a]) ** 0.5  norm_b = sum([x ** 2 for x in b]) ** 0.5  return dot_product / (norm_a * norm_b)

现在,我们来实现检索函数:

def retrieve(query, top_n=3):  query_embedding = ollama.embed(model=EMBEDDING_MODEL, input=query)['embeddings'][0]  # temporary list to store (chunk, similarity) pairs  similarities = []  for chunk, embedding in VECTOR_DB:    similarity = cosine_similarity(query_embedding, embedding)    similarities.append((chunk, similarity))  # sort by similarity in descending order, because higher similarity means more relevant chunks  similarities.sort(key=lambda x: x[1], reverse=True)  # finally, return the top N most relevant chunks  return similarities[:top_n]


生成阶段

在这一阶段,聊天机器人将根据上一步检索到的知识生成回答。具体做法是:将相关片段加入到提示语(prompt)中,然后将提示语作为聊天机器人的输入。

例如,可以这样构建一个提示语:

input_query = input('Ask me a question: ')retrieved_knowledge = retrieve(input_query)print('Retrieved knowledge:')for chunk, similarity in retrieved_knowledge:  print(f' - (similarity: {similarity:.2f}{chunk}')instruction_prompt = f'''You are a helpful chatbot.Use only the following pieces of context to answer the question. Don't make up any new information:{'\n'.join([f' - {chunk}' for chunk, similarity in retrieved_knowledge])}'''

然后,我们使用 ollama 来生成回答。在这个示例中,我们将把 instruction_prompt 作为系统消息使用:

stream = ollama.chat(  model=LANGUAGE_MODEL,  messages=[    {'role''system''content': instruction_prompt},    {'role''user''content': input_query},  ],  stream=True,)# print the response from the chatbot in real-timeprint('Chatbot response:')for chunk in stream:  print(chunk['message']['content'], end='', flush=True)

整合全部步骤

完整代码可以在此文件https://huggingface.co/ngxson/demo_simple_rag_py/blob/main/demo.py)中找到。

运行代码的方法:将其保存为 demo.py 文件,然后执行以下命令:

python demo.py

现在,你可以向聊天机器人提问,它会根据从数据集中检索到的知识生成回答。

Ask me a question: tell me about cat speedRetrieved chunks: ...Chatbot response:According to the given context, cats can travel at approximately 31 mph (49 km) over a short distance. This is their top speed.

改进空间

到目前为止,我们已经用一个小数据集实现了一个简单的 RAG 系统,但它仍然存在不少局限:

  • 无法处理多主题问题当问题同时涉及多个主题时,系统往往给不出理想答案。这是因为当前的系统只根据“查询与片段的相似度”检索信息,而没有考虑查询的上下文。一个改进思路是——让聊天机器人根据用户输入生成自己的查询语句,再用这个生成的查询去检索知识;或者使用多个查询来获取更全面的信息。

  • 检索结果排序不够精准当前返回的是余弦相似度最高的前 N 个片段,但这不一定是最优结果,尤其当每个片段信息量很大时。改进方式是使用重排序模型,在初步检索结果的基础上再次根据相关性进行排序。

  • 数据库可扩展性不足们现在的数据库是基于内存的,当数据量变大时就难以扩展。可以改用更高效的向量数据库,比如 Qdrant、Pinecone、pgvector 等。

  • 分片策略过于简单目前我们是以“句子”为一个片段。对于更复杂的任务,可能需要使用更精细的分块技术来拆分数据集,甚至在入库前对每个片段进行预处理(如去噪、摘要、关键词提取等)。

  • 语言模型规模有限示例中使用的语言模型只有 10 亿参数(1B),对于更复杂的任务,可能需要使用更大的模型来生成更高质量的回答。

其他类型的 RAG

在实际应用中,RAG 的实现方式多种多样。以下是几种常见类型:

  • Graph RAG(图结构 RAG)将知识源表示为图结构,节点代表实体,边表示实体之间的关系。模型可以在图中“漫游”以检索相关信息。目前这一方向的研究非常活跃,可以参考相关的 Graph RAG 论文合集。

  • Hybrid RAG(混合 RAG)结合知识图谱(Knowledge Graph, KG)与向量数据库技术,以提升问答系统的表现。

  • Modular RAG(模块化 RAG)这种 RAG 超越了传统的“检索—生成”两步流程,引入了路由、调度融合机制,从而形成一个灵活可重组的框架。它支持多种 RAG 模式(线性、条件、分支、循环等),能更好地应对复杂、知识密集型任务。

总结

RAG 的出现,让大模型能够更好地利用外部知识,显著提升了其准确性和实用性。

通过从零实现一个简单的 RAG 系统,我们理解了 embedding(向量表示)retrieval(检索)和 generation(生成)的核心概念。

尽管这个实现还很基础,但它展现了支撑实际生产环境中高级 RAG 系统的底层原理。

未来,RAG 的改进空间仍然广阔:从优化向量数据库的性能,到探索 Graph RAG、Hybrid RAG 等新架构,这一领域仍在快速演进中。RAG 将继续作为连接语言模型和外部知识的关键技术,帮助 AI 在保持生成能力的同时,变得更聪明、更可靠。

RAG 图书推荐

图片
《RAG极简入门:原理与实战》

张其来,徐思琪 | 著

一本注重 RAG 上手实践的书,没有堆术语,而是把整套 RAG 技术拆解得明明白白。

全书共 7 章内容,作者从背景原理讲起,到怎么搭框架、怎么处理数据、怎么做检索、生成、优化,每一块都有图、有例子,逻辑也特别清晰。甚至最后还贴心地加了个完整实战项目,让你从头跑一遍系统都不带卡壳的。

作者绘制了超多流程图,帮助你理解复杂的概念。

图片

如果你想把 RAG 真正用起来,这本书一定不要错过! 

图片

扫描进群,大模型知识学习不迷路👇

图片
原文链接:https://huggingface.co/blog/ngxson/make-your-own-rag#implement-the-retrieval-function

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询