Pular para o conteúdo
IAIntermediário

Chunking para RAG: 4 estratégias que funcionam

Compare quatro estratégias de chunking para RAG com código: tamanho fixo, parágrafo, recursiva e semântica. Veja quando usar cada uma e como medir.

Por Equipe IAUAI Estudos · 14 de agosto de 2026 · 9 min de leitura

Nesta página

O problema real

Você tem dezenas de documentos longos para indexar num sistema RAG. Pega um exemplo da internet e joga tudo em chunks gigantes, que misturam introdução com apêndice. Ou faz o oposto e gera pedaços minúsculos que cortam frases no meio. Nos dois casos o retriever devolve trechos que atrapalham o modelo, e você vê respostas genéricas ou inventadas.

A forma de dividir o texto pesa tanto quanto o modelo de embedding. Neste artigo você vai implementar quatro estratégias de chunking, entender o que cada uma ganha e perde, e montar um jeito simples de decidir com dados. Se ainda não montou um pipeline, comece por RAG na prática.

Qual estratégia de chunking usar?

Chunking é dividir um documento em pedaços que serão indexados e recuperados. As quatro estratégias mais usadas são estas.

  • Tamanho fixo, cortando por quantidade de tokens, com sobreposição entre pedaços.
  • Por parágrafo, respeitando a estrutura do texto.
  • Recursiva, que tenta cortar em separadores grandes (seções, parágrafos) e desce para separadores menores só quando o pedaço ainda é grande demais.
  • Semântica, que corta onde o assunto muda, usando embeddings das frases.

Não existe uma melhor. Depende do tipo de conteúdo e do que você mede no seu conjunto de perguntas. Os trechos abaixo usam tiktoken para contar tokens (pip install tiktoken). Contar caracteres também funciona como aproximação, mas tokens refletem o que o modelo de embedding enxerga.

Mão na massa

1. Tamanho fixo (a linha de base)

Simples, previsível e fácil de depurar. Comece por aqui para ter um número de referência.

import tiktoken

enc = tiktoken.get_encoding("cl100k_base")

def chunk_tamanho_fixo(texto: str, tamanho: int = 512, sobreposicao: float = 0.2) -> list[str]:
    tokens = enc.encode(texto)
    passo = tamanho - int(tamanho * sobreposicao)
    chunks = []
    for i in range(0, len(tokens), passo):
        chunks.append(enc.decode(tokens[i : i + tamanho]))
        if i + tamanho >= len(tokens):
            break
    return chunks

doc = (
    "A política de devolução permite devolver itens em até 30 dias. "
    "O reembolso é integral se o produto estiver em bom estado. "
    "Itens usados ou danificados pelo cliente não são aceitos. "
    "Para iniciar a devolução, abra um chamado pelo formulário do site."
)
for i, c in enumerate(chunk_tamanho_fixo(doc, tamanho=40, sobreposicao=0.25)):
    print(f"[{i}] {c}\n")

O ponto fraco é cortar frases ao meio. A sobreposição reduz o problema, mas não o elimina.

2. Por parágrafo

Respeita a estrutura natural do texto. Funciona bem em artigos, relatórios e manuais bem escritos. O código junta parágrafos curtos até atingir um tamanho mínimo.

import re

def chunk_por_paragrafo(texto: str, minimo_tokens: int = 80) -> list[str]:
    paragrafos = [p.strip() for p in re.split(r"\n\s*\n", texto) if p.strip()]
    chunks, atual = [], ""
    for p in paragrafos:
        atual = f"{atual}\n\n{p}" if atual else p
        if len(enc.encode(atual)) >= minimo_tokens:
            chunks.append(atual)
            atual = ""
    if atual:
        chunks.append(atual)
    return chunks

Parágrafos muito longos continuam longos, e tabelas ou código perdem o sentido quando separados. Para esses casos, use a próxima estratégia.

3. Recursiva

A ideia é tentar separadores em ordem, do mais "grosso" ao mais "fino". Se um pedaço já cabe no limite, fica como está. Se não cabe, divide com o próximo separador. Por isso ela se adapta bem a documentos mistos.

SEPARADORES = ["\n## ", "\n\n", "\n", ". ", " "]

def chunk_recursivo(texto: str, limite: int = 300, seps: list[str] = SEPARADORES) -> list[str]:
    if len(enc.encode(texto)) <= limite or not seps:
        return [texto]
    sep, resto = seps[0], seps[1:]
    partes = texto.split(sep)
    if len(partes) == 1:
        return chunk_recursivo(texto, limite, resto)

    chunks, atual = [], ""
    for parte in partes:
        candidato = f"{atual}{sep}{parte}" if atual else parte
        if len(enc.encode(candidato)) <= limite:
            atual = candidato
        else:
            if atual:
                chunks.append(atual)
            atual = ""
            chunks.extend(chunk_recursivo(parte, limite, resto))
    if atual:
        chunks.append(atual)
    return chunks

Na prática, muita gente usa a implementação pronta RecursiveCharacterTextSplitter, do pacote langchain-text-splitters. Ela já traz sobreposição e separadores para Markdown e vários tipos de código. Escreva a sua só para entender o mecanismo.

4. Semântica

Em vez de cortar por tamanho, cortamos onde o assunto muda. Calculamos o embedding de cada frase e, quando a similaridade entre frases vizinhas cai abaixo de um limiar, abrimos um novo chunk. A chamada é feita em lote, uma requisição para todas as frases, e não uma por frase.

import re
import numpy as np
from openai import OpenAI

client = OpenAI()

def chunk_semantico(texto: str, limiar: float = 0.6) -> list[str]:
    frases = [f.strip() for f in re.split(r"(?<=[.!?])\s+", texto.strip()) if f.strip()]
    if len(frases) < 2:
        return frases

    resp = client.embeddings.create(model="text-embedding-3-small", input=frases)
    vecs = np.array([d.embedding for d in resp.data])
    vecs = vecs / np.linalg.norm(vecs, axis=1, keepdims=True)

    chunks, atual = [], [frases[0]]
    for i in range(1, len(frases)):
        similaridade = float(vecs[i - 1] @ vecs[i])
        if similaridade < limiar:
            chunks.append(" ".join(atual))
            atual = []
        atual.append(frases[i])
    chunks.append(" ".join(atual))
    return chunks

O limiar depende do modelo de embedding e do idioma, então ajuste olhando exemplos reais. O custo extra é gerar embeddings de todo o corpus antes da indexação, e o ganho nem sempre aparece. Estudos de comparação publicados mostram resultados mistos, então só adote se o seu teste mostrar melhora.

Como escolher com dados

Monte de 30 a 50 perguntas reais, cada uma ligada ao trecho do documento que responde. Para cada estratégia, indexe, rode as perguntas e calcule em quantas o trecho correto aparece entre os 3 primeiros resultados (recall@3). Compare também o tamanho médio dos chunks e o número total, que afeta custo de armazenamento. Quem ganha no seu corpus é a estratégia a usar. O simulador de chunking ajuda a visualizar os cortes.

Armadilhas comuns

Sobreposição zero

Sem sobreposição, uma ideia na fronteira fica partida entre dois chunks e nenhum deles a contém completa. Experimente 10% a 20%.

Ignorar a estrutura do documento

Cortar um Markdown no meio de uma tabela ou de um bloco de código deixa o chunk inútil. Separe por títulos primeiro e guarde o título como metadado ou prefixo do chunk, assim o trecho carrega o contexto de onde veio.

Tamanho fixo para todo tipo de conteúdo

Documentação técnica, contratos e FAQs têm densidades diferentes. Teste tamanhos distintos por tipo de documento em vez de adotar um valor único.

Avaliar o chunk isolado

Um chunk pode parecer bom ao ler, mas ser ruim na busca. Quem decide é a métrica de recuperação, não a leitura.

Quando chunking não resolve

  • Seu conteúdo total é pequeno e cabe no contexto do modelo. Coloque tudo no prompt.
  • Cada chunk só faz sentido com o anterior. Aumente o tamanho, ou recupere o chunk vizinho junto com o encontrado.
  • Você precisa de uma citação literal e exata. Combine a busca vetorial com busca por palavra-chave.

Próximos passos

Comece com tamanho fixo de 512 tokens e 20% de sobreposição, meça o recall e só então teste recursiva ou por parágrafo. Considere a semântica apenas se os dados justificarem. Para medir ponta a ponta, veja Avaliação de LLM com evals, e para guardar os chunks, Banco vetorial na prática.

Quer aplicar isso na sua empresa? Marque uma conversa de 45 minutos em https://iauaicloud.com.br/consultoria

Aprenda jogando

Pipeline em Pânico

Roteie registros sujos pelas estações certas antes que a esteira te engula.

Jogar Pipeline em Pânico

Teste seu conhecimento

Teste o que você aprendeu sobre estratégias de chunking

Pergunta 1 de 5

Por que usar sobreposição entre chunks?

Um conteúdo prático por quinzena

Deixe o seu e-mail para receber um conteúdo prático de IA e cloud a cada quinzena. Sem spam, e você pede a exclusão quando quiser.

Continue lendo