Para RAG, converta PDFs em Markdown quando quiser trechos que sigam as seções do documento: cada título vira um ponto de divisão, e os títulos acima de um trecho viajam com ele como metadados. Confira títulos, tabelas e texto de OCR antes de indexar e depois teste a recuperação com perguntas cujas respostas você já conhece.

Este guia é para desenvolvedores que montam recuperação sobre documentos privados: políticas, manuais, contratos, pesquisas. Ele pressupõe que você já tenha em mente um modelo de embeddings e um banco vetorial.

Pilhas de fichas pautadas e tiras de papel ao lado de um laptop, uma das pilhas amarrada com uma fita lilás.
Trechos que seguem as seções do documento.

Por que os títulos geram trechos melhores

Um divisor de tamanho fixo corta o texto em pedaços de comprimento definido, onde quer que o corte caia. Um trecho pode começar no meio de uma seção e perder o título que diz do que ela trata. “As requisições são limitadas a 100 por minuto” significa uma coisa em “Sandbox” e outra em “Produção”. Sem o título, nem o recuperador nem o modelo sabem qual.

O Markdown guarda o esquema do documento como linhas que começam com #, ## e ###. Um divisor baseado em títulos corta nessas linhas, de modo que cada trecho cobre uma seção, e registra os títulos acima do trecho: o caminho da seção. O guia do LangChain sobre divisão de Markdown descreve a mesma ideia: manter o texto junto com os cabeçalhos a que ele pertence.

As seções variam de tamanho, então uma seção longa ainda precisa de uma segunda divisão por tamanho. O caminho da seção vale para cada pedaço dela.

Converta os PDFs e confira os títulos

No MD Factory, adicione a pasta com os seus PDFs. Cada arquivo Markdown é salvo ao lado do PDF com o mesmo nome, com as imagens em uma pasta ao lado. PDFs digitalizados passam por OCR no seu PC. Arquivos Word e outros formatos da pasta são convertidos do mesmo jeito.

Abra alguns resultados antes de escrever qualquer código de divisão:

  • Confirme que capítulos, seções e subseções saem como #, ## e ###. Um PDF muitas vezes marca um título apenas com uma fonte maior ou mais pesada, então qualquer conversor precisa deduzir onde as seções começam e como se aninham. Corrija os níveis onde estiverem errados.
  • Em arquivos Word, os títulos passam quando o autor usou os estilos de Título do Word. Texto que é apenas em negrito ou grande continua sendo um parágrafo comum.
  • Procure cabeçalhos e rodapés repetidos e números de página no meio do texto.
  • Clique em Precisa de revisão ao lado de um arquivo para ver o que conferir. Em um PDF, a lista pode incluir páginas em que o OCR não conseguiu ler parte do texto ou não encontrou texto algum.

Corrija os problemas no arquivo Markdown antes de indexá-lo. Cada trecho herda esses problemas.

Divida por títulos no código

O MarkdownHeaderTextSplitter do LangChain divide nos níveis de título que você listar e coloca cada título nos metadados do trecho. Um segundo divisor limita o tamanho dentro de cada seção:

from pathlib import Path
from langchain_text_splitters import (
    MarkdownHeaderTextSplitter,
    RecursiveCharacterTextSplitter,
)

corpus = Path("corpus")
by_heading = MarkdownHeaderTextSplitter(
    [("#", "h1"), ("##", "h2"), ("###", "h3")], strip_headers=False
)
by_size = RecursiveCharacterTextSplitter(chunk_size=1500, chunk_overlap=150)

chunks = []
for path in sorted(corpus.rglob("*.md")):
    sections = by_heading.split_text(path.read_text(encoding="utf-8"))
    for chunk in by_size.split_documents(sections):
        chunk.metadata["source"] = path.relative_to(corpus).as_posix()
        chunk.metadata["section"] = " > ".join(
            chunk.metadata[h] for h in ("h1", "h2", "h3") if h in chunk.metadata
        )
        chunks.append(chunk)

O tamanho do trecho e a sobreposição aqui são um ponto de partida; ajuste-os para o seu modelo de embeddings. Para manter as linhas de título no texto do trecho, de modo que o texto que você gera embeddings também nomeie a sua seção, o exemplo define strip_headers=False.

O MarkdownNodeParser do LlamaIndex faz a mesma divisão por títulos. Quando você carrega arquivos com o SimpleDirectoryReader, cada nó também carrega o nome do arquivo:

from llama_index.core import SimpleDirectoryReader
from llama_index.core.node_parser import MarkdownNodeParser

documents = SimpleDirectoryReader(
    "corpus", recursive=True, required_exts=[".md"]
).load_data()
nodes = MarkdownNodeParser().get_nodes_from_documents(documents)
print(nodes[0].metadata["file_name"], nodes[0].metadata["header_path"])

header_path lista os títulos acima de um nó, por exemplo /Employee handbook/Expenses/; o título do próprio nó é a primeira linha do texto dele.

Mantenha a fonte em cada trecho

Guarde pelo menos três coisas com cada trecho:

  • O arquivo. Um arquivo Markdown tem o mesmo nome do seu PDF, então um trecho de handbook.md leva de volta a handbook.pdf. Guarde o caminho relativo à pasta do corpus, porque dois arquivos chamados terms.md em pastas diferentes são documentos diferentes.
  • O caminho da seção, para que uma resposta possa nomear a seção que usou e o leitor vá direto ao trecho.
  • A edição ou a data. Quando uma política muda, você apaga os trechos do arquivo antigo e indexa os novos, em vez de servir as duas versões.

Se pessoas com direitos de acesso diferentes vão consultar o mesmo índice, guarde também quem pode ler cada documento e filtre por isso no momento da consulta. Um recuperador devolve qualquer trecho que corresponda à pergunta.

O Markdown que o MD Factory produz não tem números de página. Se as respostas precisam citar páginas, procure o trecho no PDF original.

Trate tabelas e texto de OCR com cuidado

Uma tabela Markdown tem a linha de cabeçalho uma única vez, no topo. Quando uma tabela é mais longa que o tamanho do trecho, o divisor por tamanho a corta, e os pedaços seguintes chegam sem os nomes das colunas. No nosso teste com o LangChain (langchain-text-splitters 1.1.3), uma tabela de 40 linhas dividida em trechos de 300 caracteres gerou quatro pedaços, e só o primeiro continha a linha de cabeçalho.

Duas formas de resolver: manter cada tabela em um único trecho, mesmo que seja maior que os outros, ou repetir a linha de cabeçalho no início de cada pedaço.

Em arquivos Word e Excel, o MD Factory marca um documento como Precisa de revisão quando células mescladas ou complexas foram simplificadas. Tabelas de PDF não recebem essa marca, então compare algumas delas com o original, principalmente tabelas com cabeçalhos mesclados.

O texto de OCR precisa de uma conferência própria. Números, nomes e códigos lidos errado entram nas respostas sem alteração, e nada no trecho parece errado. Compare os valores de alguns trechos com a digitalização e deixe de fora do índice as páginas sinalizadas até corrigi-las. O que procurar está no nosso guia para conferir o OCR em PDFs digitalizados.

Teste a recuperação com perguntas reais

Anote as perguntas que as pessoas realmente farão e, para cada uma, o arquivo e a seção que guarda a resposta. Comece com uma ou duas dúzias.

  1. Passe cada pergunta pelo seu recuperador e olhe os primeiros resultados.
  2. Veja se a seção certa está entre eles.
  3. Para cada falha, compare os trechos que voltaram com o que deveria ter voltado. Causas típicas: um nível de título errado, uma tabela separada do cabeçalho, um erro de OCR no termo-chave ou uma seção tão longa que a resposta se perde nela.
  4. Mude uma coisa, como o tamanho do trecho, os níveis de título ou a forma de dividir as tabelas, e execute as mesmas perguntas de novo.

Guarde as perguntas em um arquivo ao lado do corpus e execute-as de novo sempre que os documentos ou o código de divisão mudarem.

Quando usar o MD Factory e quando usar uma biblioteca

O MD Factory é um app de desktop para Windows. Serve para uma coleção privada que você quer converter no seu próprio PC e conferir a olho: adicione uma pasta, olhe os status, abra os arquivos que precisam de revisão, corrija-os e depois aponte o seu script de indexação para a pasta.

O MD Factory mantém os documentos no seu PC enquanto converte. Se você depois gerar embeddings dos trechos com uma API de embeddings hospedada ou os enviar a um modelo hospedado, o texto deles vai para esse provedor. Use um modelo local se os documentos não podem sair da sua rede.

Se os documentos chegam o tempo todo, ficam em um servidor ou precisam ser convertidos sem ninguém acompanhando, use uma biblioteca de conversão no seu código. Para ver as opções, veja nossa comparação de conversores de PDF para Markdown.