<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>RAG on kenji.blog</title><link>http://kenji.blog/pt/tags/rag/</link><description>Recent content in RAG on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>pt</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 13:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/pt/tags/rag/index.xml" rel="self" type="application/rss+xml"/><item><title>【Guia de Implementação RAG】Como fazer a IA local ler seus próprios documentos</title><link>http://kenji.blog/pt/p/rag-local-ai-implementation-guide/</link><pubDate>Fri, 11 Sep 2026 13:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/rag-local-ai-implementation-guide/</guid><description>&lt;img src="http://kenji.blog/p/rag-local-ai-implementation-guide/img/eyecatch.jpg" alt="Featured image of post 【Guia de Implementação RAG】Como fazer a IA local ler seus próprios documentos" />&lt;h1 id="introdução">Introdução
&lt;/h1>&lt;p>Nos últimos anos, a evolução dos Grandes Modelos de Linguagem (LLM) tem sido notável, com muitas IAs, lideradas pelo ChatGPT e Claude, permeando nossas vidas e trabalhos. No entanto, os LLMs em geral têm uma fraqueza clara. É o fato de que eles conhecem apenas &amp;ldquo;informações públicas no momento do treinamento&amp;rdquo;. Eles naturalmente não podem responder a perguntas sobre &amp;ldquo;documentos privados&amp;rdquo;, como regulamentos internos, notas pessoais ou materiais de projetos não publicados. Tentar forçá-los a responder aumenta o risco de gerar mentiras plausíveis que diferem dos fatos (alucinações).&lt;/p>
&lt;p>Portanto, a arquitetura de tecnologia que está se espalhando explosivamente pelo mundo agora é a &lt;strong>RAG (Retrieval-Augmented Generation: Geração Aumentada por Recuperação)&lt;/strong>. Ao usar a RAG, é possível fornecer dinamicamente conhecimento próprio ao LLM a partir de um banco de dados externo e fazer com que ele gere respostas precisas e fundamentadas com base nisso.&lt;/p>
&lt;p>Além disso, ao lidar com informações confidenciais na área corporativa ou pessoal, o envio de dados para APIs baseadas em nuvem, como a da OpenAI, muitas vezes não é permitido pelas políticas de segurança. Portanto, o que se exige é a construção de uma &amp;ldquo;RAG local&amp;rdquo; combinada com &lt;strong>IA local&lt;/strong> (LLMs que funcionam e se completam no seu próprio PC ou servidor on-premise).&lt;/p>
&lt;p>Neste artigo, explicaremos detalhadamente, desde a teoria básica da RAG até o método específico de implementação da RAG local usando Python, o contexto matemático (o mecanismo da pesquisa vetorial) e técnicas avançadas para colocar o sistema em produção.&lt;/p>
&lt;hr>
&lt;h1 id="1-arquitetura-geral-da-rag">1. Arquitetura Geral da RAG
&lt;/h1>&lt;p>A RAG não é um modelo de IA único, mas uma arquitetura de sistema na qual vários componentes trabalham juntos. Ela é dividida basicamente em duas partes: a &amp;ldquo;Fase de Ingestão (captura de dados)&amp;rdquo; e a &amp;ldquo;Fase de Recuperação e Geração (pesquisa e geração)&amp;rdquo;.&lt;/p>
&lt;p>O diagrama Mermaid abaixo mostra a visão geral do sistema RAG.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "Fase de Ingestão (Preparação prévia)"
Doc["Documentos Próprios (PDF, TXT, etc.)"] --> Loader["Carregador de Documentos"]
Loader --> Splitter["Divisão de Texto (Chunking)"]
Splitter --> EmbedModel1["Modelo de Incorporação (Embedding)"]
EmbedModel1 --> VectorDB["Banco de Dados Vetorial"]
end
subgraph "Fase de Inferência (Durante a consulta do usuário)"
User["Pergunta do Usuário (Consulta)"] --> EmbedModel2["Modelo de Incorporação (Embedding)"]
EmbedModel2 --> QueryVector["Vetor da Consulta"]
QueryVector --> Search["Pesquisa de Similaridade (Pesquisa Vetorial)"]
VectorDB --> Search
Search --> Context["Extração de Chunks Relevantes (Contexto)"]
User --> PromptBuilder["Construção do Prompt"]
Context --> PromptBuilder
PromptBuilder --> LocalLLM["LLM Local"]
LocalLLM --> Answer["Geração da Resposta Final"]
end&lt;/div>
&lt;h2 id="fase-de-ingestão-preparação-prévia">Fase de Ingestão (Preparação prévia)
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>Leitura de documentos&lt;/strong>: Carrega dados não estruturados, como arquivos PDF, Word e texto.&lt;/li>
&lt;li>&lt;strong>Chunking (Divisão de texto)&lt;/strong>: Divide textos longos em blocos significativos (chunks) para caber no limite de entrada do LLM (janela de contexto) e para aumentar a precisão da pesquisa.&lt;/li>
&lt;li>&lt;strong>Embedding (Vetorização)&lt;/strong>: Insere os chunks divididos em um Modelo de Incorporação (Embedding Model) e os converte em matrizes numéricas (vetores) de centenas a milhares de dimensões.&lt;/li>
&lt;li>&lt;strong>Armazenamento no banco de dados&lt;/strong>: Salva os vetores convertidos associados aos dados de texto originais em um banco de dados vetorial (Vector DB).&lt;/li>
&lt;/ol>
&lt;h2 id="fase-de-inferência-em-tempo-de-execução">Fase de Inferência (Em tempo de execução)
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>Vetorização da consulta&lt;/strong>: Vetoriza a frase da pergunta do usuário usando o mesmo modelo de incorporação da preparação prévia.&lt;/li>
&lt;li>&lt;strong>Pesquisa de similaridade&lt;/strong>: Calcula a similaridade entre o vetor da consulta e os vetores de documentos no banco de dados, recuperando os principais chunks de texto semanticamente próximos (altamente relevantes).&lt;/li>
&lt;li>&lt;strong>Construção do prompt&lt;/strong>: Combina os textos relevantes obtidos como &amp;ldquo;contexto (conhecimento prévio)&amp;rdquo; com a frase da pergunta do usuário para criar o prompt de entrada para o LLM.&lt;/li>
&lt;li>&lt;strong>Geração da resposta&lt;/strong>: O LLM recebe o prompt estendido e gera uma resposta com base nas informações de contexto fornecidas.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="2-entendimento-profundo-da-pesquisa-vetorial-e-incorporações-embeddings">2. Entendimento Profundo da Pesquisa Vetorial e Incorporações (Embeddings)
&lt;/h1>&lt;p>O núcleo da RAG é a &amp;ldquo;pesquisa vetorial (pesquisa semântica)&amp;rdquo;. Enquanto a pesquisa tradicional por palavras-chave (como o BM25) é baseada na correspondência exata e frequência de palavras, a pesquisa vetorial é baseada na &amp;ldquo;similaridade de significado&amp;rdquo;. Por exemplo, como &amp;ldquo;cão&amp;rdquo; e &amp;ldquo;filhote&amp;rdquo; ou &amp;ldquo;PC&amp;rdquo; e &amp;ldquo;computador&amp;rdquo;, mesmo palavras diferentes aparecerão na pesquisa se seus significados forem próximos.&lt;/p>
&lt;h2 id="o-que-é-um-modelo-de-incorporação-embedding-model">O que é um Modelo de Incorporação (Embedding Model)?
&lt;/h2>&lt;p>Um modelo de incorporação é uma rede neural que recebe texto em linguagem natural como entrada e gera um vetor denso (Dense Vector) de comprimento fixo como saída. Modelos comuns (como &lt;code>text-embedding-3-small&lt;/code> ou o código aberto &lt;code>multilingual-e5-large&lt;/code>) mapeiam o texto para vetores de números reais de 384 ou 1024 dimensões.&lt;/p>
&lt;p>Neste espaço multidimensional (espaço latente), eles são treinados de forma que frases com significados semelhantes fiquem mais próximas na distância dentro do espaço de coordenadas.&lt;/p>
&lt;h2 id="contexto-matemático-do-cálculo-de-similaridade-similaridade-de-cosseno">Contexto Matemático do Cálculo de Similaridade: Similaridade de Cosseno
&lt;/h2>&lt;p>Quando um banco de dados vetorial pesquisa documentos relevantes, a métrica de distância mais comumente usada é a &lt;strong>Similaridade de Cosseno (Cosine Similarity)&lt;/strong>. Diferente da distância euclidiana (distância espacial absoluta), a similaridade de cosseno foca no &amp;ldquo;ângulo formado entre dois vetores&amp;rdquo;. Como é menos afetada pelo comprimento da frase (norma do vetor), é muito adequada para calcular a similaridade de textos.&lt;/p>
&lt;p>Expresso matematicamente, a similaridade de cosseno entre os vetores $\mathbf{A}$ e $\mathbf{B}$ é a seguinte:&lt;/p>
$$ \text{Cosine Similarity}(\mathbf{A}, \mathbf{B}) = \cos(\theta) = \frac{\mathbf{A} \cdot \mathbf{B}}{\|\mathbf{A}\| \|\mathbf{B}\|} = \frac{\sum_{i=1}^{n} A_i B_i}{\sqrt{\sum_{i=1}^{n} A_i^2} \sqrt{\sum_{i=1}^{n} B_i^2}} $$
&lt;ul>
&lt;li>$\mathbf{A} \cdot \mathbf{B}$ representa o produto escalar (Dot Product).&lt;/li>
&lt;li>$\|\mathbf{A}\|$ representa a norma L2 (comprimento) do vetor $\mathbf{A}$.&lt;/li>
&lt;li>$n$ é o número de dimensões dos vetores.&lt;/li>
&lt;/ul>
&lt;p>A similaridade de cosseno varia de -1 a 1.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Próximo a 1&lt;/strong>: A direção dos dois vetores é quase a mesma (os significados são muito semelhantes).&lt;/li>
&lt;li>&lt;strong>Próximo a 0&lt;/strong>: Os dois vetores são ortogonais (não relacionados).&lt;/li>
&lt;li>&lt;strong>Próximo a -1&lt;/strong>: Os dois vetores apontam em direções opostas (significados opostos).&lt;/li>
&lt;/ul>
&lt;p>Os bancos de dados vetoriais recentes (Chroma, FAISS, Qdrant, etc.) adotam um algoritmo de Pesquisa Aproximada de Vizinhos Mais Próximos (ANN) chamado HNSW (Hierarchical Navigable Small World), sendo otimizados para pesquisar documentos com alta similaridade de cosseno em milissegundos, mesmo entre milhões de dados vetoriais.&lt;/p>
&lt;hr>
&lt;h1 id="3-pilha-de-tecnologia-para-construir-a-rag-local">3. Pilha de Tecnologia para Construir a RAG Local
&lt;/h1>&lt;p>Para construir uma RAG totalmente local, sem depender da nuvem, utilizamos o ecossistema de código aberto. A pilha de tecnologia recomendada é apresentada abaixo.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Modelo de Linguagem (LLM)&lt;/strong>
&lt;ul>
&lt;li>Ferramenta: &lt;code>Ollama&lt;/code> ou &lt;code>Llama.cpp&lt;/code>&lt;/li>
&lt;li>Modelo: Modelos abertos leves e de alto desempenho, como &lt;code>Llama-3-8B-Instruct&lt;/code>, &lt;code>Gemma-2-9B-It&lt;/code>, &lt;code>Qwen2-7B-Instruct&lt;/code>. Para tarefas em japonês, modelos ajustados como o &lt;code>Llama-3-ELYZA-JP-8B&lt;/code> são adequados.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Modelo de Incorporação (Embedding)&lt;/strong>
&lt;ul>
&lt;li>Modelo: &lt;code>intfloat/multilingual-e5-large&lt;/code> ou &lt;code>BAAI/bge-m3&lt;/code>. Ao executar localmente, geralmente é feito o download pelo Hugging Face e a execução usando o Sentence-Transformers.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Banco de Dados Vetorial (Vector DB)&lt;/strong>
&lt;ul>
&lt;li>&lt;code>ChromaDB&lt;/code>: Baseado em Python e extremamente fácil de configurar. Ideal para desenvolvimento local.&lt;/li>
&lt;li>&lt;code>FAISS&lt;/code>: Uma biblioteca rápida de pesquisa vetorial desenvolvida pela Meta.&lt;/li>
&lt;li>&lt;code>Qdrant&lt;/code> / &lt;code>Milvus&lt;/code>: Mais adequados para ambientes de produção e maior escala.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Estrutura de Orquestração&lt;/strong>
&lt;ul>
&lt;li>&lt;code>LangChain&lt;/code>: O padrão de fato para conectar componentes (Chains).&lt;/li>
&lt;li>&lt;code>LlamaIndex&lt;/code>: Um framework de conexão de dados voltado especificamente para a RAG.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Desta vez, implementaremos usando a combinação mais fácil de introduzir: &lt;strong>LangChain + ChromaDB + Ollama + HuggingFaceEmbeddings&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="4-tutorial-de-implementação-construção-completa-da-rag-local-com-python">4. Tutorial de Implementação: Construção Completa da RAG Local com Python
&lt;/h1>&lt;p>A partir daqui, vamos construir a RAG local escrevendo código Python real. Antes de começar, instale o Ollama no seu PC e inicie-o em segundo plano. Além disso, baixe o modelo no Ollama (ex: &lt;code>ollama run llama3&lt;/code>).&lt;/p>
&lt;h2 id="passo-1-instalação-das-bibliotecas-necessárias">Passo 1: Instalação das Bibliotecas Necessárias
&lt;/h2>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install langchain langchain-community langchain-huggingface
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install chromadb sentence-transformers pypdf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="passo-2-visão-geral-do-código-de-implementação">Passo 2: Visão Geral do Código de Implementação
&lt;/h2>&lt;p>Abaixo está o script Python completo para ler um arquivo PDF, vetorizá-lo e permitir perguntas e respostas usando o LLM local.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;span class="lnt">87
&lt;/span>&lt;span class="lnt">88
&lt;/span>&lt;span class="lnt">89
&lt;/span>&lt;span class="lnt">90
&lt;/span>&lt;span class="lnt">91
&lt;/span>&lt;span class="lnt">92
&lt;/span>&lt;span class="lnt">93
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_community.document_loaders&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">PyPDFLoader&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_text_splitters&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">RecursiveCharacterTextSplitter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_huggingface&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">HuggingFaceEmbeddings&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_community.vectorstores&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Chroma&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_community.llms&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Ollama&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_core.prompts&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">PromptTemplate&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain.chains&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">RetrievalQA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. Leitura do documento&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Carregando documento...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Especifique o caminho do PDF que deseja ler&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;sample_company_policy.pdf&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">loader&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PyPDFLoader&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_path&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">documents&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">loader&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">load&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. Divisão de chunks (Text Splitting)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Dividimos em tamanhos moderados para não quebrar o significado do texto&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">text_splitter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">RecursiveCharacterTextSplitter&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunk_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">500&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Número máximo de caracteres por chunk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunk_overlap&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">50&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Número de caracteres sobrepostos entre os chunks (evita a desconexão do contexto)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">separators&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;.&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;,&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34; &amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">text_splitter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split_documents&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">documents&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Dividido em &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">chunks&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> chunks.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. Inicialização do modelo de incorporação (Local HuggingFace Model)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Usando um modelo multilíngue forte&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Carregando o modelo de incorporação...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embeddings&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">HuggingFaceEmbeddings&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;intfloat/multilingual-e5-large&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;device&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;cpu&amp;#39;&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="c1"># Use &amp;#39;cuda&amp;#39; ou &amp;#39;mps&amp;#39; se tiver uma GPU&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 4. Construção do banco de dados vetorial (Chroma)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Construindo o banco de dados vetorial...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">persist_directory&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;./chroma_db&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vectorstore&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Chroma&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_documents&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">documents&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">chunks&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embedding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">embeddings&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">persist_directory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">persist_directory&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Criação do recuperador (Retriever). Configurado para buscar os 3 principais documentos relevantes&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">retriever&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">vectorstore&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">as_retriever&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">search_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;k&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 5. Inicialização do LLM Local (Ollama)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Conectando ao LLM local...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Certifique-se de obter o modelo antecipadamente usando &amp;#39;ollama pull llama3&amp;#39; etc.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Ollama&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;llama3&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 6. Definição do template de prompt&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt_template&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Você é um excelente assistente com amplo conhecimento das regras e informações internas da empresa.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">Responda à pergunta do usuário em detalhes usando APENAS o seguinte contexto (informação prévia).
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">Se a resposta não puder ser encontrada no contexto, não tente adivinhar e responda honestamente &amp;#34;Não consigo encontrar a resposta nas informações fornecidas&amp;#34;.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">【Contexto】
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&lt;/span>&lt;span class="si">{context}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">【Pergunta】
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&lt;/span>&lt;span class="si">{question}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">【Resposta】:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PROMPT&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PromptTemplate&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">template&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">prompt_template&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">input_variables&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;context&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;question&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 7. Construção da Chain da RAG&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qa_chain&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">RetrievalQA&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_chain_type&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llm&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">llm&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chain_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;stuff&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">retriever&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">retriever&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">return_source_documents&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Configuração para retornar os documentos fonte&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chain_type_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;prompt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">PROMPT&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 8. Execução da pergunta&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">query&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Por favor, explique as condições para o pagamento das despesas de transporte no trabalho remoto.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">Pergunta: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">qa_chain&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">invoke&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;query&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">query&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;【Resposta】&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;result&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;【Fontes de informação consultadas】&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">doc&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;source_documents&amp;#39;&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;- Página &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">doc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">metadata&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;page&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Desconhecida&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">doc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">page_content&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="mi">50&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="explicação-dos-pontos-chave-do-código">Explicação dos Pontos-Chave do Código
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>RecursiveCharacterTextSplitter&lt;/strong>:
É o divisor mais recomendado para o processamento de linguagem natural. Ele tenta dividir o texto na ordem de parágrafos (&lt;code>\n\n&lt;/code>), quebras de linha (&lt;code>\n&lt;/code>) e pontos finais (&lt;code>.&lt;/code>), visando manter a coerência do significado tanto quanto possível e garantir que caiba no &lt;code>chunk_size&lt;/code> especificado. Ao definir um &lt;code>chunk_overlap&lt;/code>, previne-se que os limites de contexto sejam cortados e que informações se percam.&lt;/li>
&lt;li>&lt;strong>HuggingFaceEmbeddings&lt;/strong>:
&lt;code>intfloat/multilingual-e5-large&lt;/code> é um modelo de incorporação de código aberto multilíngue muito poderoso. Ele permite vetorizar textos offline na memória local, sem o uso de APIs na nuvem (como o &lt;code>text-embedding-ada-002&lt;/code> da OpenAI).&lt;/li>
&lt;li>&lt;strong>ChromaDB&lt;/strong>:
Como roda em memória ou no armazenamento local (baseado em SQLite), não é necessário iniciar servidores de banco de dados complexos. Ao especificar o &lt;code>persist_directory&lt;/code>, você pode pular o processo de vetorização em execuções subsequentes e carregar o BD direto do disco.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="5-técnicas-avançadas-da-rag-advanced-rag-techniques">5. Técnicas Avançadas da RAG (Advanced RAG Techniques)
&lt;/h1>&lt;p>O sistema RAG básico (Naive RAG) construído no tutorial acima já funciona, mas se for exigida alta precisão nas respostas em um ambiente de produção, será necessário implementar técnicas avançadas como as descritas a seguir.&lt;/p>
&lt;h2 id="51-pesquisa-híbrida-hybrid-search">5.1 Pesquisa Híbrida (Hybrid Search)
&lt;/h2>&lt;p>A pesquisa vetorial é excelente para captar o &amp;ldquo;significado&amp;rdquo;, mas pode não lidar bem com pesquisas rigorosas por palavras-chave, como &amp;ldquo;nomes próprios específicos&amp;rdquo;, &amp;ldquo;números de modelo de produto&amp;rdquo; e &amp;ldquo;IDs de funcionários&amp;rdquo;.
Portanto, a realização da &lt;strong>pesquisa semântica&lt;/strong> baseada em vetores em paralelo com a &lt;strong>pesquisa por palavras-chave&lt;/strong> (usando algoritmos como o BM25) e a integração de ambos os resultados (usando técnicas como o Reciprocal Rank Fusion, RRF) podem reduzir drasticamente o número de omissões de pesquisa.&lt;/p>
&lt;h2 id="52-reclassificação-re-ranking">5.2 Reclassificação (Re-ranking)
&lt;/h2>&lt;p>A pesquisa vetorial é rápida, mas nem sempre avalia a relevância exata de um contexto no seu sentido literal. O pipeline geral para melhorar a precisão da pesquisa é o seguinte:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Recuperação Inicial (First-stage Retrieval)&lt;/strong>: Recupera entre 20 a 30 chunks relevantes do banco de dados vetorial, com alcance mais amplo e superficial.&lt;/li>
&lt;li>&lt;strong>Reavaliação (Re-ranking)&lt;/strong>: Utiliza-se um modelo de machine learning diferente e mais pesado chamado Cross-Encoder (por exemplo: &lt;code>bge-reranker&lt;/code>) para introduzir pares compostos da consulta do usuário e dos chunks recuperados, recalculando a pontuação de relevância semântica.&lt;/li>
&lt;li>&lt;strong>Seleção&lt;/strong>: Somente os 3 a 5 principais resultados com as maiores pontuações são repassados ao prompt do LLM como o contexto final.&lt;/li>
&lt;/ol>
&lt;p>Esse método impede que informações de ruído não relacionadas passem para o LLM, o que pode melhorar significativamente a precisão (Precision) da resposta.&lt;/p>
&lt;div class="mermaid">graph LR
Query["Consulta"] --> VSearch["Pesquisa Vetorial (Top 20)"]
VSearch --> Reranker["Modelo Reclassificador (Cross-Encoder)"]
Query --> Reranker
Reranker --> TopK["Top 3 de Alta Precisão"]
TopK --> LLM["Geração do LLM"]&lt;/div>
&lt;h2 id="53-chunking-semântico-e-pesquisa-do-documento-pai">5.3 Chunking Semântico e Pesquisa do Documento Pai
&lt;/h2>&lt;p>Em vez de dividir o texto mecanicamente por um número fixo de caracteres, existe uma técnica chamada &amp;ldquo;Semantic Chunking&amp;rdquo;, onde a IA detecta as mudanças de significado do texto para dividi-lo.
Além disso, com a técnica de &amp;ldquo;Pesquisa do Documento Pai (Parent Document Retriever)&amp;rdquo;, a vetorização é feita em unidades muito pequenas (como frases isoladas) para a pesquisa, buscando alta precisão. Mas ao passar para o LLM, o parágrafo original inteiro (&amp;ldquo;documento pai&amp;rdquo;) que contém essa frase é fornecido, dando ao LLM um contexto suficiente para compreensão.&lt;/p>
&lt;hr>
&lt;h1 id="6-desafios-e-soluções-na-operação-da-rag-local">6. Desafios e Soluções na Operação da RAG Local
&lt;/h1>&lt;p>Existem obstáculos específicos ao construir e operar uma RAG em um ambiente local.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Esgotamento da VRAM (Memória de Vídeo)&lt;/strong>:
Para executar LLMs locais a velocidades práticas (dezenas de tokens por segundo), é necessário carregar o modelo na VRAM da GPU. Um modelo de classe 8B requer aproximadamente 16GB de VRAM para rodar em fp16 (ponto flutuante de 16 bits), mas ao usar tecnologias de &lt;strong>Quantização (Quantization)&lt;/strong> (formatos GGUF ou AWQ, que comprimem os modelos para 4 ou 8 bits), é possível executá-los com rapidez satisfatória com apenas 8GB de VRAM (como em um PC gamer comum). O Llama.cpp e o Ollama já suportam nativamente esses formatos de quantização.&lt;/li>
&lt;li>&lt;strong>Limite da Janela de Contexto&lt;/strong>:
Se a quantidade de contexto recuperado for muito grande, o LLM pode exceder seu limite máximo de entrada (limite de tokens) ou o modelo pode &amp;ldquo;esquecer&amp;rdquo; informações do meio (o fenômeno &amp;ldquo;Lost in the middle&amp;rdquo;). O ajuste do número de chunks extraídos e a seleção cuidadosa usando as tecnologias de reclassificação mencionadas acima são fundamentais.&lt;/li>
&lt;li>&lt;strong>Gestão da Atualidade dos Dados&lt;/strong>:
Se o documento fonte for atualizado, o vetor do documento correspondente no banco de dados vetorial também precisará ser atualizado ou excluído (operações CRUD). Como o ChromaDB suporta atualizações baseadas em IDs de documentos, a gestão dos valores hash de arquivos para sincronizar as diferenças através de processamento em lote é a melhor prática.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="conclusão">Conclusão
&lt;/h1>&lt;p>A RAG (Geração Aumentada por Recuperação) é um poderoso paradigma que evolui a IA de um simples assistente geral para um &amp;ldquo;especialista dedicado&amp;rdquo; ou um &amp;ldquo;especialista em operações internas&amp;rdquo;.&lt;/p>
&lt;p>Mesmo com requisitos de alta confidencialidade, nos quais serviços em nuvem não podem ser usados, foi possível perceber que um ambiente RAG totalmente local pode ser construído com relativa facilidade, combinando o ecossistema de código aberto, como o Ollama, o LangChain e o ChromaDB.&lt;/p>
&lt;p>Com base no entendimento matemático do espaço vetorial, do chunking de texto e das abordagens avançadas, como a reclassificação, explicadas neste artigo, não deixe de tentar desenvolver o seu próprio sistema original de IA usando seus dados. A velocidade de evolução da IA local é espantosa; os sistemas construídos hoje podem ter seu desempenho atualizado instantaneamente apenas trocando os modelos por modelos menores e mais inteligentes lançados amanhã.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Neste blog, continuaremos postando artigos aprofundados sobre tecnologias de IA e RAG no futuro. Se você tiver dúvidas ou feedback, sinta-se à vontade para compartilhá-los na seção de comentários.&lt;/em>&lt;/p></description></item></channel></rss>