博客

高级 RAG 技术第 1 部分:数据处理

讨论并实施可提高 RAG 性能的技术。第 1 部分(共 2 部分),重点介绍高级 RAG 管道的数据处理和摄取部分。

这是我们探索高级 RAG 技术的第一部分。 点击此处查看第二部分!

最近发表的论文《在检索增强生成中寻找最佳实践》对各种 RAG 增强技术的功效进行了实证评估,目的是为 RAG 找到一套最佳实践。

王建议的 RAG 管道

Wang 及其同事推荐的 RAG 管道。

我们将实施其中一些建议的最佳实践,即旨在提高搜索质量的实践(句子分块、HyDE、反向打包)

为简洁起见,我们将省略那些侧重于提高效率的技术(查询分类和摘要)

我们还将实施一些未涉及但我个人认为有用且有趣的技术(元数据包含、复合多字段嵌入、查询丰富化)

最后,我们将进行一个简短的测试,看看搜索结果和生成答案的质量与基线相比是否有所提高。让我们开始吧!

RAG 概览

RAG 的目的是通过检索外部知识库中的信息来丰富生成的答案,从而增强 LLM。通过提供特定领域的信息,LLM 可以快速适应训练数据范围之外的用例;比微调成本低得多,也更容易保持更新。

提高 RAG 质量的措施通常集中在两个方面:

  1. 提高知识库的质量和清晰度。

  2. 提高搜索查询的覆盖面和针对性。

这两项措施将实现提高法律硕士获得相关事实和信息的几率的目标,从而减少产生幻觉或利用自身知识的可能性--这些知识可能已经过时或不相关。

方法的多样性难以用几句话说清楚。为了更清楚地说明问题,让我们直接进入实施阶段。

高级 RAG 管道

图 1:作者使用的 RAG 管道。

目录

设置

所有代码均可 在 Searchlabs 软件仓库中找到

先说第一件事。您需要以下材料

  1. 弹性云部署

  2. LLM 应用程序接口--我们在本笔记本中使用了 Azure OpenAI 上的 GPT-4o 部署

  3. Python 3.12.4 或更高版本

我们将运行 main.ipynb 笔记本 中的所有代码 。

继续 git 克隆该 repo,导航至 supporting-blog-content/Advanced-rag-techniques,然后运行以下命令:

# Create a new virtual environment named 'rag_env'
python -m venv rag_env

# Activate the virtual environment (for Unix-based systems)
source rag_env/bin/activate

# (For Windows)
.\rag_env\Scripts\activate

# Install packages listed in requirements.txt
pip install -r requirements.txt

完成后,创建一个.env文件,并填写以下字段(在.env.example 中引用)。感谢我的合著者 Claude-3.5 提出的有益意见。

# Elastic Cloud: Found in the 'Deployment' page of your Elastic Cloud 
# console
ELASTIC_CLOUD_ENDPOINT=""
ELASTIC_CLOUD_ID=""

# Elastic Cloud: Created during deployment setup or in 'Security' 
# settings
ELASTIC_USERNAME=""
ELASTIC_PASSWORD=""

# Elastic Cloud: The name of the index you created in Kibana or via API
ELASTIC_INDEX_NAME=""

# Azure AI Studio: Found in 'Keys and Endpoint' section of your Azure 
# OpenAI resource
AZURE_OPENAI_KEY_1=""
AZURE_OPENAI_KEY_2=""
AZURE_OPENAI_REGION=""
AZURE_OPENAI_ENDPOINT=""

# Azure AI Studio: Found in 'Deployments' section of your Azure OpenAI 
# resource
AZURE_OPENAI_DEPLOYMENT_NAME=""

# Using BAAI/bge-small-en-v1.5 because I think it is a good balance of 
# resource efficiency and performance. 
HUGGINGFACE_EMBEDDING_MODEL="BAAI/bge-small-en-v1.5"

接下来,我们将选择要摄取的文档,并将其放在文档文件夹中。在本文中,我们将使用 Elastic N.V. 的《 2023 年年度报告》 。这是一份相当具有挑战性的密集文件,非常适合对我们的 RAG 技术进行压力测试。

2023 年弹性年度报告

2023 年弹性年度报告

现在我们都准备好了,开始摄入。打开main.ipynb,执行前两个单元格以导入所有软件包并初始化所有服务。

返回顶部

摄取、处理和嵌入文件

数据采集

  • 个人感言:LlamaIndex 的便利性令我震惊。在还没有 LLM 和 LlamaIndex 的年代,录入各种格式的文档是一个痛苦的过程,需要从各处收集深奥的软件包。现在只需调用一个函数。狂野

SimpleDirectoryReader 将加载directory_path. 文件中的每个文档。对于.pdf 文件,它会返回一个文档对象列表,我将其转换为 Python 字典,因为我觉得它们更容易处理。

# llamaindex_processor.py
from llama_index.core import SimpleDirectoryReader

class LlamaIndexProcessor:
   def __init__(self):
       pass 
   
   def load_documents(self, directory_path):
       ''' 
       Load all documents in directory
       '''
       reader = SimpleDirectoryReader(input_dir=directory_path)
       return reader.load_data()

# main.ipynb
llamaindex_processor=LlamaIndexProcessor()
documents=llamaindex_processor.load_documents('./documents/')
documents=[dict(doc_obj) for doc_obj in documents]

每个字典都包含text 字段中的关键内容。它还包含有用的元数据,如页码、文件名、文件大小和类型。

{
  'id_': '5f76f0b3-22d8-49a8-9942-c2bbab14f63f',
  'metadata': {'page_label': '5',
   'file_name': 'Elastic_NV_Annual-Report-Fiscal-Year-2023.pdf',
   'file_path': '/Users/han/Desktop/Projects/truckasaurus/documents/Elastic_NV_Annual-Report-Fiscal-Year-2023.pdf',
   'file_type': 'application/pdf',
   'file_size': 3724426,
   'creation_date': '2024-07-27',
   'last_modified_date': '2024-07-27'},
   'text': 'Table of Contents\nPage\nPART I\nItem 1. Business 3\n15 Item 1A. Risk Factors\nItem 1B. Unresolved Staff Comments 48\nItem 2. Properties 48\nItem 3. Legal Proceedings 48\nItem 4. Mine Safety Disclosures 48\nPART II\nItem 5. Market for Registrant's Common Equity, Related Stockholder Matters and Issuer Purchases of \nEquity Securities49\nItem 6. [Reserved] 49\nItem 7. Management's Discussion and Analysis of Financial Condition and Results of Operations 50\nItem 7A. Quantitative and Qualitative Disclosures About Market Risk 64\nItem 8. Financial Statements and Supplementary Data 66\nItem 9. Changes in and Disagreements With Accountants on Accounting and Financial Disclosure 100\n100\n101Item 9A. Controls and Procedures\nItem 9B. Other Information\nItem 9C. Disclosure Regarding Foreign Jurisdictions That Prevent Inspections 101\nPART III\n102\n102\n102\n102Item 10. Directors, Executive Officers and Corporate Governance\nItem 11. Executive Compensation\nItem 12. Security Ownership of Certain Beneficial Owners and Management, and Related Stockholder Matters  \nItem 13. Certain Relationships and Related Transactions, and Director Independence\nItem 14. Principal Accountant Fees and Services 102\nPART IV\n103\n105Item 15. Exhibits and Financial Statement Schedules  \nItem 16. Form 10-K Summary\nSignatures 106\ni',
   ...
}

返回顶部

句子级标记分块

首先要做的是将我们的文件缩减成标准长度的块状(以确保一致性和可管理性)。嵌入模型有独特的标记限制(可处理的最大输入尺寸)。标记是模型处理文本的基本单位。为防止信息丢失(内容截断或遗漏),我们应提供不超过这些限制的文本(将较长的文本分割成较小的片段)。

分块对性能有重大影响。在理想情况下,每个信息块都代表一个独立的信息片段,捕捉有关单个主题的上下文信息。分块方法包括字级分块(按字数分割文档)和语义分块(使用 LLM 识别逻辑断点)。

单词级的分块处理成本低、速度快、操作简单,但存在拆分句子从而破坏上下文的风险。语义分块的速度越来越慢,成本越来越高,尤其是在处理像116页的《弹性年度报告》这样的文档时。

让我们选择一种中间路线。句子级分块仍然简单,但比单词级分块能更有效地保留上下文,而且成本更低,速度更快。此外,我们还将采用一个滑动窗口来捕捉周围的一些上下文,并减轻分割段落的影响。

# chunker.py 

import uuid
import re


class Chunker: 
    def __init__(self, tokenizer):
        self.tokenizer = tokenizer 
    
    def split_into_sentences(self, text):
        """Split text into sentences."""
        return re.split(r'(?<=[.!?])\s+', text)
 
    def sentence_wise_tokenized_chunk_documents(self, documents, chunk_size=512, overlap=20, min_chunk_size=50):
        '''
        1. Split text into sentences.
        2. Tokenize using the provided tokenizer method.
        3. Build chunks up to the chunk_size limit.
        4. Create an overlap based on tokens - to preserve context.
        5. Only keep chunks that meet the minimum token size requirement.
        '''
        chunked_documents = []

        for doc in documents:
            sentences = self.split_into_sentences(doc['text'])
            tokens = []
            sentence_boundaries = [0]

            # Tokenize all sentences and keep track of sentence boundaries
            for sentence in sentences:
                sentence_tokens = self.tokenizer.encode(sentence, add_special_tokens=True)
                tokens.extend(sentence_tokens)
                sentence_boundaries.append(len(tokens))

            # Create chunks
            chunk_start = 0
            while chunk_start < len(tokens):
                chunk_end = chunk_start + chunk_size

                # Find the last complete sentence that fits in the chunk
                sentence_end = next((i for i in sentence_boundaries if i > chunk_end), len(tokens))
                chunk_end = min(chunk_end, sentence_end)

                # Create the chunk
                chunk_tokens = tokens[chunk_start:chunk_end]

                # Check if the chunk meets the minimum size requirement
                if len(chunk_tokens) >= min_chunk_size:
                    # Create a new document object for this chunk
                    chunk_doc = {
                        'id_': str(uuid.uuid4()),
                        'chunk': chunk_tokens,
                        'original_text': self.tokenizer.decode(chunk_tokens),
                        'chunk_index': len(chunked_documents),
                        'parent_id': doc['id_'],
                        'chunk_token_count': len(chunk_tokens)
                    }

                    # Copy all other fields from the original document
                    for key, value in doc.items():
                        if key != 'text' and key not in chunk_doc:
                            chunk_doc[key] = value

                    chunked_documents.append(chunk_doc)

                # Move to the next chunk start, considering overlap
                chunk_start = max(chunk_start + chunk_size - overlap, chunk_end - overlap)

        return chunked_documents

# main.ipynb 
# Initialize Embedding Model
HUGGINGFACE_EMBEDDING_MODEL = os.environ.get('HUGGINGFACE_EMBEDDING_MODEL')
embedder=EmbeddingModel(model_name=HUGGINGFACE_EMBEDDING_MODEL)

# Initialize Chunker
chunker=Chunker(embedder.tokenizer)

Chunker 类采用嵌入模型的标记化器对文本进行编码和解码。现在,我们将构建每块 512 个令牌的分块,其中有 20 个令牌重叠。为此,我们会将文本分割成句子,对这些句子进行标记化处理,然后将标记化处理后的句子添加到当前语块中,直到无法在不超出标记限制的情况下添加更多句子为止。

最后,将句子解码回原始文本进行嵌入,将其存储在名为original_text 的字段中。数据块存储在一个名为chunk 的字段中。为了减少噪音(又称无用文件),我们将丢弃长度小于 50 个 token 的文件。

让我们在文件上运行一下:

chunked_documents=chunker.sentence_wise_tokenized_chunk_documents(documents, chunk_size=512)

然后得到类似这样的文本块:

print(chunked_documents[4]['original_text'])

[CLS] the aggregate market value of the ordinary shares held by non - affiliates of the registrant, 
based on the closing price of the shares of ordinary shares on the new york stock exchange on 
october 31, 2022 ( the last business day of the registrant 's second fiscal quarter ), was 
approximately $ 6. 1 billion. [SEP] [CLS] as of may 31, 2023, the registrant had 97, 390, 886 
ordinary shares, par value €0. 01 per share, outstanding. [SEP] [CLS] documents incorporated by 
reference portions of the registrant 's definitive proxy statement relating to the registrant 's 2
023 annual general meeting of shareholders are incorporated by reference into part iii of this annual 
...
...

返回顶部

元数据的纳入和生成

我们已将文件分块。现在是丰富数据的时候了。我想生成或提取额外的元数据。这些附加元数据可用于影响和提高搜索性能。

我们将定义一个DocumentEnricher 类,它的作用是接收文档列表(Python 字典)和处理器函数列表。这些函数将在文档的original_text 列中运行,并将其输出存储在新字段中。

首先,我们使用TextRank 提取关键词。TextRank 是一种基于图的算法,它能根据词与词之间的关系对关键短语和句子的重要性进行排序,从而从文本中提取关键短语和句子。

接下来,我们将使用 GPT-4o 生成 potential_questions

最后,我们将使用 Spacy 提取实体

由于每项工作的代码都相当冗长和复杂,我就不在此赘述了。如果您感兴趣,这些文件已在下面的代码示例中标出。

让我们运行数据浓缩:

# documentenricher.py
from tqdm import tqdm

class DocumentEnricher:

    def __init__(self):
        pass 

    def enrich_document(self, documents, processors, text_col='text'):
        for doc in tqdm(documents, desc="Enriching documents using processors: "+str(processors)): 
            for (processor, field) in processors: 
                metadata=processor(doc[text_col])
                if isinstance(metadata, list):
                    metadata='\n'.join(metadata)
                doc.update({field: metadata})
 
# main.ipynb
# Initialize processor classes 
nltkprocessor=NLTKProcessor() // nltk_processor.py
entity_extractor=EntityExtractor() // entity_extractor.py
gpt4o = LLMProcessor(model='gpt-4o') // llm.py

# Initialize LLM
documentenricher=DocumentEnricher()

# Create new fields in the documents - These are the outputs of the processor functions.
processors=[
    (nltkprocessor.textrank_phrases, "keyphrases"),
    (gpt4o.generate_questions, "potential_questions"),
    (entity_extractor.extract_entities, "entities")
    ]

# .enrich_document() will modify chunked_docs in place. 
# To view the results, we'll print chunked_docs in the next few cells!
documentenricher.enrich_document(chunked_docs, text_col='original_text', processors=processors)

看看结果吧:

通过 TextRank 提取的关键词

这些关键短语是大块核心主题的替身。如果查询与网络安全有关,这块内容的得分就会提高。

print(chunked_documents[25]['keyphrases'])

'elastic agent stop', 'agent stop malware', 
'stop malware ransomware', 'malware ransomware environment', 
'ransomware environment wide', 'environment wide visibility', 
'wide visibility threat', 'visibility threat detection', 
'sep cl key', 'cl key feature'

GPT-4o 提出的潜在问题

这些潜在问题可能与用户查询直接匹配,从而提高得分。我们会提示 GPT-4o 生成一些问题,这些问题可以用当前语块中的信息来回答。

print(chunked_documents[25]['potential_questions'])

1. What are the primary functions that Elastic Agent provides in terms of cybersecurity?
2. Describe how Logstash contributes to data management within an IT environment.
3. List and explain any key features of Logstash mentioned in the document.
4. How does Elastic Agent enhance environment-wide visibility in threat detection?
5. What capabilities does Logstash offer for handling data beyond simple collection?
6. In what ways does the document suggest that Elastic Agent stops malware and ransomware?
7. Can you identify any relationships between the functionalities of Elastic Agent and Logstash in an integrated environment?
8. What implications might the advanced threat detection capabilities of Elastic Agent have for organizational security policies?
9. Compare and contrast the roles of Elastic Agent and Logstash based on their described functions.
10. How might the centralized collection ability of Logstash support the threat detection capabilities of Elastic Agent?

Spacy 提取的实体

这些实体的作用与关键词类似,但可以捕捉到组织和个人的名称,而关键词提取可能会遗漏这些名称。

print(chunked_documents[29]['entities'])

'appdynamics', 'apm data', 'azure sentinel', 
'microsoft', 'mcafee', 'broadcom', 'cisco', 
'dynatrace', 'coveo', 'lucidworks'

返回顶部

复合多场嵌入

现在,我们已经用更多的元数据丰富了我们的文档,我们可以利用这些信息创建更强大、更能感知上下文的嵌入。

让我们回顾一下目前的进程。我们在每份文档中都有四个关注领域。

{
    "chunk": "...",
    "keyphrases": "...", 
    "potential_questions": "...", 
    "entities": "..." 
}

每个字段都代表了对文件背景的不同看法,可能突出了法律硕士应重点关注的关键领域。

RAG 中的元数据丰富管道

元数据丰富管道

我们的计划是嵌入每个字段,然后创建嵌入的加权和,即复合嵌入。

幸运的话,除了引入另一个可调整的超参数来控制搜索行为外,这种复合嵌入还能让系统变得更加了解上下文。

首先,让我们使用在 main.ipynb 笔记本开头导入的本地定义的嵌入模型,嵌入每个字段并就地更新每个文档。

# EmbeddingModel defined in embedding_model.py
embedder=EmbeddingModel(model_name=HUGGINGFACE_EMBEDDING_MODEL)

cols_to_embed=['keyphrases', 'potential_questions', 'entities']

embedding_cols=[]
for col in cols_to_embed:
    # Works on text input
    embedding_col=embedder.embed_documents_text_wise(chunked_documents, text_field=col)
    embedding_cols.append(embedding_col)
# Works on token input
embedding_col=embedder.embed_documents_token_wise(chunked_documents, token_field="chunk")
embedding_cols.append(embedding_col)

每个嵌入函数都会返回嵌入的字段,即带有_embedding 后缀的原始输入字段。

现在我们来定义复合嵌入的权重:

embedding_cols=[
                'keyphrases_embedding',
                'potential_questions_embedding',
                'entities_embedding',
                'chunk_embedding']
combination_weights=[
                    0.1,
                    0.15,
                    0.05,
                    0.7
                ]

通过权重,您可以根据用例和数据质量为每个组件分配优先级。直观地说,这些权重的大小取决于每个组件的语义值。由于大块文本本身的内容迄今为止最为丰富,我将其权重定为 70% 。由于实体最小,只是一个组织或个人名称列表,因此我将其权重定为 5% 。这些值的精确设置必须根据具体情况,根据经验来确定。

最后,让我们编写一个函数来应用权重,并创建我们的复合嵌入。为了节省空间,我们还将删除所有的组件嵌入。

from tqdm import tqdm 
def combine_embeddings(objects, embedding_cols, combination_weights, primary_embedding='primary_embedding'):
    # Ensure the number of weights matches the number of embedding columns
    assert len(embedding_cols) == len(combination_weights), "Number of embedding columns must match number of weights"
    
    # Normalize weights to sum to 1
    weights = np.array(combination_weights) / np.sum(combination_weights)
    
    for obj in tqdm(objects, desc="Combining embeddings"):
        # Initialize the combined embedding
        combined = np.zeros_like(obj[embedding_cols[0]])
        
        # Compute the weighted sum
        for col, weight in zip(embedding_cols, weights):
            combined += weight * np.array(obj[col])
        
        # Add the new combined embedding to the object
        obj.update({primary_embedding:combined.tolist()})
        
        # Remove the original embedding columns
        for col in embedding_cols:
            obj.pop(col, None)

combine_embeddings(chunked_documents, embedding_cols, combination_weights)

至此,我们完成了文件处理工作。现在我们有了一个文档对象列表,看起来像这样:

{ 'id_': '7fe71686-5cd0-4831-9e79-998c6dbeae0c', 'chunk': [2312, 14613, ...], 'original_text': 'if an emerging growth company, indicate by check mark if the registrant has elected not to use the extended ...', 'chunk_index': 3, 'chunk_token_count': 399, 'metadata': {'page_label': '3', 'file_name': 'Elastic_NV_Annual-Report-Fiscal-Year-2023.pdf', ... 'keyphrases': 'sep cl unk\ncheck mark registrant\ncl unk indicate\nunk indicate check\nindicate check mark\nprincipal executive office\naccelerate filer unk\ncompany unk emerge\nunk emerge growth\nemerge growth company', 'potential_questions': '1. What are the different types of registrant statuses mentioned in the document?\n2. Under what section of the Sarbanes-Oxley Act must registrants file a report on the effectiveness of their internal ...', 'entities': 'the effe ctiveness of\nsection 13\nSEP\nUNK\nsection 21e\n1934\n1933\nu. s. c.\nsection 404\nsection 12\nal', 'primary_embedding': [-0.3946287803351879, -0.17586839850991964, ...] }

索引至弹性

让我们将文档批量上传到 Elastic Search。为此,我很早就在elastic_helpers.py 中定义了一组 Elastic Helper 函数。这是一段非常冗长的代码,所以我们还是只看函数调用。

es_bulk_indexer.bulk_upload_documents 利用 Elasticsearch 方便的动态映射,可以处理任何字典对象列表。

# Initialize Elasticsearch
ELASTIC_CLOUD_ID = os.environ.get('ELASTIC_CLOUD_ID')
ELASTIC_USERNAME = os.environ.get('ELASTIC_USERNAME')
ELASTIC_PASSWORD = os.environ.get('ELASTIC_PASSWORD')
ELASTIC_CLOUD_AUTH = (ELASTIC_USERNAME, ELASTIC_PASSWORD)
es_bulk_indexer = ESBulkIndexer(cloud_id=ELASTIC_CLOUD_ID, credentials=ELASTIC_CLOUD_AUTH)
es_query_maker = ESQueryMaker(cloud_id=ELASTIC_CLOUD_ID, credentials=ELASTIC_CLOUD_AUTH)

# Define Index Name
index_name=os.environ.get('ELASTIC_INDEX_NAME')


# Create index and bulk upload 
index_exists = es_bulk_indexer.check_index_existence(index_name=index_name)
if not index_exists:
    logger.info(f"Creating new index: {index_name}")
    es_bulk_indexer.create_es_index(es_configuration=BASIC_CONFIG, index_name=index_name)

success_count = es_bulk_indexer.bulk_upload_documents(
    index_name=index_name, 
    documents=chunked_documents, 
    id_col='id_',
    batch_size=32
)

前往 Kibana,确认所有文件都已编入索引。应该有 224 个。对于这么大的文件来说,还算不错!

Kibana 索引

Kibana 中索引化的年度报告文件

返回顶部

猫休息

我们休息一下吧,文章有点沉重,我知道。看看我的猫

汉族管道

看她气得

真可爱帽子不见了,我半信半疑是她偷藏起来的:(

祝贺你们走到这一步 :)

请看第二部分,了解我们对 RAG 管道的测试和评估!

附录

定义

1.句子分块

  • RAG 系统中使用的一种预处理技术,用于将文本划分为更小的、有意义的单元。

  • 过程:

    1. 输入:大段文本(如文档、段落)

    2. 输出:较小的文本片段(通常是句子或小句子组)

  • 目的是

    • 创建细粒度、针对特定上下文的文本片段

    • 允许更精确的索引和检索

    • 提高 RAG 系统检索信息的相关性

  • 特点

    • 分段具有语义意义

    • 可独立索引和检索

    • 通常保留一些上下文,以确保独立的可理解性

  • 优势:

    • 提高检索精度

    • 使 RAG 管道的扩容更有针对性

2.HyDE(假设文档嵌入)

  • 在 RAG 系统中使用 LLM 生成用于查询扩展的假设文档的技术。

  • 过程:

    1. 向 LLM 输入查询

    2. LLM 生成回答查询的假设文档

    3. 嵌入生成的文件

    4. 使用嵌入进行向量搜索

  • 主要区别

    • 传统 RAG:将查询与文档匹配

    • HyDE:将文档匹配到文档

  • 目的是

    • 提高检索性能,尤其是复杂或模糊查询的检索性能

    • 捕捉比简短查询更丰富的语义上下文

  • 优势:

    • 利用 LLM 的知识扩展查询

    • 有可能提高检索文件的相关性

  • 挑战:

    • 需要额外的 LLM 推理,增加了延迟和成本

    • 性能取决于生成的假设文件的质量

3.反向包装

  • RAG 系统中使用的一种技术,用于在将搜索结果传递给 LLM 之前对其重新排序。

  • 过程:

    1. 搜索引擎(如 Elasticsearch)按相关性降序返回文档。

    2. 顺序颠倒,将最相关的文件放在最后。

  • 目的是

    • 利用 LLM 的新旧偏差,LLM 往往更关注其上下文中的最新信息。

    • 确保最相关的信息"最新鲜的" 在 LLM 的上下文窗口中。

  • 举例说明:原始顺序:[最相关、第二最相关、第三最相关、......] 倒序:[......,最重要的第三项,最重要的第二项,最相关的]

4.查询分类

  • 通过确定查询是需要 RAG 还是可以直接由 LLM 回答来优化 RAG 系统效率的技术。

  • 过程:

    1. 针对使用中的 LLM 开发定制数据集

    2. 训练专门的分类模型

    3. 使用模型对收到的查询进行分类

  • 目的是

    • 避免不必要的 RAG 处理,提高系统效率

    • 将查询引导至最合适的响应机制

  • 要求:

    • LLM 专用数据集和模型

    • 不断改进以保持准确性

  • 优势:

    • 减少简单查询的计算开销

    • 有可能缩短非 RAG 查询的响应时间

5.总结

  • 在 RAG 系统中压缩检索文档的技术。

  • 过程:

    1. 检索相关文件

    2. 生成每份文件的简明摘要

    3. 在 RAG 管道中使用摘要而非完整文件

  • 目的是

    • 关注基本信息,提高 RAG 性能

    • 减少不相关内容的噪音和干扰

  • 优势:

    • 有可能提高 LLM 答复的相关性

    • 允许在上下文限制内纳入更多文件

  • 挑战:

    • 总结时有可能丢失重要细节

    • 生成摘要的额外计算开销

6.元数据的纳入

  • 一种用额外的上下文信息来丰富文档的技术。

  • 元数据类型:

    • 关键词

    • 标题

    • 日期

    • 作者详细信息

    • 简介

  • 目的是

    • 增加 RAG 系统可用的背景信息

    • 让法律硕士更清楚地了解文件内容和相关性

  • 优势:

    • 有可能提高检索的准确性

    • 提高法律硕士评估文件实用性的能力

  • 实施:

    • 可在文件预处理过程中完成

    • 可能需要额外的数据提取或生成步骤

7.复合多字段嵌入

  • RAG 系统的高级嵌入技术,可为不同的文档组件创建单独的嵌入。

  • 过程:

    1. 确定相关字段(例如标题、关键词、简介、主要内容)

    2. 为每个字段生成单独的嵌入

    3. 合并或存储这些嵌入信息,以用于检索

  • 与标准方法的区别:

    • 传统:对整个文档进行单一嵌入

    • 复合:针对不同文档方面的多重嵌入

  • 目的是

    • 创建更细致入微、更能感知上下文的文档表示法

    • 在文件中获取更多来源的信息

  • 优势:

    • 有可能提高模糊或多方面查询的性能

    • 允许在检索中更灵活地加权不同的文件内容

  • 挑战:

    • 嵌入存储和检索流程的复杂性增加

    • 可能需要更复杂的匹配算法

8.丰富查询

  • 一种用相关术语扩展原始查询以提高搜索覆盖率的技术。

  • 过程:

    1. 分析原始查询

    2. 生成同义词和语义相关的短语

    3. 用这些附加术语来扩展查询

  • 目的是

    • 增加文件语料库中潜在匹配的范围

    • 提高使用特定或技术语言查询的检索性能

  • 优势:

    • 可能检索到与原始查询条件不完全匹配的相关文档

    • 有助于克服查询和文档之间的词汇不匹配问题

  • 挑战:

    • 如果不认真执行,则有查询偏移的风险

    • 可能会增加检索过程中的计算开销

返回顶部

相关内容

LINQ to Elasticsearch ES|QL:编写 C# 代码,查询 Elasticsearch

Florian Bernd

利用 Elasticsearch 中的 NLP 和向量搜索增强聊天机器人功能

Priscilla Parodi

Elasticsearch 与 OpenSearch:向量搜索性能比较

Ugo Sangiorgi

人工智能剽窃利用 Elasticsearch 检测剽窃行为

Priscilla Parodi

高级 RAG 技术第 2 部分:查询和测试

Han Xiang Choong

准备好打造最先进的搜索体验了吗?

足够先进的搜索不是一个人的努力就能实现的。Elasticsearch 由数据科学家、ML 操作员、工程师以及更多和您一样对搜索充满热情的人提供支持。让我们联系起来,共同打造神奇的搜索体验,让您获得想要的结果。

亲自试用