
Em pipeline de RAG↳RAG6 conteúdosTécnica RAG com a biblioteca Langchain: tutorial para aplicar agoraData · jun 2024Como avaliar LLMs, RAG e Agentes de IA: Teoria e prática.AI · abr 2026RAG Não É Memória: O Problema Real dos Agentes de IAAI · mai 2026Ver tudo em AI → (Retrieval-Augmented Generation) o primeiro passo é quase sempre o mesmo: pegar um texto grande e quebrar em pedaços antes de vetorizar. Os pedaços não podem ser grandes demais, porque o modelo tem limite de contexto, nem pequenos demais, porque aí o embedding perde semântica. E precisam ter sobreposição entre vizinhos, senão uma resposta que cai bem na fronteira fica espremida entre dois chunks e o retriever erra.
O chunker precisa:
- Quebrar o texto em janelas de até N runas.
- Fazer sobreposição configurável.
- Não cortar uma palavra no meio.
- Ser consumível com um
for-range, sem subir a lista toda na memória.
O último item é trivial a partir do Go↳Go23 conteúdosEntendendo o Green Tea GC do Go 1.26Dev (Back & Front) · mai 2026Função recursiva em Go para acessar valores em mapas aninhadosDev (Back & Front) · set 2025Publicando projeto desenvolvido em Golang em um server grátisDev (Back & Front) · mar 2025Ver tudo em Dev (Back & Front) → 1.23 com o pacote iter. A função devolve uma iter.Seq[string] e o consumidor itera como qualquer coisa:
for chunk := range Chunker(text, 60, 15) {
// embed, index, send to the LLM
}
A janela anda em runas, não em bytes.
Texto com caractere multibyte, emoji no meio do parágrafo: contar byte dá tamanho errado e ainda corre risco de partir um caractere ao meio.
Pago a conversão []rune(text) uma vez e trabalho com índice de runa daí pra frente.
O passo entre janelas é size - overlap. Se isso der <= 0 a configuração é absurda (overlap maior ou igual ao tamanho) e o iterador encerra sem emitir nada:
func Chunker(text string, size, overlap int) iter.Seq[string] {
return func(yield func(string) bool) {
runes := []rune(text)
n := len(runes)
step := size - overlap
if n == 0 || size <= 0 || step <= 0 {
return
}
// ...
}
}
Para não cortar palavra, é só recuar o fim da janela até a última fronteira de palavra (qualquer espaço). Se a palavra for tão longa que sozinha ocupa o chunk inteiro, aí corta no limite mesmo.
É a única forma de avançar:
cut := end
for cut > i && !unicode.IsSpace(runes[cut]) {
cut--
}
if cut == i {
cut = end
}
Emite o chunk e respeita o protocolo do iter.Seq: se o yield retornar false, o consumidor saiu do loop (break, return) e a gente sai junto:
if !yield(strings.TrimSpace(string(runes[i:cut]))) {
return
}
A próxima janela começa em cut - overlap. Esse índice pode cair no meio de uma palavra, então avanço até terminar a palavra parcial e depois pulo os espaços para começar limpo:
i = max(cut-overlap, 0)
if i > 0 && !unicode.IsSpace(runes[i-1]) {
for i < n && !unicode.IsSpace(runes[i]) {
i++
}
}
for i < n && unicode.IsSpace(runes[i]) {
i++
}
Quando o fim da janela passa do fim do texto, entrega o resto e encerra:
if end >= n {
if last := strings.TrimSpace(string(runes[i:n])); last != "" {
yield(last)
}
return
}
Rodando com size=60, overlap=15:
document: 174 runes | size=60 overlap=15
------------------------------------------------------------
[01] "The Go programming language favors standard libraries and"
[02] "libraries and simple tools. The use of iterators, introduced"
[03] "introduced in recent versions, simplifies the construction"
[04] "construction of complex pipelines."
Cada chunk começa repetindo o final do anterior.
É essa repetição que dá ao retriever uma chance de casar uma busca cuja resposta caiu bem em cima da fronteira de dois chunks.
O custo é mais vetores no índice e a chance da mesma passagem aparecer duas vezes no top-k. Para RAG de produção vale a pena. LangChain e LlamaIndex defaultam para algo nessa faixa: size de 500 a 1000 tokens, overlap de 10% a 20%.
Esse chunker é estupido de propósito. Não conhece frase, não conhece parágrafo, não conhece semântica. Para um pipeline sério você provavelmente vai querer cortar em fronteira de frase, ou ir num chunker semântico que olha embedding de sentença e quebra onde a similaridade cai.







