Aprendizagem pessoal com IA
e orientação prática
讯飞绘镜

Dominando a fragmentação de documentos RAG: um guia de estratégias de fragmentação para a criação de sistemas de recuperação eficientes

Se o seu RAG O aplicativo não está produzindo os resultados desejados, portanto, talvez seja hora de rever sua estratégia de fragmentação.Um melhor agrupamento significa uma recuperação mais precisa, o que, em última análise, leva a respostas de maior qualidade.

No entanto, a fragmentação não é uma abordagem única para todos, e nenhuma abordagem é absolutamente ideal. Você precisa considerar e escolher a estratégia mais adequada de acordo com as necessidades específicas do projeto, as características do documento, o orçamento e outros fatores.


 

Por que a qualidade do chunking afeta diretamente a qualidade das respostas do RAG?

Tenho certeza de que, ao ler este artigo, você já entendeu os conceitos básicos de chunking e RAG. Para recapitular rapidamente, a ideia central do RAG é fazer com que o LLM Responda às perguntas com base nas informações contextuais fornecidasIsso ocorre porque o LLM tem uma base de conhecimento rica, mas tem um atraso na atualização de seu conhecimento e não pode acessar dados privados diretamente. Isso ocorre porque, embora o LLM tenha uma base de conhecimento rica, ele tem um atraso na atualização de seu conhecimento e não tem acesso direto a dados privados.

O RAG compensa as deficiências do próprio LLM injetando fragmentos de documentos relevantes (ou seja, contexto) nos prompts e orientando o LLM a gerar respostas com base nesses fragmentos. O contexto pode ser obtido de várias maneiras, por exemplo, por meio de consulta a banco de dados, pesquisa na Internet ou extração de documentos PDF.

Há dois desafios principais para a criação de um aplicativo RAG eficiente:

  1. Limites da janela de contexto para o LLMOs primeiros LLMs, como o GPT-2 e o GPT-3, tinham janelas de contexto pequenas, o que limitava a quantidade de texto que poderia ser processada em uma única passagem. Embora agora existam modelos que suportam janelas de contexto maiores, isso não significa que podemos simplesmente amontoar um documento inteiro em um LLM.
  2. problema de ruído de contextoO que acontece é que, mesmo que a janela de contexto do LLM seja grande o suficiente, se as informações de contexto fornecidas contiverem muito conteúdo (ruído) que não seja relevante para a pergunta, isso poderá afetar a compreensão e o julgamento do LLM, levando a uma degradação da qualidade da resposta ou até mesmo a alucinações.

Para resolver esses problemas.Agrupamento de documentosA tecnologia nasceu. A ideia central é dividir documentos grandes em segmentos menores e semanticamente coerentes (pedaços) e, na fase de recuperação, apenas os pedaços mais relevantes são selecionados como o contexto fornecido ao LLM.

Há várias formas de fragmentação de documentos, como a fragmentação simples de frases e parágrafos, a fragmentação semântica complexa, a fragmentação agêntica etc. É importante escolher uma estratégia de fragmentação adequada, o que afeta diretamente a eficiência do sistema RAG e a qualidade da resposta final. A escolha de uma estratégia de fragmentação adequada é fundamental e afeta diretamente a eficiência de recuperação do sistema RAG e a qualidade da resposta final.

Neste artigo, vamos nos aprofundar em várias estratégias mais avançadas e práticas de fragmentação de documentos para ajudá-lo a criar aplicativos RAG mais robustos. Ignoraremos a fragmentação simples de frases e parágrafos e nos concentraremos em técnicas que são mais valiosas em aplicativos RAG do mundo real.

A seguir, detalharei algumas estratégias de fragmentação que aprendi e pratiquei.

 

Segmentação recursiva de caracteres: uma abordagem básica rápida e econômica

Divisão recursiva de caracteres, você pode pensar que esse é o método mais básico. De fato, ele é básico, mas ainda é uma das técnicas de fragmentação mais comumente usadas e econômicas na minha opinião. Ela é fácil de entender, simples de implementar, rápida e econômica, o que a torna especialmente adequada para prototipagem rápida e projetos sensíveis ao custo.

A ideia central da segmentação recursiva de caracteres éUsar uma janela deslizante de tamanho fixoe permite a sobreposição entre janelas. Ele gera blocos de texto ao deslizar continuamente a janela a partir da posição inicial do documento com um tamanho de bloco predefinido e um número de caracteres sobrepostos.

A figura a seguir mostra como funciona a segmentação recursiva de caracteres:

RAGs 文档分块策略:提升检索质量的实战指南-1Como funciona a segmentação recursiva de caracteres - desenhado por Thuwarakesh
O exemplo da figura, em que o tamanho do bloco é definido como 20 caracteres e o número de caracteres sobrepostos é 2, mostra como um bloco de texto pode ser gerado por meio de uma janela deslizante.

A vantagem da segmentação recursiva de caracteres é sua simplicidade e eficiência. Ela permite o processamento rápido de documentos grandes e a fragmentação de relatórios anuais em nível de minuto. A implementação da segmentação recursiva de caracteres na Langchain é muito simples:

from langchain.text_splitter import RecursiveCharacterTextSplitter
text = """
Hydroponics is an intelligent way to grow veggies indoors or in small spaces. In hydroponics, plants are grown without soil, using only a substrate and nutrient solution. The global population is rising fast, and there needs to be more space to produce food for everyone. Besides, transporting food for long distances involves lots of issues. You can grow leafy greens, herbs, tomatoes, and cucumbers with hydroponics.
"""
rc_splits = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
chunk_size=20, chunk_overlap=2
).split_text(text)

Variantes de janelas deslizantes

Na prática, o tamanho da janela deslizante e a etapa deslizante podem ser variados para atender a diferentes necessidades:

  • Janelas deslizantes baseadas em caracteres vs. baseadas em tokens: O exemplo acima é uma janela deslizante baseada em caracteres. Também é possível usar uma janela deslizante baseada em caracteres Token janela deslizante para garantir que os tamanhos dos blocos estejam mais alinhados com o processamento do LLM.Langchain RecursiveCharacterTextSplitter Há suporte para os modos de caractere e token.
  • Tamanho da janela dinâmicaObservação: embora os tamanhos fixos de janela caracterizem a segmentação recursiva de caracteres, o redimensionamento dinâmico da janela também pode ser considerado em determinados cenários. Por exemplo, o ajuste adaptativo do tamanho da janela de acordo com o comprimento da frase ou a estrutura do parágrafo para garantir a integridade semântica do bloco.

limitações

A segmentação recursiva de caracteres é umaAbordagem de chunking baseada em posição. Ela simplesmente pressupõe que o texto que é adjacente em termos de posição em um documento também é semanticamente relacionado. No entanto, essa suposição não se sustenta em muitos casos.

Reflita: Por que o chunking baseado em localização leva a um desempenho ruim dos RAGs? Como implementar o chunking semântico e obter melhores resultados?

Por exemplo, em um mesmo capítulo, o autor pode primeiro discutir vários conceitos diferentes antes de finalmente relacioná-los. Se apenas a segmentação recursiva de caracteres for usada, o conteúdo que deveria pertencer à mesma unidade semântica poderá ser dividido ou o conteúdo semanticamente não relacionado poderá ser combinado, afetando a recuperação.

Apesar de suas limitações, a segmentação recursiva de caracteres é ideal para começar a usar o RAG. Ela geralmente fornece resultados satisfatórios durante a fase de prototipagem ou para documentos simplesmente estruturados. A segmentação recursiva de caracteres também é uma opção interessante se o seu projeto tiver requisitos de alto custo e velocidade.

 

Chunking semântico: uma abordagem de chunking para entender o significado do texto

O chunking semântico é uma estratégia de chunking mais avançada queEm vez de confiar apenas nas informações de posição do texto, obtém-se uma compreensão mais profunda do significado semântico do texto. A ideia central é segmentar os documentos quando sua semântica muda significativamente, garantindo que cada bloco seja centrado em um único tópico, tanto quanto possível.

A figura abaixo mostra como funciona o chunking semântico:

RAGs 文档分块策略:提升检索质量的实战指南-2O chunking semântico funciona - desenhado por Thuwarakesh
Por exemplo, as duas primeiras frases discutem a agricultura hidropônica, depois as duas frases seguintes mudam para questões globais e depois voltam para a agricultura hidropônica. O chunking semântico é capaz de reconhecer essas mudanças de tópico semântico e segmentar nas mudanças de tópico.

Ao contrário da segmentação recursiva de caracteres, o chunking semântico gera blocos de comprimento tipicamente variável. Ele determinará os limites do bloco com base na integridade semântica, em vez de predefinir um número fixo de caracteres ou tokens.

Principais etapas para o chunking semântico

A dificuldade com o chunking semântico é comoProgramado para entender a semântica das frases**. Isso geralmente é feito com a ajuda deModelos de incorporaçãopara implementar. A incorporação de modelos como o da OpenAI incorporação de texto-3-grandeAs frases podem ser convertidas em representações vetoriais, e os vetores são capazes de capturar as informações semânticas de uma frase. As frases que são semanticamente semelhantes têm vetores que também são mais próximos no espaço. **

Um processo típico de chunking semântico consiste nas cinco etapas a seguir:

  • Construção do bloco inicialDivisão do documento em frases ou parágrafos: inicialmente divide o documento em frases ou parágrafos e combina frases ou parágrafos adjacentes em um bloco inicial.
  • Gerar incorporação de blocosUse o modelo de incorporação para gerar incorporação de vetores para cada bloco inicial.
  • Calcular a distância entre os blocosDistância semântica: Calcule a distância semântica entre blocos vizinhos. As métricas de distância comumente usadas incluem a distância cosseno e assim por diante. Quanto maior a distância, maior a diferença semântica.
  • Determinar o ponto de divisãoDefinir um limite de distância. Quando a distância entre os blocos vizinhos exceder o limite, quebre-os para formar novos blocos semânticos. A seleção do limite precisa ser ajustada de acordo com o documento específico e o efeito experimental.
  • Visualização (opcional)Visualização da distância entre os blocos: a visualização da distância entre os blocos ajuda a entender o efeito de fragmentação de forma mais intuitiva e a ajustar os limites.

O código a seguir mostra como implementar o chunking semântico:

# Step 1 : Create initial chunks by combining concecutive sentences.
# ------------------------------------------------------------------
#Split the text into individual sentences.
sentences = re.split(r"(?<=[.?!])\s+", text)
initial_chunks = [
{"chunk": str(sentence), "index": i} for i, sentence in enumerate(sentences)
]
# Function to combine chunks with overlapping sentences
def combine_chunks(chunks):
for i in range(len(chunks)):
combined_chunk = ""
if i > 0:
combined_chunk += chunks[i - 1]["chunk"]
combined_chunk += chunks[i]["chunk"]
if i < len(chunks) - 1:
combined_chunk += chunks[i + 1]["chunk"]
chunks[i]["combined_chunk"] = combined_chunk
return chunks
# Combine chunks
combined_chunks = combine_chunks(initial_chunks)
# Step 2 : Create embeddings for the initial chunks.
# ------------------------------------------------------------------
# Embed the combined chunks
chunk_embeddings = embeddings.embed_documents(
[chunk["combined_chunk"] for chunk in combined_chunks]
# If you haven't created combined_chunk, use the following.
# [chunk["chunk"] for chunk in combined_chunks]
)
# Add embeddings to chunks
for i, chunk in enumerate(combined_chunks):
chunk["embedding"] = chunk_embeddings[i]
# Step 3 : Calculate distance between the chunks
# ------------------------------------------------------------------
def calculate_cosine_distances(chunks):
distances = []
for i in range(len(chunks) - 1):
current_embedding = chunks[i]["embedding"]
next_embedding = chunks[i + 1]["embedding"]
similarity = cosine_similarity([current_embedding], [next_embedding])[0][0]
distance = 1 - similarity
distances.append(distance)
chunks[i]["distance_to_next"] = distance
return distances
# Calculate cosine distances
distances = calculate_cosine_distances(combined_chunks)
# Step 4 : Find chunks with significant different to it's previous ones.
# ----------------------------------------------------------------------
import numpy as np
threshold_percentile = 90
threshold_value = np.percentile(cosine_distances, threshold_percentile)
crossing_points = [
i for i, distance in enumerate(distances) if distance > threshold_value
]
len(crossing_points)
# Step 5 (Optional) : Create a plot of chunk distances to get a better view
# -------------------------------------------------------------------------
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
def visualize_cosine_distances_with_thresholds_multicolored(
cosine_distances, threshold_percentile=90
):
# Calculate the threshold value based on the percentile
threshold_value = np.percentile(cosine_distances, threshold_percentile)
# Identify the points where the cosine distance crosses the threshold
crossing_points = [0]  # Start with the first segment beginning at index 0
crossing_points += [
i
for i, distance in enumerate(cosine_distances)
if distance > threshold_value
]
crossing_points.append(
len(cosine_distances)
)  # Ensure the last segment goes to the end
# Set up the plot
plt.figure(figsize=(14, 6))
sns.set(style="white")  # Change to white to turn off gridlines
# Plot the cosine distances
sns.lineplot(
x=range(len(cosine_distances)),
y=cosine_distances,
color="blue",
label="Cosine Distance",
)
# Plot the threshold line
plt.axhline(
y=threshold_value,
color="red",
linestyle="--",
label=f"{threshold_percentile}th Percentile Threshold",
)
# Highlight segments between threshold crossings with different colors
colors = sns.color_palette(
"hsv", len(crossing_points) - 1
)  # Use a color palette for segments
for i in range(len(crossing_points) - 1):
plt.axvspan(
crossing_points[i], crossing_points[i + 1], color=colors[i], alpha=0.3
)
# Add labels and title
plt.title(
"Cosine Distances Between Segments with Multicolored Threshold Highlighting"
)
plt.xlabel("Segment Index")
plt.ylabel("Cosine Distance")
plt.legend()
# Adjust the x-axis limits to remove extra space
plt.xlim(0, len(cosine_distances) - 1)
# Display the plot
plt.show()
return crossing_points
# Example usage with cosine_distances and threshold_percentile
crossing_poings = visualize_cosine_distances_with_thresholds_multicolored(
distances, threshold_percentile=bp_threashold
)

Gráfico de Seborn para visualização de distâncias:

RAGs 文档分块策略:提升检索质量的实战指南-3Usado para ilustrar o chunking semântico Diagrama de Seaborn - desenhado por Thuwarakesh
Na figura, quando a distância entre os blocos excede um limite de 0,12, os blocos anteriores são mesclados em um bloco semântico maior. No final, foram gerados seis blocos semânticos de comprimentos variados.

Vantagens do Semantic Chunking e cenários aplicáveis

A vantagem do chunking semântico é a capacidade deCaptura melhor a estrutura semântica dos documentos e agrega fragmentos de texto semanticamente relacionados, melhorando assim a qualidade de recuperação do sistema RAG. É mais adequado para processar os seguintes tipos de documentos:

  • Documentos com estruturas complexas e tópicos diversosPor exemplo, relatórios extensos, documentos técnicos, livros etc. que contêm vários subtópicos.
  • Documentos com grandes saltos semânticosO que significa que os autores podem dar saltos em seus pensamentos ao escrever, e a fragmentação semântica pode acomodar melhor esse estilo de escrita.

Em comparação com a segmentação recursiva de caracteres, a fragmentação semântica doO cálculo é mais caro** e mais lento. Isso se deve principalmente à necessidade de incorporar o cálculo do vetor e as métricas de distância. Portanto, em cenários com recursos limitados, é necessário considerar as compensações.

 

Agentic chunking: estratégias de chunking que imitam a compreensão humana

A fragmentação agêntica é mais um passo em direção à fragmentação inteligente. ElaCom base na maneira como os seres humanos leem e entendem os documentos, o LLM é usado como um "agente inteligente" para ajudar na divisão em blocos.

Os hábitos humanos de leitura não são totalmente linearesO Agentic Chunking tenta simular esse processo de compreensão humana. Quando lemos, passamos de um tópico para outro ou de um conceito para outro e construímos a estrutura lógica de um documento em nossa mente.

Ao contrário dos dois métodos anteriores, o Agentic Chunkingnão pressupõe que o conteúdo semanticamente semelhante ocorra consecutivamente em um documento**. Ele pode agregar partes dispersas, mas semanticamente relacionadas, de um documento para formar blocos semânticos que são mais compatíveis com a percepção humana.

Fluxo de trabalho de fragmentação autêntica

A ideia central do Agentic Chunking éPermita que o LLM "leia" o documento como um ser humano, identificando os principais conceitos e temas do documento e fazendo a fragmentação com base neles. Um processo típico de chunking do Agentic inclui:

  • ProposiçãoConversão: Converta cada frase em um documento em uma proposição mais independente. Por exemplo, substituir pronomes desconhecidos por objetos para dar a cada frase um significado semântico mais completo.
  • Contêineres de blocos de construçãoChunk Containers: Crie um ou mais Chunk Containers para proposições semanticamente relacionadas. Cada Chunk Container pode ter um título e um resumo que descreva o assunto desse contêiner.
  • Atribuição proposicional orientada por agenteUsando o LLM como um agente, "leia" as proposições uma a uma e determine a qual contêiner de bloco a proposição deve pertencer.
    • Se o Agente considerar que a proposição é relevante para o tópico de um dos contêineres de bloco existentes, ela será adicionada a esse contêiner.
    • Se o agente achar que a proposta propõe um novo tópico, ele criará um novo contêiner de bloco para armazenar a proposta.
  • Reprocessamento de contêineres de blocosProcessamento posterior de contêineres de blocos, por exemplo, gerando resumos e títulos de blocos mais refinados com base nas proposições do contêiner.

O código a seguir mostra a implementação do Agentic Chunking:

from langchain import hub
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field
# Step 1: Convert paragraphs to propositions.
# --------------------------------------------
# Load the propositioning prompt from langchain hub
obj = hub.pull("wfh/proposal-indexing")
# Pick the LLM
llm = ChatOpenAI(model="gpt-4o")
# A Pydantic model to extract sentences from the passage
class Sentences(BaseModel):
sentences: List[str]
extraction_llm = llm.with_structured_output(Sentences)
# Create the sentence extraction chain
extraction_chain = obj | extraction_llm
# NOTE: text is your actual document
paragraphs = text.split("\n\n")
propositions = []
for i, p in enumerate(paragraphs):
propositions = extraction_chain.invoke(p
propositions.extend(propositions)
# Step 2: Create a placeholder to store chunks
chunks = {}
# Step 3: Deine helper classes and functions for agentic chunking.
class ChunkMeta(BaseModel):
title: str = Field(description="The title of the chunk.")
summary: str = Field(description="The summary of the chunk.")
def create_new_chunk(chunk_id, proposition):
summary_llm = llm.with_structured_output(ChunkMeta)
summary_prompt_template = ChatPromptTemplate.from_messages(
[
(
"system",
"Generate a new summary and a title based on the propositions.",
),
(
"user",
"propositions:{propositions}",
),
]
)
summary_chain = summary_prompt_template | summary_llm
chunk_meta = summary_chain.invoke(
{
"propositions": [proposition],
}
)
chunks[chunk_id] = {
"summary": chunk_meta.summary,
"title": chunk_meta.title,
"propositions": [proposition],
}
def add_proposition(chunk_id, proposition):
summary_llm = llm.with_structured_output(ChunkMeta)
summary_prompt_template = ChatPromptTemplate.from_messages(
[
(
"system",
"If the current_summary and title is still valid for the propositions return them."
"If not generate a new summary and a title based on the propositions.",
),
(
"user",
"current_summary:{current_summary}\n\ncurrent_title:{current_title}\n\npropositions:{propositions}",
),
]
)
summary_chain = summary_prompt_template | summary_llm
chunk = chunks[chunk_id]
current_summary = chunk["summary"]
current_title = chunk["title"]
current_propositions = chunk["propositions"]
all_propositions = current_propositions + [proposition]
chunk_meta = summary_chain.invoke(
{
"current_summary": current_summary,
"current_title": current_title,
"propositions": all_propositions,
}
)
chunk["summary"] = chunk_meta.summary
chunk["title"] = chunk_meta.title
chunk["propositions"] = all_propositions
# Step 5: The main functino that creates chunks from propositions.
def find_chunk_and_push_proposition(proposition):
class ChunkID(BaseModel):
chunk_id: int = Field(description="The chunk id.")
allocation_llm = llm.with_structured_output(ChunkID)
allocation_prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You have the chunk ids and the summaries"
"Find the chunk that best matches the proposition."
"If no chunk matches, return a new chunk id."
"Return only the chunk id.",
),
(
"user",
"proposition:{proposition}" "chunks_summaries:{chunks_summaries}",
),
]
)
allocation_chain = allocation_prompt | allocation_llm
chunks_summaries = {
chunk_id: chunk["summary"] for chunk_id, chunk in chunks.items()
}
best_chunk_id = allocation_chain.invoke(
{"proposition": proposition, "chunks_summaries": chunks_summaries}
).chunk_id
if best_chunk_id not in chunks:
best_chunk_id = create_new_chunk(best_chunk_id, proposition)
return
add_proposition(best_chunk_id, proposition)

Exemplos de proposição

原始文本
===================
A crow sits near the pond. It's a white one.
命题化文本
==================
A crow sits near the pond. This crow is a white one.

Benefícios e desafios do Agentic Chunking

Agentic chunkedA maior vantagem é sua flexibilidade e inteligência**. Ele pode entender melhor a estrutura semântica profunda dos documentos e gerar blocos semânticos mais alinhados com a cognição humana, e é particularmente bom em lidar com os seguintes tipos de documentos:**

  • Documentação de estrutura não linearPor exemplo, documentos que se movem em pensamentos e contêm muito conhecimento de base ou informações implícitas.
  • Documentos que precisam integrar informações entre parágrafos e seçõesAgentic chunking permite a agregação de fragmentos semanticamente relacionados que estão espalhados em diferentes locais em um documento.

No entanto, o Agentic Chunking também enfrenta alguns desafios:

  • alto custoA fragmentação agêntica requer chamadas frequentes ao LLM, o que é caro em termos de tempo e computação.
  • Solicitar dependências do projetoA eficácia do Agentic Chunking depende muito do design do Prompt. Os prompts precisam ser cuidadosamente projetados para orientar o LLM a fazer chunking de forma eficaz.
  • Incerteza do resultadoNão há dúvida de que pode haver alguma incerteza na saída do LLM, o que leva a resultados instáveis de fragmentação.

Cenários de aplicativos de chunking autêntico

A fragmentação autêntica, embora mais cara, ainda é uma opção que vale a pena considerar em alguns cenários em que a eficácia do RAG é fundamental. Exemplo:

  • Base de conhecimento em áreas especializadasPor exemplo, as bases de conhecimento nas áreas de direito, medicina, finanças, etc., exigem precisão e recuperação extremamente altas.
  • sistema complexo de perguntas e respostasSistema de perguntas e respostas: Um sistema de perguntas e respostas que precisa lidar com perguntas complexas que exigem raciocínio e integração de informações.

Leitura aprofundada:Chunking agêntico: Chunking de texto semântico orientado por agentes de IA

 

Estratégias de fragmentação para diferentes formatos de documentos

A discussão anterior se concentrou principalmente na fragmentação de texto simples. No entanto, em aplicativos práticos, frequentemente encontramos uma variedade de formatos de documentos diferentes, como Markdown, HTML, PDF, código e assim por diante. Para formatos diferentes, é necessária uma estratégia de fragmentação mais refinada para fazer uso total das informações estruturais do documento.

Agrupamento de documentos Markdown e HTML

Os documentos Markdown e HTML têm informações estruturadas de marcação, como títulos, parágrafos, listas, blocos de código e assim por diante. PodemosUse esses rótulos como base para a classificação em blocos** para uma classificação mais precisa. **

  • Bloco por títuloTítulo: Trate cada título e o conteúdo abaixo dele como um bloco separado. Isso é adequado para documentos claramente estruturados com seções distintas.
  • pedaçoParágrafo: Trate cada parágrafo como um bloco. Os parágrafos geralmente são unidades semanticamente completas e são adequados como unidades básicas de chunking.
  • fragmentaçãoCombinação de cabeçalhos e parágrafos para fragmentação. Por exemplo, um documento é dividido primeiro por títulos de primeiro nível e, em seguida, no conteúdo de cada título de primeiro nível, ele é dividido por parágrafos.

Exemplo: fragmentação baseada em tag HTML (Python)

from bs4 import BeautifulSoup
html_text = """
<h1>Section 1</h1>
<p>This is the first paragraph of section 1.</p>
<p>This is the second paragraph of section 1.</p>
<h2>Subsection 1.1</h2>
<ul>
<li>List item 1</li>
<li>List item 2</li>
</ul>
"""
soup = BeautifulSoup(html_text, 'html.parser')
chunks = []
# 按 h1 标题分块
for h1_tag in soup.find_all('h1'):
chunk_text = h1_tag.text + "\n"
next_sibling = h1_tag.find_next_sibling()
while next_sibling and next_sibling.name not in ['h1', 'h2']: #  假设按 h1 和 h2 分级
chunk_text += str(next_sibling) + "\n" #  保留 HTML 标签,或 next_sibling.text  只保留文本
next_sibling = next_sibling.find_next_sibling()
chunks.append(chunk_text)
#  可以类似地处理 h2, p, ul, ol 等标签
print(chunks)

Separação de documentos PDF

A divisão de documentos PDF é relativamente complexa porque o PDF é essencialmente um formato tipográfico em que o conteúdo textual e as informações tipográficas estão misturados. A divisão de PDFs diretamente por caractere ou linha pode destruir a integridade semântica.

As principais etapas da fragmentação de PDFs geralmente incluem:

  • Extração de texto em PDFUso de bibliotecas de análise de PDF (por exemplo, PyPDF2, pdfminer ou outras bibliotecas profissionais) não estruturado.io) para extrair conteúdo de texto de arquivos PDF.
  • Limpeza e pré-processamento de textoRemova caracteres ruidosos, manipule quebras de linha, corrija erros de OCR e muito mais.
  • Extração de informações estruturadasExtração de informações estruturadas de PDFs: tente extrair informações estruturadas de PDFs, como títulos, cabeçalhos e rodapés, tabelas, listas e assim por diante. Algumas bibliotecas avançadas de análise de PDF (por exemplo, unstructured.io) podem ajudar na extração de informações estruturadas.
  • Opções de estratégia de fragmentaçãoSeleção de estratégias de fragmentação apropriadas (por exemplo, fragmentação semântica, segmentação recursiva de caracteres etc.) com base no conteúdo do texto extraído e nas informações estruturais.

chamar a atenção para algonão estruturado.io é uma ferramenta avançada que pode lidar com uma ampla variedade de formatos de documentos (inclusive PDF) e tenta extrair informações estruturadas de documentos, simplificando o processo de fragmentação de PDFs.

Divisão da documentação do código

A fragmentação de documentos de código (por exemplo, arquivos de código Python, Java, C++) exige a consideração da estrutura sintática e das unidades lógicas do código. A simples divisão do código por linhas ou caracteres provavelmente destruirá a integridade e a capacidade de execução do código.

As estratégias comuns para a documentação do código em blocos incluem:

  • Separação por função/classeTratamento: Trate cada função ou classe como um bloco separado. Funções e classes são geralmente unidades lógicas de código.
  • Separação por bloco de códigoIdentificação de blocos de lógica no código (por exemplo, loops, instruções condicionais, blocos try-except etc.), tratando cada bloco como uma parte.
  • Combinado com a fragmentação de comentários de códigoComentários de código: Os comentários de código geralmente são explicações sobre a funcionalidade e a lógica do código. Os comentários de código e seus blocos de código associados podem ser divididos em pedaços como um todo.

artefatoAnálise estruturada e fragmentação do código podem ser auxiliadas pelo uso de ferramentas de análise de sintaxe, como o tree-sitter, que analisa o código em uma variedade de linguagens de programação e gera uma árvore de sintaxe abstrata (AST), o que facilita a fragmentação do código de acordo com sua estrutura sintática.

 

Escolha do tamanho correto do bloco e da sobreposição

O tamanho do bloco e a sobreposição do bloco são dois parâmetros importantes na política de fragmentação que afetam diretamente o desempenho do sistema RAG.

  • tamanho do blocoTamanho do bloco: A quantidade de texto contida em cada bloco. Um tamanho de bloco muito pequeno pode levar a informações semânticas incompletas; um tamanho de bloco muito grande pode introduzir ruído e reduzir a precisão da recuperação.
  • Tamanho da sobreposiçãoSobreposição: A quantidade de texto que se sobrepõe entre blocos vizinhos. O objetivo da sobreposição é garantir a continuidade contextual e evitar a perda de informações nos limites dos blocos.

Como faço para escolher o tamanho correto do bloco e a sobreposição?

Não há uma resposta absolutamente ideal para escolher o tamanho correto do bloco e a sobreposição, e isso geralmente precisa ser determinado peloRecursos do documentoresponder cantandoefeito experimentalpara determinar. Aqui estão algumas regras de ouro e sugestões:

  • método heurístico::
    • Com base na extensão da frase/parágrafoTamanho médio da frase ou do parágrafo de um documento pode ser analisado como referência para o tamanho do bloco. Por exemplo, se o comprimento médio do parágrafo for de 150 tokens, você pode tentar definir o tamanho do bloco para 150-200 tokens.
    • Considere a janela de contexto do LLMTamanho do bloco: O tamanho do bloco não deve ser muito grande para evitar exceder as limitações da janela de contexto do LLM. Ao mesmo tempo, não deve ser muito pequeno para garantir que o bloco contenha informações semânticas suficientes.
  • Experimentação e avaliação:
    • Ajuste iterativoDefinição: Defina um conjunto inicial de parâmetros de tamanho de bloco e sobreposição (por exemplo, 500 tokens para tamanho de bloco e 50 tokens para sobreposição), crie o sistema RAG e avalie-o. Em seguida, ajuste gradualmente os parâmetros, observe as alterações nos efeitos de recuperação e de perguntas e respostas e escolha a combinação ideal de parâmetros.
    • Avaliação de indicadoresQuantificar o desempenho do sistema RAG usando métricas de avaliação adequadas, como Recall@k, Precision@k, NDCG (Normalised Discounted Cumulative Gain) etc. para recuperação. Essas métricas podem ajudá-lo a avaliar objetivamente a eficácia de diferentes estratégias de fragmentação.

Ferramentas de avaliação em Langchain

A Langchain fornece várias ferramentas de avaliação que podem ajudar na avaliação e no ajuste de parâmetros dos sistemas RAG. Por exemplo, ferramentas como DatasetEvaluator e RetrievalQAChain podem ajudá-lo a automatizar a avaliação dos efeitos das combinações de diferentes estratégias de fragmentação, modelos de recuperação e modelos LLM.

 

Avaliação da eficácia da estratégia de fragmentação

Depois de escolher a estratégia de fragmentação correta, como você avalia sua eficácia? "Melhor fragmentação significa melhor recuperação", mas como quantificar "melhor"? Precisamos de algumas métricas para avaliar os méritos das estratégias de fragmentação.

A seguir estão algumas métricas de avaliação comuns que podem ajudá-lo a avaliar o impacto de uma estratégia de fragmentação no desempenho de um sistema RAG:

  • Recuperação de indicadores:
    • Recall (Recall@k)refere-se à proporção de documentos (ou blocos) relevantes entre os resultados recuperados do Top-k. Quanto maior o recall, mais informações relevantes são recuperadas pela estratégia de fragmentação.
    • Exatidão (Precision@k)refere-se à proporção de documentos (ou blocos) realmente relevantes entre os resultados recuperados do Top-k. Quanto maior a precisão, maior a qualidade dos resultados da pesquisa.
    • NDCG (Ganho acumulado descontado normalizado)NDCG: é uma métrica de avaliação de qualidade de classificação mais refinada que leva em conta o nível de relevância e a posição dos resultados recuperados. um NDCG mais alto indica uma melhor qualidade da classificação de recuperação.
  • Indicadores de perguntas e respostas:
    • Relevância da respostaAvaliar a relevância das respostas geradas pelo LLM para a pergunta. Quanto maior for a relevância da resposta, melhor será a capacidade do sistema RAG de gerar respostas significativas com base nas informações recuperadas.
      • Precisão/fidelidade da respostaAvaliação das respostas: Avaliar se as respostas geradas pelo LLM são fiéis às informações contextuais recuperadas, evitando "ilusões" e informações imprecisas. Uma maior precisão de resposta indica que a estratégia de fragmentação é mais capaz de fornecer um contexto confiável e orientar o LLM a gerar respostas mais confiáveis.
      • Fluência e coerência das respostasEmbora seja influenciada principalmente pelas habilidades do próprio LLM, uma boa estratégia de fragmentação também pode melhorar indiretamente a fluência e a coerência das respostas. Por exemplo, a fragmentação semântica fornece um contexto mais coerente e ajuda os LLMs a produzir uma linguagem mais natural.

Ferramentas e metodologias de avaliação

  • avaliação manualMétodo de avaliação: o método mais direto e confiável. Um avaliador humano é convidado a classificar os resultados da pesquisa e as respostas de perguntas e respostas do sistema RAG com base em critérios de avaliação predefinidos. As desvantagens da avaliação manual são que ela é cara, demorada e altamente subjetiva.
  • Avaliação automatizadaUso de indicadores e ferramentas de avaliação automatizados, por exemplo:
    • Recuperação de indicadoresPor exemplo, a recuperação, a precisão, o NDCG etc. podem ser medidos usando ferramentas padrão de avaliação de recuperação de informações (por exemplo rank_bm25sentence-transformers etc.) para cálculos automatizados.
    • Indicadores de perguntas e respostasAlgumas métricas de avaliação de NLP (por exemplo, BLEU, ROUGE, METEOR, BERTScore etc.) podem ser usadas para auxiliar na avaliação da qualidade das respostas. No entanto, deve-se observar que as métricas de avaliação automatizada de perguntas e respostas ainda têm limitações e não podem substituir completamente a avaliação manual.
    • Ferramenta de avaliação de LangchainLangchain oferece uma série de ferramentas de avaliação integradas, como DatasetEvaluator responder cantando RetrievalQAChainIsso simplifica o processo de avaliação automatizada do sistema RAG.

Recomendações para o processo de avaliação

  1. Construção do conjunto de dados de avaliaçãoDescrição: preparar um conjunto de dados de avaliação contendo perguntas e respostas padrão correspondentes. O conjunto de dados deve abranger, na medida do possível, cenários típicos de aplicativos e tipos de perguntas para sistemas RAG.
  2. Seleção de indicadores de avaliaçãoSeleção de indicadores apropriados de pesquisa e de perguntas e respostas com base no objetivo da avaliação. Uma combinação de avaliação manual e automatizada pode ser usada simultaneamente.
  3. Execução do sistema RAGExecute o sistema RAG no conjunto de dados de avaliação usando diferentes combinações de estratégias de fragmentação, modelos de recuperação e modelos LLM para registrar os resultados da avaliação.
  4. Análise e comparaçãoComparação: Compare as métricas de avaliação de diferentes estratégias, analise seus pontos fortes e fracos e selecione a combinação ideal de estratégias.
  5. Otimização iterativaCom base nos resultados da avaliação, os parâmetros da estratégia de fragmentação, do modelo de recuperação e do modelo LLM são continuamente ajustados para otimização iterativa a fim de melhorar o desempenho do sistema RAG.

 

Em resumo: escolha a estratégia de fragmentação que funciona melhor para você

Este documento apresenta uma discussão aprofundada das técnicas de fragmentação de documentos que são cruciais nos aplicativos RAG, desde a segmentação recursiva básica de caracteres até a fragmentação semântica mais inteligente e a fragmentação agêntica, passando por estratégias de fragmentação refinadas para diferentes formatos de documentos, bem como métodos para selecionar e avaliar tamanhos de blocos e parâmetros de sobreposição.

Revisão dos pontos principais

  • A massa do pedaço determina a massa do RAGUma boa estratégia de fragmentação é a pedra angular da criação de um sistema RAG de alto desempenho.
  • Não existe uma estratégia de fragmentação única para todos os casosEstratégia de fragmentação: Diferentes estratégias de fragmentação têm suas próprias vantagens e desvantagens e são adequadas para diferentes cenários. Você precisa escolher a estratégia mais adequada com base nos requisitos específicos do seu projeto, nas características do documento e nas restrições de recursos.
  • Segmentação recursiva de caracteresSimples, rápido e econômico para prototipagem e projetos sensíveis ao custo.
  • fragmentação semânticaCompreensão da semântica do texto e geração de partes semanticamente coerentes melhoram a qualidade da recuperação, mas são computacionalmente caras.
  • Chunking autênticoSimula a compreensão humana, é mais inteligente, mais flexível e pode lidar com documentos complexos, mas é caro e a engenharia do Prompt é complexa.
  • Chunking para diferentes formatosPara diferentes formatos, como Markdown, HTML, PDF, código, etc., é necessária uma estratégia de fragmentação refinada para aproveitar as informações estruturais do documento.
  • Tamanho e sobreposição de pedaçosPrecisa ser ajustado de acordo com as características do documento e os resultados experimentais; não há um valor ideal absoluto.
  • A avaliação é fundamental: quantificar a eficácia da estratégia de fragmentação por meio de métricas de avaliação e avaliação manual, e realizar otimização iterativa.

Como escolher? Meu conselho.

  • Prototipagem rápida:: Tentativas de prioridadeSegmentação recursiva de caracteresO RAG é uma maneira rápida de construir um protótipo de um RAG e verificar a viabilidade do sistema.
  • A busca por maior qualidadeSe houver uma alta demanda pela qualidade do RAG e os recursos computacionais permitirem, você pode tentar ofragmentação semântica.
  • Manuseio de documentos complexosPara documentos com estruturas complexas e saltos semânticos.Chunking autênticoEssa pode ser a opção preferida, mas o custo e a eficácia precisam ser cuidadosamente avaliados.
  • Específico do formatoSe estiver trabalhando com documentos em um formato específico, como Markdown, HTML, PDF, código, etc., certifique-se de usar a opçãoEstratégia de fragmentação direcionadaAs informações estruturais do documento são totalmente utilizadas.
  • Otimização iterativa contínuaObservação: A escolha da estratégia de chunking não é um processo que ocorre da noite para o dia. Em projetos reais, é necessário avaliar constantementeExperimentação, avaliação e otimização iterativapara encontrar a melhor solução de chunking para você.

Espero que este artigo possa ajudá-lo a entender melhor a tecnologia de chunking do RAG e a selecionar e aplicar estratégias de chunking adequadas em projetos reais para criar aplicativos RAG mais avançados!

Não pode ser reproduzido sem permissão:Chefe do Círculo de Compartilhamento de IA " Dominando a fragmentação de documentos RAG: um guia de estratégias de fragmentação para a criação de sistemas de recuperação eficientes
pt_BRPortuguês do Brasil