RAG 是一种混合方法,既利用从数据存储(例如ChromaDB)检索特定信息,又利用LLM(例如Ollama 的 llama3.2 )的生成功能。这种组合可实现更准确、更符合上下文且更基于事实的输出。在这篇文章中,我们将探讨如何使用 Ollama 的 llama3.2进行文本生成和使用ChromaDB进行高效的信息检索来实现 RAG 。
检索增强生成 (RAG)是一种通过集成检索步骤来增强模型生成相关且明智响应的能力的方法。RAG 并不完全依赖预先训练的语言模型,而是从外部来源(例如数据库或知识库)检索相关文档或数据,并通过将检索到的数据输入模型来增强生成过程。这使模型能够根据实时、最新和特定于领域的信息生成答案。
例如,当提出一个问题时,RAG 不会仅仅基于模型的现有知识来生成响应,而是首先查询外部数据库(在我们的例子中是 ChromaDB)以检索最相关的信息,然后使用该信息作为生成响应的上下文。
Ollama 的 llama3.2是一款功能强大且性能卓越的 LLM,可处理各种文本生成任务,但与大多数 LLM 一样,它受到训练数据的限制。这意味着它可能无法访问特定或更新的信息。通过集成ChromaDB(专为高效文本检索而设计的高性能嵌入数据库),我们可以增强 llama3.2 将其答案建立在相关、可检索数据中的能力。这种方法提高了生成答案的准确性和相关性。
让我们来看看这个 RAG 设置的代码实现。我们将使用ChromaDB作为文档存储,使用Ollama 的 llama3.2作为生成模型。
1.安装所需的软件包
在开始之前,我们将安装该项目所需的软件包,即 ChromaDB 和 Ollama。
2.设置 ChromaDB
ChromaDB 用于存储和检索文档块。对于每个文档,我们还将存储相关元数据,例如页码。进行查询时,将从 ChromaDB 中检索最相关的块。
# 导入chromadb
# 初始化 ChromaDB 客户端
chroma_client = chromadb.PersistentClient(path= "./" ) # 我将其保存到当前目录文件路径
# 创建或获取集合
collection = chroma_client.get_or_create_collection(name= "my_collection" ) # 默认情况下,chromadb 集合使用 L2,您可以更改元数据以使用余弦相似度。
# 使用元数据将文本块更新插入 ChromaDB 的函数
def upsert_into_chromadb ( chunks, metadata ):
# 使用元数据和唯一 ID 将文档更新插入 ChromaDB
collection.add(
documents=chunks,
metadatas=metadata,
ids=[ f"chunk_ {i+ 1 } " for i in range ( len (chunks))] # 生成唯一 ID,如“chunk_1”、“chunk_2”等。
)
3.查询 ChromaDB
当用户提出问题时,ChromaDB 会根据输入查询来查询最相关的文档块。检索到的数据将传递给 LLM 以生成答案。
# 查询 ChromaDB
def query_chromadb ( prompt, n_results= 3 ):
# ChromaDB 将为查询生成嵌入并找到最相似的块
results = collection.query(
query_texts=[prompt], # Chroma 将为您嵌入
n_results=n_results,
include =[ "documents" , "metadatas" ] # 在结果中同时包含文档和元数据
) 返回结果
ChromaDB 返回的数据可能包含嵌套列表。我们将文档块及其相关元数据展平,以简化处理并确保对齐
# 展平文档列表
def flatten_documents ( documents ):
return [sentence for doc in documents for sentence in doc]
# 展平元数据列表
def flatten_metadatas ( metadatas ):
return [meta for meta_list in metadatas for meta in meta_list]
5.RAG 流程:检索和生成
RAG 过程包括从 ChromaDB 检索相关信息,然后使用 llama3.2 模型生成响应。
import ollama
def rag_process ( prompt, SYSTEM_PROMPT, filename ):
# 定义我用来模拟数据的文档和元数据。
chunks = [
“彼得潘是苏格兰小说家和剧作家JM Barrie创作的虚构人物......”,
“彼得潘喜欢冒险并且无所畏惧,经常与虎克船长战斗......”,
“彼得将温迪·达林和她的兄弟们带到了梦幻岛。他们经历了惊心动魄的冒险......”,
“彼得潘代表了永恒青春的复杂性。温迪最终回到了现实世界......”,
“彼得潘故事中的其他关键人物包括美国原住民公主虎莲......”,
“彼得潘的故事被改编成无数电影、戏剧和书籍......”,
“彼得潘是一个英俊的年轻人。”
]
metadata = [
{ "page" : "第 1 页" }, { "page" : "第 2 页" }, { "page" : "第 3 页" },
{ "page" : "第 4 页" }, { "page" : "第 5 页" }, { "page" : "第 6 页" },
{ "page" : "第 7 页" }
]
# 1. 使用元数据将块更新插入 ChromaDB
upsert_into_chromadb(chunks, metadata)
# 2. 查询 ChromaDB 以查找最相关的块
chromadb_results = query_chromadb(prompt, n_results= 3 )
# 展平文档和元数据的嵌套列表
flat_chunks = flatten_documents(chromadb_results[ "documents" ])
flat_metadata = flatten_metadatas(chromadb_results[ "metadatas" ])
# 连接最相关的扁平块
retrieved_chunks = []
for i, chunk in enumerate (flat_chunks):
if i < len (flat_metadata):
metadata_entry = flat_metadata[i]
if metadata_entry and isinstance (metadata_entry, dict ):
retrieved_chunks.append( f" {chunk} (来源:{metadata_entry.get( '页面' , '没有可用页面' )} )” )
else :
retrieved_chunks.append( f" {chunk} (来源:元数据缺失)" )
# 3. 使用聊天方法生成带有证据和来源的响应
full_retrieved_chunks = " " .join(retrieved_chunks)
response = ollama.chat(
model= "llama3.2" ,
messages=[
{
"role" : "system" ,
"content" : f" {SYSTEM_PROMPT} \nContext:\n {full_retrieved_chunks} "
},
{
"role" : "user" ,
"content" : f"回答这个问题:{prompt}在你的答案中包含来源。"
}
]
)[ "message" ][ "content" ]
return response
6.定义系统提示符
系统提示向 LLM 提供指令,以确保它在引用证据和提供元数据的同时根据检索到的上下文生成响应。
SYSTEM_PROMPT = """
你是一个有用的人工智能助手,仅使用提供的上下文回答问题。
对于每个答案,请包括以下内容:
1. 直接引用相关文本作为答案的证据。2
. 提供引用证据的来源,包括页码或文档 ID 等元数据。3
. 回答时尽量简洁。
如果您不确定或上下文没有提供足够的信息,只需说“我不知道”。
上下文:
"""
检索增强生成 (RAG)是一种强大的方法,它通过将响应建立在可检索数据中来提高 AI 生成内容的准确性和相关性。通过结合Ollama 的 llama3.2和ChromaDB的功能,我们可以确保生成的响应不仅准确,而且还有可验证的证据支持。此设置对于需要高事实准确性的应用程序特别有用,例如问答系统、研究工具和教育平台。
通过这种混合方法,人工智能生成的内容未来可以既智能又信息丰富——不仅依赖于预先训练的知识,还依赖于实时、特定于查询的数据检索。
完整代码可在后台私信获取!!!!
powered by kaifamiao