RAG系统从零构建:Python与Ollama实战指南

从零构建RAG系统,用Python和Ollama实现检索增强生成,提升大模型表现,实用教程!

原文标题:从零实现一个简单的 RAG 系统

原文作者:图灵编辑部

冷月清谈:

检索增强生成(RAG)作为人工智能和大模型领域的新范式,它通过结合信息检索和文本生成,有效解决了传统大模型无法访问最新信息或特定领域知识的问题,显著提升了模型的准确性和实用性。文章深入剖析了RAG的运作机制,并带领读者使用Python和Ollama从零搭建了一个基础的RAG系统

RAG系统由检索模型和生成模型两大核心组成。在构建过程中,主要依赖Embedding模型将文本转换为语义向量,使用向量数据库存储向量化后的知识片段,并借助聊天机器人根据检索结果生成回答。其中,索引阶段负责将数据集切分成小片段并向量化存储,检索阶段则通过计算查询向量与数据库中向量的相似度(如余弦相似度)来查找最相关的知识片段。生成阶段会将这些相关片段作为提示语(prompt)的一部分输入给大型语言模型,从而生成最终的答案。

文章通过实际代码示例,展示了如何用Ollama加载预训练的Embedding模型和语言模型,实现向量化、余弦相似度计算和检索功能。它还探讨了当前简单RAG系统的局限性,例如无法处理多主题问题、检索排序不够精准、数据库可扩展性不足以及分片策略过于简单等,并提出了如重排序模型、高效向量数据库和复杂分块技术等改进方向。此外,文章还介绍了Graph RAG、Hybrid RAG和Modular RAG等更高级的实现方式,预示了RAG未来广阔的演进空间。

怜星夜思:

1、文章里提到RAG系统在处理多主题问题、检索结果排序精准度等方面还有改进空间。如果让你在一个实际项目中优先解决其中一个局限性,你会选哪个?为什么呢?有没有什么具体的思路或者技术方案可以分享?
2、文章中提到了Qdrant、Pinecone、pgvector等多种向量数据库。大家在实际开发或者学习中都用过哪些向量数据库?有没有什么特别推荐的或者踩过什么“非典型”的坑?
3、除了文章中提到的Graph RAG、Hybrid RAG、Modular RAG,大家觉得RAG技术还有哪些潜在的发展方向?或者换个角度,哪些行业或者应用场景中,RAG的潜力会得到爆发式的释放?

原文内容

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

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

在这篇文章中,作者将带你深入了解 RAG 的工作原理,并使用 Python 和 ollama 从零构建一个简单的 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-gguf
ollama pull hf.co/bartowski/Llama-3.2-1B-Instruct-GGUF

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

pulling manifest
...
verifying sha256 digest
writing manifest
success

在继续之前,为了在 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 ollama
EMBEDDING_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-time
print('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 speed
Retrieved 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-the-retrieval-function

Q3 这事儿就像点外卖和自己做饭的区别吧!ollama 本地部署,那就是自己买菜自己做,省钱、食材(数据)安全放心,但得自己洗菜切菜(配置环境、更新模型),还得有大厨房(高性能显卡)。云端 API 呢,就是点外卖,方便快捷,味道(效果)好,想吃啥都有(模型多),但每顿饭(每次调用)都要花钱,而且食材(数据)是不是新鲜,你就只能信商家了。所以我一般是,自己探索美食(研究 RAG)的时候就自己做,请客吃饭(商业应用)的时候就点外卖,毕竟‘好吃不贵’才是硬道理,哈哈!

关于分片策略,我认为没有一劳永逸的最佳方案。核心在于平衡信息粒度与上下文完整性。例如,对于精准问答系统,可能倾向于较小的片段(如句子或语义单元),以减少无关信息干扰;对于需要广泛综合的摘要任务,大片段(如段落或固定字符数)可能更有利于保留上下文。实践中常采用重叠分块或基于内容结构(如Markdown标题)的分块策略,再结合实验性评估(如使用RAGAS框架)来优化。

分块策略确实是个大学问!我遇到过最“考验智商”的场景是处理法律合同文档。这些文档结构非常复杂,包含很多条款、子条款、定义和引用。如果简单按句子或固定长度切分,很容易把一个完整条款拆开,或者把条款的重要上下文丢失。我的小妙招是结合结构化信息进行分块:比如,先识别文档的逻辑结构(章节、段落、列表),然后在一个逻辑单元内,再考虑语义聚合。我会尝试使用递归字符拆分器(RecursiveCharacterTextSplitter),它能根据一系列分隔符(如\n\n, \n, .等)递归地切分,这样既能保留结构的完整性,又能避免片段过长。有时甚至需要自定义分隔符来准确捕捉特定文档类型中的语义边界。

内存向量库就像我们大脑里短期记忆,零散而快速。一旦知识量庞大了,我们就需要一个更结构化、更系统化的’图书馆’来存储,这就是专业向量数据库的意义。它们不仅仅是存储,更重要的是提供了高效的索引和检索算法,甚至能处理复杂的过滤条件和多模态向量。什么时候升级,我觉得核心是看你的‘知识库’有多复杂,以及‘查询速度’有多重要,毕竟你的用户可不会一直等你的内存数据库慢悠悠地匹配,性能上去了才能有更好的用户体验。

我之前也用过内存库,跑几个小 demo 还行。后来数据量一上来,每次启动程序都要重新构建索引,特别慢,而且还容易吃满内存。换到 Qdrant 之后,感觉世界都清净了。它支持增量更新,而且检索速度真的快好多。对于个人项目或者小团队,Qdrant 社区版就很够用了,部署起来也不复杂,有些同学用 Docker 跑起来很方便。Pinecone 这些托管服务,适合那些不想自己操心运维,直接用 API 开箱即用的团队,但费用肯定是会比自己部署开源的要高一些。

问得好!内存向量库在学习和原型验证阶段确实很好用,代码简单直观。但如果你的数据量开始达到几千甚至上万条,并且对检索速度、并发访问有要求,就得考虑升级了。Qdrant、Pinecone这些专业库的优势在于它们为向量搜索做了深度优化,支持分布式、持久化、过滤、高并发等特性。
选型上,可以先看看数据规模和未来增长预期。小规模、注重本地部署和控制成本的可以考虑 pgvector(基于PostgreSQL)或 Qdrant(开源,安装部署较灵活);如果对扩展性要求极高、预算充足,且希望享受托管服务, PineconeWeaviate 这类云原生服务会是强项。
简单来说,从数据量性能要求预算运维能力去权衡,基本就能做出选择了。

问到向量数据库选择,我觉得主要得看你的业务场景和预算。“成本、易用性、性能”这三点非常关键。像Qdrant和Pinecone,性能都不错,但一个倾向于开源自部署,一个更多是云服务。自部署灵活性高,但维护成本高;云服务开箱即用,但长期成本可能更高。还有就是查询速度、数据量、是否支持混合查询(结合常规SQL条件)、以及社区活跃度也是我考虑的重点。如果是小型项目,pgvector可能就够了。

嘿,回答关于分块的问题!这简直就是个艺术活儿!我之前做项目,为了分块大小,团队吵了两天。最后发现,哪有什么标准答案,就得多试!我们甚至试过把一整篇新闻稿按段落分,结果用户问个日期都找不到。后来改按句子分,又太碎。现在流行用一些带语义分割能力的工具,比方说LangChain里就有不少现成的,省心。反正就是一句话:根据你的数据特性和你想解决的问题,灵活调整,没有银弹!

这个问题很好!RAG和Fine-tuning是LLM增强的两种主流策略,各有侧重。RAG的优势在于能够访问最新、动态的外部知识,且不需要重新训练模型,对知识更新迅速的领域非常友好,成本相对较低。Fine-tuning则是在模型的参数层面进行调整,让模型“学习”特定领域的语言风格和事实,对于需要理解复杂语境、生成高度专业化文本的场景效果显著,但更新知识成本高,且容易出现“幻觉”。通常,两者可以结合使用,先Fine-tune模型使其掌握领域知识和风格,再用RAG提供实时、精准的外部信息。

简单的RAG面临的关键挑战是其基于局部相似性的检索可能忽略知识的结构化关联和推理能力。Graph RAG通过将知识表示为图,能捕捉实体间复杂的语义关系,支持多跳推理,解决多事实、复杂逻辑问题的能力远超传统RAG。Hybrid RAG则结合了结构化(知识图谱)和非结构化(向量)知识的优势,旨在提升检索的全面性与准确性。它们的核心不同在于将单点匹配提升至关系网络与多模态匹配,更接近人类的知识组织与推理方式。

针对向量数据库的选型,除了性能、扩展性与成本,数据治理与安全属性亦是关键考量。例如,对数据敏感性高的应用,需关注其权限管理、数据加密及合规性认证;对实时性要求高的系统,则需评估其写入延迟与索引更新机制。此外,生态系统的成熟度、社区支持以及与现有技术栈的集成便利性也至关重要,以确保长期可维护性与开发效率。

问到RAG的优先级改进,我个人认为数据库可扩展性不足是一个比较紧迫的问题。现在文章里用的是内存版数据库,跑个小Demo没问题,但在生产环境里,数据量动辄就是TB甚至PB级别,内存数据库肯定顶不住啊!一旦数据量上来了,性能瓶颈马上暴露。

解决思路嘛,就是尽快迁移到专业级的向量数据库,比如Qdrant、Pinecone或者Milvus。这些数据库都是为大规模向量检索优化的,支持分布式部署、高并发查询、持久化存储等等。选哪个就看具体需求和团队熟悉度了。当然,迁移过程中也要考虑数据一致性、索引构建效率这些问题。毕竟,RAG落地第一步,得要有个能装下所有知识的“大仓库”才行!

关于“RAG的潜在发展方向”,我认为**“多模态RAG”会是一个非常重要的趋势。目前RAG主要处理文本信息,但未来随着多模态大模型的普及,我们需要RAG能够检索和理解图像、视频、音频等多种形式的知识源。例如,用户可以提问关于某个视频内容的问题,RAG系统能够从视频片段中检索出相关信息并生成回答。这无疑会极大地拓展RAG的应用边界。

至于“行业爆发点”,我非常看好
医疗健康领域**。医生和研究人员需要快速获取最新的医学文献、临床指南、患者病例等。RAG系统可以帮助他们从海量、复杂的医疗数据中精准检索信息,并以自然语言的形式提供摘要和建议,显著提高诊断效率和治疗效果。法律、金融等知识密集型行业也同样潜力巨大。

针对“RAG技术发展方向”,我想到的是**“自适应RAG(Adaptive RAG)”或者“智能RAG策略选择”。现在RAG通常采用一个固定的检索和生成流程,但不同的用户查询、不同的知识领域可能需要不同的检索策略、不同的生成方式。未来的RAG系统也许能够根据问题的复杂性、用户意图,甚至用户的历史偏好,动态地调整其检索和生成策略,例如是进行单次检索、多次迭代检索,还是结合知识图谱进行推理等。

对于“爆发式增长的应用场景”,我认为
智能教育和在线学习**会是一个非常契合RAG的领域。学生在学习过程中会遇到各种问题,RAG可以像一个私人导师一样,结合课程内容、教材知识点,甚至学生的学习进度和薄弱环节,为其提供个性化的、深入浅出的解释和补充材料,极大地提升学习效率和体验。

我个人体验过Pinecone,主要是因为它提供了托管服务,省去了自己部署、维护的麻烦。对于初期的小团队或者快速验证项目来说,Pinecone确实很友好,上手快,文档也挺清晰的。

不过,要说“非典型”的坑,我觉得主要还是成本问题。如果你的数据量和查询量增长得很快,Pinecone的费用可能会成为不小的压力。当然,这是所有托管服务都会面临的问题。另外,由于是托管服务,在一些高度定制化的需求上,或者当你需要深入底层进行性能调优时,可能会感到有些受限。所以,选择Pinecone前,最好能预估一下未来的规模和预算。

哈哈,说到“向量数据库”的坑,我得说说pgvector!一开始觉得用PostgreSQL自带的扩展,多优雅啊,不用额外部署一个服务,管理也方便。但真用起来,数据量一上去,那检索速度简直是龟速!我的项目里只有几十万条向量,查询就已经慢到让人发指了。

所以我的经验是,pgvector适合那种数据量不大、QPS要求不高,或者你已经有一套成熟的PostgreSQL运维体系,不想引入新组件的场景。但如果追求高性能和可扩展性,还是老老实实上专业的向量数据库吧,比如Milvus或者Qdrant。千万别为了图省事,把整个RAG系统的性能都拖垮了!血泪教训啊!

哎呀,这问题问得好!要是让我选,肯定选**“无法处理多主题问题”这个。你想啊,现在用户问的问题越来越复杂,一个问题里可能涉及到好几个不同的方面。如果RAG只能根据一个查询来检索,那肯定会漏掉很多关键信息,导致回答四不像。

我的思路是,可以试试让大模型自己
“拆解”用户的问题**。用户输入一个复杂问题后,先让LLM把这个问题分解成几个子问题,然后为每个子问题生成一个独立的检索查询。把这几个查询都扔到向量数据库里检索一遍,最后把所有相关片段汇集起来,再让LLM综合这些信息给出最终答案。这样虽然会增加一些计算量,但肯定能让RAG变得更“聪明”,处理复杂场景的能力会大大提升!

关于“RAG系统改进空间”的问题,我觉得在实际项目中,我会优先解决检索结果排序精准度这个问题。原因很简单,如果前端召回的知识片段就不够准确或者相关度不高,那后面生成模型再怎么聪明也无济于事,所谓“巧妇难为无米之炊”。

具体的改进思路可以是引入一个重排序(Re-ranking)模型。它可以在初步检索出 Top-N 个片段后,再根据查询的完整语境对这些片段进行更细致的打分和排序。比如,可以使用基于BERT或更复杂Transformer结构的交叉注意力模型,让它同时考虑查询和每个检索到的片段,从而更全面地评估它们的语义相关性。这样可以有效过滤掉表面相似但深层无关的片段,把最精华的内容送给LLM,显著提升最终回答的质量和相关性。

关于“用过的向量数据库”这个问题,我们公司目前主要用的是Qdrant,因为它开源、部署灵活,而且社区活跃度也挺高。性能方面,对于我们目前的数据规模(千万级别向量)和QPS(每秒查询次数),表现都还不错,检索速度和准确性都能满足要求。

踩过的“坑”嘛,主要是初期在部署和参数调优上花了不少时间。比如,Qdrant的索引类型(HNSW、Flat等)和HNSW参数(m、ef_construct等)对检索性能和内存占用影响很大,需要根据你的向量维度、数据分布和查询需求仔细测试和选择。另外,数据备份和恢复策略也需要提前规划好,毕竟数据安全是第一位的。总体而言,Qdrant是一个非常值得推荐的选择,但前期投入学习和实践是必不可少的。