<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Local AI on kenji.blog</title><link>http://kenji.blog/pt/tags/local-ai/</link><description>Recent content in Local AI on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>pt</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 16:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/pt/tags/local-ai/index.xml" rel="self" type="application/rss+xml"/><item><title>Como Fazer o Ajuste Fino Mais Rápido do TinyLLaMA em um Ambiente On-Premises</title><link>http://kenji.blog/pt/p/tinyllama-on-premises-fast-tuning-guide/</link><pubDate>Fri, 11 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/tinyllama-on-premises-fast-tuning-guide/</guid><description>&lt;img src="http://kenji.blog/p/tinyllama-on-premises-fast-tuning-guide/img/eyecatch.jpg" alt="Featured image of post Como Fazer o Ajuste Fino Mais Rápido do TinyLLaMA em um Ambiente On-Premises" />&lt;h2 id="1-introdução-por-que-tinyllama-e-on-premises-agora">1. Introdução: Por que TinyLLaMA e On-Premises agora?
&lt;/h2>&lt;p>A evolução dos grandes modelos de linguagem (LLM) está avançando a uma velocidade incrível, mas, consequentemente, o número de parâmetros dos modelos continua a inchar para a escala de centenas de bilhões. Embora modelos supergigantes como GPT-4 e Claude 3 possuam um desempenho inigualável, o custo computacional para inferência e treinamento, bem como as preocupações de segurança e privacidade de dados ao usar APIs externas, tornaram-se grandes obstáculos para as empresas. Especialmente em operações que lidam com dados corporativos altamente confidenciais e informações pessoais, enviar dados para uma API de LLM pública na nuvem frequentemente não é permitido do ponto de vista da conformidade (como GDPR e LGPD).&lt;/p>
&lt;p>É aí que os &lt;strong>Pequenos Modelos de Linguagem (SLM: Small Language Models)&lt;/strong> e as &lt;strong>operações locais em ambientes on-premises&lt;/strong> estão ganhando destaque. Entre eles, o &amp;ldquo;&lt;strong>TinyLLaMA&lt;/strong>&amp;rdquo; tem um tamanho compacto de apenas 1.1B (1.1 bilhão) de parâmetros, mas foi pré-treinado com um enorme conjunto de dados de cerca de 3 trilhões de tokens, demonstrando um desempenho impressionante em comparação com modelos da mesma classe.&lt;/p>
&lt;p>Neste artigo, forneceremos um guia completo para realizar o fine-tuning (ajuste fino) deste TinyLLaMA de forma &amp;ldquo;mais rápida e altamente eficiente&amp;rdquo; para tarefas específicas da sua empresa em um ambiente on-premises (servidores locais ou estações de trabalho). Explicaremos de forma abrangente desde os fundamentos matemáticos e as mais recentes tecnologias de otimização até códigos práticos de implementação em PyTorch.&lt;/p>
&lt;hr>
&lt;h2 id="2-arquitetura-e-características-do-tinyllama">2. Arquitetura e Características do TinyLLaMA
&lt;/h2>&lt;p>O TinyLLaMA segue a arquitetura LLaMA (Large Language Model Meta AI) desenvolvida pela Meta. Embora mantenha o número de parâmetros em 1.1B, ele utiliza a mesma pilha de tecnologia do LLaMA 2, o que o caracteriza por uma compatibilidade extremamente alta com o ecossistema.&lt;/p>
&lt;h3 id="principais-componentes-da-arquitetura">Principais Componentes da Arquitetura
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>RMSNorm (Root Mean Square Normalization):&lt;/strong>
Um método de normalização que omite a subtração da média dos cálculos do LayerNorm tradicional, melhorando a eficiência computacional. Ele aumenta a taxa de transferência enquanto mantém a estabilidade do treinamento.&lt;/li>
&lt;li>&lt;strong>Função de Ativação SwiGLU:&lt;/strong>
Na Feed Forward Network (FFN), o SwiGLU é adotado em vez do ReLU ou GELU tradicionais. Matematicamente, isso é expresso da seguinte forma:
$$ \text{SwiGLU}(x, W, V) = \text{Swish}(xW) \otimes (xV) $$
Aqui, $\otimes$ representa o produto elemento a elemento (Produto de Hadamard) e a função Swish é $\text{Swish}(z) = z \cdot \sigma(\beta z)$. Isso melhora significativamente a capacidade de representação.&lt;/li>
&lt;li>&lt;strong>RoPE (Rotary Position Embedding):&lt;/strong>
Um método que combina as vantagens da codificação de posição absoluta e da codificação de posição relativa. Possui alta capacidade de generalização mesmo quando o comprimento da sequência é estendido.&lt;/li>
&lt;li>&lt;strong>Grouped Query Attention (GQA):&lt;/strong>
Uma abordagem intermediária entre a Multi-Head Attention (MHA) e a Multi-Query Attention (MQA), que economiza largura de banda de memória e melhora drasticamente a velocidade de inferência agrupando as cabeças de chaves e valores.&lt;/li>
&lt;/ol>
&lt;p>O diagrama Mermaid a seguir mostra o fluxo de dados geral e a estrutura dos blocos Transformer do TinyLLaMA.&lt;/p>
&lt;div class="mermaid">graph TD
A["Texto de Entrada"] --> B["Tokenizador (BPE)"]
B --> C["Camada de Embedding"]
C --> D["Blocos Transformer (x22 Camadas para TinyLLaMA)"]
D --> E["RMSNorm (Final)"]
E --> F["Projeção Linear (Tamanho do Vocabulário)"]
F --> G["Probabilidades de Saída (Softmax)"]
subgraph "Anatomia do Bloco Transformer"
D1["Estado Oculto de Entrada"] --> D2["RMSNorm"]
D2 --> D3["Grouped Query Attention (GQA)"]
D3 --> D4["Adição Residual"]
D4 --> D5["RMSNorm"]
D5 --> D6["SwiGLU FFN"]
D6 --> D7["Adição Residual"]
D7 --> D8["Saída para a Próxima Camada"]
D1 -.-> D4
D4 -.-> D7
end&lt;/div>
&lt;hr>
&lt;h2 id="3-um-avanço-no-fine-tuning-lora-e-qlora">3. Um Avanço no Fine-Tuning: LoRA e QLoRA
&lt;/h2>&lt;p>Realizar um fine-tuning com todos os parâmetros em um ambiente on-premises, mesmo para um modelo de 1.1B, consome dezenas de GBs de VRAM (memória de vídeo) para manter os estados do otimizador e gradientes. Para treinar eficientemente com recursos limitados, o método &lt;strong>PEFT (Parameter-Efficient Fine-Tuning)&lt;/strong> chamado &amp;ldquo;&lt;strong>LoRA&lt;/strong>&amp;rdquo; e sua extensão quantizada &amp;ldquo;&lt;strong>QLoRA&lt;/strong>&amp;rdquo; são essenciais.&lt;/p>
&lt;h3 id="31-contexto-matemático-do-lora-low-rank-adaptation">3.1 Contexto Matemático do LoRA (Low-Rank Adaptation)
&lt;/h3>&lt;p>LoRA é uma técnica que fixa (congela) as matrizes de pesos pré-treinadas e aproxima a atualização desses pesos ($\Delta W$) como o produto de duas matrizes pequenas de baixo posto.&lt;/p>
&lt;p>Suponha que os pesos pré-treinados sejam $W_0 \in \mathbb{R}^{d \times k}$. No fine-tuning completo, o próprio $W_0$ é atualizado para $W_0 + \Delta W$, mas no LoRA a matriz de atualização $\Delta W$ é decomposta da seguinte forma:&lt;/p>
$$ \Delta W = B \times A $$
&lt;p>Aqui, $B \in \mathbb{R}^{d \times r}$, $A \in \mathbb{R}^{r \times k}$, e $r$ é um hiperparâmetro chamado posto (Rank), que é um valor muito pequeno que satisfaz $r \ll \min(d, k)$ (geralmente 8, 16, 32, etc.).&lt;/p>
&lt;p>O cálculo na passagem para frente (forward pass) é o seguinte:&lt;/p>
$$ h = W_0 x + \Delta W x = W_0 x + B A x $$
&lt;p>No estado inicial, a matriz $A$ é inicializada aleatoriamente com uma distribuição normal (distribuição Gaussiana), e a matriz $B$ é inicializada com uma matriz zero. Isso garante que $\Delta W$ seja zero no início do treinamento, permitindo iniciar o treinamento preservando totalmente a saída do modelo base.&lt;/p>
&lt;div class="mermaid">graph LR
X["Vetor de Entrada x"] --> W0["Peso Pré-treinado Congelado (W_0)"]
X --> A["Matriz LoRA Treinável A (r x k)"]
A --> B["Matriz LoRA Treinável B (d x r)"]
W0 --> Add["Adição de Vetores"]
B --> Add
Add --> Y["Vetor de Saída h"]&lt;/div>
&lt;h3 id="32-a-inovação-do-qlora-quantized-lora">3.2 A Inovação do QLoRA (Quantized LoRA)
&lt;/h3>&lt;p>QLoRA impulsiona ainda mais a abordagem do LoRA, quantizando o modelo base $W_0$ em precisão de 4 bits (NormalFloat 4, NF4) e carregando-o na memória. Isso reduz drasticamente o consumo de VRAM.&lt;/p>
&lt;p>O QLoRA incorpora 3 tecnologias cruciais:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Quantização de 4 bits NormalFloat (NF4):&lt;/strong> Um tipo de dados teoricamente ideal otimizado para pesos que seguem uma distribuição normal.&lt;/li>
&lt;li>&lt;strong>Double Quantization (Quantização Dupla):&lt;/strong> Economiza ainda mais memória quantizando a própria constante de quantização (fator de escala).&lt;/li>
&lt;li>&lt;strong>Paged Optimizers:&lt;/strong> Um mecanismo que utiliza o recurso de memória unificada da NVIDIA para descarregar temporariamente o status do otimizador para a RAM da CPU quando a VRAM se esgota.&lt;/li>
&lt;/ol>
&lt;p>Como resultado, o fine-tuning que normalmente requeriria 16GB a 24GB de VRAM pode ser executado facilmente até mesmo em GPUs de nível consumidor (como RTX 3060 de 12GB e RTX 4070).&lt;/p>
&lt;hr>
&lt;h2 id="4-requisitos-de-hardware-e-configuração-em-um-ambiente-on-premises">4. Requisitos de Hardware e Configuração em um Ambiente On-Premises
&lt;/h2>&lt;p>Os requisitos de hardware para o fine-tuning do TinyLLaMA (1.1B) com QLoRA podem ser mantidos muito baixos.&lt;/p>
&lt;h3 id="especificações-de-hardware-recomendadas">Especificações de Hardware Recomendadas
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>GPU:&lt;/strong> NVIDIA RTX 3060 (12GB), RTX 3090/4090 (24GB), ou NVIDIA A10G/A100, etc. Funcionará com pelo menos 8GB de VRAM, mas recomenda-se 12GB ou mais para aumentar o tamanho do batch.&lt;/li>
&lt;li>&lt;strong>CPU:&lt;/strong> Uma CPU moderna com 8 núcleos ou mais (Intel Core i7/i9, AMD Ryzen 7/9).&lt;/li>
&lt;li>&lt;strong>RAM:&lt;/strong> 32GB ou mais (importante como destino de backup da VRAM ao usar Paged Optimizers).&lt;/li>
&lt;li>&lt;strong>Armazenamento:&lt;/strong> NVMe SSD (para acelerar a leitura de conjuntos de dados e o salvamento de modelos).&lt;/li>
&lt;/ul>
&lt;h3 id="configuração-do-ambiente-de-software">Configuração do Ambiente de Software
&lt;/h3>&lt;p>O procedimento de configuração a seguir assume um ambiente Ubuntu 22.04 LTS. Usa-se o Python 3.10 ou superior.&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;/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">&lt;span class="c1"># Criação e ativação do ambiente virtual&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">python3 -m venv tinyllama_env
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">source&lt;/span> tinyllama_env/bin/activate
&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"># Instalação do PyTorch (para CUDA 12.1)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
&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"># Instalação das bibliotecas relacionadas aos transformers&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install transformers datasets peft trl accelerate bitsandbytes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="5-técnicas-de-otimização-para-o-ajuste-fino-mais-rápido">5. Técnicas de Otimização para o Ajuste Fino Mais Rápido
&lt;/h2>&lt;p>Para concluir o fine-tuning de forma &amp;ldquo;mais rápida&amp;rdquo;, além de simplesmente executar o script, é necessário combinar as seguintes técnicas de otimização.&lt;/p>
&lt;h3 id="51-flash-attention-2">5.1 Flash Attention 2
&lt;/h3>&lt;p>O mecanismo padrão de Attention tem uma complexidade computacional de tempo e espaço de $O(N^2)$ para um comprimento de sequência $N$. O Flash Attention 2 otimiza o acesso à memória entre a SRAM da GPU e a HBM (High Bandwidth Memory), eliminando o gargalo de IO sem reduzir a quantidade de cálculos, o que aumenta a velocidade de treinamento em várias vezes e reduz drasticamente o consumo de memória.&lt;/p>
&lt;h3 id="52-gradient-checkpointing-ponto-de-verificação-de-gradiente">5.2 Gradient Checkpointing (Ponto de Verificação de Gradiente)
&lt;/h3>&lt;p>Em vez de salvar todas as ativações intermediárias calculadas na passagem para frente (forward pass) na VRAM, apenas uma parte é salva e recalculada quando necessária na passagem para trás (backward pass). Embora o tempo de computação aumente em cerca de 20%, ele reduz o consumo de memória dramaticamente, permitindo a definição de um tamanho de batch maior e melhorando a taxa de transferência geral.&lt;/p>
&lt;h3 id="53-mixed-precision-training-treinamento-de-precisão-mista-e-bfloat16">5.3 Mixed Precision Training (Treinamento de Precisão Mista) e Bfloat16
&lt;/h3>&lt;p>Para maximizar a utilização dos Tensor Cores da GPU, os cálculos durante o treinamento são realizados em &lt;code>bfloat16&lt;/code> (Brain Floating Point). Comparado ao &lt;code>float16&lt;/code>, o comprimento de bits da parte expoente é o mesmo que no &lt;code>float32&lt;/code>, portanto o risco de overflow e underflow é extremamente baixo, resultando em um treinamento mais estável.&lt;/p>
&lt;hr>
&lt;h2 id="6-prática-código-de-fine-tuning-qlora-do-tinyllama">6. Prática: Código de Fine-Tuning QLoRA do TinyLLaMA
&lt;/h2>&lt;p>Agora, explicaremos o script PyTorch para o fine-tuning mais rápido, incorporando todas as otimizações acima. Aqui, utilizaremos o &lt;code>SFTTrainer&lt;/code> da biblioteca &lt;code>trl&lt;/code> (Transformer Reinforcement Learning) da Hugging Face.&lt;/p>
&lt;h3 id="61-preparação-do-conjunto-de-dados-e-carregamento-do-modelo">6.1 Preparação do Conjunto de Dados e Carregamento do Modelo
&lt;/h3>&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;/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">torch&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">datasets&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">load_dataset&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">transformers&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">AutoModelForCausalLM&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">AutoTokenizer&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">BitsAndBytesConfig&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">TrainingArguments&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="kn">from&lt;/span> &lt;span class="nn">peft&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">LoraConfig&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">get_peft_model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">prepare_model_for_kbit_training&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">trl&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">SFTTrainer&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"># 1. Especificar modelo e tokenizador&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;TinyLlama/TinyLlama-1.1B-Chat-v1.0&amp;#34;&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. Configuração de quantização de 4 bits para QLoRA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">bnb_config&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">BitsAndBytesConfig&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">load_in_4bit&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bnb_4bit_use_double_quant&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bnb_4bit_quant_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;nf4&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">bnb_4bit_compute_dtype&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">bfloat16&lt;/span> &lt;span class="c1"># O cálculo é feito em bfloat16&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"># 3. Carregamento do modelo (Habilitar Flash Attention 2)&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...&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&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoModelForCausalLM&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&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_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">quantization_config&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">bnb_config&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">device_map&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;auto&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">use_flash_attention_2&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span> &lt;span class="c1"># A chave para o treinamento mais rápido&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. Carregamento do tokenizador&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoTokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">trust_remote_code&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pad_token&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">eos_token&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">padding_side&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;right&amp;#34;&lt;/span> &lt;span class="c1"># Definido como right para evitar bugs durante o treinamento fp16/bf16&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="62-aplicação-do-adaptador-lora-e-formatação-do-conjunto-de-dados">6.2 Aplicação do Adaptador LoRA e Formatação do Conjunto de Dados
&lt;/h3>&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;/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="c1"># 5. Preparação para o treinamento k-bit e ativação do gradient checkpointing&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">gradient_checkpointing_enable&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&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">prepare_model_for_kbit_training&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&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. Configuração do LoRA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">peft_config&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">LoraConfig&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">r&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">16&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Posto&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lora_alpha&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">32&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Fator de escala&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lora_dropout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.05&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bias&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;none&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">task_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;CAUSAL_LM&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">target_modules&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;q_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;k_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;v_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;o_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;gate_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;up_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;down_proj&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># O desempenho melhora se todas as camadas Lineares forem os alvos&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="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_peft_model&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">peft_config&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&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">print_trainable_parameters&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exemplo de saída: trainable params: 14,286,848 || all params: 1,114,335,232 || trainable%: 1.282%&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. Carregamento do conjunto de dados (Aqui, usamos um dataset de instruções em japonês como exemplo)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Na prática, você carregará arquivos JSONL privados em seu ambiente on-premises&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dataset&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">load_dataset&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;kunishou/databricks-dolly-15k-ja&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">split&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;train&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">def&lt;/span> &lt;span class="nf">format_instruction&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">):&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="s2"> Formata a string para corresponder ao formato ChatML ou ao template de prompt
&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="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;|im_start|&amp;gt;user&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;instruction&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">sample&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;input&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="o">!=&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="n">prompt&lt;/span> &lt;span class="o">+=&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="si">{&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;input&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&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="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;|im_end|&amp;gt;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;lt;|im_start|&amp;gt;assistant&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;output&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;lt;|im_end|&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;text&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>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dataset&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dataset&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">format_instruction&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;h3 id="63-execução-do-treinamento">6.3 Execução do Treinamento
&lt;/h3>&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;/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="c1"># 8. Definição dos argumentos de treinamento&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">training_args&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TrainingArguments&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output_dir&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-lora-output&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">per_device_train_batch_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Aumente se houver VRAM suficiente&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">gradient_accumulation_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Tamanho de batch efetivo = 8 * 2 = 16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">optim&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;paged_adamw_32bit&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Economia de VRAM através do Paged Optimizer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">save_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logging_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">learning_rate&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">2e-4&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fp16&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bf16&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"># Mixed precision training (bfloat16)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_grad_norm&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.3&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_steps&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"># 500 passos para teste. Em produção, especifique pelo número de épocas&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">warmup_ratio&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.03&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">group_by_length&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lr_scheduler_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;cosine&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"># 9. Iniciar o treinamento com o SFTTrainer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">trainer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SFTTrainer&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&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">train_dataset&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">dataset&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">peft_config&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">peft_config&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dataset_text_field&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;text&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">max_seq_length&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Ajuste conforme o comprimento de entrada esperado&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokenizer&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">tokenizer&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">args&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">training_args&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="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Iniciando o treinamento...&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">trainer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">train&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"># 10. Salvar o adaptador LoRA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">trainer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-lora-final&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">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-lora-final&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;Treinamento completo e modelo salvo.&amp;#34;&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;hr>
&lt;h2 id="7-avaliação-de-desempenho-e-solução-de-problemas">7. Avaliação de Desempenho e Solução de Problemas
&lt;/h2>&lt;p>Ao realizar o treinamento em um ambiente on-premises, aqui estão alguns problemas frequentes e suas soluções.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Ocorre OOM (Out Of Memory):&lt;/strong>
&lt;ul>
&lt;li>Reduza &lt;code>per_device_train_batch_size&lt;/code> para &lt;code>1&lt;/code>.&lt;/li>
&lt;li>Aumente &lt;code>gradient_accumulation_steps&lt;/code> para manter o tamanho de batch efetivo.&lt;/li>
&lt;li>Reduza &lt;code>max_seq_length&lt;/code> de &lt;code>2048&lt;/code> para &lt;code>1024&lt;/code> ou &lt;code>512&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>A perda (Loss) não diminui ou diverge:&lt;/strong>
&lt;ul>
&lt;li>A taxa de aprendizado (&lt;code>learning_rate&lt;/code>) pode estar muito alta. Tente reduzi-la de &lt;code>2e-4&lt;/code> para algo em torno de &lt;code>5e-5&lt;/code>.&lt;/li>
&lt;li>Se você estiver usando Float16 em vez de Bfloat16, pode estar ocorrendo underflow dos gradientes. Verifique se &lt;code>bf16=True&lt;/code> está ativado.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Strings estranhas são geradas durante a inferência:&lt;/strong>
&lt;ul>
&lt;li>Verifique se &lt;code>padding_side=&amp;quot;right&amp;quot;&lt;/code> está configurado corretamente. Além disso, você precisa verificar se o formato do conjunto de dados (tokens especiais como &lt;code>&amp;lt;|im_start|&amp;gt;&lt;/code>) é consistente com os usados durante o pré-treinamento do modelo base.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-implantação-do-modelo-após-o-ajuste-fino-deployment">8. Implantação do Modelo Após o Ajuste Fino (Deployment)
&lt;/h2>&lt;p>Quando o fine-tuning estiver completo, o que será salvo não é o &amp;ldquo;modelo base inteiro&amp;rdquo;, mas apenas um &amp;ldquo;&lt;strong>Adaptador LoRA (pesos de diferença)&lt;/strong>&amp;rdquo; de alguns MB a algumas dezenas de MB. Para realizar a inferência em alta velocidade, você precisa fundir (integrar) esses pesos LoRA de volta ao modelo base original e exportá-lo como um modelo único.&lt;/p>
&lt;h3 id="script-de-fusão-do-modelo">Script de Fusão do Modelo
&lt;/h3>&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;/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">torch&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">peft&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AutoPeftModelForCausalLM&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">transformers&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AutoTokenizer&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">output_dir&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;./tinyllama-lora-final&amp;#34;&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"># Carrega o modelo e o adaptador em FP16/BF16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoPeftModelForCausalLM&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output_dir&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">device_map&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;auto&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">torch_dtype&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">bfloat16&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">tokenizer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoTokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output_dir&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"># Funde os pesos e salva&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">merged_model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">merge_and_unload&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">merged_model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-merged&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">safe_serialization&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-merged&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;Model merged and saved successfully!&amp;#34;&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;h3 id="configuração-de-um-servidor-de-inferência-ultrarrápido-com-vllm">Configuração de um Servidor de Inferência Ultrarrápido com vLLM
&lt;/h3>&lt;p>Na implantação em um ambiente on-premises, para maximizar a velocidade de inferência (Tokens por segundo), é fortemente recomendado o uso do &lt;strong>vLLM&lt;/strong> ou &lt;strong>TGI (Text Generation Inference)&lt;/strong>, em vez do &lt;code>pipeline&lt;/code> padrão da Hugging Face. O vLLM usa a tecnologia PagedAttention para evitar a fragmentação da memória da GPU, melhorando drasticamente a capacidade de lidar com requisições concorrentes.&lt;/p>
&lt;p>O diagrama Mermaid a seguir mostra o pipeline desde o treinamento até a implantação do servidor de inferência.&lt;/p>
&lt;div class="mermaid">graph TD
A["Dados Privados Brutos"] --> B["Pré-processamento e Formatação (JSONL)"]
B --> C["Fine-Tuning QLoRA (SFTTrainer)"]
C --> D["Pesos do Adaptador LoRA (.safetensors)"]
D --> E["Fuselagem com o Base TinyLLaMA 1.1B"]
E --> F["Modelo Fundido"]
F --> G["Implantação via Servidor vLLM"]
G --> H["Endpoint da API / UI (ex: Chatbot)"]&lt;/div>
&lt;p>Iniciar um servidor de API usando o vLLM pode ser concluído com o seguinte comando.&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;/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">python -m vllm.entrypoints.openai.api_server &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --model ./tinyllama-merged &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --host 0.0.0.0 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --port &lt;span class="m">8000&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --max-model-len &lt;span class="m">2048&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --dtype bfloat16
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Com isso, um endpoint compatível com a API da OpenAI será configurado em seu ambiente on-premises, permitindo que você utilize a IA local de forma segura e rápida.&lt;/p>
&lt;hr>
&lt;h2 id="9-conclusão">9. Conclusão
&lt;/h2>&lt;p>Neste artigo, explicamos um método para realizar o fine-tuning do &amp;ldquo;TinyLLaMA&amp;rdquo; — um modelo de alto desempenho, apesar de ser leve com apenas 1.1B parâmetros — em um ambiente on-premises de maneira rápida e com baixo uso de memória.&lt;/p>
&lt;ul>
&lt;li>O &lt;strong>LoRA / QLoRA&lt;/strong> possibilita o fine-tuning completo de LLMs, mesmo em GPUs de nível consumidor.&lt;/li>
&lt;li>O uso intenso de &lt;strong>Flash Attention 2&lt;/strong> e &lt;strong>Gradient Checkpointing&lt;/strong> otimiza o tempo de treinamento e o consumo de VRAM ao máximo.&lt;/li>
&lt;li>O deployment utilizando o &lt;strong>vLLM&lt;/strong> atinge uma alta taxa de transferência, mesmo em ambientes de produção.&lt;/li>
&lt;/ul>
&lt;p>A operação de um LLM local on-premises não apenas protege a confidencialidade dos dados, mas também se torna uma arma poderosa para construir IAs especializadas em domínios específicos (como jurídico, médico, regulamentos internos, etc.) a um baixo custo. Utilize este guia como referência para cultivar o TinyLLaMA exclusivo da sua própria empresa.&lt;/p></description></item><item><title>Guia de Desenvolvimento de Modelos de IA em Pequena Escala (como TinyLLaMA) com C++</title><link>http://kenji.blog/pt/p/cpp-small-ai-model-tinyllama-dev-guide/</link><pubDate>Fri, 11 Sep 2026 14:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/cpp-small-ai-model-tinyllama-dev-guide/</guid><description>&lt;img src="http://kenji.blog/p/cpp-small-ai-model-tinyllama-dev-guide/img/eyecatch.jpg" alt="Featured image of post Guia de Desenvolvimento de Modelos de IA em Pequena Escala (como TinyLLaMA) com C++" />&lt;h1 id="guia-de-desenvolvimento-de-modelos-de-ia-em-pequena-escala-como-tinyllama-com-c">Guia de Desenvolvimento de Modelos de IA em Pequena Escala (como TinyLLaMA) com C++
&lt;/h1>&lt;p>Recentemente, o interesse na execução de Grandes Modelos de Linguagem (LLMs) em ambientes locais aumentou rapidamente. Em particular, modelos de pequena escala como o TinyLLaMA (1.1B parâmetros) são capazes de inferir a uma velocidade prática mesmo em dispositivos de borda com recursos limitados ou notebooks comuns (incluindo ambientes Windows). Enquanto o desenvolvimento usando Python e PyTorch é a tendência principal, a combinação de C++ e &amp;ldquo;ggml&amp;rdquo;, uma biblioteca de tensores baseada em C, tornou-se o padrão de fato quando se busca o máximo de desempenho e eficiência de memória.&lt;/p>
&lt;p>Neste artigo, explicaremos o procedimento de desenvolvimento muito detalhado para construir um motor de inferência do zero (ou compreender profundamente a estrutura interna do &lt;code>llama.cpp&lt;/code> existente) para carregar o TinyLLaMA e gerar texto usando C++.&lt;/p>
&lt;hr>
&lt;h2 id="1-por-que-c-e-ggml">1. Por que C++ e ggml?
&lt;/h2>&lt;p>Na fase de treinamento da IA, o Python, com sua flexibilidade e ecossistema rico, é esmagadoramente vantajoso. No entanto, nas fases de implantação e &amp;ldquo;Inferência&amp;rdquo;, o C++ torna-se uma escolha poderosa pelas seguintes razões:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Redução de Sobrecarga&lt;/strong>: Pode eliminar completamente a sobrecarga do Global Interpreter Lock (GIL) e do tempo de execução do Python.&lt;/li>
&lt;li>&lt;strong>Eficiência de Memória e Alocação de Arena&lt;/strong>: Como a alocação e liberação de memória podem ser controladas manualmente, é possível evitar picos imprevisíveis causados pela coleta de lixo.&lt;/li>
&lt;li>&lt;strong>Acesso Direto ao Hardware&lt;/strong>: É possível chamar diretamente funções intrínsecas (Intrinsics) SIMD, como AVX-512, AVX2 e ARM NEON, para maximizar o poder de computação da CPU.&lt;/li>
&lt;li>&lt;strong>Eliminação de Dependências&lt;/strong>: O ggml é uma biblioteca C/C++ sem dependências (Zero dependencies) que pode ser facilmente compilada em um ambiente MSVC no Windows, desde que haja um compilador.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="2-visão-geral-da-arquitetura">2. Visão Geral da Arquitetura
&lt;/h2>&lt;p>O fluxo completo do pipeline de inferência é mostrado no diagrama Mermaid abaixo. É um processo em série que começa com o texto de entrada do usuário até a geração final do próximo token.&lt;/p>
&lt;div class="mermaid">graph TD
A["Texto de Entrada do Usuário"] --> B["Tokenizador BPE"]
B --> C["Matriz de IDs de Tokens"]
C --> D["Busca na Camada de Embedding"]
D --> E["Blocos Transformer"]
E --> F["RMSNorm"]
F --> G["Camada Head LM"]
G --> H["Matriz de Logits"]
H --> I["Módulo Amostrador"]
I --> J["Próximo ID de Token"]
J --> K["Detokenizador"]
K --> L["Pedaço de Texto de Saída"]
J -.-> |"Adicionar ao Contexto"| C&lt;/div>
&lt;p>Por ser um modelo autorregressivo, o token de saída é adicionado novamente ao contexto e circula como entrada para a previsão do próximo token (parte tracejada do diagrama).&lt;/p>
&lt;hr>
&lt;h2 id="3-formato-do-modelo-e-mapeamento-de-memória-mmap">3. Formato do Modelo e Mapeamento de Memória (mmap)
&lt;/h2>&lt;p>O maior obstáculo ao lidar com os pesos de uma rede neural gigantesca é a E/S de disco e o consumo de memória. Na implementação em C++, isso é resolvido com o &lt;strong>mapeamento de memória (mmap)&lt;/strong>.&lt;/p>
&lt;h3 id="31-mecanismo-de-mapeamento-de-memória-e-implementação-no-windows">3.1 Mecanismo de Mapeamento de Memória e Implementação no Windows
&lt;/h3>&lt;p>O mmap permite mapear o conteúdo de um arquivo diretamente para o espaço de memória virtual do processo.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Zero-copy&lt;/strong>: Os dados são lidos diretamente do disco para o cache de página do kernel, sem causar cópias extras para o espaço do usuário.&lt;/li>
&lt;li>&lt;strong>Carregamento sob Demanda (Page Fault)&lt;/strong>: No exato momento em que a CPU acessa aquele endereço de memória, ocorre uma falha de página, e apenas o pedaço necessário (geralmente 4KB) é carregado na memória física.&lt;/li>
&lt;/ul>
&lt;p>No ambiente Windows, usa-se as APIs Win32 &lt;code>CreateFileMapping&lt;/code> e &lt;code>MapViewOfFile&lt;/code> em vez do &lt;code>mmap&lt;/code> POSIX.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant OS["Sistema Operacional Windows"]
participant RAM["Memória Física"]
participant App["Aplicativo C++"]
App->>OS: "CreateFileMapping / MapViewOfFile"
OS-->>App: "Ponteiro de Endereço de Memória Virtual"
App->>App: "Ler Dados do Tensor no Ponteiro"
OS->>RAM: "Page Fault / Carregar página do Disco"
RAM-->>App: "Dados prontos para Computação SIMD"&lt;/div>
&lt;h3 id="32-estrutura-binária-do-formato-gguf">3.2 Estrutura Binária do Formato GGUF
&lt;/h3>&lt;p>O &lt;strong>GGUF (GPT-Generated Unified Format)&lt;/strong>, convertido a partir de formatos como &lt;code>.safetensors&lt;/code> do Hugging Face, é o formato definitivo para inferência. Ele possui o seguinte layout binário estrito:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Magic Bytes&lt;/strong>: &lt;code>0x46554747&lt;/code> (GGUF).&lt;/li>
&lt;li>&lt;strong>Version&lt;/strong>: Número da versão do formato.&lt;/li>
&lt;li>&lt;strong>Tensor Count &amp;amp; Metadata Count&lt;/strong>: Número de tensores e número de pares chave-valor de metadados.&lt;/li>
&lt;li>&lt;strong>Metadata (Key-Value Pairs)&lt;/strong>: Chaves com prefixo de comprimento de string e valores tipados.&lt;/li>
&lt;li>&lt;strong>Tensor Info&lt;/strong>: Nome de cada tensor, número de dimensões, tipo de dados (FP16, Q4_K, etc.) e a posição de deslocamento no arquivo.&lt;/li>
&lt;li>&lt;strong>Padding&lt;/strong>: Preenchimento inserido para garantir que os dados do tensor sejam alinhados a um limite específico (geralmente 32 bytes ou 64 bytes). Isso é essencial para acessos rápidos à memória em instruções SIMD (especialmente AVX).&lt;/li>
&lt;li>&lt;strong>Tensor Data&lt;/strong>: A matriz real de dados de peso alinhados.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="4-base-matemática-do-tinyllama-e-algoritmo-c">4. Base Matemática do TinyLLaMA e Algoritmo C++
&lt;/h2>&lt;p>O TinyLLaMA incorpora várias inovações arquitetônicas avançadas para maior eficiência. Explicaremos as representações matemáticas para implementá-las corretamente em C++.&lt;/p>
&lt;h3 id="41-rmsnorm-root-mean-square-normalization">4.1 RMSNorm (Root Mean Square Normalization)
&lt;/h3>&lt;p>Reduz o custo de cálculo ao omitir a centralização da média do LayerNorm e realizar apenas o dimensionamento da variância.&lt;/p>
$$ \text{RMSNorm}(x) = \frac{x}{\sqrt{\frac{1}{d}\sum_{i=1}^{d} x_i^2 + \epsilon}} \odot \gamma $$
&lt;p>$d$ é o número de dimensões, e $\gamma$ é o tensor de escalonamento aprendido.
Ao implementar em C++, ele é otimizado primeiramente calculando rapidamente a soma dos quadrados da matriz com &lt;code>_mm256_fmadd_ps&lt;/code> do AVX2, e multiplicando pela raiz quadrada inversa (como a instrução &lt;code>_mm256_rsqrt_ps&lt;/code>).&lt;/p>
&lt;h3 id="42-rope-rotary-position-embedding">4.2 RoPE (Rotary Position Embedding)
&lt;/h3>&lt;p>Esta é uma técnica para aplicar informações de posição de tokens como uma rotação no espaço tensorial. Pode ser vista como uma rotação no plano complexo, e aplica a seguinte rotação a pares de dimensões adjacentes $(x_1, x_2)$ do vetor $x$:&lt;/p>
$$ \text{RoPE}(x, m) = \begin{pmatrix} x_{1} \cos(m\theta) - x_{2} \sin(m\theta) \\ x_{1} \sin(m\theta) + x_{2} \cos(m\theta) \end{pmatrix} $$
&lt;p>Aqui, $m$ é o índice absoluto de posição do token e $\theta$ é a frequência fundamental pré-calculada. No ggml, a execução paralela é feita simplesmente adicionando o operador &lt;code>ggml_rope&lt;/code> durante a construção do grafo de inferência.&lt;/p>
&lt;h3 id="43-grouped-query-attention-gqa">4.3 Grouped-Query Attention (GQA)
&lt;/h3>&lt;p>Na Multi-Head Attention (MHA) comum, há o mesmo número de cabeças para Query, Key e Value. No entanto, o TinyLLaMA adota o &lt;strong>Grouped-Query Attention (GQA)&lt;/strong> para reduzir drasticamente o consumo de largura de banda de memória e cache KV.&lt;/p>
$$ \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{Q K^T}{\sqrt{d_k}}\right) V $$
&lt;p>No GQA, várias cabeças de Query compartilham uma única cabeça de Key/Value. Na implementação C++, antes de executar o produto de matrizes &lt;code>ggml_mul_mat&lt;/code>, é necessária uma operação para transmitir (broadcast) os tensores KV para corresponder ao número de Queries.&lt;/p>
&lt;h3 id="44-função-de-ativação-swiglu">4.4 Função de Ativação SwiGLU
&lt;/h3>&lt;p>Na camada Feed-Forward Network (FFN), SwiGLU é usado em vez de GELU.&lt;/p>
$$ \text{SwiGLU}(x) = \text{Swish}(x W_{\text{gate}}) \otimes (x W_{\text{up}}) $$
$$ \text{Swish}(z) = z \cdot \sigma(z) = z \cdot \frac{1}{1 + e^{-z}} $$
&lt;p>No grafo computacional, isso é expresso pela combinação do operador &lt;code>ggml_silu&lt;/code> com &lt;code>ggml_mul&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="5-construção-de-grafo-computacional-e-gerenciamento-de-memória-com-ggml">5. Construção de Grafo Computacional e Gerenciamento de Memória com ggml
&lt;/h2>&lt;p>O ggml adota uma abordagem &amp;ldquo;Define-and-Run&amp;rdquo;, onde um grafo computacional estático para inferência é construído e então avaliado posteriormente.&lt;/p>
&lt;h3 id="51-ggml_context-e-alocador-de-arena">5.1 ggml_context e Alocador de Arena
&lt;/h3>&lt;p>A característica mais singular do ggml é a &amp;ldquo;alocação de arena&amp;rdquo;, que evita qualquer alocação dinâmica de memória (&lt;code>malloc&lt;/code> ou &lt;code>new&lt;/code>) dentro do loop de inferência.
Uma região contígua e gigante de memória (arena) é alocada no momento da inicialização, e toda vez que &lt;code>ggml_new_tensor&lt;/code> é chamado, o ponteiro dessa região é incrementado. Quando uma etapa de inferência é concluída, simplesmente redefinir o ponteiro de alocação para a posição inicial conclui instantaneamente a alocação de memória para a próxima etapa de inferência.&lt;/p>
&lt;h3 id="52-exemplo-concreto-de-construção-de-grafo">5.2 Exemplo Concreto de Construção de Grafo
&lt;/h3>&lt;p>Para cada etapa de inferência, o seguinte grafo computacional é montado na memória.&lt;/p>
&lt;div class="mermaid">graph TD
A["ID de Entrada de Tokens"] --> B["Busca de Embedding"]
B --> C["ggml_rms_norm"]
C --> D["Projeções Q / K / V"]
D --> E["Posicional ggml_rope"]
E --> F["Armazenar em Cache KV"]
E --> G["Carregar Cache KV"]
G --> H["Self Attention"]
H --> I["Escalar &amp; Softmax"]
I --> J["Saída da Atenção"]
J --> K["Projeção de Saída"]
K --> L["Adicionar Residual"]&lt;/div>
&lt;hr>
&lt;h2 id="6-quantização-quantization-e-otimização-para-windows--simd">6. Quantização (Quantization) e Otimização para Windows / SIMD
&lt;/h2>&lt;p>Lidar com o TinyLLaMA (1.1B) em FP16 requer cerca de 2.2GB de memória, mas por meio da quantização de 4 bits (como Q4_K), pode ser comprimido drasticamente para cerca de 600MB.&lt;/p>
&lt;h3 id="61-arquitetura-de-quantização-em-bloco">6.1 Arquitetura de Quantização em Bloco
&lt;/h3>&lt;p>O ggml não quantiza o tensor inteiro de maneira uniforme, mas o faz em unidades de &amp;ldquo;blocos&amp;rdquo;.
No formato &lt;code>Q4_0&lt;/code>, 32 valores FP16 são agrupados em um bloco.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Fator de escala&lt;/strong>: 1 valor FP16 (2 bytes)&lt;/li>
&lt;li>&lt;strong>Dados quantizados&lt;/strong>: 32 valores de 4 bits (16 bytes)
Isso minimiza a influência de outliers locais.&lt;/li>
&lt;/ul>
&lt;h3 id="62-aceleração-de-produto-escalar-com-avx2">6.2 Aceleração de Produto Escalar com AVX2
&lt;/h3>&lt;p>Ao compilar para a CPU x86 mais recente no ambiente Windows, sinalizadores de compilador como &lt;code>/arch:AVX2&lt;/code> são utilizados, e o processamento SIMD é realizado no fluxo abaixo.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Carregar&lt;/strong>: Dados quantizados de 4 bits são carregados da memória em registradores AVX de 256 bits.&lt;/li>
&lt;li>&lt;strong>Expansão e Desempacotamento&lt;/strong>: Os valores de 4 bits são expandidos para Int8 ou Int16 com máscaras de bits e operações de deslocamento.&lt;/li>
&lt;li>&lt;strong>Desquantização&lt;/strong>: O fator de escala é multiplicado para converter em ponto flutuante.&lt;/li>
&lt;li>&lt;strong>Operação FMA&lt;/strong>: Executa o cálculo paralelo de multiplicar e somar usando o valor de ativação e &lt;code>_mm256_fmadd_ps&lt;/code> (Fused Multiply-Add).&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="7-detalhes-de-implementação-do-cache-kv">7. Detalhes de Implementação do Cache KV
&lt;/h2>&lt;p>Na geração autorregressiva, o &amp;ldquo;cache KV&amp;rdquo; é um recurso indispensável para pular o cálculo de Key e Value dos tokens anteriores.&lt;/p>
&lt;p>Os pontos da implementação em C++ são os seguintes:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Alocação Prévia do Tensor&lt;/strong>: Um tensor gigante para o tamanho máximo do contexto (ex: 2048 tokens) é inicializado para o cache KV (recomenda-se FP16).&lt;/li>
&lt;li>&lt;strong>Cópia com Deslocamento&lt;/strong>: Quando o cálculo para a posição $N$ do token for realizado, os vetores K e V obtidos nessa etapa são armazenados na $N$-ésima linha do tensor de cache KV usando &lt;code>ggml_cpy&lt;/code> ou similares.&lt;/li>
&lt;li>&lt;strong>Criação de Visualização na Atenção&lt;/strong>: Ao calcular a atenção, uma &amp;ldquo;visualização&amp;rdquo; apontando apenas para a parte dos tokens de 0 a $N$ é criada e passada para a multiplicação de matrizes.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-tokenizador-bpe-e-decodificação">8. Tokenizador BPE e Decodificação
&lt;/h2>&lt;p>Trata as strings de entrada como sequências de bytes UTF-8 e as combina com um vocabulário pré-definido. Em C++, algoritmos utilizando &lt;strong>Árvore Trie (árvore de prefixo)&lt;/strong> ou filas de prioridade são implementados para acelerar a busca no vocabulário.&lt;/p>
&lt;p>A partir dos logits emitidos pelo LM Head, as probabilidades são escalonadas usando o parâmetro Temperature, os candidatos são reduzidos por meio da extração Top-K ou Top-P (Nucleus Sampling), e o próximo token final é determinado por meio de números aleatórios.&lt;/p>
&lt;hr>
&lt;h2 id="9-configuração-do-projeto-c-ambiente-windows--powershell">9. Configuração do Projeto C++ (Ambiente Windows / PowerShell)
&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;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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cmake_minimum_required&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">VERSION&lt;/span> &lt;span class="s">3.14&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">project&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">TinyLLaMACpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_STANDARD&lt;/span> &lt;span class="s">17&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Otimização e definição do sinalizador AVX2 para Windows (MSVC)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MSVC&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">add_compile_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">/O2&lt;/span> &lt;span class="s">/arch:AVX2&lt;/span> &lt;span class="s">/fp:fast&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">add_link_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">/STACK:8388608&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">else&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">add_compile_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">-O3&lt;/span> &lt;span class="s">-march=native&lt;/span> &lt;span class="s">-ffast-math&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">endif&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_library&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ggml&lt;/span> &lt;span class="s">OBJECT&lt;/span> &lt;span class="s">ggml/ggml.c&lt;/span> &lt;span class="s">ggml/ggml-alloc.c&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">target_compile_definitions&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ggml&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s">GGML_USE_AVX2&lt;/span> &lt;span class="s">GGML_USE_F16C&lt;/span> &lt;span class="s">GGML_USE_FMA&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_executable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">main&lt;/span> &lt;span class="s">main.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">main&lt;/span> &lt;span class="s">ggml&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Exemplo de comando de build no PowerShell:&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">mkdir&lt;/span> &lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd &lt;/span>&lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmake&lt;/span> &lt;span class="p">..&lt;/span> &lt;span class="n">-G&lt;/span> &lt;span class="s2">&amp;#34;Visual Studio 17 2022&amp;#34;&lt;/span> &lt;span class="n">-A&lt;/span> &lt;span class="n">x64&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmake&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-build&lt;/span> &lt;span class="p">.&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-config&lt;/span> &lt;span class="n">Release&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="10-resumo">10. Resumo
&lt;/h2>&lt;p>Implementar o motor de inferência de um modelo de IA em pequena escala como o TinyLLaMA do zero usando C++ e ggml é uma excelente oportunidade para descobrir a caixa preta do deep learning e aprender a beleza do controle de hardware de baixo nível. Vamos abrir o futuro da IA de borda (Edge AI) aproveitando a essência da programação de sistemas, como o carregamento de zero cópia usando mapeamento de memória, otimização SIMD e construção de cache KV.&lt;/p></description></item><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><item><title>【Atualizado em 2026】Guia Completo para Executar LLM Local em Ambiente Windows</title><link>http://kenji.blog/pt/p/local-llm-windows-2026/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/local-llm-windows-2026/</guid><description>&lt;img src="http://kenji.blog/p/local-llm-windows-2026/img/eyecatch.jpg" alt="Featured image of post 【Atualizado em 2026】Guia Completo para Executar LLM Local em Ambiente Windows" />&lt;h1 id="1-introdução-por-que-llm-local-no-windows-agora">1. Introdução: Por que LLM Local no Windows agora?
&lt;/h1>&lt;p>Em 2026, a evolução da IA generativa e dos Grandes Modelos de Linguagem (LLM) está mostrando uma grande mudança de paradigma de serviços gigantescos de API na nuvem para &amp;ldquo;LLMs Locais&amp;rdquo; rodando em PCs pessoais ou ambientes locais (on-premises). IAs na nuvem como o GPT-5 da OpenAI e o Claude 3.5 da Anthropic são extremamente poderosas, mas nem todas as empresas ou indivíduos podem enviar todos os seus dados para a nuvem. Do ponto de vista de privacidade, segurança, latência e custos sustentáveis a longo prazo, a demanda por LLMs locais explodiu como nunca antes.&lt;/p>
&lt;p>Particularmente no ambiente Windows, a evolução do ecossistema de LLM local tem sido notável. Até poucos anos atrás, &amp;ldquo;Desenvolvimento e execução de IA significa Linux&amp;rdquo; era o senso comum, mas em 2026, o Windows se transformou em uma plataforma de IA extremamente poderosa e acessível.&lt;/p>
&lt;p>Neste artigo, com base nas últimas tendências tecnológicas de 2026, forneceremos um guia completo para construir, operar e otimizar LLMs locais em ambientes Windows. Explicaremos detalhadamente, com um volume esmagador, desde configurações simples com o Ollama para iniciantes, passando por otimizações extremas usando o llama.cpp para usuários avançados, até abordagens matemáticas para cálculo de VRAM, compreensão profunda da arquitetura e fine-tuning local.&lt;/p>
&lt;h2 id="11-tendências-tecnológicas-de-llm-local-em-2026">1.1 Tendências Tecnológicas de LLM Local em 2026
&lt;/h2>&lt;p>As principais tendências que moldam o atual ecossistema de LLM local são as seguintes:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Adoção total do formato GGUF&lt;/strong>: O GGUF (GPT-Generated Unified Format), que integra metadados e tensores em um único arquivo, tornou-se completamente o padrão de fato. Isso permite a execução em qualquer ambiente apenas baixando um único arquivo do Hugging Face.&lt;/li>
&lt;li>&lt;strong>Democratização da arquitetura MoE (Mixture of Experts)&lt;/strong>: Vários modelos MoE pequenos, porém de alto desempenho, foram lançados. Ao ativar apenas alguns especialistas durante a inferência, eles alcançam um desempenho comparável ao de modelos gigantes, mantendo a carga computacional baixa em PCs de consumo.&lt;/li>
&lt;li>&lt;strong>Abstração avançada e otimização de motores de inferência&lt;/strong>: Ferramentas como Ollama, LM Studio e AnythingLLM foram refinadas, eliminando a necessidade de os usuários se preocuparem com dependências complexas, como a instalação de drivers CUDA. Além disso, o suporte nativo do FlashAttention 3 para Windows melhorou drasticamente a velocidade de inferência.&lt;/li>
&lt;li>&lt;strong>Utilização da NPU e a ascensão dos PCs Windows Copilot+&lt;/strong>: Mesmo em laptops sem GPU, a tecnologia para executar pequenos LLMs (SLMs: Small Language Models) com baixo consumo de energia usando a NPU (Neural Processing Unit) integrada entrou em fase prática.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="2-requisitos-de-hardware-e-preparação-do-so">2. Requisitos de Hardware e Preparação do SO
&lt;/h1>&lt;p>Para que um LLM local opere em uma velocidade prática (15 a 30+ tokens por segundo), a escolha do hardware é o fator mais importante.&lt;/p>
&lt;h2 id="21-configuração-de-hardware-recomendada">2.1 Configuração de Hardware Recomendada
&lt;/h2>&lt;p>Com a evolução dos AI PCs, as especificações exigidas também estão mudando.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>SO&lt;/strong>: Windows 11 Pro (24H2 ou posterior). Essencial para utilizar as funções completas do WSL2, gerenciamento avançado de memória e as APIs mais recentes do DirectML.&lt;/li>
&lt;li>&lt;strong>CPU&lt;/strong>: Série Intel Core Ultra 200 ou superior, ou série AMD Ryzen 9000 ou superior. Quando usado em conjunto com inferência de CPU, a comunicação de memória de alta largura de banda é indispensável.&lt;/li>
&lt;li>&lt;strong>RAM&lt;/strong>: Mínimo de 32GB, recomendado 64GB ou mais. A largura de banda da memória principal (MB/s) torna-se o gargalo decisivo durante a inferência na CPU ou offloading. Memória de alta velocidade, como DDR5-6000 ou superior, é o ideal.&lt;/li>
&lt;li>&lt;strong>GPU&lt;/strong>: Séries NVIDIA RTX 4000/5000. O que mais importa para LLMs locais não é o desempenho de processamento, mas sim a &amp;ldquo;Capacidade de VRAM&amp;rdquo;.
&lt;ul>
&lt;li>&lt;strong>Entrada&lt;/strong>: RTX 4060 Ti (versão de 16GB) - Melhor custo-benefício. Ideal para modelos na classe de 8B a 14B.&lt;/li>
&lt;li>&lt;strong>Intermediário&lt;/strong>: RTX 4070 Ti SUPER (16GB) / RTX 4080 SUPER (16GB)&lt;/li>
&lt;li>&lt;strong>High-end&lt;/strong>: RTX 4090 (24GB) / RTX 5090 (32GB) - Necessário para rodar modelos quantizados na classe de 30B a 70B.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Armazenamento&lt;/strong>: NVMe SSD PCIe Gen4 ou Gen5. Reduz drasticamente o tempo de carregamento de dezenas de GB de modelos.&lt;/li>
&lt;/ul>
&lt;h2 id="22-configuração-do-wsl2-windows-subsystem-for-linux-2">2.2 Configuração do WSL2 (Windows Subsystem for Linux 2)
&lt;/h2>&lt;p>Embora muitas ferramentas GUI funcionem nativamente no Windows, o WSL2 é extremamente útil para desenvolvimento com Python, compilação de ferramentas mais recentes e para o fine-tuning LoRA mencionado posteriormente. Nos ambientes Windows 11 mais recentes, você pode usar GPUs (CUDA) de forma transparente no WSL2 apenas instalando o driver da NVIDIA no host.&lt;/p>
&lt;p>Abra o PowerShell com privilégios de administrador e execute o seguinte:&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Instalação do WSL2 e do Ubuntu mais recente&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-install&lt;/span> &lt;span class="n">-d&lt;/span> &lt;span class="n">Ubuntu&lt;/span>&lt;span class="p">-&lt;/span>&lt;span class="mf">24.04&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="c"># Atualização do kernel&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-update&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Após a instalação, execute &lt;code>nvidia-smi&lt;/code> no terminal do WSL2; se a GPU for reconhecida corretamente, a configuração foi bem-sucedida.&lt;/p>
&lt;hr>
&lt;h1 id="3-arquitetura-de-llm-local-e-mecanismo-de-inferência">3. Arquitetura de LLM Local e Mecanismo de Inferência
&lt;/h1>&lt;p>Compreender a estrutura interna de como o modelo gera texto em um ambiente local é extremamente útil para solução de problemas e otimização.&lt;/p>
&lt;p>O diagrama Mermaid abaixo mostra um pipeline típico de inferência de LLM local.&lt;/p>
&lt;div class="mermaid">graph TD
User["Entrada do usuário (Prompt)"] --> Tokenizer["Tokenizador (Tokenizer)"]
Tokenizer --> Embedding["Camada de Embedding (Embedding)"]
subgraph "Transformer Block (x Layers)"
Embedding --> Attn["Autoatenção (Self-Attention)"]
Attn --> KVCache["Cache KV (Retenção Key/Value)"]
Attn --> FFN["Rede Feed-Forward (FFN)"]
end
FFN --> Logits["Cálculo de Logits (Logits)"]
Logits --> Sampler["Amostrador (Temperature, Top-K, Top-P)"]
Sampler --> OutputToken["Token de saída"]
OutputToken --> |"Geração autorregressiva"| Tokenizer
OutputToken --> Decoder["Detokenizador (Detokenizer)"]
Decoder --> FinalOutput["Texto de saída final"]&lt;/div>
&lt;h2 id="31-duas-fases-prefill-e-decode">3.1 Duas Fases: Prefill e Decode
&lt;/h2>&lt;p>A geração de texto do LLM é dividida em duas fases com características computacionais diferentes.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Fase Prefill (Processamento de Prompt)&lt;/strong>: A fase onde todo o prompt inserido é processado e compreendido de uma só vez. Devido à possibilidade de cálculo paralelo, a capacidade de cálculo da GPU (FLOPS) está diretamente ligada à velocidade. Se o prompt for longo, esta fase pode levar alguns segundos.&lt;/li>
&lt;li>&lt;strong>Fase Decode (Geração de Tokens)&lt;/strong>: A fase onde se prevê um token de cada vez, que é repassado como próxima entrada (autorregressivo). Nesta fase, o cálculo paralelo é limitado, portanto a largura de banda de memória VRAM da GPU (Memory Bandwidth) se torna um gargalo decisivo.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="4-cálculo-do-consumo-de-vram-e-compreensão-matemática-do-tamanho-do-modelo">4. Cálculo do Consumo de VRAM e Compreensão Matemática do Tamanho do Modelo
&lt;/h1>&lt;p>Para julgar corretamente &amp;ldquo;quais modelos rodam no meu PC?&amp;rdquo;, é necessário entender a fórmula de cálculo da VRAM. Se a falta de VRAM causar fallback para a memória do sistema (RAM), a velocidade de inferência cairá de 10x a 100x.&lt;/p>
&lt;h2 id="41-vram-base-com-base-no-tamanho-dos-parâmetros">4.1 VRAM Base com Base no Tamanho dos Parâmetros
&lt;/h2>&lt;p>Esta é a quantidade de memória necessária para carregar os pesos (weights) do modelo para a VRAM.
É calculada usando o tamanho do modelo $P$ (número de parâmetros, unidade: 1 bilhão = 1B) e os bytes por parâmetro $B$.&lt;/p>
$$
V_{base} = P \times B \quad \text{(GB)}
$$
&lt;p>Por exemplo, ao carregar um modelo de 8B (8 bilhões) de parâmetros em FP16 (ponto flutuante de meia precisão, 16 bits = 2 bytes):&lt;/p>
$$
V_{base} = 8 \times 2 = 16 \text{ GB}
$$
&lt;p>Em outras palavras, mesmo uma GPU com 16GB de VRAM estará no seu limite apenas carregando o modelo.&lt;/p>
&lt;h2 id="42-a-magia-da-quantização-quantization">4.2 A Magia da Quantização (Quantization)
&lt;/h2>&lt;p>Aí entra a &amp;ldquo;quantização&amp;rdquo;. Ao reduzir a precisão dos parâmetros, o tamanho do modelo é reduzido drasticamente. Na quantização de 4 bits mais comum (ex: Q4_K_M), a média é cerca de 0,55 bytes por parâmetro.&lt;/p>
$$
V_{base\_4bit} = 8 \times 0.55 = 4.4 \text{ GB}
$$
&lt;p>Com isso, se você tiver 16GB de VRAM, terá bastante margem para rodar um modelo 8B de forma muito tranquila.&lt;/p>
&lt;h2 id="43-cálculo-do-cache-kv-versão-compatível-com-gqa">4.3 Cálculo do Cache KV (Versão Compatível com GQA)
&lt;/h2>&lt;p>Durante a inferência, o &amp;ldquo;Cache KV&amp;rdquo;, usado para manter o contexto passado, consome VRAM. Nos modelos mais recentes, como o Llama 3, o GQA (Grouped Query Attention) é adotado para economizar memória.&lt;/p>
&lt;p>O consumo do Cache KV $V_{kv}$ (em gigabytes) é expresso pela seguinte fórmula:&lt;/p>
$$
V_{kv} = 2 \times b \times s \times l \times \left( \frac{h_{kv}}{h_q} \right) \times h_q \times d \times B_{kv} \div 10^9
$$
&lt;p>Simplificando, podemos calcular usando o número de cabeças de chave/valor (key/value heads) $h_{kv}$:&lt;/p>
$$
V_{kv} = 2 \times b \times s \times l \times h_{kv} \times d \times B_{kv} \div 10^9
$$
&lt;p>Onde:&lt;/p>
&lt;ul>
&lt;li>$b$: Tamanho do batch (geralmente 1 para uso local pessoal)&lt;/li>
&lt;li>$s$: Comprimento da sequência (comprimento do contexto, ex: 8192)&lt;/li>
&lt;li>$l$: Número de camadas (ex: 32)&lt;/li>
&lt;li>$h_{kv}$: Número de cabeças KV (ex: 8)&lt;/li>
&lt;li>$d$: Dimensões por cabeça (ex: 128)&lt;/li>
&lt;li>$B_{kv}$: Bytes do Cache KV (2 para FP16)&lt;/li>
&lt;/ul>
&lt;p>Exemplo de cálculo (Llama 3 8B, Contexto 8192, Cache FP16):
$V_{kv} = 2 \times 1 \times 8192 \times 32 \times 8 \times 128 \times 2 \div 10^9 \approx 1.07 \text{ GB}$&lt;/p>
&lt;p>Note que quanto mais longo for o comprimento do contexto $s$, mais a VRAM necessária aumentará linearmente.&lt;/p>
&lt;hr>
&lt;h1 id="5-prática-1-configuração-rápida-e-curta-com-ollama">5. Prática 1: Configuração Rápida e Curta com Ollama
&lt;/h1>&lt;p>Agora que entendemos a teoria, vamos rodar um LLM num ambiente Windows na prática.
A partir de 2026, a ferramenta mais amigável ao usuário é o &amp;ldquo;Ollama&amp;rdquo;. Ele fornece uma CLI intuitiva semelhante à do Docker.&lt;/p>
&lt;h2 id="51-instalação-e-execução">5.1 Instalação e Execução
&lt;/h2>&lt;ol>
&lt;li>Baixe e execute o instalador para Windows no &lt;a class="link" href="https://ollama.com/" target="_blank" rel="noopener"
>Site Oficial do Ollama&lt;/a>.&lt;/li>
&lt;li>Abra o PowerShell e insira o seguinte comando. Aqui usaremos o &lt;code>llama3:8b&lt;/code>, que possui suporte para japonês.&lt;/li>
&lt;/ol>
&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">ollama&lt;/span> &lt;span class="n">run&lt;/span> &lt;span class="n">llama3&lt;/span>&lt;span class="err">:&lt;/span>&lt;span class="n">8b&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Na primeira execução, o modelo será baixado. Ao concluir, você poderá conversar diretamente no terminal.&lt;/p>
&lt;h2 id="52-criação-de-uma-ia-customizada-via-modelfile">5.2 Criação de uma IA Customizada via Modelfile
&lt;/h2>&lt;p>Você pode criar facilmente uma IA com uma persona específica. Crie um &lt;code>Modelfile&lt;/code> em qualquer 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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">FROM llama3:8b
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">SYSTEM &amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Você é um excelente engenheiro de software sênior.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Sempre responda às perguntas dos usuários com exemplos de código, de forma lógica e concisa.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">PARAMETER temperature 0.3
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">PARAMETER num_ctx 8192
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Execute os comandos a seguir para compilar e executar o seu próprio modelo customizado.&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">ollama&lt;/span> &lt;span class="n">create&lt;/span> &lt;span class="n">SeniorDev&lt;/span> &lt;span class="o">-f&lt;/span> &lt;span class="p">./&lt;/span>&lt;span class="n">Modelfile&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ollama&lt;/span> &lt;span class="n">run&lt;/span> &lt;span class="n">SeniorDev&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="53-utilização-de-aplicações-externas-editores-de-ia">5.3 Utilização de Aplicações Externas (Editores de IA)
&lt;/h2>&lt;p>O Ollama expõe um endpoint de API compatível com OpenAI em &lt;code>http://localhost:11434&lt;/code>.
Ao especificar esta URL nas configurações de backend de extensões do VS Code, como Cursor ou Continue.dev, e designar o nome do modelo como &lt;code>SeniorDev&lt;/code>, você tem um assistente de codificação local poderoso e gratuito.&lt;/p>
&lt;hr>
&lt;h1 id="6-prática-2-afinação-extrema-de-desempenho-com-llamacpp">6. Prática 2: Afinação Extrema de Desempenho com llama.cpp
&lt;/h1>&lt;p>Se você quiser ter uma gestão fina de memória ou testar antecipadamente novos formatos (como EXL2, quantização IQ), interaja diretamente com o mecanismo central &lt;code>llama.cpp&lt;/code>.&lt;/p>
&lt;h2 id="61-procedimento-de-compilação-do-llamacpp">6.1 Procedimento de Compilação do llama.cpp
&lt;/h2>&lt;p>No ambiente Windows, a melhor forma é compilá-lo a partir do código-fonte usando CUDA Toolkit e CMake.&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">git&lt;/span> &lt;span class="n">clone&lt;/span> &lt;span class="n">https&lt;/span>&lt;span class="err">:&lt;/span>&lt;span class="p">//&lt;/span>&lt;span class="n">github&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">ggerganov&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">llama&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">cpp
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd &lt;/span>&lt;span class="n">llama&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">cpp
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">&lt;/span>&lt;span class="n">mkdir&lt;/span> &lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd &lt;/span>&lt;span class="n">build&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="c"># Configurar e compilar com suporte a CUDA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmake&lt;/span> &lt;span class="p">..&lt;/span> &lt;span class="n">-DLLAMA_CUBLAS&lt;/span>&lt;span class="p">=&lt;/span>&lt;span class="n">ON&lt;/span> &lt;span class="n">-DBUILD_SHARED_LIBS&lt;/span>&lt;span class="p">=&lt;/span>&lt;span class="n">OFF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmake&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-build&lt;/span> &lt;span class="p">.&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-config&lt;/span> &lt;span class="n">Release&lt;/span> &lt;span class="n">-j&lt;/span> &lt;span class="mf">16&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="62-execução-avançada-no-modo-servidor">6.2 Execução Avançada no Modo Servidor
&lt;/h2>&lt;p>Use o &lt;code>llama-server.exe&lt;/code> compilado para hospedar o modelo.&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="p">.\&lt;/span>&lt;span class="n">bin&lt;/span>&lt;span class="p">\&lt;/span>&lt;span class="n">Release&lt;/span>&lt;span class="p">\&lt;/span>&lt;span class="nb">llama-server&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">exe&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 class="n">-model&lt;/span> &lt;span class="s2">&amp;#34;C:\models\Llama-3-8B-Instruct.Q4_K_M.gguf&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 class="n">-ctx-size&lt;/span> &lt;span class="mf">8192&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 class="n">-n-gpu-layers&lt;/span> &lt;span class="mf">99&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 class="n">-threads&lt;/span> &lt;span class="mf">8&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 class="n">-flash-attn&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 class="n">-port&lt;/span> &lt;span class="mf">8080&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ul>
&lt;li>&lt;code>--n-gpu-layers 99&lt;/code>: Descarrega (offload) todas as camadas possíveis para a VRAM da GPU.&lt;/li>
&lt;li>&lt;code>--flash-attn&lt;/code>: Habilita o FlashAttention 3, alcançando uma melhoria de velocidade de inferência e redução de consumo de VRAM para o Cache KV.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="7-front-end-gui-lm-studio-e-construção-de-rag-local">7. Front-end GUI: LM Studio e Construção de RAG Local
&lt;/h1>&lt;p>Se você não gosta de linhas de comando ou quer usar a RAG (Geração Aumentada por Recuperação) intuitivamente, utilize uma GUI.&lt;/p>
&lt;h2 id="71-lm-studio">7.1 LM Studio
&lt;/h2>&lt;p>O LM Studio é um aplicativo maravilhoso que centraliza a busca de modelos, o download, as verificações de pré-requisitos do sistema e a interface de chat. Ao simplesmente apertar o botão &amp;ldquo;Local Server&amp;rdquo; no app, uma API compatível com OpenAI é iniciada.&lt;/p>
&lt;h2 id="72-arquitetura-de-rag-usando-o-anythingllm">7.2 Arquitetura de RAG usando o AnythingLLM
&lt;/h2>&lt;p>Este é o diagrama de arquitetura do ambiente RAG para carregar documentos internos e notas pessoais.&lt;/p>
&lt;div class="mermaid">graph LR
Document["Documentos (PDF, MD)"] --> Chunking["Divisão em Chunks"]
Chunking --> EmbedModel["Modelo de Embedding"]
EmbedModel --> VectorDB["Banco de Dados Vetorial"]
UserQuery["Pergunta do usuário"] --> EmbedQuery["Embedding da Pergunta"]
EmbedQuery --> VectorDB
VectorDB --> |"Busca de similaridade"| RetrievedDocs["Extração de Documentos Relevantes"]
UserQuery --> PromptBuilder["Geração do Prompt"]
RetrievedDocs --> PromptBuilder
PromptBuilder --> LocalLLM["LLM Local"]
LocalLLM --> Answer["Resposta Final"]&lt;/div>
&lt;p>Com a versão desktop do AnythingLLM (Windows), você só precisa designar o Ollama (para LLM e Embedding) e configurar o VectorDB local (LanceDB) nas opções, e essa arquitetura estará concluída em minutos. É o nascimento de uma IA Privada que nunca envia os dados a terceiros.&lt;/p>
&lt;hr>
&lt;h1 id="8-fine-tuning-no-wsl2-do-windows-lora">8. Fine-tuning no WSL2 do Windows (LoRA)
&lt;/h1>&lt;p>Além de rodar os modelos localmente, se você deseja que eles fiquem mais inteligentes com seus próprios dados, o fine-tuning através do LoRA (Low-Rank Adaptation) é possível. Em 2026, com uma biblioteca chamada &amp;ldquo;Unsloth&amp;rdquo;, o treinamento de um modelo 8B é finalizado em algumas horas, mesmo com 16GB de VRAM, no ambiente Windows WSL2.&lt;/p>
&lt;p>Crie o ambiente executando o seguinte dentro do Ubuntu do WSL2:&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;/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">conda create --name unsloth_env &lt;span class="nv">python&lt;/span>&lt;span class="o">=&lt;/span>3.11
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">conda activate unsloth_env
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install &lt;span class="s2">&amp;#34;unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install --no-deps trl peft accelerate bitsandbytes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>O Unsloth otimiza ao extremo os kernels do CUDA. Se comparado a uma biblioteca padronizada do Hugging Face, sua velocidade de treinamento é duas vezes maior e o consumo de VRAM é reduzido pela metade. Bastará iniciar um Jupyter Notebook e carregar o seu dataset (formato JSONL) para que ocorram as épocas de treinamento em GPUs com VRAM entre 12GB a 16GB, como a RTX 4060 Ti, por exemplo.&lt;/p>
&lt;hr>
&lt;h1 id="9-solução-de-problemas-de-desempenho">9. Solução de Problemas de Desempenho
&lt;/h1>&lt;p>Abaixo, encontre os problemas comumente encontrados e suas soluções.&lt;/p>
&lt;h3 id="1-a-velocidade-de-inferência-é-extremamente-lenta-12-tokenss">1. A velocidade de inferência é extremamente lenta (1~2 tokens/s)
&lt;/h3>&lt;p>&lt;strong>Causa&lt;/strong>: O modelo extrapolou a capacidade da VRAM e o processamento offload recaiu à memória do sistema (RAM).
&lt;strong>Solução&lt;/strong>: Inspecione o espaço de &amp;ldquo;Memória da GPU Dedicada&amp;rdquo; no Gerenciador de Tarefas do Windows. Se já atingiu o limite, reduza o tamanho do contexto (&lt;code>-c&lt;/code>) ou utilize um modelo quantizado com menor número de bits (como o Q4_K_M).&lt;/p>
&lt;h3 id="2-erro-cuda-out-of-memory">2. Erro &amp;ldquo;CUDA out of memory&amp;rdquo;
&lt;/h3>&lt;p>&lt;strong>Causa&lt;/strong>: A VRAM foi completamente esgotada. Geralmente ocorre quando a conversa se estende, inchando o tamanho do Cache KV.
&lt;strong>Solução&lt;/strong>: Restrinja intencionalmente o valor de &lt;code>num_ctx&lt;/code> no Ollama ou o parâmetro &lt;code>-c&lt;/code> do llama.cpp para um número mais baixo.&lt;/p>
&lt;h3 id="3-a-geração-em-japonês-está-estranha">3. A geração em japonês está estranha
&lt;/h3>&lt;p>&lt;strong>Causa&lt;/strong>: Incompatibilidade no template de prompt ou o modelo não possui suporte.
&lt;strong>Solução&lt;/strong>: Utilize modelos que incluam &lt;code>Instruct&lt;/code> no nome, e confirme na ferramenta se o template exigido pelos criadores do modelo, como os formatos ChatML ou Llama3, encontra-se devidamente selecionado.&lt;/p>
&lt;hr>
&lt;h1 id="10-resumo-e-perspectivas-futuras">10. Resumo e Perspectivas Futuras
&lt;/h1>&lt;p>Em 2026, criar um ambiente local de LLM no Windows não é mais privilégio de apenas alguns engenheiros. Devido à padronização do formato GGUF, à ascensão de ecossistemas refinados como Ollama e LM Studio, e a otimizações de hardware como FlashAttention, qualquer pessoa pode obter um ambiente de IA corporativo com extrema facilidade.&lt;/p>
&lt;p>Aproveite ao máximo os seguintes pontos detalhados neste artigo:&lt;/p>
&lt;ol>
&lt;li>Fazer uso do &lt;strong>cálculo matemático de VRAM&lt;/strong> para logicamente selecionar o nível de quantização e o tamanho do modelo ideais para as especificações do seu computador.&lt;/li>
&lt;li>Usar o &lt;strong>Ollama&lt;/strong> para um ambiente o mais rápido de construir e integrá-lo a um editor de IA, com o objetivo de aumentar drasticamente a produtividade.&lt;/li>
&lt;li>Usar os parâmetros de controle avançado no &lt;strong>llama.cpp&lt;/strong> para extrair as margens de desempenho do hardware.&lt;/li>
&lt;li>Construir através do &lt;strong>AnythingLLM&lt;/strong> um ambiente e sistema RAG Local seguro o suficiente para manipular os dados da sua empresa.&lt;/li>
&lt;li>Fazer uso do &lt;strong>Unsloth (WSL2)&lt;/strong> para criar a sua própria customizada IA, baseada no seu nível e especialidade de conhecimento.&lt;/li>
&lt;/ol>
&lt;p>A &amp;ldquo;democratização&amp;rdquo; da IA não se resume a um mero jargão tecnológico. Trata-se do real cenário em que os próprios sistemas são executados na tela de desktop de seu Windows. Livre-se dos riscos de vazamento de dados e custos nas APIs em nuvem, e comece hoje mesmo sua imersão em um mundo onde a IA Privada é poderosa e completamente sua.&lt;/p></description></item></channel></rss>