18种RAG技术大比拼:谁才是检索增强生成的最佳选择? 原创 精华

发布于 2025-3-25 09:44
浏览
0收藏

在当今信息爆炸的时代,如何从海量数据中快速准确地获取所需信息,是人工智能领域的一大挑战。Retrieval-Augmented Generation(RAG,检索增强生成)技术应运而生,它结合了检索和生成的优势,通过从大量文档中检索相关信息,再利用这些信息生成高质量的回答。然而,RAG 的实现方式多种多样,不同的技术路径有着不同的优势和局限。今天,我们就来深入探讨一下这些 RAG 技术,看看谁才是真正的“最佳选手”。

1. Simple RAG:基础而不失经典

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

在探索各种复杂的 RAG 技术之前,我们先从最简单的 RAG 方法说起。**简单 RAG **的工作流程非常直观:从 PDF 文档中提取文本,将其分割成小块(chunks),将这些文本块转换为数值化的嵌入向量(embeddings),根据查询(query)搜索最相关的文本块,最后利用检索到的文本块生成回答。

# 定义 PDF 文件路径
pdf_path = "data/AI_information.pdf"

# 提取文本并分割成文本块
extracted_text = extract_text_from_pdf(pdf_path)
text_chunks = chunk_text(extracted_text, chunk_size=1000, overlap=200)

# 打印文本块数量
print("Number of text chunks:", len(text_chunks))
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

这种方法虽然简单,但却为后续更复杂的技术奠定了基础。它就像是一个“新手村”,让我们能够初步了解 RAG 的工作原理。然而,简单 RAG 也有它的局限性。由于文本块是按照固定大小分割的,可能会导致一些句子被拆分开,或者将不相关的句子组合在一起,从而影响检索的准确性。

2. Semantic Chunking语义分块:让文本块更有意义

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

为了解决简单 RAG 中文本块分割不够合理的问题,语义分块(Semantic Chunking)应运而生。与简单 RAG 不同,语义分块不再是按照固定大小来分割文本,而是尝试根据文本的语义来划分,将语义相关的句子组合在一起形成文本块。

# 将提取的文本分割成句子
sentences = extracted_text.split(". ")

# 为每个句子生成嵌入向量
embeddings = [get_embedding(sentence) for sentence in sentences]

# 计算连续句子之间的相似度
similarities = [cosine_similarity(embeddings[i], embeddings[i + 1]) for i in range(len(embeddings) - 1)]

# 使用百分位法计算断点
breakpoints = compute_breakpoints(similarities, method="percentile", threshold=90)

# 根据断点将句子分组成语义块
text_chunks = split_into_chunks(sentences, breakpoints)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

这种方法听起来很完美,但在实际测试中,它的表现却不尽如人意。语义分块的评分甚至低于简单 RAG,这说明仅仅改变文本块的分割策略,并不能保证检索效果的提升。这也提醒我们,技术的改进并非一蹴而就,需要更多的思考和尝试。

3. 上下文增强检索:邻居也能提供帮助

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

既然语义分块没有达到预期的效果,我们不妨换个思路。简单 RAG 的问题在于文本块过于孤立,缺乏上下文信息。那么,如果我们能够为每个文本块添加一些上下文信息,是不是就能提高检索的准确性呢?上下文增强检索(Context Enriched Retrieval)正是基于这样的想法。

# 定义上下文增强检索函数
def context_enriched_search(query, text_chunks, embeddings, k=1, context_size=1):
    query_embedding = create_embeddings(query).data[0].embedding
    similarity_scores = []

    for i, chunk_embedding in enumerate(embeddings):
        similarity_score = cosine_similarity(np.array(query_embedding), np.array(chunk_embedding.embedding))
        similarity_scores.append((i, similarity_score))

    similarity_scores.sort(key=lambda x: x[1], reverse=True)
    top_index = similarity_scores[0][0]

    start = max(0, top_index - context_size)
    end = min(len(text_chunks), top_index + context_size + 1)

    return [text_chunks[i] for i in range(start, end)]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

在上下文增强检索中,我们不仅检索与查询最相关的文本块,还会检索其周围的文本块作为上下文信息。这些“邻居”文本块能够为检索提供更多的背景信息,帮助生成更准确的回答。经过测试,上下文增强检索的评分达到了 0.6,相较于简单 RAG 和语义分块有了显著的提升。这表明,上下文信息在检索过程中确实起到了关键作用。

4. 上下文块头:给文本块加上“标签”

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

上下文增强检索虽然有效,但仍然存在一个问题:即使有了上下文信息,文本块本身可能仍然缺乏足够的语义信息。例如,一个文档可能包含多个主题,每个主题都对应着不同的文本块。在这种情况下,如何快速准确地找到与查询最相关的文本块呢?

上下文块头(Contextual Chunk Headers)技术为我们提供了一个解决方案。它在每个文本块的前面添加了一个描述性的标题(header),这个标题就像是一个“标签”,能够概括文本块的主要内容。

# 为每个文本块生成描述性标题
text_chunks_with_headers = chunk_text_with_headers(extracted_text, chunk_size=1000, overlap=200)

# 打印一个样本以查看效果
print("Sample Chunk with Header:")
print("Header:", text_chunks_with_headers[0]['header'])
print("Content:", text_chunks_with_headers[0]['text'])
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

在检索过程中,系统不仅会考虑文本块的内容,还会参考其标题,从而更准确地找到与查询相关的文本块。经过测试,上下文块头的评分达到了 0.5,虽然没有上下文增强检索高,但也比简单 RAG 和语义分块有了明显的提升。这说明,通过给文本块添加标题,我们能够为检索提供更多的语义信息,从而提高检索的准确性。

5. 文档增强:从文本块到问题

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

上下文块头虽然能够提供更多的语义信息,但仍然存在局限性。在某些情况下,文本块的内容可能过于复杂,难以用一个简单的标题来概括。那么,有没有一种方法能够让文本块更容易被检索到呢?

文档增强(Document Augmentation)技术为我们提供了一个新的思路。它不仅将文本块转换为嵌入向量,还会为每个文本块生成一些相关的问题,并将这些问题也转换为嵌入向量。

# 处理文档,提取文本、创建文本块、生成问题并构建向量库
text_chunks, vector_store = process_document(
    pdf_path,
    chunk_size=1000,
    chunk_overlap=200,
    questions_per_chunk=3
)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

这样一来,在检索过程中,系统不仅能够匹配文本块的内容,还能够匹配与查询相关的问题,从而提高检索的准确性。经过测试,文档增强的评分达到了 0.8,这是一个非常高的分数,表明文档增强技术能够显著提高检索的准确性。这也说明,通过为文本块生成相关问题,我们能够为检索提供更多的入口,从而更容易找到与查询相关的文本块。

6. 查询转换:让查询更“友好”

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

在前面的讨论中,我们主要关注了如何改进文本块的表示和检索策略。然而,我们忽略了一个重要的因素:用户提出的查询可能并不总是能够很好地匹配文档中的内容,这可能会导致检索结果不准确。那么,有没有一种方法能够让查询更“友好”,更容易被检索到呢?

查询转换(Query Transformation)技术为我们提供了一个解决方案。它通过三种不同的方法来改进查询:查询重写(Query Rewriting)、后退提示(Step-back Prompting)和子查询分解(Sub-query Decomposition)。

# 查询重写
rewritten_query = rewrite_query(query)

# 后退提示
step_back_query = generate_step_back_query(query)

# 子查询分解
sub_queries = decompose_query(query, num_subqueries=4)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

查询重写是将查询变得更加具体和详细;后退提示是创建一个更广泛的查询,以检索有用的背景信息;子查询分解则是将一个复杂的查询分解为多个简单的子查询。经过测试,查询转换的评分达到了 0.5。虽然这个分数并不高,但它仍然表明查询转换技术在某些情况下能够提高检索的准确性。这也提醒我们,在 RAG 系统中,不仅需要关注文本块的表示和检索策略,还需要关注查询的质量。

7. 重排序:让检索结果更有条理

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

在前面的讨论中,我们主要关注了如何改进文本块的表示和检索策略,以及如何改进查询的质量。然而,我们忽略了一个重要的环节:检索结果的排序。简单相似性搜索通常会返回一组相关性和不相关性混杂的结果,这可能会导致生成的回答不够准确。那么,有没有一种方法能够让检索结果更有条理,更容易被利用呢?

重排序(Reranker)技术为我们提供了一个解决方案。它在初始检索的基础上,通过一个额外的步骤对检索结果进行重新排序,将最相关的文本块放在最前面。重排序可以使用不同的方法,例如基于关键词的重排序或基于 LLM 的重排序。

# 定义重排序函数
def rag_with_reranking(query, vector_store, reranking_method="llm", top_n=3, model="meta-llama/Llama-3.2-3B-Instruct"):
    query_embedding = create_embeddings(query)
    initial_results = vector_store.similarity_search(query_embedding, k=10)

    if reranking_method == "llm":
        reranked_results = rerank_with_llm(query, initial_results, top_n=top_n)
    else:
        reranked_results = initial_results[:top_n]

    context = "\n\n===\n\n".join([result["text"] for result in reranked_results])
    response = generate_response(query, context, model)

    return {
        "query": query,
        "reranking_method": reranking_method,
        "initial_results": initial_results[:top_n],
        "reranked_results": reranked_results,
        "context": context,
        "response": response
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

这种方法的效果如何呢?经过测试,重排序的评分达到了 0.7。这个分数表明,重排序技术能够显著提高检索结果的质量,从而提高生成回答的准确性。这也说明,对检索结果进行重新排序是一个非常重要的步骤,能够帮助我们更好地利用检索到的信息。

8. 相关段落提取(RSE):寻找连续的相关文本

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

在前面的讨论中,我们主要关注了如何改进文本块的表示和检索策略,以及如何改进查询的质量和检索结果的排序。然而,我们忽略了一个重要的问题:有时候,最佳的信息可能分散在多个连续的文本块中。那么,有没有一种方法能够让系统自动识别并提取这些连续的相关文本呢?

相关段落提取(Relevant Segment Extraction,RSE)技术为我们提供了一个解决方案。它不是简单地检索最相关的文本块,而是尝试识别并提取整个相关段落。

# 运行 RAG 并应用相关段落提取
rse_result = rag_with_rse(pdf_path, query)
  • 1.
  • 2.

这种方法能够为生成回答提供更连贯和完整的上下文信息,从而提高回答的质量。经过测试,相关段落提取的评分达到了 0.8。这个分数表明,相关段落提取技术能够显著提高检索结果的质量,从而提高生成回答的准确性。这也说明,识别并提取连续的相关文本是一个非常重要的步骤,能够帮助我们更好地利用检索到的信息。

9. 上下文压缩:让信息更精炼

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

在前面的讨论中,我们主要关注了如何改进文本块的表示和检索策略,以及如何改进查询的质量和检索结果的排序,以及如何识别并提取连续的相关文本。然而,我们忽略了一个重要的问题:有时候,检索到的信息可能过于冗长,包含了大量与查询不相关的内容。这不仅会浪费计算资源,还可能会影响生成回答的质量。那么,有没有一种方法能够让检索到的信息更精炼,只保留与查询最相关的内容呢?

上下文压缩(Contextual Compression)技术为我们提供了一个解决方案。它在检索到文本块之后,通过一个额外的步骤对文本块进行压缩,只保留与查询最相关的内容。

# 定义上下文压缩函数
def rag_with_compression(pdf_path, query, k=10, compression_type="selective", model="meta-llama/Llama-3.2-3B-Instruct"):
    vector_store = process_document(pdf_path)
    results = vector_store.similarity_search(create_embeddings(query), k=k)
    retrieved_chunks = [r["text"] for r in results]

    compressed = batch_compress_chunks(retrieved_chunks, query, compression_type, model)
    compressed_chunks, compression_ratios = zip([(c, r) for c, r in compressed if c.strip()] or [(chunk, 0.0) for chunk in retrieved_chunks])

    context = "\n\n---\n\n".join(compressed_chunks)
    response = generate_response(query, context, model)

    return {
        "query": query,
        "original_chunks": retrieved_chunks,
        "compressed_chunks": compressed_chunks,
        "compression_ratios": compression_ratios,
        "context_length_reduction": f"{sum(compression_ratios)/len(compression_ratios):.2f}%",
        "response": response
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

这种方法的效果如何呢?经过测试,上下文压缩的评分达到了 0.75。这个分数表明,上下文压缩技术能够显著提高检索结果的质量,从而提高生成回答的准确性。这也说明,对检索到的信息进行压缩是一个非常重要的步骤,能够帮助我们更好地利用检索到的信息。

10. 反馈循环:让系统不断学习

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

在前面的讨论中,我们主要关注了如何改进文本块的表示和检索策略,以及如何改进查询的质量和检索结果的排序,以及如何识别并提取连续的相关文本,以及如何对检索到的信息进行压缩。然而,我们忽略了一个重要的问题:这些改进都是基于预先设定的策略,系统无法根据实际的使用情况进行自我调整。那么,有没有一种方法能够让系统根据用户的反馈不断学习和调整呢?

反馈循环(Feedback Loop)技术为我们提供了一个解决方案。它允许用户对系统的回答进行评价,并将这些评价作为反馈信息存储起来。在后续的检索过程中,系统会根据这些反馈信息对检索策略进行调整,从而提高检索结果的质量。

# 定义完整的 RAG 流程,包含反馈机制
def full_rag_workflow(pdf_path, query, feedback_data=None, feedback_file="feedback_data.json", fine_tune=False):
    if feedback_data isNone:
        feedback_data = load_feedback_data(feedback_file)
        print(f"Loaded {len(feedback_data)} feedback entries from {feedback_file}")

    chunks, vector_store = process_document(pdf_path)

    if fine_tune and feedback_data:
        vector_store = fine_tune_index(vector_store, chunks, feedback_data)

    result = rag_with_feedback_loop(query, vector_store, feedback_data)

    print("\n=== Would you like to provide feedback on this response? ===")
    print("Rate relevance (1-5, with 5 being most relevant):")
    relevance = input()

    print("Rate quality (1-5, with 5 being highest quality):")
    quality = input()

    print("Any comments? (optional, press Enter to skip)")
    comments = input()

    feedback = get_user_feedback(
        query=query,
        respnotallow=result["response"],
        relevance=int(relevance),
        quality=int(quality),
        comments=comments
    )

    store_feedback(feedback, feedback_file)
    print("Feedback recorded. Thank you!")

    return result
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.

这种方法的效果如何呢?经过测试,反馈循环的评分达到了 0.7。虽然这个分数并不高,但它仍然表明反馈循环技术能够让系统不断学习和调整,从而提高检索结果的质量。这也说明,用户反馈是一个非常重要的资源,能够帮助系统更好地满足用户的需求。

11. Adaptive RAG:智能选择检索策略

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

在前面的讨论中,我们主要关注了如何改进文本块的表示和检索策略,以及如何改进查询的质量和检索结果的排序,以及如何识别并提取连续的相关文本,以及如何对检索到的信息进行压缩,以及如何根据用户的反馈不断学习和调整。然而,我们忽略了一个重要的问题:不同的查询可能需要不同的检索策略。那么,有没有一种方法能够让系统根据查询的类型自动选择最合适的检索策略呢?

自适应 RAG(Adaptive RAG)技术为我们提供了一个解决方案。它根据查询的类型,自动选择最合适的检索策略。例如,对于事实性查询,系统会选择事实检索策略;对于分析性查询,系统会选择分析检索策略;对于观点性查询,系统会选择观点检索策略;对于上下文相关查询,系统会选择上下文检索策略。

# 定义自适应 RAG 函数
def rag_with_adaptive_retrieval(pdf_path, query, k=4, user_cnotallow=None):
    chunks, vector_store = process_document(pdf_path)
    query_type = classify_query(query)
    print(f"Query classified as: {query_type}")

    retrieved_docs = adaptive_retrieval(query, vector_store, k, user_context)
    response = generate_response(query, retrieved_docs, query_type)

    return {
        "query": query,
        "query_type": query_type,
        "retrieved_documents": retrieved_docs,
        "response": response
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

这种方法的效果如何呢?经过测试,自适应 RAG 的评分达到了 0.86,这是所有方法中最高的分数。这个分数表明,自适应 RAG 技术能够显著提高检索结果的质量,从而提高生成回答的准确性。这也说明,根据查询的类型自动选择检索策略是一个非常重要的步骤,能够帮助我们更好地利用检索到的信息。

12. Self RAG:让系统自我反思

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

在前面的讨论中,我们主要关注了如何改进文本块的表示和检索策略,以及如何改进查询的质量和检索结果的排序,以及如何识别并提取连续的相关文本,以及如何对检索到的信息进行压缩,以及如何根据用户的反馈不断学习和调整,以及如何根据查询的类型自动选择检索策略。然而,我们忽略了一个重要的问题:系统是否能够自我反思,判断是否需要检索,以及如何利用检索到的信息呢?

自我 RAG(Self RAG)技术为我们提供了一个解决方案。它不仅能够检索和生成回答,还能够自我反思,判断是否需要检索,以及如何利用检索到的信息。

# 运行自我 RAG
result = self_rag(query, vector_store)
  • 1.
  • 2.

这种方法的效果如何呢?经过测试,自我 RAG 的评分达到了 0.65。虽然这个分数并不高,但它仍然表明自我 RAG 技术能够让系统更加智能和灵活。这也说明,自我反思是一个非常重要的能力,能够帮助系统更好地适应不同的查询需求。

13. Knowledge Graph:构建知识网络

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

在前面的讨论中,我们主要关注了如何改进文本块的表示和检索策略,以及如何改进查询的质量和检索结果的排序,以及如何识别并提取连续的相关文本,以及如何对检索到的信息进行压缩,以及如何根据用户的反馈不断学习和调整,以及如何根据查询的类型自动选择检索策略,以及如何让系统自我反思。然而,我们忽略了一个重要的问题:文档中的信息可能是相互关联的,如何构建一个知识网络,将这些信息有机地结合起来呢?

知识图谱 RAG(Knowledge Graph RAG)技术为我们提供了一个解决方案。它将文档中的信息构建成一个知识图谱,其中节点代表概念、实体或信息片段,边代表这些节点之间的关系。

# 构建知识图谱
def build_knowledge_graph(chunks):
    graph, texts = nx.Graph(), [c["text"] for c in chunks]
    embeddings = create_embeddings(texts)

    for i, (chunk, emb) in enumerate(zip(chunks, embeddings)):
        graph.add_node(i, text=chunk["text"], cnotallow=extract_concepts(chunk["text"]), embedding=emb)

    for i, j in ((i, j) for i in range(len(chunks)) for j in range(i + 1, len(chunks))):
        if shared_concepts := set(graph.nodes[i]["concepts"]) & set(graph.nodes[j]["concepts"]):
            sim = np.dot(embeddings[i], embeddings[j]) / (np.linalg.norm(embeddings[i]) * np.linalg.norm(embeddings[j]))
            weight = 0.7 * sim + 0.3 * (len(shared_concepts) / min(len(graph.nodes[i]["concepts"]), len(graph.nodes[j]["concepts"])))
            if weight > 0.6:
                graph.add_edge(i, j, weight=weight, similarity=sim, shared_cnotallow=list(shared_concepts))

    print(f"Graph built: {graph.number_of_nodes()} nodes, {graph.number_of_edges()} edges")
    return graph, embeddings
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

在检索过程中,系统不仅能够检索与查询直接相关的节点,还能够通过遍历知识图谱找到间接相关的节点,从而为生成回答提供更全面的上下文信息。经过测试,知识图谱 RAG 的评分达到了 0.78。这个分数表明,知识图谱 RAG 技术能够显著提高检索结果的质量,从而提高生成回答的准确性。这也说明,构建知识图谱是一个非常重要的步骤,能够帮助我们更好地利用文档中的信息。

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

14. 层次化索引:平衡上下文和精确性

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

在前面的讨论中,我们主要关注了如何改进文本块的表示和检索策略,以及如何改进查询的质量和检索结果的排序,以及如何识别并提取连续的相关文本,以及如何对检索到的信息进行压缩,以及如何根据用户的反馈不断学习和调整,以及如何根据查询的类型自动选择检索策略,以及如何让系统自我反思,以及如何构建知识图谱。然而,我们忽略了一个重要的问题:如何平衡上下文信息和检索的精确性呢?

层次化索引(Hierarchical Indices)技术为我们提供了一个解决方案。它创建了两个层次的表示:摘要和详细文本块。首先,系统在摘要层次进行检索,快速缩小相关文档的范围;然后,在详细文本块层次进行检索,提供精确的检索结果。

# 定义层次化 RAG 函数
def hierarchical_rag(query, pdf_path, chunk_size=1000, chunk_overlap=200, k_summaries=3, k_chunks=5, regenerate=False):
    summary_store_file = f"{os.path.basename(pdf_path)}_summary_store.pkl"
    detailed_store_file = f"{os.path.basename(pdf_path)}_detailed_store.pkl"

    if regenerate ornot os.path.exists(summary_store_file) ornot os.path.exists(detailed_store_file):
        print("Processing document and creating vector stores...")
        summary_store, detailed_store = process_document_hierarchically(pdf_path, chunk_size, chunk_overlap)

        with open(summary_store_file, 'wb') as f:
            pickle.dump(summary_store, f)
        with open(detailed_store_file, 'wb') as f:
            pickle.dump(detailed_store, f)
    else:
        print("Loading existing vector stores...")
        with open(summary_store_file, 'rb') as f:
            summary_store = pickle.load(f)
        with open(detailed_store_file, 'rb') as f:
            detailed_store = pickle.load(f)

    retrieved_chunks = retrieve_hierarchically(query, summary_store, detailed_store, k_summaries, k_chunks)
    response = generate_response(query, retrieved_chunks)

    return {
        "query": query,
        "response": response,
        "retrieved_chunks": retrieved_chunks,
        "summary_count": len(summary_store.texts),
        "detailed_count": len(detailed_store.texts)
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.

这种方法既保留了上下文信息,又提高了检索的精确性。经过测试,层次化索引的评分达到了 0.84。这个分数表明,层次化索引技术能够显著提高检索结果的质量,从而提高生成回答的准确性。这也说明,平衡上下文信息和检索精确性是一个非常重要的步骤,能够帮助我们更好地利用检索到的信息。

15. HyDE:从假设文档出发

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

在前面的讨论中,我们主要关注了如何改进文本块的表示和检索策略,以及如何改进查询的质量和检索结果的排序,以及如何识别并提取连续的相关文本,以及如何对检索到的信息进行压缩,以及如何根据用户的反馈不断学习和调整,以及如何根据查询的类型自动选择检索策略,以及如何让系统自我反思,以及如何构建知识图谱,以及如何平衡上下文信息和检索精确性。然而,我们忽略了一个重要的问题:如何更好地表示查询,以便更准确地检索到相关信息呢?

HyDE(Hypothetical Document Embedding)技术为我们提供了一个解决方案。它不是直接对查询进行嵌入,而是先生成一个假设文档,这个文档是查询的理想答案。然后,系统对这个假设文档进行嵌入,并利用这个嵌入进行检索。

# 定义 HyDE RAG 函数
def hyde_rag(query, vector_store, k=5, should_generate_respnotallow=True):
    print(f"\n=== Processing query with HyDE: {query} ===\n")

    print("Generating hypothetical document...")
    hypothetical_doc = generate_hypothetical_document(query)
    print(f"Generated hypothetical document of {len(hypothetical_doc)} characters")

    print("Creating embedding for hypothetical document...")
    hypothetical_embedding = create_embeddings([hypothetical_doc])[0]

    print(f"Retrieving {k} most similar chunks...")
    retrieved_chunks = vector_store.similarity_search(hypothetical_embedding, k=k)

    results = {
        "query": query,
        "hypothetical_document": hypothetical_doc,
        "retrieved_chunks": retrieved_chunks
    }

    if should_generate_response:
        print("Generating final response...")
        response = generate_response(query, retrieved_chunks)
        results["response"] = response

    return results
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.

这种方法能够更好地捕捉查询的语义信息,从而提高检索的准确性。经过测试,HyDE 的评分达到了 0.5。虽然这个分数并不高,但它仍然表明 HyDE 技术在某些情况下能够提高检索的准确性。这也说明,从假设文档出发是一个非常有趣的思路,能够帮助我们更好地表示查询。

16. 融合 RAG:结合多种检索方法

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

在前面的讨论中,我们主要关注了如何改进文本块的表示和检索策略,以及如何改进查询的质量和检索结果的排序,以及如何识别并提取连续的相关文本,以及如何对检索到的信息进行压缩,以及如何根据用户的反馈不断学习和调整,以及如何根据查询的类型自动选择检索策略,以及如何让系统自我反思,以及如何构建知识图谱,以及如何平衡上下文信息和检索精确性,以及如何从假设文档出发。然而,我们忽略了一个重要的问题:不同的检索方法有各自的优缺点,如何将它们结合起来,发挥各自的优点呢?

融合 RAG(Fusion RAG)技术为我们提供了一个解决方案。它结合了向量检索和关键词检索两种方法,取两者的优点,为检索结果提供更全面的语义信息和精确的关键词匹配。

# 定义融合检索函数
def fusion_retrieval(query, chunks, vector_store, bm25_index, k=5, alpha=0.5):
    query_embedding = create_embeddings(query)
    vector_results = {r["metadata"]["index"]: r["similarity"] for r in vector_store.similarity_search_with_scores(query_embedding, len(chunks))}
    bm25_results = {r["metadata"]["index"]: r["bm25_score"] for r in bm25_search(bm25_index, chunks, query, len(chunks))}

    all_docs = vector_store.get_all_documents()
    scores = [(i, alpha * vector_results.get(i, 0) + (1 - alpha) * bm25_results.get(i, 0)) for i in range(len(all_docs))]
    top_docs = sorted(scores, key=lambda x: x[1], reverse=True)[:k]

    return [{"text": all_docs[i]["text"], "metadata": all_docs[i]["metadata"], "score": s} for i, s in top_docs]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

这种方法能够更好地满足不同查询的需求,提高检索的准确性。经过测试,融合 RAG 的评分达到了 0.83。这个分数表明,融合 RAG 技术能够显著提高检索结果的质量,从而提高生成回答的准确性。这也说明,结合多种检索方法是一个非常有效的策略,能够帮助我们更好地利用检索到的信息。

17. 多模态RAG:解锁图像信息

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

在前面的讨论中,我们主要关注了如何改进文本块的表示和检索策略,以及如何改进查询的质量和检索结果的排序,以及如何识别并提取连续的相关文本,以及如何对检索到的信息进行压缩,以及如何根据用户的反馈不断学习和调整,以及如何根据查询的类型自动选择检索策略,以及如何让系统自我反思,以及如何构建知识图谱,以及如何平衡上下文信息和检索精确性,以及如何从假设文档出发,以及如何结合多种检索方法。然而,我们忽略了一个重要的问题:文档中的信息不仅包含文本,还可能包含图像、图表等其他形式的信息,如何将这些信息也纳入检索范围呢?

多模态 RAG(Multi Model RAG)技术为我们提供了一个解决方案。它不仅从文档中提取文本,还会提取图像,并为图像生成描述性的标题。然后,系统将文本和图像的嵌入向量一起存储在向量库中,从而实现对文本和图像的联合检索。

# 处理多模态文档
def process_document(pdf_path, chunk_size=1000, chunk_overlap=200):
    image_dir = "extracted_images"
    os.makedirs(image_dir, exist_ok=True)

    text_data, image_paths = extract_content_from_pdf(pdf_path, image_dir)
    chunked_text = chunk_text(text_data, chunk_size, chunk_overlap)
    image_data = process_images(image_paths)

    all_items = chunked_text + image_data
    contents = [item["content"] for item in all_items]
    embeddings = create_embeddings(contents)

    vector_store = MultiModalVectorStore()
    vector_store.add_items(all_items, embeddings)

    doc_info = {
        "text_count": len(chunked_text),
        "image_count": len(image_data),
        "total_items": len(all_items),
    }

    print(f"Added {len(all_items)} items to vector store ({len(chunked_text)} text chunks, {len(image_data)} image captions)")
    return vector_store, doc_info
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

这种方法能够更好地利用文档中的信息,提高检索的准确性。经过测试,多模态 RAG 的评分达到了 0.79。这个分数表明,多模态 RAG 技术能够显著提高检索结果的质量,从而提高生成回答的准确性。这也说明,将图像信息纳入检索范围是一个非常重要的步骤,能够帮助我们更好地利用文档中的信息。

18. CRAG:动态调整检索策略

18种RAG技术大比拼:谁才是检索增强生成的最佳选择?-AI.x社区

在前面的讨论中,我们主要关注了如何改进文本块的表示和检索策略,以及如何改进查询的质量和检索结果的排序,以及如何识别并提取连续的相关文本,以及如何对检索到的信息进行压缩,以及如何根据用户的反馈不断学习和调整,以及如何根据查询的类型自动选择检索策略,以及如何让系统自我反思,以及如何构建知识图谱,以及如何平衡上下文信息和检索精确性,以及如何从假设文档出发,以及如何结合多种检索方法,以及如何将图像信息纳入检索范围。然而,我们忽略了一个重要的问题:检索到的信息可能并不总是理想的,如何动态调整检索策略,以应对不同的情况呢?

纠正性 RAG(Corrective RAG,CRAG)技术为我们提供了一个解决方案。它在检索之后,对检索到的信息进行评估,根据评估结果动态调整检索策略。如果检索到的信息质量高,系统会直接利用这些信息生成回答;如果检索到的信息质量低,系统会转而进行网络搜索;如果检索到的信息质量中等,系统会结合文档信息和网络搜索结果生成回答。

# 运行纠正性 RAG
crag_result = rag_with_compression(pdf_path, query, compression_type="selective")
  • 1.
  • 2.

这种方法能够更好地应对不同的情况,提高检索的准确性和可靠性。经过测试,纠正性 RAG 的评分达到了 0.824。这个分数表明,纠正性 RAG 技术能够显著提高检索结果的质量,从而提高生成回答的准确性。这也说明,动态调整检索策略是一个非常重要的步骤,能够帮助我们更好地利用检索到的信息。

结论:选择最适合的 RAG 技术

通过上述对 18 种 RAG 技术的测试和分析,我们可以看到,不同的技术有各自的优缺点,适用于不同的场景和需求。简单 RAG 提供了一个基础的框架,但其检索效果有限;语义分块、上下文增强检索、上下文块头、文档增强等技术通过改进文本块的表示和检索策略,提高了检索的准确性;查询转换、重排序、相关段落提取、上下文压缩等技术通过改进查询的质量和检索结果的排序,进一步提高了检索的效果;反馈循环、自适应 RAG、自我 RAG 等技术通过引入反馈机制和动态调整检索策略,让系统能够更好地适应不同的查询需求;知识图谱 RAG、层次化索引、HyDE、融合 RAG、多模态 RAG、纠正性 RAG 等技术通过结合多种方法和信息源,显著提高了检索的准确性和可靠性。

在这些技术中,自适应 RAG 以 0.86 的评分脱颖而出,成为表现最佳的 RAG 技术。它通过根据查询的类型自动选择最合适的检索策略,能够更好地满足不同用户的需求,生成更准确的回答。然而,这并不意味着其他技术没有价值。实际上,不同的技术可以在不同的场景下发挥重要作用,关键在于根据具体的需求和场景选择最适合的技术。

未来,随着人工智能技术的不断发展,RAG 技术也将不断进化。我们可以预见,结合多种技术的优点,开发出更加智能、高效、可靠的 RAG 系统,将为信息检索和自然语言处理领域带来更多的可能性和突破。


以上就是对 18 种 RAG 技术的详细分析和代码示例。希望这篇文章能够帮助你更好地了解 RAG 技术的多样性和潜力。如果你对某一种技术特别感兴趣,或者有其他问题,欢迎在评论区留言,我们一起探讨!


本文转载自公众号Halo咯咯    作者:基咯咯

原文链接:​​https://mp.weixin.qq.com/s/16Ra_wrH1igwiySPV9KkNA​


©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报


回复
相关推荐
这是一个AI学习、AI资讯类的公众号,我们将定期向您推荐最新讯息
觉得TA不错?点个关注精彩不错过
28
帖子
233
声望
2
粉丝
社区精华内容