Type something to search...
构建rag系统的完整指南:使用nvidia 10-k文件实现数据驱动的生成与检索

构建rag系统的完整指南:使用nvidia 10-k文件实现数据驱动的生成与检索

与NVIDIA最新的10-K文件聊天

作者提供的图片。

在本教程中,我们将探索使用NVIDIA最新的10-K文件作为数据源创建检索增强生成(RAG)系统

RAG结合了检索生成,从给定的数据集中提供基于事实和上下文的答案。

这种方法确保响应基于提供的信息,从而最小化与语言模型相关的幻觉。

在本教程结束时,我们将构建一个管道,该管道:

  1. 从SEC EDGAR数据库下载并处理真实的金融数据。
  2. 将数据拆分和分块以实现高效的检索。
  3. 将分块嵌入高维空间,以便使用FAISS进行相似性搜索。
  4. 为给定查询检索相关信息。
  5. 使用大型语言模型(LLM)生成连贯且准确的答案。

为什么检索增强生成?

它非常适合以下任务:

  • 总结公司报告。
  • 为特定领域的问题提供上下文答案。
  • 使用户能够“与他们的数据聊天。”

教程概述

我们将使用 NVIDIA 最新的 10-K 文件 作为我们的数据集。以下是我们将要涵盖的内容:

  1. 数据获取:如何直接从 SEC EDGAR 数据库获取最新的 10-K 文件。
  2. 数据预处理:将内容拆分为可管理的块,并具有重叠的上下文。
  3. 嵌入和索引:利用 sentence-transformers 进行嵌入,并使用 FAISS 进行高效的相似性搜索。
  4. 查询数据:检索与用户查询相关的块。
  5. 基于上下文的回答:使用预训练的大型语言模型生成基于检索信息的答案。

在我们开始之前

如果您在 Google Colab(或任何其他云平台)上运行此代码,请确保已安装所有必要的依赖项。

运行以下代码块以安装所需的软件包:

%%capture
!pip install transformers faiss-gpu==1.7.2 sentence-transformers==3.0.1

加载最新的 NVIDIA 年度财务报表

您无需理解或甚至阅读以下代码。

import requests
from bs4 import BeautifulSoup

def get_latest_10k_text(cik):
    """
    获取给定公司 CIK 的最新 10-K 文件,并将内容作为单个文本返回。

    参数:
        - cik (str): 公司的 CIK 号码。

    返回:
        - str: 最新 10-K 文件的文本内容。
    """

    base_url = "https://data.sec.gov/submissions/"
    headers = {"User-Agent": "YourName [email protected]"}

    response = requests.get(f"{base_url}CIK{cik}.json", headers=headers)
    response.raise_for_status()
    data = response.json()

    filings = data["filings"]["recent"]
    for i, form_type in enumerate(filings["form"]):
        if form_type == "10-K":
            accession_number = filings["accessionNumber"][i].replace("-", "")
            file_url = f"https://www.sec.gov/Archives/edgar/data/{cik}/{accession_number}/index.json"
            break
    else:
        raise ValueError("未找到给定 CIK 的 10-K 文件。")

    filing_response = requests.get(file_url, headers=headers)
    filing_response.raise_for_status()
    filing_data = filing_response.json()

    primary_doc = None
    for doc in filing_data["directory"]["item"]:
        if doc["name"].endswith(".htm") or doc["name"].endswith(".txt"):
            primary_doc = doc["name"]
            break

    if not primary_doc:
        raise ValueError("无法在文件中找到主要文档。")

    filing_url = f"https://www.sec.gov/Archives/edgar/data/{cik}/{accession_number}/{primary_doc}"
    filing_content = requests.get(filing_url, headers=headers).text

    soup = BeautifulSoup(filing_content, "html.parser")
    text_content = soup.get_text(separator=" ", strip=True)

    return text_content

cik = "0001045810"  
try:
    latest_10k_text = get_latest_10k_text(cik)
    print(latest_10k_text[:1000])  
except Exception as e:
    print(f"错误: {e}")

输出:

我们将仅保留项目 1 和项目 1A 用于本项目。

latest_10k_text = latest_10k_text[30332:185600]

步骤 1. 将文本分割成块

首先,让我们将文本分割并创建一个包含所有句子的列表。

sentences = [sentence.strip() for sentence in latest_10k_text.split('.') if sentence.strip()]

len(sentences)

输出:

如果按字符“.”分割,我们得到了 878 个句子。

我们可以直接使用这些句子来创建块,但我们将使用 重叠块

在处理用于检索系统的文本时,确保没有关键信息丢失是至关重要的。

这对于那些思想和事实常常跨越多个句子或部分的文档尤其重要。

一种称为 重叠块 的技术可以帮助保持上下文的连贯性和相关性。

重叠块包括来自周围文本的部分句子,确保每个块的边界保留相邻部分的上下文。

这种方法最小化了在将文本分割成离散部分时可能发生的意义丧失。

例如,如果我们将文本分成三个句子的块,并重叠一个句子:

  • 块 1: 句子 1, 2, 3
  • 块 2: 句子 3, 4, 5
  • 块 3: 句子 5, 6, 7

注意,每个块与前一个块共享一些句子,这提高了上下文的连贯性,并确保没有重要信息被遗漏。

重叠块的优势

  1. 改善上下文:通过重叠句子,每个块向前传递其前一个块的重要信息,创造出无缝的思路流动。
  2. 减少碎片化:位于块边缘的关键信息得以保留,降低了不完整或不准确检索的风险。
  3. 更高的相关性:重叠确保在查询处理过程中相关信息不太可能被排除,从而产生更准确的结果。
def chunk_sentences_with_context(sentences, sentences_per_chunk=3, overlap=1):
    """
    Chunk sentences into groups with overlap for context.

    Parameters:
        - sentences (list): A list of sentences.
        - sentences_per_chunk (int): The number of sentences per chunk.
        - overlap (int): The number of sentences that should overlap between chunks.

    Returns:
        - list: A list of overlapping chunks.
    """
    chunks = []
    for i in range(0, len(sentences), sentences_per_chunk - overlap):
        chunk = sentences[i:i + sentences_per_chunk]
        chunks.append(' '.join(chunk))

        if i + sentences_per_chunk >= len(sentences):
            break
    return chunks

sentences_per_chunk = 10
overlap = 2
texts = chunk_sentences_with_context(sentences, sentences_per_chunk, overlap)

让我们看看第三个块:

输出:

自创立以来,我们在研究和开发方面投资超过 453 亿美元,产生了对现代计算至关重要的发明。我们在 1999 年发明的 GPU 刺激了 PC 游戏市场的增长,并重新定义了计算机图形。2006 年推出的 CUDA 编程模型,使我们的 GPU 的并行处理能力能够广泛应用于计算密集型应用,铺平了现代 AI 的出现之路。2012 年,在 NVIDIA GPU 上训练的 AlexNet 神经网络赢得了 ImageNet 计算机图像识别比赛,标志着 AI 的“宇宙大爆炸”时刻。我们在 2017 年推出了首款 Tensor Core GPU,专为 AI 新时代从零开始构建,并在 2018 年推出了首款自动驾驶系统芯片(SoC)。我们在 2020 年收购了 Mellanox,扩大了我们的创新范围,包括网络,并引入了一种新的处理器类别——数据处理单元(DPU)。在过去的 5 年中,我们构建了在我们的 GPU 和 CUDA 之上运行的完整软件堆栈,将 AI 带入全球最大的行业,包括用于自动驾驶的 NVIDIA DRIVE 堆栈、用于医疗保健的 Clara 和用于工业数字化的 Omniverse;并推出了 NVIDIA AI Enterprise 软件——本质上是企业 AI 应用的操作系统。2023 年,我们推出了首款数据中心 CPU Grace,专为大规模 AI 和高性能计算而构建。凭借强大的工程文化,我们在计算的所有维度(包括硅、系统、网络、软件和算法)推动快速而和谐的产品和技术创新。

Step 2: Convert chunks to embeddings

在创建文本块之后,下一步是将这些块转换为称为 嵌入 的数值表示。

这些嵌入对于实现基于相似性的检索和检索任务至关重要。

什么是嵌入?

嵌入是在高维空间中对文本的密集向量表示。

它们捕捉文本的语义含义,使得能够基于上下文相似性而不仅仅是匹配关键字来比较和检索文本块。

例如:

  • 句子“狗叫得很大声。”和“狗发出了很大的噪音。”尽管使用了不同的词,但可能具有相似的嵌入。
  • 这种语义理解对于检索系统找到相关结果至关重要。

嵌入模型

为了生成嵌入,我们使用 sentence-transformers 库和 all-mpnet-base-v2 模型,该模型非常适合捕捉文本中的语义关系。

该模型为每个输入文本输出一个固定维度的嵌入(768 维)。

from sentence_transformers import SentenceTransformer

model = SentenceTransformer('sentence-transformers/all-mpnet-base-v2')

embeds = model.encode(texts, show_progress_bar=True)

第3步:将嵌入存储在索引数据库中

现在我们已经为文本块生成了嵌入,下一步是将这些嵌入存储在索引数据库中。

索引使得高效的相似性检索成为可能,让我们能够快速找到任何查询的最相关文本块。

为什么使用索引数据库?

当处理大量嵌入时,逐个搜索它们的相似性会变得计算上昂贵。

通过创建一个 索引,我们可以:

  • 优化搜索速度:即使在数百万个嵌入中,也能在毫秒内执行最近邻搜索。
  • 支持可扩展性:处理大型数据集而不降低性能。
  • 支持复杂查询:为给定查询检索多个相关块。

使用 FAISS

我们使用 FAISS (Facebook AI Similarity Search),这是一个专为相似性检索任务设计的高效库。

它支持高维向量数据,并提供多种针对速度和可扩展性优化的索引方法。

import numpy as np
import pandas as pd
import faiss

dim = embeds.shape[1]
index = faiss.IndexFlatL2(dim)
index.add(np.float32(embeds))

第4步:检索查询的相关信息

在我们的FAISS索引准备好后,我们现在可以根据给定的查询搜索最相关的文本块。

这是**检索增强生成 (RAG)**管道中的检索步骤。

它使我们能够提取最具上下文相关的信息,以支持后续的生成任务。

它是如何工作的

编码查询

  • 查询被嵌入到与已索引文本块相同的向量空间中,使用相同的 SentenceTransformer 模型。
  • 这确保了查询和文本块可以在语义上进行比较。

搜索 FAISS 索引

  • 查询 FAISS 索引以找到与查询嵌入最近的邻居(最相似的文本块)。
  • 搜索返回最近嵌入的索引及其距离(相似性分数)。

检索和格式化结果

  • 使用索引获取相应的文本块。
  • 结果,包括文本及其相似性距离,存储在结构化的 DataFrame 中,以便于分析和使用。
def retrieve(query, number_of_results=3):
    """
    Search for the nearest neighbors of a query in the FAISS index.

    Parameters:
        - query (str): The query text to search for.
        - number_of_results (int): Number of nearest neighbors to retrieve.

    Returns:
        - pd.DataFrame: A DataFrame containing the nearest texts and their distances.
    """

    query_embed = model.encode([query])

    distances, similar_item_ids = index.search(np.float32(query_embed), number_of_results)

    texts_np = np.array(texts)  
    results = pd.DataFrame(data={
        'texts': texts_np[similar_item_ids[0]],
        'distance': distances[0]
    })

    return results

query = "which are the executive officers?"
results = retrieve(query)
results

输出:

作者提供的图片。

第5步. 使用大型语言模型回答

我们检索增强生成 (RAG) 管道的最后一步涉及利用大型语言模型 (LLM) 根据检索到的文本提供一个基于上下文的回答。

这一步通常被称为基于上下文的生成,确保大型语言模型生成的响应既在上下文上准确,又与查询相关。

工作原理

  1. 大型语言模型集成:
  • 使用预训练的大型语言模型处理查询和检索到的上下文。
  • Hugging Face 的 pipeline 使得集成文本生成模型变得简单。
  1. 提示设计:
  • 大型语言模型通过精心设计的提示进行引导,其中包括:
    • 角色: 定义模型的角色或专长。
    • 指令: 指定大型语言模型如何处理检索到的信息。
    • 查询: 将用户的问题与检索到的上下文结合起来。
  1. 基于上下文的回答:
  • 大型语言模型基于检索到的上下文生成响应。
  • 如果信息不足或不相关,大型语言模型会被指示承认这一点(例如,“我不确定”)。
from transformers import pipeline

pipe = pipeline(
    task="text-generation",
    model="Qwen/Qwen2.5-1.5B-Instruct",
    return_full_text=False,
    max_new_tokens=500,
    do_sample=True,
    temperature=0.2,
)

persona = "You are a helpful assistant specialized in company annual financial statements.\\n"
instruction = "Answer using the relevant information provided above. If you didn't find the information say 'I am not sure'.\\n"

llm_query = persona + results["texts"][0] + instruction + query

messages = [
    {"role": "user", "content": llm_query}
]

output = pipe(messages)
print(output[0]["generated_text"])

输出:

给定文本中提到的高管有:

  1. Jen-Hsun Huang - 他被描述为总裁和首席执行官(CEO),自公司成立以来就是董事会成员。

  2. Colette M Kress - 她被列为执行副总裁和首席财务官。

  3. Ajay K Puri - 他被认定为执行副总裁,负责全球现场运营。

  4. Debora Shoquist - 她被命名为执行副总裁,负责运营。

  5. Timothy S Teter - 他被称为执行副总裁和总法律顾问。

这些个人在 NVIDIA 中担任重要角色,并在其运营和领导中发挥关键作用。

它根据最新的 NVIDIA 年度财务报表第 12 页完美回答了。

图片来自 sec.gov

保持联系

Medium 上关注我,获取更多类似内容。 让我们在 LinkedIn𝕏 上联系。 查看我的 GitHub

不知道接下来该读什么?这里有两个推荐:

这个故事发布在 Generative AI 上。

Related Posts

结合chatgpt-o3-mini与perplexity Deep Research的3步提示:提升论文写作质量的终极指南

结合chatgpt-o3-mini与perplexity Deep Research的3步提示:提升论文写作质量的终极指南

AI 研究报告和论文写作 合并两个系统指令以获得两个模型的最佳效果 Perplexity AI 的 Deep Research 工具提供专家级的研究报告,而 OpenAI 的 ChatGPT-o3-mini-high 擅长推理。我发现你可以将它们结合起来生成令人难以置信的论文,这些论文比任何一个模型单独撰写的都要好。你只需要将这个一次性提示复制到 **

阅读更多
让 Excel 过时的 10 种 Ai 工具:实现数据分析自动化,节省手工作业时间

让 Excel 过时的 10 种 Ai 工具:实现数据分析自动化,节省手工作业时间

Non members click here作为一名软件开发人员,多年来的一个发现总是让我感到惊讶,那就是人们还在 Excel

阅读更多
使用 ChatGPT 搜索网络功能的 10 种创意方法

使用 ChatGPT 搜索网络功能的 10 种创意方法

例如,提示和输出 你知道可以使用 ChatGPT 的“搜索网络”功能来完成许多任务,而不仅仅是基本的网络搜索吗? 对于那些不知道的人,ChatGPT 新的“搜索网络”功能提供实时信息。 截至撰写此帖时,该功能仅对使用 ChatGPT 4o 和 4o-mini 的付费会员开放。 ![](https://images.weserv.nl/?url=https://cdn-im

阅读更多
掌握Ai代理:解密Google革命性白皮书的10个关键问题解答

掌握Ai代理:解密Google革命性白皮书的10个关键问题解答

10 个常见问题解答 本文是我推出的一个名为“10 个常见问题解答”的新系列的一部分。在本系列中,我旨在通过回答关于该主题的十个最常见问题来分解复杂的概念。我的目标是使用简单的语言和相关的类比,使这些想法易于理解。 图片来自 [Solen Feyissa](https://unsplash.com/@solenfeyissa?utm_source=medium&utm_medi

阅读更多
在人工智能和技术领域保持领先地位的 10 项必学技能 📚

在人工智能和技术领域保持领先地位的 10 项必学技能 📚

在人工智能和科技这样一个动态的行业中,保持领先意味着不断提升你的技能。无论你是希望深入了解人工智能模型性能、掌握数据分析,还是希望通过人工智能转变传统领域如法律,这些课程都是你成功的捷径。以下是一个精心策划的高价值课程列表,可以助力你的职业发展,并让你始终处于创新的前沿。 1. 生成性人工智能简介课程: [生成性人工智能简介](https://genai.works

阅读更多
揭开真相!深度探悉DeepSeek AI的十大误区,您被误导了吗?

揭开真相!深度探悉DeepSeek AI的十大误区,您被误导了吗?

在AI军备竞赛中分辨事实与虚构 DeepSeek AI真的是它所宣传的游戏规则改变者,还是仅仅聪明的营销和战略炒作?👀 虽然一些人将其视为AI效率的革命性飞跃,但另一些人则认为它的成功建立在借用(甚至窃取的)创新和可疑的做法之上。传言称,DeepSeek的首席执行官在疫情期间像囤积卫生纸一样囤积Nvidia芯片——这只是冰山一角。 从其声称的550万美元培训预算到使用Open

阅读更多
Type something to search...