Ingestão e Segmentação (Chunking)

Visão geral

“Ingestão (ingestion) e fragmentação (chunking)” é a primeira metade da maioria dos sistemas de recuperação (retrieval): transformar documentos brutos (PDFs, páginas HTML, tickets, e-mails, páginas wiki, código, imagens) em unidades pesquisáveis com o texto, a estrutura e os metadados (metadata) corretos. Em sistemas de Geração Aumentada por Recuperação (RAG), essas unidades normalmente são convertidas em vetores de incorporação (embeddings) e armazenadas em um índice vetorial (vector index), às vezes junto com um índice esparso (sparse index) (por exemplo, BM25) para Busca Híbrida (Esparsa + Densa) (Hybrid Search (Sparse + Dense)).

Um pipeline de recuperação (retrieval pipeline) de alto desempenho geralmente depende mais da qualidade de ingestão do que de qualquer escolha individual de modelo. Se o parsing de documentos (document parsing) for frágil, se os limites dos fragmentos forem ruins, ou se faltarem metadados, etapas posteriores como Reranqueamento (Reranking) e a síntese de respostas terão menos material para trabalhar — levando a alucinações (hallucinations), citações ausentes ou falha ao recuperar as evidências certas.

Este artigo aborda:

  • Parsing de documentos e extração de texto (text extraction) (incluindo layout e reconhecimento óptico de caracteres (OCR))
  • Estratégias de fragmentação e seus trade-offs
  • Design de metadados para filtragem, citações e controle de acesso
  • Pipelines de indexação (indexing), versionamento (versioning) e melhores práticas operacionais

Por que ingestão e fragmentação importam (a teoria)

A recuperação funciona com *unidades*, não com documentos

A maioria dos sistemas de recuperação não recupera “um PDF”; ela recupera fragmentos — trechos menores de texto que podem ser transformados em vetores de incorporação, indexados e retornados de forma eficiente. A fragmentação cria a granularidade de recuperação (retrieval granularity).

  • Grande demais: as incorporações vetoriais borram vários tópicos; a recuperação retorna contexto ruidoso; modelos atingem limites da janela de contexto (context window).
  • Pequeno demais: os fragmentos perdem contexto; a revocação (recall) cai; a síntese de respostas precisa costurar muitos fragmentos.

A fragmentação é, portanto, um problema de otimização entre:

  • Coerência semântica (cada fragmento deve tratar de uma coisa)
  • Revocação/precisão de recuperação (recall/precision) (a evidência certa aparece no top-k)
  • Eficiência da janela de contexto (empacotar tokens úteis, evitar desperdício)
  • Latência/custo (latency/cost) (volume de incorporação vetorial e indexação)

Vetores de incorporação e limites dos fragmentos

Vetores de incorporação densos (dense embeddings) (veja Busca Vetorial e Vetores de Incorporação (Vector Search & Embeddings)) comprimem um fragmento em um vetor. Se o fragmento contiver vários tópicos não relacionados, o vetor vira um “compromisso” que pode ficar distante de consultas sobre qualquer um dos tópicos. Esse é um grande motivo pelo qual a fragmentação sensível à estrutura (structure-aware) frequentemente supera a simples divisão de tamanho fixo.

Fragmentação também é uma decisão de *prompts*

Em RAG, os fragmentos recuperados viram entrada do modelo. A fragmentação determina:

Pipeline de ingestão: etapas e responsabilidades

Um pipeline típico de ingestão se parece com isto:

  1. Descoberta e coleta de fontes
    • Fazer crawl de URLs, sincronizar armazenamentos de arquivos, exportar tickets, puxar de bancos de dados
  2. Parsing e extração
    • Converter para texto + estrutura; extrair imagens/tabelas se necessário
  3. Normalização e limpeza
    • Corrigir codificação, remover boilerplate, normalizar espaços em branco, deduplicar
  4. Segmentação e fragmentação
    • Dividir em unidades de recuperação; atribuir IDs de fragmento
  5. Enriquecimento de metadados
    • Adicionar fonte, timestamps, títulos/seções, controle de acesso, tags, idioma
  6. Incorporação vetorial e indexação
    • Calcular vetores de incorporação; fazer inserção/atualização (upsert) no banco de dados vetorial; opcionalmente construir índice esparso
  7. Validação e monitoramento
    • Checagens de qualidade, amostragem, detecção de deriva (drift), políticas de reingestão (reingestion)

Em sistemas agênticos (agentic systems) (veja RAG Agêntico (Agentic RAG)), decisões de ingestão também afetam o comportamento das ferramentas — por exemplo, se um agente consegue buscar de forma confiável “a seção exata da política” versus parágrafos vagos.

Parsing e extração de documentos

O parsing costuma ser a parte de maior variância do pipeline. PDFs, em particular, são formatos de apresentação, não formatos semânticos.

Entradas comuns e o que pode dar errado

HTML / Markdown / Documentos com estrutura

  • Normalmente contêm títulos, listas e links que mapeiam bem para a estrutura de fragmentos.
  • Armadilhas: boilerplate de navegação, cabeçalhos/rodapés repetidos, banners de cookies, texto oculto.

PDFs (digitais)

  • O texto existe, mas a ordem de leitura é ambígua.
  • Falha comum: layouts com múltiplas colunas viram frases intercaladas.

PDFs (escaneados) e imagens

  • Exigem OCR; a qualidade depende da resolução do scan e do idioma.
  • É preciso preservar números de página e regiões para citações.

Planilhas e tabelas

  • Tabelas são difíceis para fragmentação em texto puro:
    • Relações de linha/coluna podem se perder.
    • Tabelas “achatadas” podem ficar ilegíveis.

Repositórios de código

  • Código deve ser fragmentado por funções/classes e incluir caminhos de arquivo e símbolos.
  • Comentários/docstrings podem ser mais úteis do que detalhes de implementação para muitas consultas.

Objetivos do parsing: texto *e* estrutura

Um parser robusto deve produzir:

  • Texto limpo (legível para humanos, mínimo de lixo)
  • Estrutura do documento
    • títulos e hierarquia
    • números de página / offsets
    • tipos de bloco (parágrafo, lista, tabela, bloco de código)
  • Âncoras para citações
    • identificadores estáveis como doc_id + page + bbox ou doc_id + heading path

Essa estrutura permite uma fragmentação melhor e citações melhores.

Considerações de OCR (quando necessário)

Se você fizer OCR:

  • Armazene a confiança do OCR por página/região (útil para filtrar texto de baixa qualidade).
  • Mantenha imagens de página ou caixas delimitadoras (bounding boxes) se você quiser citações precisas na interface.
  • Detecção de idioma pode melhorar a precisão do OCR (e, mais tarde, a seleção do modelo de incorporação).

Passos práticos de limpeza

Limpezas típicas que melhoram a qualidade de recuperação:

  • Remover cabeçalhos/rodapés repetidos e menus de navegação
  • Remover banners e boilerplate de “política de cookies”
  • Normalizar espaços em branco e hifenização (quebras de linha de PDFs)
  • Corrigir codificação (aspas inteligentes, Unicode quebrado)
  • Canonicalizar URLs e IDs de documentos

A deduplicação também importa: conteúdo duplicado pode “lotar” os resultados relevantes no top-k.

Estratégias de fragmentação (e quando usá-las)

Fragmentação é escolher limites e tamanhos que se alinham a como usuários fazem perguntas.

1) Fragmentação de tamanho fixo (baseline)

Abordagem: dividir o texto a cada N caracteres ou tokens, muitas vezes com sobreposição.

  • Prós: simples, rápida, previsível.
  • Contras: quebra frases/seções; mistura tópicos; ruim para tabelas e código.

Quando é aceitável: conteúdo homogêneo como entradas curtas de FAQ ou texto bem estruturado onde limites importam menos.

2) Fragmentação recursiva / baseada em delimitadores (padrão comum)

Abordagem: dividir por separadores do documento em ordem de prioridade, por exemplo:

  1. parágrafos \n\n
  2. linhas \n
  3. limites de sentença
  4. fallback baseado em tokens

Isso mantém limites naturais quando possível.

  • Prós: preserva parágrafos e listas; robusta em diferentes formatos.
  • Contras: ainda é cega a mudanças semânticas dentro de parágrafos longos; depende de bom parsing.

3) Fragmentação sensível à estrutura (títulos e seções)

Abordagem: usar títulos (H1/H2/H3, cabeçalhos markdown, sumário/outline de PDF) para definir fragmentos por seção/subseção. Opcionalmente, manter um “caminho de títulos (heading path)” como metadado.

  • Prós: alinha com a organização humana do documento; melhora citações (“Seção 3.2”).
  • Contras: exige extração confiável de estrutura.

Melhor para: políticas, documentação técnica, wikis, referências de API.

4) Fragmentação semântica (ciente de incorporações vetoriais)

Abordagem: dividir onde a similaridade semântica cai — frequentemente pontuando a coerência de sentença a sentença usando vetores de incorporação ou algoritmos de segmentação de tópicos.

  • Prós: pode superar divisão heurística para textos narrativos longos.
  • Contras: mais cara; pode ser instável entre versões de modelos; mais difícil de depurar.

5) Janela deslizante com sobreposição (para contextos longos)

Abordagem: janelas de tamanho fixo com sobreposição (por exemplo, 300 tokens, sobreposição de 60 tokens).

A sobreposição ajuda quando respostas cruzam limites de fragmentos, mas sobreposição demais aumenta o tamanho do índice e a recuperação redundante.

Um bom modelo mental:

  • A sobreposição deve preservar a cola contextual (definições, nomes de variáveis, antecedentes).
  • A sobreposição não deve duplicar parágrafos inteiros, a menos que você precise de forte continuidade.

6) Fragmentação pai–filho (hierárquica)

Abordagem: indexar fragmentos “filhos” pequenos para recuperação, mas manter referências a um trecho “pai” maior para o contexto final.

  • Recuperar: filhos (alta precisão)
  • Ler/responder: pais (melhor contexto)

Isso frequentemente melhora a qualidade das respostas sem sacrificar a precisão da recuperação.

7) Fragmentação específica por modalidade

Em RAG Multimodal (Multimodal RAG):

  • Imagens: fragmentar por figura; armazenar legenda + texto ao redor; opcionalmente armazenar vetores de incorporação de imagem (image embeddings).
  • Tabelas: fragmentar por tabela, além de fragmentos curtos por grupo de linhas se as tabelas forem grandes.
  • Código: fragmentar por símbolo (função/classe), incluir assinatura e docstring.

Escolhendo o tamanho do fragmento: orientação prática

Não existe um tamanho universalmente ideal, mas faixas comuns para RAG de texto:

  • 200–500 tokens por fragmento para muitas tarefas de perguntas e respostas
  • 500–1000 tokens para conteúdo técnico denso em que o contexto é essencial

Ajuste com base em:

  • Tipo médio de consulta (busca de fato vs. explicação)
  • Estilo dos documentos (manuais densos vs. notas curtas)
  • Janela de contexto do modelo e orçamento de prompt
  • Se você usa reranqueamento (veja Reranqueamento)

Metadados: a diferença entre “encontrei algo” e “encontrei a coisa certa”

Metadados permitem filtragem, ranqueamento, citações, controle de acesso e analytics.

Campos principais de metadados (recomendado)

No mínimo, armazene:

  • doc_id: identificador estável do documento-fonte
  • chunk_id: identificador estável do fragmento
  • source: URL/caminho/repo + título legível
  • created_at, updated_at, ingested_at
  • chunk_index: ordem dentro do documento
  • text: o conteúdo do fragmento (ou um ponteiro)
  • heading_path: por exemplo, ["Políticas de RH", "Licenças", "Licença Parental"]
  • page_range ou char_range: para citações
  • content_type: pdf/html/wiki/code/table
  • language: útil para sistemas multilíngues

Controle de acesso (crítico em empresas)

Se seu sistema for multiusuário, armazene metadados de lista de controle de acesso (ACL):

  • tenant_id
  • allowed_user_ids e/ou allowed_group_ids
  • visibility: public/internal/confidential

A filtragem por ACL deve ser aplicada no momento da consulta antes de os resultados serem retornados.

Metadados para qualidade e operações

Campos adicionais úteis:

  • parser_version, chunker_version, embedding_model
  • ocr_confidence
  • hash: hash de conteúdo para deduplicação e reingestão idempotente
  • tags: área de produto, time, categoria do documento

Isso torna a reindexação mais segura e a depuração mais fácil.

Metadados e citações

Para suportar Fundamentação e Citações, armazene informação suficiente para reconstruir de onde veio o fragmento:

  • URL com âncora (#section-...) para HTML
  • Número de página para PDF
  • Caminho do arquivo + intervalo de linhas para código
  • ID da tabela + intervalo de linhas para planilhas

Pipelines de indexação: denso, esparso e híbrido

Indexação vetorial densa

Recuperação densa (dense retrieval) usa vetores de incorporação + vizinhos mais próximos aproximados (approximate nearest neighbors, ANN). Decisões-chave:

  • Escolha do modelo de incorporação e versionamento
  • Dimensão do vetor e métrica de distância (cosseno vs produto escalar)
  • Tipo de índice (HNSW, IVF, PQ, etc.)
  • Estratégia de inserção/atualização e semântica de deleção

Recuperação densa é ótima para paráfrase e correspondência conceitual, mas pode falhar em palavras-chave exatas, IDs e termos raros.

Indexação esparsa e híbrida

Busca esparsa (sparse search) (estilo BM25) se destaca em correspondência exata e tokens raros. Muitos sistemas em produção combinam as duas (veja Busca Híbrida (Esparsa + Densa)):

  • Recuperar candidatos dos índices denso e esparso
  • Mesclar pontuações (ponderadas) ou fazer união e depois reranquear

Busca híbrida é particularmente útil para:

  • códigos de erro, IDs de ticket, SKUs
  • nomes próprios e siglas
  • nomes de símbolos de código

Interação entre reranqueamento e fragmentação

Um reranqueador pode compensar algumas imperfeições de fragmentação ao selecionar os melhores fragmentos entre os candidatos. Mas reranqueadores não fazem milagres:

  • Se a evidência certa nunca aparecer no top-N de candidatos (porque parsing/fragmentação falhou), o reranqueamento não consegue recuperá-la.
  • Limites melhores de fragmentos frequentemente reduzem o pool de candidatos necessário, melhorando latência e custo.

Exemplo prático: um fluxo mínimo de ingestão + fragmentação + indexação

A seguir, um exemplo simplificado em estilo Python ilustrando o formato de um pipeline. (As bibliotecas exatas vão variar: você pode usar um parser de HTML, um extrator de PDF e um cliente de banco de dados vetorial.)

import hashlib
from datetime import datetime

def stable_hash(text: str) -> str:
    return hashlib.sha256(text.encode("utf-8")).hexdigest()

def chunk_recursive(text: str, max_tokens=400, overlap_tokens=60):
    """
    Placeholder: in practice, use a tokenizer and split by paragraphs/sentences first.
    Returns a list of chunk strings.
    """
    words = text.split()
    chunks = []
    i = 0
    while i < len(words):
        chunk_words = words[i:i+max_tokens]
        chunks.append(" ".join(chunk_words))
        i += max_tokens - overlap_tokens
    return chunks

def ingest_document(doc_id: str, title: str, source_url: str, raw_text: str, headings=None):
    headings = headings or []
    cleaned = normalize_text(raw_text)  # remove boilerplate, fix whitespace, etc.

    # idempotency: if content unchanged, skip
    content_hash = stable_hash(cleaned)

    chunks = chunk_recursive(cleaned, max_tokens=400, overlap_tokens=60)

    records = []
    for idx, chunk in enumerate(chunks):
        chunk_id = f"{doc_id}:{idx}"
        record = {
            "doc_id": doc_id,
            "chunk_id": chunk_id,
            "title": title,
            "source": source_url,
            "heading_path": headings,
            "chunk_index": idx,
            "text": chunk,
            "content_hash": content_hash,
            "ingested_at": datetime.utcnow().isoformat(),
            "chunker_version": "v1-recursive-400-60",
            "embedding_model": "text-embedding-3-large"  # example label
        }
        records.append(record)

    # Embed + upsert
    vectors = embed([r["text"] for r in records])  # returns list of float vectors
    upsert_to_vector_db(vectors=vectors, metadata=records)

    return len(records)

def normalize_text(text: str) -> str:
    # extremely simplified normalization
    text = text.replace("\r\n", "\n")
    text = "\n".join(line.strip() for line in text.split("\n"))
    return text.strip()

Em um pipeline de produção, normalmente você:

  • Faz parsing específico por fonte (PDF vs HTML vs código)
  • Usa divisão baseada em tokens com um tokenizador real
  • Adiciona metadados de controle de acesso
  • Armazena intervalos de páginas / offsets para citações
  • Acompanha parser_version, embedding_model e hashes de conteúdo para reindexação

Padrões avançados e melhores práticas

Mantenha IDs de fragmento estáveis entre reingestões

Se os IDs de fragmento mudarem a cada execução, você não consegue atualizar ou deletar fragmentos de forma confiável. Prefira IDs determinísticos derivados de:

  • doc_id + section_id + chunk_index, ou
  • doc_id + char_range, ou
  • doc_id + hash(chunk_text) (cuidado: pequenas edições causam churn)

IDs estáveis reduzem a “rotatividade do índice (index churn)” e tornam o cache mais efetivo (veja Cache (Caching)).

Trate atualizações com uma estratégia clara

Abordagens comuns:

  • Reconstrução completa (full rebuild): mais simples; cara; boa para corpora pequenos
  • Reingestão incremental (incremental reingestion):
    • detectar mudanças via timestamps de última modificação + hashes de conteúdo
    • deletar fragmentos de documentos atualizados e então inserir/atualizar os novos
  • Indexação versionada (versioned indexing):
    • escrever em uma nova versão do índice e então alternar leitores atomicamente

Versionamento ajuda ao mudar a lógica de fragmentação ou modelos de incorporação.

Avalie fragmentação como um problema de IR

Meça a qualidade de recuperação com um conjunto de teste de consultas e fontes relevantes conhecidas:

  • Recall@k: o fragmento correto aparece no top-k?
  • MRR / nDCG: os fragmentos mais relevantes ficam bem ranqueados?
  • Fidelidade da resposta: as respostas geradas são suportadas pelos fragmentos recuperados? (se conecta a Fundamentação e Citações)

Faça teste A/B de tamanhos de fragmento, sobreposição e segmentação sensível à estrutura. Muitas vezes, pequenas mudanças na fragmentação superam a troca de modelos de incorporação.

Observe modos comuns de falha na ingestão

  • Domínio de boilerplate: texto de navegação aparece em muitos documentos e “lota” a recuperação
  • Ordem de leitura quebrada: colunas de PDF se intercalam
  • Colapso de tabela: relações de coluna são perdidas
  • Duplicatas com sobreposição: sobreposição demais + conteúdo repetido infla o índice
  • Tópicos misturados por fragmento: “um fragmento contém três seções”
  • ACL vazando: metadados ausentes/incorretos permitem recuperação não autorizada

Combine fragmentação com ferramentas downstream

Decisões de fragmentação devem combinar com como o sistema vai usar os fragmentos:

Juntando tudo: uma arquitetura de referência para ingestão

Um pipeline prático “maduro” frequentemente inclui:

  • Conectores: crawler web, sincronização Google Drive/SharePoint, sincronização Git, exportador de tickets
  • Serviço de parsing: parsers por formato, OCR, extração de layout
  • Serviço de fragmentação: sensível à estrutura + fallbacks, suporte a pai–filho
  • Enriquecimento: detecção de idioma, tags, ACL, extração de entidades (opcional)
  • Escritores de índice:
    • índice vetorial denso
    • índice esparso/BM25 opcional para recuperação híbrida
  • Observabilidade (observability):
    • logs de ingestão por documento
    • painéis para falhas, throughput, tamanho do índice
    • interface de amostragem para “ver texto parseado + fragmentos”

Essa base torna muito mais fácil iterar depois em estratégias de recuperação como recuperação híbrida, reranqueamento e consulta agêntica multi-salto (multi-hop querying).

Resumo

Ingestão e fragmentação são as camadas de engenharia que transformam documentos confusos do mundo real em unidades de recuperação de alta qualidade. Sistemas fortes:

  • Fazem parsing de documentos em texto limpo com estrutura
  • Fragmentam ao longo de limites significativos (frequentemente títulos/seções), não tamanhos arbitrários
  • Anexam metadados ricos para filtragem, ACL e citações
  • Indexam de forma consistente com IDs estáveis, versionamento e iteração guiada por avaliação

Quando essas peças são bem-feitas, componentes downstream — recuperação densa, recuperação híbrida, reranqueamento e geração fundamentada (grounded generation) — tornam-se marcadamente mais confiáveis e mais fáceis de operar em escala.