百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

总结了 13 个 顶级 RAG 技术_rt-raa技术

zhezhongyun 2025-09-29 15:51 32 浏览

AI 能否大规模生成真正相关的答案?我们如何确保它理解复杂的多轮对话?我们如何防止它轻率地吐出错误的事实?这些都是现代 AI 系统面临的挑战,尤其是使用 RAG 构建的系统。RAG 将文档检索的强大功能与语言生成的流畅性相结合,使系统能够基于上下文感知、基于事实的响应来回答问题。虽然基本的 RAG 系统在处理简单任务时表现良好,但在处理复杂查询、幻听以及长时间交互中的上下文记忆时,它们往往会遇到问题。这时,高级 RAG 技术就派上用场了。

在本篇博文中,我们将探讨如何升级你的 RAG 流水线,从而增强堆栈的每个阶段:索引、检索和生成。我们将逐步介绍一些强大的方法(并附上实际代码),这些方法可以帮助你提升相关性、降低噪音并扩展系统性能——无论你是构建医疗助理、教育导师还是企业知识机器人。

基本 RAG 的不足之处是什么?

让我们看一下基本 RAG 框架:

这个 RAG 系统架构展示了向量存储中块嵌入的基本存储方式。第一步是加载文档,然后使用各种分块技术对其进行拆分或分块,最后使用嵌入模型进行嵌入,以便 LLM 能够轻松理解。

这张图描绘了RA G的检索和生成步骤:用户提出一个问题,然后我们的系统通过搜索 Vector 库,根据该问题提取结果。检索到的内容连同问题一起传递给 LLM,LLM 提供结构化的输出。

基本的 RAG 系统有明显的局限性,尤其是在苛刻的情况下。

  • 幻觉:幻觉是一个主要问题。该模型创建的内容在事实上是错误的,或者没有源文档的支持。这会损害可靠性,尤其是在医学或法律等精确性至关重要的领域。
  • 缺乏领域特异性:标准 RAG 模型难以处理专业主题。如果不根据领域的具体细节调整检索和生成过程,系统可能会发现不相关或不准确的信息。
  • 复杂对话:基本的 RAG 系统难以处理复杂的查询或多轮对话。它们经常在交互过程中丢失上下文信息,导致答案不连贯或不完整。RAG 系统必须能够处理日益复杂的查询。

因此,我们将逐一介绍 RAG 堆栈的高级 RAG 技术,即索引、检索和生成。我们将讨论如何使用开源库和资源进行改进。无论你构建的是医疗聊天机器人、教育机器人还是其他应用程序,这些高级 RAG 技术都具有普遍适用性。它们将改进大多数 RAG 系统。

让我们从高级 RAG 技术开始吧!

索引和分块:构建坚实的基础

良好的索引对于任何 RAG 系统都至关重要。第一步涉及如何导入、拆分和存储数据。让我们探索索引数据的方法,重点介绍如何索引和分块文本以及使用元数据。

1. HNSW

Hierarchical Navigable Small Worlds (HNSW)是一种在大型数据集中查找相似项的有效算法。它使用基于图的结构化方法,帮助快速定位近似最近邻 (ANN) 。

  • 邻近图:HNSW 构建了一个图,其中每个点都连接到附近的点。这种结构可以实现高效的搜索。
  • 层次结构:该算法将点组织成多层。顶层连接较远的点,而较低层连接较近的点。这种设置加快了搜索过程。
  • 贪婪路由:HNSW 使用贪婪算法来寻找邻居。它从高阶点开始,然后移动到最近的邻居,直到达到局部最小值。这种方法减少了查找相似项目所需的时间。

HNSW如何运作?

HNSW 的工作包括几个关键部分:

  • 每次将一个节点添加到图中。

  • 每个节点根据概率函数被分配到某一层。该函数决定了节点被放置在更高层的可能性。

  • 该算法平衡了连接数和搜索速度。

  • 搜索过程:
    • 搜索从顶层的特定入口点开始。

    • 该算法每一步都会移动到最近的邻居。

    • 一旦达到局部最小值,它就会转移到下一个较低层并继续搜索,直到找到底层的最近点。

  • 参数:
    • M:连接到每个节点的邻居数量。
    • efConstruction:此参数影响算法在构建图形时考虑的邻居数量。
    • efSearch:此参数影响搜索过程,确定要评估多少个邻居。

    HNSW 的设计使其能够快速准确地找到相似的项目。这使得它成为需要在大型数据集中高效搜索的任务的理想选择。

    该图描绘了一个简化的 HNSW 搜索:算法从“入口点”(蓝色)开始,将图导航至“查询向量”(黄色)。“最近邻”(条纹)是通过基于邻近度的边遍历来识别的。这说明了高效近似最近邻搜索的图导航核心概念。

    体验 HNSW

    请按照以下步骤使用 FAISS 实现分层可导航小世界 (HNSW) 算法。本指南包含示例输出,用于说明该过程。

    步骤 1:设置 HNSW 参数

    首先,定义 HNSW 索引的参数。需要指定向量的大小以及每个节点的邻居数量。

    import faiss
    import numpy as np
    # Set up HNSW parameters
    d = 128 # Size of the vectors
    M = 32 # Number of neighbors for each nodel

    步骤 2:初始化 HNSW 索引

    使用上面定义的参数创建 HNSW 索引。

    # Initialize the HNSW index
    index = faiss.IndexHNSWFlat(d, M)

    步骤 3:设置 efConstruction

    在将数据添加到索引之前,请设置 efConstruction参数。此参数控制算法在构建索引时考虑的邻居数量。

    efConstruction = 200  # Example value for efConstruction
    index.hnsw.efConstruction = efConstruction

    步骤4:生成示例数据

    在此示例中,生成要索引的随机数据。其中,“xb”表示要索引的数据集。

    # Generate random dataset of vectors
    n = 10000 # Number of vectors to index
    xb = np.random.random((n, d)).astype('float32')
    # Add data to the index
    index.add(xb) # Build the index

    步骤 5:设置 efSearch

    建立索引后,设置 efSearch参数。此参数影响搜索过程。

    efSearch = 100  # Example value for efSearch
    index.hnsw.efSearch = efSearch

    步骤 6:执行搜索

    现在,你可以搜索查询向量的最近邻。这里,“xq”表示查询向量。

    # Generate random query vectors
    nq = 5 # Number of query vectors
    xq = np.random.random((nq, d)).astype('float32')
    # Perform a search for the top k nearest neighbors
    k = 5 # Number of nearest neighbors to retrieve
    distances, indices = index.search(xq, k)
    # Output the results
    print("Query Vectors:\n", xq)
    print("\nNearest Neighbors Indices:\n", indices)
    print("\nNearest Neighbors Distances:\n", distances)

    输出

    查询向量:

    [[0.12345678 0.23456789 ... 0.98765432]
    [0.23456789 0.34567890 ... 0.87654321]
    [0.34567890 0.45678901 ... 0.76543210]
    [0.45678901 0.56789012 ... 0.65432109]
    [0.56789012 0.67890123 ... 0.54321098]]

    最近邻索引:

    [[123 456 789 101 112]
    [234 567 890 123 134]
    [345 678 901 234 245]
    [ 456 789 012 345 356]
    [ 567 890 123 456 467]]

    最近邻距离:

    [[0.123 0.234 0.345 0.456 0.567]
    [0.234 0.345 0.456 0.567 0.678]
    [0.345 0.456 0.567 0.678 0.789]
    [0.456 0.567 0.678 0.789 0.890]
    [0.567 0.678 0.789 0.890 0.901]]

    2. 语义分块

    这种方法根据含义而非固定大小划分文本。每个块代表一段连贯的信息。我们计算句子嵌入之间的余弦距离。如果两个句子语义相似(低于阈值),则将它们归入同一块。这会根据内容的含义创建不同长度的块。

    • 优点:创建更连贯、更有意义的块,改善检索。

    • 缺点:需要更多计算(使用基于 BERT 的编码器)。

    动手语义分块

    from langchain_experimental.text_splitter import SemanticChunker
    from langchain_openai.embeddings import OpenAIEmbeddings
    text_splitter = SemanticChunker(OpenAIEmbeddings)
    docs = text_splitter.create_documents([document])
    print(docs[0].page_content)

    这段代码使用了 LangChain 的 SemanticChunker,它使用 OpenAI 嵌入将文档拆分为语义相关的块。它创建的文档块旨在捕获连贯的语义单元,而不是任意的文本片段。

    3.基于语言模型的分块

    这种先进的方法使用语言模型从文本中创建完整的语句。每个块在语义上都是完整的。语言模型(例如,一个拥有 70 亿个参数的模型)负责处理文本。它将文本分解成各自有意义的语句。然后,该模型将这些语句组合成块,在完整性和上下文之间取得平衡。这种方法计算量很大,但准确率很高。

    • 优点:适应文本的细微差别并创建高质量的块。

    • 缺点:计算成本高;可能需要针对特定用途进行微调。

    基于语言模型的分块实践

    async def generate_contexts(document, chunks):
    asyncdef process_chunk(chunk):
    response = await client.chat.completions.create(
    model="gpt-4o",
    messages=[
    {"role": "system", "content": "Generate a brief context explaining how this chunk relates to the full document."},
    {"role": "user", "content": f"
    ],
    temperature=0.3,
    max_tokens=100
    )
    context = response.choices[0].message.content
    returnf"{context} {chunk}"
    # Process all chunks concurrently
    contextual_chunks = await asyncio.gather(
    *[process_chunk(chunk) for chunk in chunks]
    )
    return contextual_chunks

    此代码片段利用 LLM(可能是 OpenAI 的 deepseek,通过
    client.chat.completions.create 调用)为文档的每个块生成上下文信息。它异步处理每个块,促使 LLM 解释该块与完整文档的关系。最后,它返回一个原始块列表,并在列表前面添加了生成的上下文,从而有效地丰富了这些块,从而改进了搜索检索。

    4. 利用元数据:添加上下文

    添加和过滤元数据

    元数据提供额外的上下文信息,从而提高检索的准确性。通过添加日期、患者年龄和既往病史等元数据,你可以在搜索过程中过滤掉不相关的信息。过滤功能可以缩小搜索范围,提高检索效率和相关性。索引时,请将元数据与文本一起存储。

    例如,医疗保健数据包括患者记录中的年龄、就诊日期和具体病情。使用这些元数据来筛选搜索结果,确保系统只检索相关信息。例如,如果查询与儿童相关,则过滤掉 18 岁以上患者的记录。这可以减少噪音并提高相关性。

    例子

    Source Metadata:  {'id': 'doc:1c6f3e3f7ee14027bc856822871572dc:26e9aac7d5494208a56ff0c6cbbfda20', 'source': 'https://plato.stanford.edu/entries/goedel/'}

    源文本:

    2.2.1 The First Incompleteness Theorem
    In his Logical Journey (Wang 1996) Hao Wang published the
    full text of material G"odel had written (at Wang’s request)
    about his discovery of the incompleteness theorems. This material had
    formed the basis of Wang’s “Some Facts about Kurt
    G"odel,” and was read and approved by G"odel:

    Source Metadata:  {'id': 'doc:1c6f3e3f7ee14027bc856822871572dc:d15f62c453c64072b768e136080cb5ba', 'source': 'https://plato.stanford.edu/entries/goedel/'}

    源文本:

    The First Incompleteness Theorem provides a counterexample to
    completeness by exhibiting an arithmetic statement which is neither
    provable nor refutable in Peano arithmetic, though true in the
    standard model. The Second Incompleteness Theorem shows that the
    consistency of arithmetic cannot be proved in arithmetic itself. Thus
    G"odel’s theorems demonstrated the infeasibility of the
    Hilbert program, if it is to be characterized by those particular
    desiderata, consistency and completeness.

    在这里,我们可以看到元数据包含块的唯一 ID 和来源,这为块提供了更多上下文并有助于轻松检索。

    5. 使用 GLiNER 生成元数据

    你不会总是拥有大量的元数据,但使用像 GLiNER 这样的模型可以动态生成元数据!GLiNER 在摄取过程中标记和标记块以创建元数据。

    执行

    为每个块添加标签以供 GLiNER 识别。如果找到标签,它会对其进行标记。如果没有匹配的标签,则不会生成标签。 通常情况下效果良好,但对于小众数据集可能需要进行微调。这提高了检索准确率,但增加了一个处理步骤。GLiNER 可以解析传入的查询,并将其与元数据标签进行匹配以进行过滤。

    GLiNER:使用双向 Transformer 进行命名实体识别的通用模型演示:

    这些技术构建了强大的 RAG 系统,能够高效地从大型数据集中检索数据。分块和元数据的使用取决于数据集的具体需求和特性。

    检索:找到正确的信息

    现在,我们来关注一下 RAG 中的“R”。如何改进向量数据库的检索?这指的是检索与查询相关的所有文档。这大大提高了 LLM 生成高质量结果的几率。以下是一些技巧:

    6.Hybrid Search混合搜索

    结合向量搜索(查找语义含义)和关键词搜索(查找精确匹配)。混合搜索兼具两者的优势。在人工智能领域,许多术语都是特定的关键词:算法名称、技术术语、LLM (LLM)。单独的向量搜索可能会遗漏这些术语。关键词搜索可以确保这些重要术语得到考虑。结合两种方法可以创建更完整的检索流程。这些搜索同时运行。

    使用加权系统对结果进行合并和排序。例如,使用 Weaviate,你可以调整 alpha 参数来平衡向量和关键词结果。这样就可以创建一个合并的排序列表。

    • 优点:平衡精度和召回率,提高检索质量。

    • 缺点:需要仔细调整重量。

    动手混合搜索

    from langchain_community.retrievers import WeaviateHybridSearchRetriever
    from langchain_core.documents import Document
    retriever = WeaviateHybridSearchRetriever(
    client=client,
    index_name="LangChain",
    text_key="text",
    attributes=[],
    create_schema_if_missing=True,
    )
    retriever.invoke("the ethical implications of AI")

    此代码初始化了一个
    WeaviateHybridSearchRetriever,用于从 Weaviate 矢量数据库中检索文档。它将矢量搜索和关键字搜索结合到了 Weaviate 的混合检索功能中。最后,它执行了一个名为“the ethical implications of AI”的查询,并使用此混合方法检索相关文档。

    7.查询重写

    认识到人类查询可能并非数据库或语言模型的最佳选择。使用语言模型重写查询可以显著提高检索效果。

    1. 向量数据库重写:这将用户的初始查询转换为数据库友好的格式。例如,“什么是人工智能代理以及为什么它们是 2025 年的下一个大事件”可以转换为“人工智能代理是 2025 年的重大事件”。我们可以使用任何 LLM 来重写查询,以便它能够捕捉查询的重要方面。
    2. 语言模型的提示重写:这涉及自动创建提示以优化与语言模型的交互。这可以提高结果的质量和准确性。我们可以使用 DSPy 等框架或任何 LLM 来重写查询。这些重写的查询和提示确保搜索过程检索到相关文档,并有效地提示语言模型。

    多查询检索

    查询措辞的细微变化可能会导致检索结果不同。如果嵌入不能准确反映数据的含义,这个问题可能会更加突出。为了应对这些挑战,通常会采用快速工程或调优的方法,但这个过程可能非常耗时。

    MultiQueryRetriever简化了这项任务。它使用大型语言模型 (LLM),基于单个用户输入从不同角度创建多个查询。对于每个生成的查询,它会检索一组相关文档。MultiQueryRetriever通过整合所有查询的独特结果, 提供了更广泛的潜在相关文档集。这种方法提高了找到有用信息的机会,而无需进行大量的手动调整。

    from langchain_openai import ChatOpenAI
    chatgpt = ChatOpenAI(model_name="gpt-4o", temperature=0)
    from langchain.retrievers.multi_query import MultiQueryRetriever
    # Set logging for the queries
    import logging
    similarity_retriever3 = chroma_db3.as_retriever(search_type="similarity",
    search_kwargs={"k": 2})
    mq_retriever = MultiQueryRetriever.from_llm(
    retriever=similarity_retriever3, llm=chatgpt,
    include_original=True
    )
    logging.basicConfig
    # so we can see what queries are generated by the LLM
    logging.getLogger("langchain.retrievers.multi_query").setLevel(logging.INFO)
    query = "what is the capital of India?"
    docs = mq_retriever.invoke(query)
    docs

    此代码使用 LangChain 构建了一个多查询检索系统。它会生成输入查询(“what is the capital of India?”)的多个变体。然后,这些变体会通过相似性检索器查询 Chroma 向量数据库 (chroma_db3),旨在扩大搜索范围并捕获各种相关文档。MultiQueryRetriever 最终会聚合并返回检索到的文档。

    输出

    [Document(metadata={'article_id': '5117', 'title': 'New Delhi'},
    page_content='New Delhi () is the capital of India and a union territory of
    the megacity of Delhi. It has a very old history and is home to several
    monuments where the city is expensive to live in. In traditional Indian
    geography it falls under the North Indian zone. The city has an area of
    about 42.7\xa0km. New Delhi has a population of about 9.4 Million people.'),

    Document(metadata={'article_id': '4062', 'title': 'Kolkata'},
    page_content="Kolkata (spelled Calcutta before 1 January 2001) is the
    capital city of the Indian state of West Bengal. It is the second largest
    city in India after Mumbai. It is on the east bank of the River Hooghly.
    When it is called Calcutta, it includes the suburbs. This makes it the third
    largest city of India. This also makes it the world's 8th largest
    metropolitan area as defined by the United Nations. Kolkata served as the
    capital of India during the British Raj until 1911. Kolkata was once the
    center of industry and education. However, it has witnessed political
    violence and economic problems since 1954. Since 2000, Kolkata has grown due
    to economic growth. Like other metropolitan cities in India, Kolkata
    struggles with poverty, pollution and traffic congestion."),

    Document(metadata={'article_id': '22215', 'title': 'States and union
    territories of India'}, page_content='The Republic of India is divided into
    twenty-eight States,and eight union territories including the National
    Capital Territory.')]

    8. LLM基于提示的上下文压缩检索

    上下文压缩有助于提高检索文档的相关性。这主要通过两种方式实现:

    1. 提取相关内容:删除检索到的文档中与查询无关的部分。这意味着只保留回答问题的部分。
    2. 过滤不相关文档:排除与查询无关的文档,而不改变文档本身的内容。

    为了实现这一点,我们可以使用 LLMChainExtractor,它会审查最初返回的文档,并仅提取与查询相关的内容。它也可能删除完全不相关的文档。

    以下是使用 LangChain 实现此目的的方法:

    from langchain.retrievers import ContextualCompressionRetriever
    from langchain.retrievers.document_compressors import LLMChainExtractor
    from langchain_openai import ChatOpenAI
    # Initialize the language model
    chatgpt = ChatOpenAI(model_name="gpt-4o", temperature=0)

    # Set up a similarity retriever
    similarity_retriever = chroma_db3.as_retriever(search_type="similarity", search_kwargs={"k": 3})

    # Create the extractor to get relevant content
    compressor = LLMChainExtractor.from_llm(llm=chatgpt)

    # Combine the retriever and the extractor
    compression_retriever = ContextualCompressionRetriever(base_compressor=compressor, base_retriever=similarity_retriever)

    # Example query
    query = "What is the capital of India?"
    docs = compression_retriever.invoke(query)
    print(docs)

    输出:

    [Document(metadata={'article_id': '5117', 'title': 'New Delhi'},
    page_content='New Delhi is the capital of India and a union territory of the
    megacity of Delhi.')]

    对于不同的查询:

    query = "What is the old capital of India?"
    docs = compression_retriever.invoke(query)
    print(docs)

    输出

    [Document(metadata={'article_id': '4062', 'title': 'Kolkata'},
    page_content='Kolkata served as the capital of India during the British Raj
    until 1911.')]

    LLMChainFilter 提供了一种更简单但有效的文档过滤方法。它使用 LLM 链来决定哪些文档需要保留、哪些文档需要丢弃,且不会改变文档的内容。

    以下是实现过滤器的方法:

    from langchain.retrievers.document_compressors import LLMChainFilter
    # Set up the filter
    _filter = LLMChainFilter.from_llm(llm=chatgpt)
    # Combine the retriever and the filter
    compression_retriever = ContextualCompressionRetriever(base_compressor=_filter, base_retriever=similarity_retriever)

    # Example query
    query = "What is the capital of India?"
    docs = compression_retriever.invoke(query)
    print(docs)

    输出:

    [Document(metadata={'article_id': '5117', 'title': 'New Delhi'},
    page_content='New Delhi is the capital of India and a union territory of the
    megacity of Delhi.')]

    对于另一个查询:

    query = "What is the old capital of India?"
    docs = compression_retriever.invoke(query)
    print(docs)

    输出:

    [Document(metadata={'article_id': '4062', 'title': 'Kolkata'},
    page_content='Kolkata served as the capital of India during the British Raj
    until 1911.')]

    这些策略通过关注相关内容来帮助优化检索过程。“LLMChainExtractor”仅提取文档的必要部分,而“LLMChainFilter”则决定保留哪些文档。这两种方法都提高了检索信息的质量,使其与用户的查询更加相关。

    9. 微调嵌入模型

    预先训练好的嵌入模型是一个不错的开始。根据你的数据对这些模型进行微调可以显著提升检索效果。

    选择合适的模型:对于医学等专业领域,请选择基于相关数据预训练的模型。例如,你可以使用 MedCPT 系列查询和文档编码器,这些编码器已基于 PubMed 搜索日志中的 2.55 亿个查询-文章对进行大规模预训练。

    使用正样本对和负样本对进行微调:收集你自己的数据,并创建相似(正样本)和不相似(负样本)的样本对。对模型进行微调以理解这些差异。这有助于模型学习特定领域的关系,从而改进检索。

    这些技术的组合构建了一个强大的检索系统。这提高了提供给 LLM 的对象的相关性,从而提升了生成质量。

    生成:制作高质量的响应

    最后,我们来讨论一下如何提高语言模型 (LLM) 的生成质量。目标是为 LLM 提供尽可能与提示相关的上下文。不相关的数据可能会引发幻觉。以下是一些提高生成质量的技巧:

    10.自动剪切以删除不相关信息

    Autocut 会过滤掉从数据库中检索到的不相关信息,从而防止LLM 被误导。

    • 检索和评分相似度:进行查询时,将检索具有相似度分数的多个对象。
    • 识别并剔除:使用相似度得分找到一个得分显著下降的临界点。排除超出此点的对象。这确保只向 LLM 提供最相关的信息。例如,如果你检索了六个对象,那么在第四个之后,得分可能会急剧下降。通过查看变化率,你可以确定要排除哪些对象。
    from langchain_openai import OpenAIEmbeddings
    from langchain_pinecone import PineconeVectorStore
    from typing import List
    from langchain_core.documents import Document
    from langchain_core.runnables import chain
    vectorstore = PineconeVectorStore.from_documents(
    docs, index_name="sample", embedding=OpenAIEmbeddings
    )
    @chain
    def retriever(query: str):
    docs, scores = zip(*vectorstore.similarity_search_with_score(query))
    for doc, score in zip(docs, scores):
    doc.metadata["score"] = score
    return docs
    result = retriever.invoke("dinosaur")
    result

    此代码片段使用 LangChain 和 Pinecone 执行相似性搜索。它使用 OpenAI 嵌入来嵌入文档,将其存储在 Pinecone 向量存储中,并定义一个检索器函数。检索器搜索与给定查询(“dinosaur”)相似的文档,计算相似度分数,并将这些分数添加到文档元数据中,然后返回结果。

    输出

    [Document(page_content='In her second book, Dr. Simmons delves deeper into
    the ethical considerations surrounding AI development and deployment. It is
    an eye-opening examination of the dilemmas faced by developers,
    policymakers, and society at large.', metadata={}),

    Document(page_content='A comprehensive analysis of the evolution of
    artificial intelligence, from its inception to its future prospects. Dr.
    Simmons covers ethical considerations, potentials, and threats posed by
    AI.', metadata={}),

    Document(page_content="In his follow-up to 'Symbiosis', Prof. Sterling takes
    a look at the subtle, unnoticed presence and influence of AI in our everyday
    lives. It reveals how AI has become woven into our routines, often without
    our explicit realization.", metadata={}),

    Document(page_content='Prof. Sterling explores the potential for harmonious
    coexistence between humans and artificial intelligence. The book discusses
    how AI can be integrated into society in a beneficial and non-disruptive
    manner.', metadata={})]

    我们可以看到,它还给出了相似度分数,我们可以根据阈值进行截断。

    11. 重新排序检索到的对象

    重新排序使用更高级的模型来重新评估和排序最初检索到的对象。这可以提高最终检索集的质量。

    • 过度获取:最初检索的对象多于所需。
    • 应用排序模型:使用高延迟模型(通常是交叉编码器)重新评估相关性。该模型会逐对考虑查询和每个对象,以重新评估相似度。
    • 重新排序结果:根据新的评估结果,重新排序对象。将最相关的结果置于顶部。这可确保最相关的文档优先显示,从而改进提供给LLM (LLM) 的数据。
    from langchain.retrievers import ContextualCompressionRetriever
    from langchain.retrievers.document_compressors import FlashrankRerank
    from langchain_openai import ChatOpenAI

    llm = ChatOpenAI(temperature=0)

    compressor = FlashrankRerank
    compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor, base_retriever=retriever
    )
    compressed_docs = compression_retriever.invoke(
    "What did the president say about Ketanji Jackson Brown"
    )
    print([doc.metadata["id"] for doc in compressed_docs])
    pretty_print_docs(compressed_docs)

    此代码片段利用
    ContextualCompressionRetriever 中的 FlashrankRerank 来提升检索到的文档的相关性。它根据查询“总统对 Ketanji Jackson Brown 有何评价”的相关性,对基础检索器(用 retriever 表示)获取的文档进行重新排序。最后,它会打印文档 ID 以及压缩后、重新排序后的文档。

    输出

    [0, 5, 3]

    Document 1:

    One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court.

    And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.

    ----------------------------------------------------------------------------------------------------

    Document 2:

    He met the Ukrainian people.

    From President Zelenskyy to every Ukrainian, their fearlessness, their courage, their determination, inspires the world.

    Groups of citizens blocking tanks with their bodies. Everyone from students to retirees teachers turned soldiers defending their homeland.

    In this struggle as President Zelenskyy said in his speech to the European Parliament “Light will win over darkness.” The Ukrainian Ambassador to the United States is here tonight.

    ----------------------------------------------------------------------------------------------------

    Document 3:

    And tonight, I’m announcing that the Justice Department will name a chief prosecutor for pandemic fraud.

    By the end of this year, the deficit will be down to less than half what it was before I took office.

    The only president ever to cut the deficit by more than one trillion dollars in a single year.

    Lowering your costs also means demanding more competition.

    I’m a capitalist, but capitalism without competition isn’t capitalism.

    It’s exploitation—and it drives up prices.

    输出显示它根据相关性对检索到的块进行重新排序。

    12. 微调LLM

    使用特定领域数据对 LLM 进行微调可以显著提升其性能。例如,使用 Meditron 70B 这样的模型。这是针对医疗数据对 LLaMA 2 70b 进行微调的版本,同时使用了以下两种方法:

    • 无监督微调:继续对大量特定领域的文本进行预训练。

    • 监督微调:使用监督学习针对特定领域任务(例如医学多项选择题)进一步完善模型。这种专门的训练有助于模型在目标领域表现良好。在某些特定任务上,它的表现优于基础模型以及规模更大、专业性较低的模型(例如 GPT-3.5)。

    微调

    此图表示针对特定任务示例进行微调的过程。这种方法允许开发人员指定所需的输出、鼓励某些行为,或更好地控制模型的响应。

    13. 使用 RAFT:将语言模型适配到特定领域的 RAG

    RAFT(检索增强微调)是一种改进大型语言模型 (LLM) 在特定领域工作方式的方法。它可以帮助这些模型利用文档中的相关信息更准确地回答问题。

    • 检索增强微调:RAFT 将微调与检索方法相结合。这使得模型在训练过程中能够从有用和不太有用的文档中学习。
    • 思路链推理:该模型生成的答案展现了其推理过程。这有助于它根据检索到的文档提供清晰准确的响应。
    • 动态文档处理:RAFT 训练模型查找和使用最相关的文档,同时忽略那些无助于回答问题的文档。

    RAFT 的架构

    RAFT 架构包含几个关键组件:

    1. 输入层:模型输入一个问题(Q)和一组检索到的文档(D),其中包括相关文档和不相关文档。
    2. 处理层:
    • 该模型分析输入以在文档中查找重要信息。

    • 它创建了一个引用相关文档的答案(A*)。

  • 输出层:模型根据相关文档产生最终答案,同时忽略不相关的文档。
  • 训练机制:在训练过程中,一些数据包含相关和不相关的文档,而其他数据仅包含不相关的文档。这种设置鼓励模型专注于上下文而不是记忆。
  • 评估:根据模型使用检索到的文档准确回答问题的能力来评估模型的性能。
  • 通过采用这种架构,RAFT 增强了模型在特定领域的工作能力,并提供了一种生成准确且相关响应的可靠方法。

    RAFT 的架构

    左上图展示了一种调整 LLM 的方法,使其能够从一组正向文档和干扰文档中读取解决方案。与标准 RAG 设置不同,标准 RAG 设置基于检索器输出进行训练,检索器输出是记忆和阅读的混合。测试时,所有方法均遵循标准 RAG 设置,并在上下文中提供前 k 个检索到的文档。

    结论

    改进 RAG 系统的检索和生成能力对于打造更优秀的 AI 应用至关重要。本文讨论的技术涵盖从低投入、高效率的方法(查询重写、重新排序)到更复杂的流程(嵌入和 LLM 微调)。最佳技术取决于你应用的具体需求和限制。先进的 RAG 技术,如果经过深思熟虑地应用,可以帮助开发人员构建更准确、更可靠、更具备情境感知能力的 AI 系统,从而处理复杂的信息需求。

    相关推荐

    Python入门学习记录之一:变量_python怎么用变量

    写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...

    python变量命名规则——来自小白的总结

    python是一个动态编译类编程语言,所以程序在运行前不需要如C语言的先行编译动作,因此也只有在程序运行过程中才能发现程序的问题。基于此,python的变量就有一定的命名规范。python作为当前热门...

    Python入门学习教程:第 2 章 变量与数据类型

    2.1什么是变量?在编程中,变量就像一个存放数据的容器,它可以存储各种信息,并且这些信息可以被读取和修改。想象一下,变量就如同我们生活中的盒子,你可以把东西放进去,也可以随时拿出来看看,甚至可以换成...

    绘制学术论文中的“三线表”具体指导

    在科研过程中,大家用到最多的可能就是“三线表”。“三线表”,一般主要由三条横线构成,当然在变量名栏里也可以拆分单元格,出现更多的线。更重要的是,“三线表”也是一种数据记录规范,以“三线表”形式记录的数...

    Python基础语法知识--变量和数据类型

    学习Python中的变量和数据类型至关重要,因为它们构成了Python编程的基石。以下是帮助您了解Python中的变量和数据类型的分步指南:1.变量:变量在Python中用于存储数据值。它们充...

    一文搞懂 Python 中的所有标点符号

    反引号`无任何作用。传说Python3中它被移除是因为和单引号字符'太相似。波浪号~(按位取反符号)~被称为取反或补码运算符。它放在我们想要取反的对象前面。如果放在一个整数n...

    Python变量类型和运算符_python中变量的含义

    别再被小名词坑哭了:Python新手常犯的那些隐蔽错误,我用同事的真实bug拆给你看我记得有一次和同事张姐一起追查一个看似随机崩溃的脚本,最后发现罪魁祸首竟然是她把变量命名成了list。说实话...

    从零开始:深入剖析 Spring Boot3 中配置文件的加载顺序

    在当今的互联网软件开发领域,SpringBoot无疑是最为热门和广泛应用的框架之一。它以其强大的功能、便捷的开发体验,极大地提升了开发效率,成为众多开发者构建Web应用程序的首选。而在Spr...

    Python中下划线 ‘_’ 的用法,你知道几种

    Python中下划线()是一个有特殊含义和用途的符号,它可以用来表示以下几种情况:1在解释器中,下划线(_)表示上一个表达式的值,可以用来进行快速计算或测试。例如:>>>2+...

    解锁Shell编程:变量_shell $变量

    引言:开启Shell编程大门Shell作为用户与Linux内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是...

    一文学会Python的变量命名规则!_python的变量命名有哪些要求

    目录1.变量的命名原则3.内置函数尽量不要做变量4.删除变量和垃圾回收机制5.结语1.变量的命名原则①由英文字母、_(下划线)、或中文开头②变量名称只能由英文字母、数字、下画线或中文字所组成。③英文字...

    更可靠的Rust-语法篇-区分语句/表达式,略览if/loop/while/for

    src/main.rs://函数定义fnadd(a:i32,b:i32)->i32{a+b//末尾表达式}fnmain(){leta:i3...

    C++第五课:变量的命名规则_c++中变量的命名规则

    变量的命名不是想怎么起就怎么起的,而是有一套固定的规则的。具体规则:1.名字要合法:变量名必须是由字母、数字或下划线组成。例如:a,a1,a_1。2.开头不能是数字。例如:可以a1,但不能起1a。3....

    Rust编程-核心篇-不安全编程_rust安全性

    Unsafe的必要性Rust的所有权系统和类型系统为我们提供了强大的安全保障,但在某些情况下,我们需要突破这些限制来:与C代码交互实现底层系统编程优化性能关键代码实现某些编译器无法验证的安全操作Rus...

    探秘 Python 内存管理:背后的神奇机制

    在编程的世界里,内存管理就如同幕后的精密操控者,确保程序的高效运行。Python作为一种广泛使用的编程语言,其内存管理机制既巧妙又复杂,为开发者们提供了便利的同时,也展现了强大的底层控制能力。一、P...