掘金 人工智能 10月08日 19:53
本地化RAG技术:打造专属AI知识问答应用
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文详细介绍了如何利用检索增强生成(RAG)技术,搭建一个全开源、全本地的AI问答应用。文章首先解释了RAG的核心原理,即结合外部知识库与大模型进行问答,以提升回答的准确性和时效性。随后,作者通过实际代码演示,指导读者完成环境配置、PDF文本提取、文本分块、向量化,并利用ChromaDB构建本地知识库。最后,文章展示了如何构建包含检索上下文的提示词,并交由本地大模型(通过LM Studio运行)生成精准答案。整个过程强调了DIY的乐趣和灵活性,并为后续优化和扩展提供了方向。

💡 RAG技术核心:通过“检索增强生成”(Retrieval-Augmented Generation, RAG)技术,可以为通用大模型注入特定领域的知识,使其在回答用户问题时更加精准,有效解决“一本正经地胡说八道”的问题。RAG的核心思想是先从一个外部知识库中检索相关信息,再将这些信息与用户的问题一同交给大模型,让模型基于这些“参考资料”生成答案。

🛠️ 本地化开发环境搭建:文章提供了一套完整的本地化开发流程,无需依赖云服务。通过Python的`pymupdf`、`openai`(用于连接本地服务)、`numpy`和`chromadb`库,以及LM Studio软件,用户可以在自己的电脑上搭建起一个完整的RAG问答系统。这大大降低了AI应用的门槛,实现了“AI成为专属知识问答专家”的愿景。

📚 构建智能检索系统(R):该部分详细介绍了如何将原始文档转化为可检索的知识库。包括使用`pymupdf`从PDF提取文本,将长文本分割成易于处理的“知识块”(Chunks),利用本地大模型进行文本向量化(Embedding),以及使用`chromadb`作为向量数据库存储和索引这些信息,从而实现高效的语义检索。

✍️ 增强答案生成(G):在检索到相关信息后,文章展示了如何通过精心设计的提示词(Prompt)将检索到的上下文信息与用户问题结合起来。这个提示词模板要求模型严格依据提供的参考资料回答,避免生成虚假信息,从而实现了“有理有据”的答案生成,提升了AI回答的可靠性。

本文较长,建议点赞收藏。更多AI大模型应用开发学习视频及资料,在智泊AI

你是否曾遇到过这样的窘境:当你问一个通用大模型(比如DeepSeek)关于你公司内部文档、专业领域论文或者某个小众爱好的问题时,它总是始一本正经地胡说八道?

这不怪大模型,毕竟大模型在训练的时候没有学习过我们的专属知识。但如果我们能给它“开小灶”,让它在回答问题前,先“阅读”一下我们指定的资料,那效果会不会炸裂?

答案是肯定的!这就是我们今天要介绍的主角—— RAG(Retrieval-Augmented Generation,检索增强生成) 技术。

简单来说,RAG就像是给大模型配上了一个可以随时查阅的“开卷考试”资料库。当用户提问时,系统会先从这个资料库里检索出最相关的内容,然后把这些内容连同问题一起交给大模型,让它根据这些“参考资料”来生成最终答案。

这样做的好处显而易见:

    提升准确性:有效减少模型“幻觉”,让回答都有据可循。知识实时更新:只需更新我们的知识库,就能让模型掌握最新信息。降低成本:无需重新训练一个庞大的模型,省时又省钱。

今天我们尝试使用全开源、全本地的工具,搭建一个属于我们自己的RAG问答应用。我们只需要一台能跑得动本地模型的电脑,就能让AI成为我们专属的知识问答专家!

准备工作:我们的“兵器库”

在开始之前,我们需要先配置好开发环境。打开你的终端,运行以下命令来安装所有必需的Python库:

pip install pymupdf openai==1.99.0 numpy chromadb pydantic==2.11.0

同时,请确保你已经安装并运行了 LM Studio。

什么是LM Studio? LM Studio是一款能让你在个人电脑上(Windows/Mac/Linux)轻松下载、管理和运行各种开源大模型的软件。它还提供了一个与OpenAI API兼容的服务端点,让我们可以像调用官方API一样调用本地模型。 操作步骤:

    前往 lmstudio.ai 下载并安装。在应用内搜索并下载一个适合中文的开源模型(例如 Qwen、Yi 或 DeepSeek 系列的GGUF格式模型)。切换到 "developer" 标签页,选择你下载好的模型,然后点击 "开发者"标签,将"status"切换为start。

第一部分:RAG之“R” - 构建智能检索系统

这部分是RAG的基石,我们将完成从原始文档到可检索知识库的转化。

第1步:知识注入 - 从PDF中提取文本

万丈高楼平地起,我们的第一步是建立知识库。这里,我们以一个PDF文件(PDF文件需要那些内容都是文字形式的,如果PDF内容都是图片将无法解析)为例,你可以将其换成任何你希望AI学习的中文文档。

import fitz  # PyMuPDF库import osdefextract_text_from_pdf(pdf_path):    """从PDF文件中提取纯文本内容。"""    try:        doc = fitz.open(pdf_path)        full_text = ""        for page in doc:            full_text += page.get_text("text")        doc.close()        return full_text    except Exception as e:        print(f"读取PDF失败: {e}")        returnNone# 为了方便演示,如果PDF不存在,我们直接使用一段示例文本# 你可以创建自己的 "data" 文件夹和 "人工智能简史.pdf" 文件ifnot os.path.exists("data"):    os.makedirs("data")pdf_path = "data/LLMBook.pdf"if os.path.exists(pdf_path):     extracted_text = extract_text_from_pdf(pdf_path)else:    print("PDF文件未找到,将使用内置的示例文本。")    extracted_text = """2022 年底,ChatGPT震撼上线,大语言模型技术迅速“席卷”了整个社会,人工智能技术因此迎来了一次重要进展。面对大语言模型的强大性能,我们不禁要问:支撑这些模型的背后技术究竟是什么?这一问题无疑成为了众多科研人员的思考焦点。必须指出的是,大模型技术并不是一蹴而就,其发展历程中先后经历了统计语言模型、神经网络语言模型、预训练语言模型等多个发展阶段,每一步的发展都凝结了众多科研工作者的心血与成果。作为大语言模型技术的重要推动者,OpenAI公司引领了本次技术变革,让我们再次回顾其针对大模型技术的研发历程。2015年,OpenAI 公司正式创立,开始探索通用人工智能的技术路线。早期的OpenAI团队围绕强化学习、多模态、语言模型等几个重要方向进行了深入研究。其中,由Ilya Sutskever 领导的团队主要关注语言模型的研究。当谷歌2017年推出基于注意力机制的Transformer模型后,OpenAI团队迅速洞察到了其潜在的优越性,认为这种模型可能是一种大规模可扩展训练的理想架构。基于此,OpenAI团队开始构建GPT系列模型,并于2018年推出了第一代GPT模型—GPT-1,能够通过“通用文本训练-特定任务微调”的范式去解决下游任务。接下来,GPT-2和GPT-3模型通过扩大预训练数据和模型参数规模,显著提升了模型性能,并且确立了基于自然语言形式的通用任务解决路径。在GPT-3的基础上,OpenAI又通过代码训练、人类对齐、工具使用等技术对于模型性能不断升级,推出了功能强大的GPT-3.5系列模型。2022年11月,ChatGPT正式上线,能够以对话形式解决多种任务,使得用户能够通过网络API体验到语言模型的强大功能。2023年3月,OpenAI推出了标志性的GPT-4模型,将模型能力提升至全新高度,并将其扩展至拥有多模态功能的GPT-4V模型。反观GPT系列模型的发展历程,有两点令人印象深刻。第一点是可拓展的训练架构与学习范式:Transformer架构能够拓展到百亿、千亿甚至万亿参数规模,并且将预训练任务统一为预测下一个词这一通用学习范式;第二点是对于数据质量与数据规模的重视:不同于BERT时代的预训练语言模型,这次大语言模型的成功与数据有着更为紧密的关系,高质量数据、超大规模数据成为大语言模型的关键基础。上述的思路看似简单,但能够从早期众多的技术路线中寻找到这条路线,并且坚定地去执行这条路线,这就是OpenAI成功的关键所在。回顾OpenAI的早期论文,实际上早在GPT-2的论文中,就深入讨论了基于大规模文本预训练的通用任务学习范式,让人不禁感叹OpenAI团队的技术前瞻性。虽然这种研究模式很难复制,但是值得我们去思考、学习。"""# print(extracted_text[:200]) # 打印前200个字符看看

第2步:文本分块 - 把“大象”装进“冰箱”

直接把整篇文章丢给模型是不现实的,太长的文本会超出模型的“记忆”上限(上下文窗口)。因此,我们需要把长文本切分成一个个更小、更易于管理和检索的“知识块”(Chunks)。

def chunk_text(text, chunk_size=300, overlap=50):    """    将文本按指定大小和重叠率进行分块。        参数:    text (str): 待分块的文本。    chunk_size (int): 每个块的理想字符数。    overlap (int): 相邻块之间的重叠字符数,有助于保持上下文连续。        返回:    list[str]: 文本块列表。    """    chunks = []    start = 0    while start < len(text):        end = start + chunk_size        chunks.append(text[start:end])        start += chunk_size - overlap    return chunkstext_chunks = chunk_text(extracted_text)print(f"文本被分成了 {len(text_chunks)} 个块。")print("--- 第一个块示例 ---")print(text_chunks[0])

第3步:向量化 - 让文字变成“数学”

计算机不理解文字,只懂数字。为了让计算机能“理解”文本并比较其相似度,我们需要将文本块转换成一串数字,这个过程叫做嵌入(Embedding),生成的结果就是向量(Vector)。

我们将使用本地LM Studio服务来生成这些向量。你需要确保在LM Studio中加载的模型支持生成嵌入向量(大部分模型都支持)。

from openai import OpenAIimport numpy as np# 配置客户端,使其指向你的本地LM Studio服务器client = OpenAI(base_url="http://localhost:1234/v1", api_key="not-needed")defcreate_embeddings(chunks, model="text-embedding-qwen3-embedding-0.6b"):    """使用本地模型为文本块列表创建向量嵌入。"""    # 注意:LM Studio可能默认使用其加载的聊天模型进行嵌入,    # model参数可能不会切换模型,但仍建议填写以保持代码清晰。    response = client.embeddings.create(        model=model,        input=chunks    )    # 从响应中提取嵌入向量    embeddings = [np.array(data.embedding) for data in response.data]    return embeddings# 为我们所有的文本块创建向量chunk_embeddings = create_embeddings(text_chunks)print(f"成功为 {len(chunk_embeddings)} 个文本块创建了向量。")print(f"每个向量的维度是: {len(chunk_embeddings[0])}")

第4步:向量入库 - 用ChromaDB构建知识索引

现在我们有了文本块和对应的向量,是时候把它们存入专业的向量数据库ChromaDB了。这就像是为我们的知识建立了一个高效的索引,方便后续快速查找。

import chromadb# 1. 初始化ChromaDB客户端# 这会在你的项目目录下创建一个 .chroma 文件夹来持久化存储数据chroma_client = chromadb.Client()# 2. 创建一个集合(Collection),类似于数据库中的一张表# 如果集合已存在,先删除再创建,确保我们从一个干净的状态开始collection_name"ai_history_db"if collection_name in [c.name for c in chroma_client.list_collections()]:    chroma_client.delete_collection(name=collection_name)collection = chroma_client.create_collection(name=collection_name)# 3. 将文本块、向量和唯一ID存入集合# 我们需要为每个块创建一个唯一的IDchunk_ids = [str(i) for i inrange(len(text_chunks))]collection.add(    embeddings=chunk_embeddings,    documents=text_chunks,    ids=chunk_ids)print(f"知识库 '{collection_name}' 创建并填充完毕!")

第5步:语义检索 - 智能查询

知识库建好了,现在来试试效果。我们定义一个函数,它接收一个问题,将其向量化,然后在ChromaDB中查询最相似的文本块。

def semantic_search(query, k=3):    """    在ChromaDB中执行语义搜索。    参数:    query (str): 用户的查询问题。    k (int): 需要返回的最相关文本块的数量。    返回:    list[str]: 包含最相关文本块的列表。    """    # 1. 将查询问题也转换成向量    query_embedding = create_embeddings([query])[0]        # 2. 在集合中查询最相似的 k 个结果    results = collection.query(        query_embeddings=[query_embedding.tolist()], # 查询向量需要是 list 格式        n_results=k    )        return results['documents'][0]# 测试一下!my_query = "大模型有什么特点?"relevant_chunks = semantic_search(my_query)print(f"对于问题: '{my_query}'")print("\n--- 检索到的相关信息如下 ---")for i, chunk inenumerate(relevant_chunks):    print(f"【相关片段 {i+1}】\n{chunk}\n")

第二部分:RAG之“G” - 结合上下文生成答案

检索(R)部分已经完成!我们成功地根据问题找到了相关的“参考资料”。现在,我们进入生成(G)部分,让本地大模型基于这些资料,给出精准的回答。

第6步:构建提示词(Prompt)

这是RAG的“灵魂”所在。我们不能只把问题丢给模型,而是要创建一个包含“指令”、“上下文(检索到的知识)”和“用户问题”的完整提示词。

def build_prompt(query, context_chunks):    """构建最终的提示词。"""        context = "\n\n".join(context_chunks)        # 一个优秀的提示词模板至关重要    prompt_template = f"""你是一个严谨的AI问答助手。请严格根据下面提供的“参考资料”来回答用户的问题。不要编造任何参考资料中没有的信息。如果资料无法回答问题,请回复:“根据我手头的资料,我无法回答这个问题。”--- 参考资料 ---{context}--- 用户问题 ---{query}--- 你的回答 ---"""    return prompt_template# 构建最终的提示词final_prompt = build_prompt(my_query, relevant_chunks)print("--- 发送给大模型的最终提示词 ---")print(final_prompt)

第7步:生成最终答案

万事俱备,只欠东风!我们将这个精心构造的提示词发送给在LM Studio中运行的大模型,获取最终答案。

def generate_response(prompt, model="qwen3-14b-128k"):    """使用本地大模型生成回答。"""        # client 已经在前面初始化过了    response = client.chat.completions.create(        model=model, # 'qwen3-14b-128k' 是LM Studio的默认占位符        messages=[            {"role""user""content": prompt}        ],        temperature=0.7# temperature可以控制回复的创造性,对于问答,低一点好    )    return response.choices[0].message.content# 获取最终答案!final_answer = generate_response(final_prompt)print("\n\n============ 最终回答 ============")print(final_answer)

示例输出可能如下:

============ 最终回答 ============

根据提供的资料,大模型(Large Language Model, LLM)具有以下特点:

    性能提升趋势的多样性
    训练过程复杂性与成本高
    数据依赖与潜在局限

训练数据在开始前需完成采集,可能导致信息过时或知识错误。因此,需要有效的微调策略以注入更新后的知识。

    特定任务的显著优势
    学术关注度高

看到这个结果了吗?大模型没有泛泛而谈,有使用了我们提供的《LLMBook.pdf》中的内容来回答问题,但是回答的效果貌似没有最优,但是后续我们可以通过一些列的优化措施进行优化,提升RAG的效果。

总结与展望

我们已经成功地走完了一个最简RAG应用的完整流程,从数据处理到本地部署,全程DIY!

回顾一下我们的旅程:

    环境配置:安装了必要的库,并启动了LM Studio本地服务。知识检索 (R):我们提取、分块、向量化了PDF文本,并使用ChromaDB构建了一个可随时查询的本地知识库。增强生成 (G):我们将检索到的知识与用户问题整合成一个强大的提示词,并交由本地大模型生成了有理有据的答案。

这只是一个开始。基于这个框架,我们可以继续探索:

学习资源推荐

如果你想更深入地学习大模型,以下是一些非常有价值的学习资源,这些资源将帮助你从不同角度学习大模型,提升你的实践能力。

本文较长,建议点赞收藏。更多AI大模型应用开发学习视频及资料,在智泊AI

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

RAG 检索增强生成 本地化AI 大模型 问答系统 ChromaDB LM Studio AI应用开发 LLM Retrieval-Augmented Generation Local AI Large Language Models Q&A System AI Application Development
相关文章