<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>LLM on kenji.blog</title><link>http://kenji.blog/pt/categories/llm/</link><description>Recent content in LLM 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/categories/llm/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>ChatGPT・Gemini・Claude API: Comparação Completa e Qual Escolher?</title><link>http://kenji.blog/pt/p/chatgpt-gemini-claude-api-comparison/</link><pubDate>Fri, 11 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/chatgpt-gemini-claude-api-comparison/</guid><description>&lt;img src="http://kenji.blog/p/chatgpt-gemini-claude-api-comparison/img/eyecatch.jpg" alt="Featured image of post ChatGPT・Gemini・Claude API: Comparação Completa e Qual Escolher?" />&lt;h1 id="chatgptgeminiclaude-api-comparação-completa-e-qual-escolher">ChatGPT・Gemini・Claude API: Comparação Completa e Qual Escolher?
&lt;/h1>&lt;p>A evolução da tecnologia de IA é notável, especialmente no campo dos Grandes Modelos de Linguagem (LLM: Large Language Model), onde o ChatGPT (série GPT) da OpenAI, o Gemini do Google e o Claude da Anthropic estão travando uma intensa batalha tripartida pela supremacia. A partir de 2026, cada empresa tem lançado novos modelos e funcionalidades de API em questão de meses, ou até mesmo semanas, e para desenvolvedores e arquitetos de TI corporativos, a questão de &amp;ldquo;qual API integrar ao produto&amp;rdquo; tornou-se uma decisão crítica que dita o sucesso de um projeto.&lt;/p>
&lt;p>Neste artigo, não apenas listaremos as especificações, mas compararemos e explicaremos detalhadamente as APIs desses três grandes provedores de IA sob a perspectiva do desenvolvedor, cobrindo o design da arquitetura, estrutura detalhada de preços, análise matemática da latência (atraso), exemplos práticos de implementação em Python e Node.js, e até os mais recentes métodos de otimização de custos, como o cache de prompt.&lt;/p>
&lt;p>Nosso objetivo é que este seja um guia completo para ajudar os leitores a selecionar a API de LLM ideal para seus casos de uso e construir aplicativos de IA escaláveis e econômicos.&lt;/p>
&lt;hr>
&lt;h2 id="1-filosofia-e-conceito-de-design-de-cada-api-de-llm">1. Filosofia e Conceito de Design de Cada API de LLM
&lt;/h2>&lt;p>Na escolha de tecnologia, é muito importante primeiro entender qual é a filosofia que cada empresa utiliza para construir seus modelos e APIs.&lt;/p>
&lt;h3 id="11-openai-chatgpt">1.1 OpenAI (ChatGPT)
&lt;/h3>&lt;p>A OpenAI tem como missão a &amp;ldquo;realização da Inteligência Artificial Geral (AGI)&amp;rdquo; e está sempre liderando o padrão de fato da indústria. Ela oferece uma ampla variedade de modelos adaptados aos casos de uso, como GPT-4o e GPT-4o-mini, além do modelo o1 especializado em raciocínio. Seu ecossistema é o mais maduro, com a documentação e bibliotecas mais ricas, sejam elas oficiais ou não oficiais.&lt;/p>
&lt;h3 id="12-google-gemini">1.2 Google (Gemini)
&lt;/h3>&lt;p>O Google defende a abordagem &amp;ldquo;AI First&amp;rdquo; e utiliza a escalabilidade de sua infraestrutura (rede TPU) ao máximo como sua principal arma. A maior característica do Gemini 1.5 Pro/Flash é sua enorme janela de contexto de até 2 milhões de tokens, permitindo que processe documentos extensos e horas de vídeo e áudio de uma só vez. Sua forte integração com o Google Cloud (Vertex AI) também é muito atraente para empresas.&lt;/p>
&lt;h3 id="13-anthropic-claude">1.3 Anthropic (Claude)
&lt;/h3>&lt;p>A Anthropic é uma empresa fundada por ex-membros da OpenAI e adota uma abordagem de segurança exclusiva chamada &amp;ldquo;Constitutional AI&amp;rdquo; (IA Constitucional). O Claude 3.5 Sonnet e o Opus conquistaram o apoio entusiástico de muitos desenvolvedores por suas altas capacidades de raciocínio, habilidades de geração de código e, acima de tudo, seus &amp;ldquo;diálogos naturais semelhantes aos humanos&amp;rdquo; e &amp;ldquo;baixa taxa de alucinação&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="2-comparação-detalhada-de-especificações-das-famílias-de-modelos">2. Comparação Detalhada de Especificações das Famílias de Modelos
&lt;/h2>&lt;p>Aqui está uma comparação das especificações dos principais modelos até 2026.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Provedor&lt;/th>
&lt;th>Modelo Principal&lt;/th>
&lt;th>Contexto Máximo&lt;/th>
&lt;th>Principais Pontos Fortes&lt;/th>
&lt;th>Casos de Uso Recomendados&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>OpenAI&lt;/strong>&lt;/td>
&lt;td>GPT-4o&lt;/td>
&lt;td>128K&lt;/td>
&lt;td>Velocidade, reconhecimento visual, suporte a áudio&lt;/td>
&lt;td>Aplicativos interativos, tarefas gerais&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>OpenAI&lt;/strong>&lt;/td>
&lt;td>o1-preview&lt;/td>
&lt;td>128K&lt;/td>
&lt;td>Raciocínio lógico avançado, matemática, codificação&lt;/td>
&lt;td>Geração de algoritmos complexos, pesquisa&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Google&lt;/strong>&lt;/td>
&lt;td>Gemini 1.5 Pro&lt;/td>
&lt;td>2.000K&lt;/td>
&lt;td>Processamento de textos ultralongos, multimodal (vídeo, áudio)&lt;/td>
&lt;td>Análise de grandes bases de código, resumo de vídeos&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Google&lt;/strong>&lt;/td>
&lt;td>Gemini 1.5 Flash&lt;/td>
&lt;td>2.000K&lt;/td>
&lt;td>Baixa latência, alta taxa de transferência, custo extremamente baixo&lt;/td>
&lt;td>Processamento em tempo real, processamento em lote de dados em massa&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Anthropic&lt;/strong>&lt;/td>
&lt;td>Claude 3.5 Sonnet&lt;/td>
&lt;td>200K&lt;/td>
&lt;td>Habilidades de codificação, geração de texto natural&lt;/td>
&lt;td>Suporte ao desenvolvimento de software, suporte avançado ao cliente&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Anthropic&lt;/strong>&lt;/td>
&lt;td>Claude 3.5 Haiku&lt;/td>
&lt;td>200K&lt;/td>
&lt;td>Resposta ultrarrápida, custo-benefício&lt;/td>
&lt;td>Edge AI, chatbots em tempo real&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="3-aprofundamento-na-arquitetura-os-bastidores-das-requisições-de-api">3. Aprofundamento na Arquitetura: Os Bastidores das Requisições de API
&lt;/h2>&lt;p>Quando uma API de LLM é chamada, que tipo de processamento ocorre no back-end? Para otimizar o desempenho, é necessário entender essa arquitetura.&lt;/p>
&lt;p>O diagrama Mermaid abaixo mostra a visão geral desde o momento em que a requisição da API é enviada pelo cliente até o momento em que os tokens são retornados em fluxo contínuo (streaming).&lt;/p>
&lt;div class="mermaid">graph TD
A["Aplicação Cliente"] -->|HTTP/REST ou gRPC| B["Gateway de API"]
B --> C["Balanceador de Carga"]
C --> D["Cluster de Inferência"]
D --> E["Tokenizador (BPE / SentencePiece)"]
E --> F["Cache KV &amp; Mecanismo de Atenção"]
F --> G["Blocos Transformer (Passagem Direta)"]
G --> H["Camada de Saída (Logits)"]
H --> I["Amostrador (Temperature, Top-p, Top-k)"]
I --> J["Destokenizador"]
J -->|Resposta em Streaming (Chunk)| A&lt;/div>
&lt;h3 id="31-algoritmo-de-tokenização-tokenization">3.1 Algoritmo de Tokenização (Tokenization)
&lt;/h3>&lt;p>O texto de entrada na API é dividido internamente em unidades chamadas &amp;ldquo;tokens&amp;rdquo;.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>OpenAI (tiktoken)&lt;/strong>: Adota o Byte-Pair Encoding (BPE). Ele é compactado com extrema eficiência, especialmente em inglês, mas o número de tokens tende a aumentar em idiomas não alfabéticos, como o japonês.&lt;/li>
&lt;li>&lt;strong>Google (Gemini)&lt;/strong>: Adota o SentencePiece (Unigram Language Model). Ele lida bem com múltiplos idiomas e tende a conseguir representar textos em japonês com um número relativamente pequeno de tokens.&lt;/li>
&lt;li>&lt;strong>Anthropic (Claude)&lt;/strong>: Usa uma versão customizada do BPE. O suporte multilíngue foi fortalecido e, a partir do Claude 3, a eficiência dos tokens em japonês também melhorou significativamente.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="4-análise-matemática-de-latência-e-desempenho">4. Análise Matemática de Latência e Desempenho
&lt;/h2>&lt;p>Em aplicações de tempo real, a latência está diretamente ligada à experiência do usuário (UX). A latência da API do LLM, $T_{total}$, pode ser matematicamente modelada da seguinte forma:&lt;/p>
$$ T_{total} = T_{network} + T_{TTFT} + (N \times T_{TPOT}) $$
&lt;p>Aqui, cada variável tem o seguinte significado:&lt;/p>
&lt;ul>
&lt;li>$T_{network}$: Tempo de ida e volta da rede (RTT).&lt;/li>
&lt;li>$T_{TTFT}$ (Time To First Token): O tempo até que o primeiro caractere seja gerado. Ele depende fortemente do custo do cálculo da atenção, que é proporcional ao quadrado do comprimento do prompt (número de tokens de entrada).&lt;/li>
&lt;li>$N$: O número total de tokens gerados na saída.&lt;/li>
&lt;li>$T_{TPOT}$ (Time Per Output Token): Tempo de geração por token. Por se tratar de um modelo autorregressivo, o cálculo é feito em série dependendo da saída anterior.&lt;/li>
&lt;/ul>
&lt;h3 id="41-complexidade-computacional-do-mecanismo-de-autoatenção">4.1 Complexidade Computacional do Mecanismo de Autoatenção
&lt;/h3>&lt;p>A complexidade computacional da autoatenção (Self-Attention) na arquitetura Transformer aumenta de forma quadrática em relação ao comprimento da sequência de entrada $L$.&lt;/p>
$$ \text{Complexity} = O(L^2 \cdot d) $$
&lt;p>Onde $d$ é o número de dimensões do vetor de incorporação (embedding). Devido a essa restrição, o $T_{TTFT}$ normalmente se degrada muito rapidamente à medida que o prompt se torna mais longo.
No entanto, o Gemini 1.5 do Google adota arquiteturas inovadoras de otimização como &amp;ldquo;Ring Attention&amp;rdquo; e &amp;ldquo;Block-wise Compute&amp;rdquo;, conseguindo gerar o primeiro token em um tempo realista (de alguns segundos a dezenas de segundos), mesmo ao inserir textos longos de até 2 milhões de tokens.&lt;/p>
&lt;hr>
&lt;h2 id="5-estrutura-de-preços-e-estratégias-de-otimização-de-custos">5. Estrutura de Preços e Estratégias de Otimização de Custos
&lt;/h2>&lt;p>O custo das APIs é basicamente calculado com base no número de tokens de entrada e no número de tokens de saída.&lt;/p>
$$ Cost = (Tokens_{in} \times Rate_{in}) + (Tokens_{out} \times Rate_{out}) $$
&lt;p>No entanto, as APIs mais recentes introduziram novos mecanismos para reduzir os custos drasticamente.&lt;/p>
&lt;h3 id="51-cache-de-prompt-prompt-caching">5.1 Cache de Prompt (Prompt Caching)
&lt;/h3>&lt;p>O envio de um prompt de sistema extremamente longo ou de uma grande quantidade de documentos pesquisados via RAG a cada vez custa muito dinheiro. Para lidar com isso, cada empresa oferece um recurso de cache.&lt;/p>
&lt;p>Na Anthropic (Claude) e no Google (Gemini), ao fazer o cache de blocos específicos de texto, você pode reduzir significativamente (em até 90%) o custo de entrada.&lt;/p>
&lt;p>O modelo de custo ao utilizar o cache seria o seguinte:&lt;/p>
$$ Cost_{cached} = (Tokens_{cache\_write} \times Rate_{cache\_write}) + (Tokens_{cache\_read} \times Rate_{cache\_read}) + (Tokens_{out} \times Rate_{out}) $$
&lt;p>Aqui, $Rate_{cache\_read}$ é definido para algo em torno de 10% a 25% da $Rate_{in}$ normal. Isso possibilita a operação de chatbots a baixo custo, mantendo sempre em memória bases de código de dezenas de milhares de linhas como conhecimento contextual.&lt;/p>
&lt;h3 id="52-api-em-lote-batch-api">5.2 API em Lote (Batch API)
&lt;/h3>&lt;p>Para tarefas que não exigem resultados em tempo real (como análise de logs, classificação de grandes volumes de dados, etc.), a OpenAI e a Anthropic oferecem APIs em lote. Ao enviar requisições de forma agrupada e receber os resultados em até 24 horas, é possível obter um poderoso mecanismo pela metade do preço (50% de desconto) da tarifa regular da API.&lt;/p>
&lt;hr>
&lt;h2 id="6-experiência-do-desenvolvedor-dx-e-comparação-de-sdks">6. Experiência do Desenvolvedor (DX) e Comparação de SDKs
&lt;/h2>&lt;p>Do ponto de vista da eficiência do desenvolvimento, comparamos os SDKs (Software Development Kits) fornecidos por cada empresa.&lt;/p>
&lt;h3 id="61-openai-api">6.1 OpenAI API
&lt;/h3>&lt;p>É o mais amplamente utilizado e possui o suporte mais rápido para bibliotecas de terceiros (LangChain, LlamaIndex, etc.). Além disso, a funcionalidade de Structured Outputs (Saídas Estruturadas) garante o retorno de respostas que aderem com 100% de precisão aos esquemas JSON, tornando a integração de sistemas muito fácil.&lt;/p>
&lt;h3 id="62-anthropic-api-claude">6.2 Anthropic API (Claude)
&lt;/h3>&lt;p>As interfaces do seu SDK são muito bem trabalhadas, e sua definição de tipos em TypeScript tem a reputação de ser extremamente fácil de manusear. A estrutura da API de Mensagens, em particular, é muito intuitiva, tornando requisições multimodais com várias imagens simples de descrever.&lt;/p>
&lt;h3 id="63-google-gemini-api">6.3 Google Gemini API
&lt;/h3>&lt;p>Existem dois tipos de acesso: um via Google Cloud Vertex AI e outro via AI Studio (Google Gen AI SDK), o que pode ser um pouco confuso para iniciantes. No entanto, o Vertex AI SDK voltado para corporações é totalmente integrado com o IAM (Sistema de Autenticação e Autorização) do GCP, permitindo a construção de ambientes de desenvolvimento seguros.&lt;/p>
&lt;hr>
&lt;h2 id="7-prática-implementação-de-teste-de-integração-simultânea-com-python">7. Prática! Implementação de Teste de Integração Simultânea com Python
&lt;/h2>&lt;p>Aqui, usaremos o Python para implementar um script que envia solicitações assíncronas simultaneamente às três APIs (OpenAI, Anthropic e Gemini) e compara as latências.&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;/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">asyncio&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">time&lt;/span>
&lt;/span>&lt;/span>&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">openai&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AsyncOpenAI&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">anthropic&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AsyncAnthropic&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">google.generativeai&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">genai&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"># Inicialização dos clientes&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">openai_client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AsyncOpenAI&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&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;OPENAI_API_KEY&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">anthropic_client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AsyncAnthropic&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&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;ANTHROPIC_API_KEY&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">genai&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">configure&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&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;GEMINI_API_KEY&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">prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Por favor, explique aos iniciantes os fundamentos dos computadores quânticos e seu impacto nas tecnologias atuais de criptografia.&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="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">fetch_openai&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start_time&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">openai_client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">chat&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">completions&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&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="s2">&amp;#34;gpt-4o&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">messages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[{&lt;/span>&lt;span class="s2">&amp;#34;role&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;content&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="n">max_tokens&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&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">elapsed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start_time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;OpenAI (GPT-4o)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">elapsed&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">choices&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">content&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">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">fetch_anthropic&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start_time&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">anthropic_client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">messages&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&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="s2">&amp;#34;claude-3-5-sonnet-20240620&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">messages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[{&lt;/span>&lt;span class="s2">&amp;#34;role&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;content&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="n">max_tokens&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&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">elapsed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start_time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;Anthropic (Claude 3.5 Sonnet)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">elapsed&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">content&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&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">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">fetch_gemini&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start_time&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&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">genai&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">GenerativeModel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;gemini-1.5-pro&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="c1"># Uso do método assíncrono do SDK Python do Gemini&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">generate_content_async&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="n">elapsed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start_time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;Google (Gemini 1.5 Pro)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">elapsed&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&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">async&lt;/span> &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="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Enviando requisições para as APIs de LLM...&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"># Executar as 3 APIs em paralelo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">results&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">gather&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fetch_openai&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fetch_anthropic&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fetch_gemini&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="k">for&lt;/span> &lt;span class="n">provider&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">latency&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">text&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">results&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;--- &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">provider&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 class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Latency: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">latency&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.2f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> segundos&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="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Response (Excerpt): &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">...&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="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">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&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;p>Ao executar este script, você pode facilmente medir qual modelo responde mais rapidamente (minimizando $T_{total}$) em um ambiente de rede real.&lt;/p>
&lt;hr>
&lt;h2 id="8-implementação-de-tool-calling-chamada-de-função-em-nodejs">8. Implementação de Tool Calling (Chamada de Função) em Node.js
&lt;/h2>&lt;p>Para que o LLM funcione não apenas como um chatbot, mas como um &amp;ldquo;Agente de IA&amp;rdquo; que interage com sistemas externos, o Tool Calling (ou Function Calling) é essencial. Abaixo está um exemplo em Node.js (TypeScript) instruindo a API da OpenAI a chamar uma API de clima.&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">import&lt;/span> &lt;span class="nx">OpenAI&lt;/span> &lt;span class="kr">from&lt;/span> &lt;span class="s2">&amp;#34;openai&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="kr">const&lt;/span> &lt;span class="nx">openai&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">OpenAI&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">apiKey&lt;/span>: &lt;span class="kt">process.env.OPENAI_API_KEY&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="kr">async&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nx">runAgent() {&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">tools&lt;/span> &lt;span class="o">=&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="kr">type&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;function&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="kd">function&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;get_weather&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="nx">description&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Obtém o clima atual da cidade especificada.&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="nx">parameters&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">type&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;object&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="nx">properties&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">location&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">type&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;string&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="nx">description&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Nome da cidade (ex: Tóquio, Nova York)&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="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">required&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;location&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="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="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="kr">const&lt;/span> &lt;span class="nx">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="nx">openai&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">chat&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">completions&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">create&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">model&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;gpt-4o&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="nx">messages&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[{&lt;/span> &lt;span class="nx">role&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;content&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Como está o clima hoje em Tóquio? Preciso de um guarda-chuva?&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="nx">tools&lt;/span>: &lt;span class="kt">tools&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tool_choice&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="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="kr">const&lt;/span> &lt;span class="nx">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">response&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">choices&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="nx">message&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="p">(&lt;/span>&lt;span class="nx">message&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">tool_calls&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">toolCall&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">message&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">tool_calls&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sb">`O LLM solicitou a chamada de uma ferramenta: Nome da função = &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">toolCall&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">`&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="kr">const&lt;/span> &lt;span class="nx">args&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">JSON&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">parse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">toolCall&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">arguments&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sb">`Argumentos: &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">args&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">location&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">`&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">// Aqui seria implementada a chamada real da API de clima (ex: OpenWeatherMap)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// const weather = await fetchWeatherFromAPI(args.location);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Depois, o resultado é passado de volta ao LLM para gerar a resposta final
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&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="nx">runAgent&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="k">catch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">error&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;p>O Claude 3.5 Sonnet e o Gemini 1.5 Pro possuem capacidades equivalentes de Tool Calling, e embora existam pequenas diferenças na definição do esquema, o fluxo básico é comum a todos.&lt;/p>
&lt;hr>
&lt;h2 id="9-rag-vs-janela-de-contexto-longa-qual-adotar">9. RAG vs Janela de Contexto Longa: Qual Adotar?
&lt;/h2>&lt;p>Um dos maiores debates atuais em arquiteturas de IA empresariais é se devemos &amp;ldquo;usar o RAG (Geração Aumentada por Recuperação) para trazer conhecimento externo, ou se devemos simplesmente jogar tudo em uma enorme janela de contexto (Contexto Longo)&amp;rdquo;.&lt;/p>
&lt;h3 id="vantagens-e-desafios-do-rag-retrieval-augmented-generation">Vantagens e Desafios do RAG (Retrieval-Augmented Generation)
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Vantagens&lt;/strong>: Baixo custo (já que apenas os chunks necessários são colocados no prompt), e é mais fácil identificar a fundamentação (fonte) da resposta.&lt;/li>
&lt;li>&lt;strong>Desafios&lt;/strong>: Uma vez que depende da precisão da busca semântica, ele não é adequado para tarefas de raciocínio complexo onde o contexto se espalha por vários documentos (ex: &amp;ldquo;A partir das atas de todas as reuniões do ano passado, analise cronologicamente a causa raiz dos atrasos no Projeto A&amp;rdquo;).&lt;/li>
&lt;/ul>
&lt;h3 id="contexto-longo-ex-2-milhões-de-tokens-do-gemini-15-pro">Contexto Longo (ex: 2 milhões de tokens do Gemini 1.5 Pro)
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Vantagens&lt;/strong>: Nenhuma informação é perdida por conta da pesquisa. Mesmo no teste de &amp;ldquo;Achar a agulha num palheiro (Needle In A Haystack: NIAH)&amp;rdquo;, o Gemini 1.5 Pro e o Claude 3.5 Sonnet podem extrair informações com mais de 99% de precisão.&lt;/li>
&lt;li>&lt;strong>Desafios&lt;/strong>: O consumo de tokens torna-se enorme e eleva os custos, e há um aumento na latência ($T_{TTFT}$).&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Conclusão&lt;/strong>: A melhor prática em 2026 é uma &lt;strong>&amp;ldquo;Abordagem Híbrida&amp;rdquo;&lt;/strong>. A tendência principal de design é usar o RAG com bancos de dados vetoriais para Q&amp;amp;A rotineiros e usar um Contexto Longo em combinação com o cache de prompt para tarefas especializadas que exigem análises complexas ou a revisão de todo o código.&lt;/p>
&lt;hr>
&lt;h2 id="10-comparação-de-capacidades-de-processamento-multimodal">10. Comparação de Capacidades de Processamento Multimodal
&lt;/h2>&lt;p>Em aplicativos de IA de próxima geração, a capacidade de entender diretamente imagens, áudio e vídeo em vez de apenas texto é cada vez mais necessária.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant User as "Usuário"
participant Client as "App Frontend"
participant API as "LLM API (Multimodal)"
User->>Client: Enviar Vídeo &amp; Prompt de Texto
Client->>API: Enviar Bytes/URI de Vídeo + Texto
Note over API: Fragmentação do vídeo &amp; Separação do áudio
Note over API: Modelo de Incorporação Multimodal
API-->>Client: Retornar Resumo de Texto &amp; Timestamps
Client-->>User: Mostrar Insights&lt;/div>
&lt;ul>
&lt;li>&lt;strong>OpenAI (GPT-4o)&lt;/strong>: Precisão de reconhecimento de imagem extremamente alta, superando na leitura de desenhos manuscritos e gráficos complexos. A interação por voz nativa usando a Realtime API com latência ultrabaixa (centenas de milissegundos) também é poderosa.&lt;/li>
&lt;li>&lt;strong>Google (Gemini 1.5 Pro)&lt;/strong>: &lt;strong>Apresenta superioridade esmagadora na análise de vídeos.&lt;/strong> É capaz de processar 1 hora de vídeo (quadros + áudio) de uma só vez e responder a perguntas pontuais como &amp;ldquo;Qual o título do documento segurado pela pessoa no canto direito da tela aos 12 minutos e 45 segundos?&amp;rdquo;.&lt;/li>
&lt;li>&lt;strong>Anthropic (Claude 3.5 Sonnet)&lt;/strong>: A capacidade de reconhecimento visual (Vision) está no mesmo nível do GPT-4o e é altamente capaz. Ele é incomparável em suporte ao desenvolvimento de frontend, lidando com pedidos como &amp;ldquo;Gere o código de componentes React a partir desta captura de tela da UI&amp;rdquo;.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="11-segurança-e-conformidade-de-nível-empresarial">11. Segurança e Conformidade de Nível Empresarial
&lt;/h2>&lt;p>A maior preocupação quando empresas usam APIs de LLM em ambientes de produção é &amp;ldquo;nossos dados serão usados para treinar a IA?&amp;rdquo; e &amp;ldquo;isso atende aos requisitos de conformidade?&amp;rdquo;.&lt;/p>
&lt;p>As 3 empresas declararam explicitamente que os dados enviados através de suas APIs (prompts e respostas) &lt;strong>não são usados para treinar os modelos (Zero Data Retention / No Training on Customer Data)&lt;/strong> (※ A interface de chat da Web gratuita para consumidores é diferente).&lt;/p>
&lt;p>Se for exigido um nível mais elevado de segurança:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>OpenAI&lt;/strong>: Usando o Azure OpenAI Service, pode-se obter a segurança de nível empresarial da Microsoft, SLAs e conexão privada via Azure Private Link.&lt;/li>
&lt;li>&lt;strong>Google&lt;/strong>: Usando o Google Cloud Vertex AI, é possível contar com o isolamento rígido de rede pelo VPC Service Controls e a proteção de dados através do CMEK (Chaves de Criptografia Gerenciadas pelo Cliente).&lt;/li>
&lt;li>&lt;strong>Anthropic&lt;/strong>: Ao utilizar as plataformas AWS Bedrock ou Google Cloud Vertex AI, as empresas podem se beneficiar da infraestrutura de segurança robusta desses provedores em nuvem.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="12-conclusão-guia-de-escolha-definitivo-por-caso-de-uso">12. Conclusão: Guia de Escolha Definitivo por Caso de Uso
&lt;/h2>&lt;p>Comparamos extensamente sob vários ângulos, mas, no final, a resposta para &amp;ldquo;Qual devo escolher?&amp;rdquo; depende do caso de uso.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Desenvolvimento de Software Complexo, Geração de Código, Raciocínio Avançado&lt;/strong>:
&lt;strong>👑 Vencedor: Claude 3.5 Sonnet (Anthropic)&lt;/strong>
Atualmente oferece a melhor performance em entender o contexto de códigos, refatoração e elaboração de textos mais humanos e naturais. A facilidade de uso da API e o custo-benefício por causa do cache de prompt também são notáveis.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Análise de Documentos Ultralongos, Processamento em Lote de Vídeo/Áudio&lt;/strong>:
&lt;strong>👑 Vencedor: Gemini 1.5 Pro (Google)&lt;/strong>
A janela de contexto de 2 milhões de tokens é uma arma incomparável. Para tarefas que precisam compreender a visão geral dos dados, como a análise de manuais em PDF de centenas de páginas e o resumo de gravações de reuniões longas, o Gemini é imbatível.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Versatilidade, Velocidade de Execução, Saídas Estruturadas Estáveis (JSON)&lt;/strong>:
&lt;strong>👑 Vencedor: GPT-4o / GPT-4o-mini (OpenAI)&lt;/strong>
Lida bem com qualquer tarefa perfeitamente e oferece o suporte mais rico para ferramentas de terceiros. Se a sua empresa necessita de parsing de JSON confiável por meio das Structured Outputs (Saídas Estruturadas) ou raciocínio lógico muito avançado usando o modelo o1, o ecossistema da OpenAI é indispensável.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h3 id="recomendação-de-roteamento-multimodelo">Recomendação de Roteamento Multimodelo
&lt;/h3>&lt;p>A tendência futura de arquitetura é não depender (e sofrer vendor lock-in) de uma única API, mas adotar o &lt;strong>&amp;ldquo;Roteamento de LLM&amp;rdquo; (LLM Routing)&lt;/strong> para alternar de forma dinâmica o modelo dependendo da dificuldade e importância da tarefa.
Por exemplo, responder perguntas simples dos usuários usando as opções mais baratas e rápidas, como o &lt;code>GPT-4o-mini&lt;/code> ou o &lt;code>Gemini 1.5 Flash&lt;/code>, e recorrer ao &lt;code>Claude 3.5 Sonnet&lt;/code> apenas quando for determinado que um processamento complexo é necessário, para se obter o equilíbrio perfeito entre custo e desempenho.&lt;/p>
&lt;p>A evolução da IA é incessante. Entenda profundamente as forças e fraquezas de cada API e as características de sua arquitetura, e construa aplicações de IA flexíveis e escaláveis.&lt;/p></description></item><item><title>Como usar o llama.cpp e uma introdução à customização em C++</title><link>http://kenji.blog/pt/p/llama-cpp-cxx-customization/</link><pubDate>Fri, 11 Sep 2026 11:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/llama-cpp-cxx-customization/</guid><description>&lt;img src="http://kenji.blog/p/llama-cpp-cxx-customization/img/eyecatch.jpg" alt="Featured image of post Como usar o llama.cpp e uma introdução à customização em C++" />&lt;p>Nos últimos anos, a evolução dos Grandes Modelos de Linguagem (LLM) tem sido impressionante, e sua área de aplicação se expande dia após dia. No entanto, para executar modelos com bilhões ou dezenas de bilhões de parâmetros em um ambiente local, normalmente é necessária uma GPU de ponta com uma quantidade enorme de VRAM. O &lt;strong>llama.cpp&lt;/strong> é o que quebrou essa &amp;ldquo;barreira de hardware&amp;rdquo; e tornou possível a inferência prática de LLM em PCs comuns, Macs e até dispositivos como o Raspberry Pi.&lt;/p>
&lt;p>Neste artigo, explicaremos de forma extremamente detalhada para engenheiros, indo além do simples uso de ferramentas de linha de comando, para cobrir a arquitetura de sua tecnologia base &lt;code>ggml&lt;/code>, a base matemática do Transformer e a quantização, e até mesmo métodos para incorporar e customizar LLMs em suas próprias aplicações usando a API C++.&lt;/p>
&lt;hr>
&lt;h2 id="1-visão-geral-do-llamacpp-e-ggml">1. Visão geral do llama.cpp e ggml
&lt;/h2>&lt;p>O &lt;code>llama.cpp&lt;/code> é um motor de inferência de LLM leve escrito em C/C++, desenvolvido por Georgi Gerganov. Inicialmente criado com o propósito de rodar o modelo LLaMA da Meta rapidamente no Apple Silicon (Macs M1/M2), agora ele suporta várias arquiteturas e modelos.&lt;/p>
&lt;p>Sua principal característica é ser uma &lt;strong>implementação pura em C/C++ sem dependências externas&lt;/strong>. Ele não requer grandes ecossistemas como Python ou PyTorch e pode ser compilado como um único arquivo executável, o que torna o deploy extremamente fácil.&lt;/p>
&lt;p>No coração deste &lt;code>llama.cpp&lt;/code> está a biblioteca de operações tensoriais &lt;strong>ggml&lt;/strong>. A ggml foi projetada do zero para otimizar operações de matriz em aprendizado de máquina no CPU (e algumas GPUs) ao limite absoluto.&lt;/p>
&lt;h3 id="11-por-que-o-llamacpp-é-tão-rápido">1.1 Por que o llama.cpp é tão rápido?
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>Utilização de mapeamento de memória (mmap)&lt;/strong>: Ao carregar os pesos do modelo na memória, ele usa o &lt;code>mmap&lt;/code> do SO, evitando um carregamento completo na RAM, alcançando assim uma inicialização rápida e economia de memória.&lt;/li>
&lt;li>&lt;strong>Otimização exaustiva de instruções SIMD&lt;/strong>: Ele utiliza conjuntos de instruções específicos do CPU, como AVX2, AVX-512, ARM NEON e Apple AMX para acelerar enormemente a multiplicação de matrizes.&lt;/li>
&lt;li>&lt;strong>Quantização (Quantization)&lt;/strong>: Ele comprime pesos de ponto flutuante de 16 bits (FP16) em inteiros de 4 bits, 5 bits ou 8 bits, eliminando o gargalo na largura de banda da memória (mais detalhes abaixo).&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="2-base-matemática-transformer-e-quantização-quantization">2. Base Matemática: Transformer e Quantização (Quantization)
&lt;/h2>&lt;p>Para entender profundamente o llama.cpp, você precisa saber quais fórmulas matemáticas ele está calculando e como ele aproxima esses cálculos.&lt;/p>
&lt;h3 id="21-o-processo-de-inferência-do-transformer">2.1 O Processo de Inferência do Transformer
&lt;/h3>&lt;p>Modelos como o LLaMA adotam uma arquitetura de decodificador Transformer auto-regressiva (Auto-regressive). O núcleo da geração de texto é o mecanismo de &lt;strong>Self-Attention&lt;/strong>.&lt;/p>
&lt;p>Para uma matriz de estado oculto de entrada $X \in \mathbb{R}^{N \times d}$, as queries $Q$, keys $K$ e values $V$ são calculadas por produtos com matrizes de pesos.&lt;/p>
$$
Q = X W_Q, \quad K = X W_K, \quad V = X W_V
$$
&lt;p>Aqui, a saída da Attention é definida como a seguir.&lt;/p>
$$
\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V
$$
&lt;p>No loop de inferência do llama.cpp, o gargalo é o produto dessas enormes matrizes $W_Q, W_K, W_V$ ou das matrizes de pesos da rede feed-forward (FFN) com o vetor $X$ (já que processa um token por vez na fase de geração, $N=1$), isto é, &lt;strong>GEMV (General Matrix-Vector Multiplication)&lt;/strong>.&lt;/p>
&lt;h3 id="22-base-matemática-da-quantização-quantization">2.2 Base Matemática da Quantização (Quantization)
&lt;/h3>&lt;p>Na inferência, onde a largura de banda de acesso à memória se torna um gargalo, a quantização, que expressa parâmetros de peso em um número menor de bits, é essencial. Explicaremos o princípio básico da quantização em blocos amplamente utilizada no llama.cpp (por exemplo, &lt;code>Q4_K&lt;/code> e &lt;code>Q4_0&lt;/code>).&lt;/p>
&lt;p>Por exemplo, considere um bloco $w = [w_1, w_2, \dots, w_B]$ de comprimento $B$ (geralmente 32 ou 64) que é parte da matriz de pesos FP16 $W$. Nós aproximamos este bloco para um inteiro de 4 bits $q_i \in [-8, 7]$ e um único fator de escala $\Delta$ (FP16 ou FP32).&lt;/p>
$$
w_i \approx \Delta \times q_i
$$
&lt;p>O $\Delta$ é determinado com base no valor absoluto máximo dentro do bloco.&lt;/p>
$$
\Delta = \frac{\max_i |w_i|}{7}
$$
&lt;p>Ao calcular o produto escalar $y = w \cdot x$ usando os pesos quantizados, se o vetor de entrada $x$ for similarmente quantizado de modo que $x_i \approx \Delta_x \times q_{x, i}$, então&lt;/p>
$$
y = \sum_{i=1}^{B} w_i x_i \approx \Delta \Delta_x \sum_{i=1}^{B} q_i q_{x, i}
$$
&lt;p>Esta parte de $\sum q_i q_{x, i}$ se torna uma &lt;strong>operação inteira pura&lt;/strong>, a qual pode ser calculada em paralelo em altíssima velocidade usando instruções SIMD. Este é o truque matemático de como o llama.cpp alcança sua velocidade incrível em CPUs.&lt;/p>
&lt;hr>
&lt;h2 id="3-arquitetura-e-fluxo-de-inferência">3. Arquitetura e Fluxo de Inferência
&lt;/h2>&lt;p>Para entender o funcionamento interno do llama.cpp, o diagrama Mermaid a seguir mostra a arquitetura de todo o sistema e o fluxo de dados.&lt;/p>
&lt;div class="mermaid">graph TD
A["Entrada do Usuário (String)"] --> B["Tokenizer llama.cpp"]
B --> C["IDs de Tokens (array int32)"]
C --> D["Buffer de Contexto (KV Cache)"]
D --> E["Grafo de Computação ggml"]
E --> F["Camadas do Transformer"]
subgraph "Motor ggml"
F --> G["Self-Attention (RoPE)"]
G --> H["Rede Feed Forward"]
H --> F
end
F --> I["Logits (Tamanho do Vocabulário)"]
I --> J["Sampler (Temperature, Top-K, Top-P)"]
J --> K["ID do Token Selecionado"]
K --> L["Detokenizer llama.cpp"]
L --> M["String de Saída"]
K -. "Loop auto-regressivo" .-> D&lt;/div>
&lt;p>A geração de texto é um loop auto-regressivo onde cada vez que um token é emitido, ele é adicionado ao KV Cache como a próxima entrada e passa novamente pelo grafo de computação.&lt;/p>
&lt;hr>
&lt;h2 id="4-configuração-do-ambiente-e-métodos-de-build">4. Configuração do Ambiente e Métodos de Build
&lt;/h2>&lt;p>Antes de incorporar o llama.cpp ao seu projeto em C++, vamos primeiro tentar compilar o código-fonte.&lt;/p>
&lt;h3 id="41-clonando-o-repositório">4.1 Clonando o Repositório
&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;/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">git clone https://github.com/ggerganov/llama.cpp.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> llama.cpp
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="42-compilando-usando-cmake">4.2 Compilando Usando CMake
&lt;/h3>&lt;p>Para integrá-lo em outros aplicativos como um projeto C++, usar o CMake é a abordagem mais padrão. Ativar o acelerador (backend) para cada plataforma pode aumentar a velocidade de computação.&lt;/p>
&lt;p>&lt;strong>Apenas CPU (Build básico):&lt;/strong>&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;/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">mkdir build &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake ..
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build . --config Release -j &lt;span class="m">8&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>Ao usar NVIDIA GPU (CUDA):&lt;/strong>&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;/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">mkdir build &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake .. -DGGML_CUDA&lt;span class="o">=&lt;/span>ON
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build . --config Release -j &lt;span class="m">8&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>Ao usar Apple Silicon (Metal):&lt;/strong>&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;/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">mkdir build &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake .. -DGGML_METAL&lt;span class="o">=&lt;/span>ON
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build . --config Release -j &lt;span class="m">8&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Uma vez que a compilação for bem-sucedida, arquivos executáveis como o &lt;code>llama-cli&lt;/code>, bem como a biblioteca &lt;code>llama&lt;/code> (e a biblioteca &lt;code>ggml&lt;/code>) para vinculação com a API C++ descrita mais adiante, serão gerados no diretório &lt;code>build/bin/&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="5-introdução-à-customização-em-c-usando-a-api-do-llamacpp">5. Introdução à Customização em C++: Usando a API do llama.cpp
&lt;/h2>&lt;p>A partir daqui, discutiremos o tema principal: controlar o llama.cpp a partir de código C++.
Para não apenas usar a ferramenta de linha de comando, mas também incorporar o LLM em sua própria aplicação (como motores de jogos, aplicativos de desktop, sistemas embarcados, etc.), você precisa chamar a API C++ diretamente.&lt;/p>
&lt;p>O llama.cpp fornece uma interface de linguagem C principalmente através de um arquivo de cabeçalho chamado &lt;code>llama.h&lt;/code>. Quando você o chama do C++, você também utilizará esta interface.&lt;/p>
&lt;h3 id="51-includes-e-configurações-mínimas-necessárias">5.1 Includes e Configurações Mínimas Necessárias
&lt;/h3>&lt;p>Ao usar o llama.cpp em seu próprio projeto, você incluirá 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;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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;#34;llama.h&amp;#34;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdexcept&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Macro para tratamento de erros
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#define LLAMA_ASSERT(x) \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> do { \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> if (!(x)) { \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> std::cerr &amp;lt;&amp;lt; &amp;#34;Assertion failed: &amp;#34; &amp;lt;&amp;lt; #x &amp;lt;&amp;lt; std::endl; \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> std::terminate(); \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> } \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> } while (0)
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="52-carregando-o-modelo-e-inicializando-o-contexto">5.2 Carregando o Modelo e Inicializando o Contexto
&lt;/h3>&lt;p>Primeiro, carregamos um arquivo de modelo no formato &lt;code>.gguf&lt;/code> e alocamos um contexto (espaço de memória e KV cache) para inferência.&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">argc&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">char&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="n">argv&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">argc&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Usage: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">argv&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; &amp;lt;model.gguf&amp;gt;&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&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">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">model_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">argv&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&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">// 1. Inicialização do backend (configuração do ambiente como CPU/GPU, etc.)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_backend_init&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. Obter configurações padrão de parâmetros do modelo
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_model_params&lt;/span> &lt;span class="n">model_params&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_model_default_params&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_params&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_gpu_layers&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">35&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Número de camadas a descarregar para a GPU
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 3. Carregando o modelo
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_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">llama_load_model_from_file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model_path&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">c_str&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">model_params&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to load model&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&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">// 4. Configuração dos parâmetros de contexto
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_context_params&lt;/span> &lt;span class="n">ctx_params&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_context_default_params&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ctx_params&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_ctx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2048&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Tamanho máximo de contexto (em tokens)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">ctx_params&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_threads&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">// Número de threads da CPU para inferência
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 5. Criação do contexto
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_context&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">ctx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_new_context_with_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">ctx_params&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to create context&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_free_model&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 class="k">return&lt;/span> &lt;span class="mi">1&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="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Model and context loaded successfully!&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ... Processamento subsequente
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="53-tokenização-do-prompt-tokenization">5.3 Tokenização do Prompt (Tokenization)
&lt;/h3>&lt;p>Um LLM não entende textos diretamente, mas sim os processa como uma sequência de IDs inteiros (tokens). A string de entrada deve ser convertida em tokens.&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;Q: Qual é a capital do Japão?&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">A:&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">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">llama_token&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">resize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">prompt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Tamanho de buffer com margem
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Adicionar um token especial (como BOS: Begin of Sequence) ao início
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">bool&lt;/span> &lt;span class="n">add_special&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Converter a string para um array de IDs de tokens
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_tokens&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_tokenize&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="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="p">.&lt;/span>&lt;span class="n">c_str&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="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">add_special&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">false&lt;/span> &lt;span class="c1">// parse_special
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&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="p">(&lt;/span>&lt;span class="n">n_tokens&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Se o buffer for insuficiente, é necessário realocar e tentar novamente (omitido por simplificação)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to tokenize prompt&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&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">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">resize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_tokens&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="54-loop-de-inferência-e-amostragem-sampling">5.4 Loop de Inferência e Amostragem (Sampling)
&lt;/h3>&lt;p>Construímos um loop onde os tokens são inseridos no modelo, obtemos a distribuição de probabilidade (Logits) do próximo token e realizamos amostragem a partir dela para determinar o próximo token.&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Número máximo de tokens a gerar
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">max_gen_tokens&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>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Inicializar a estrutura para avaliação em lote (batch)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_batch&lt;/span> &lt;span class="n">batch&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_batch_init&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">512&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&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">// Adicionar tokens de prompt ao batch
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">size_t&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_batch_add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="p">},&lt;/span> &lt;span class="nb">false&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="c1">// Configurar para produzir logits (resultados previstos) apenas para o último token do prompt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">logits&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_tokens&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&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">// Avaliação inicial (alimentando o modelo com o prompt)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_decode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;llama_decode() failed&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&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="kt">int&lt;/span> &lt;span class="n">n_cur&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_tokens&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Tamanho atual do contexto
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_decode&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&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">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">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>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Inicialização do contexto do sampler (configurações como Temperature, Top-K, Top-P, etc.)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_sampler&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">smpl&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_sampler_chain_init&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">llama_sampler_chain_default_params&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_sampler_chain_add_top_k&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">40&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_sampler_chain_add_top_p&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">0.9f&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_sampler_chain_add_temp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">0.7f&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_sampler_chain_add_dist&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1234&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Valor da semente (Seed)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n_decode&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">max_gen_tokens&lt;/span>&lt;span class="p">)&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. Amostragem: Prever o próximo token com base no contexto atual
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_token&lt;/span> &lt;span class="n">new_token_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_sampler_sample&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&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. Se o token for EOS (End of Sequence), encerrar o loop
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_token_is_eog&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">new_token_id&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&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">// 3. Decodificar o token para uma string (texto) e exibir
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">char&lt;/span> &lt;span class="n">buf&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">128&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_chars&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_token_to_piece&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">new_token_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">buf&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">buf&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n_chars&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">buf&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_chars&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">flush&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">// 4. Preparar o token recém-gerado para o próximo batch
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_batch_clear&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_batch_add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new_token_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_cur&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="p">},&lt;/span> &lt;span class="nb">true&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. Avaliação do modelo (atualiza a KV cache e prevê a seguir)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_decode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to evaluate&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&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="n">n_cur&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n_decode&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">1&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="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&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">// Cleanup (Limpeza)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_sampler_free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_batch_free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_free_model&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 class="n">llama_backend_free&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">return&lt;/span> &lt;span class="mi">0&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;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Este código implementa um loop de inferência customizado usando a API básica do llama.cpp.
Ele usa a estrutura &lt;code>llama_batch&lt;/code> para gerenciar grupos de tokens e executa um forward pass (propagação para frente) na rede neural com &lt;code>llama_decode&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="6-exemplo-de-customização-avançada-manipulação-de-logits-e-controle-de-penalidade-com-c">6. Exemplo de Customização Avançada: Manipulação de Logits e Controle de Penalidade com C++
&lt;/h2>&lt;p>Se além da simples geração de texto você deseja forçar a saída de um formato específico (por exemplo, apenas JSON) ou quer controlar para evitar a geração de palavras proibidas específicas, você manipula diretamente os &lt;strong>Logits&lt;/strong> antes da amostragem no lado do C++.&lt;/p>
&lt;p>Você pode obter o array de pontuações brutas (valores antes de serem convertidos para probabilidades) de cada token imediatamente antes que o modelo o emita.&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Logo após a inferência e antes de realizar a amostragem, obter o array bruto de logits
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">float&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">logits&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_get_logits_ith&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_tokens&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="n">n_vocab&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_n_vocab&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">// Lista de IDs de tokens proibidos (por exemplo, 1234, 5678)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">llama_token&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">forbidden_tokens&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="mi">1234&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5678&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">// Define a probabilidade de um token proibido como 0 (o Logit vai para menos infinito)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_token&lt;/span> &lt;span class="nl">bad_tok&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">forbidden_tokens&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logits&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">bad_tok&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="n">INFINITY&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;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Dessa forma, usando a API C++ diretamente, uma &lt;strong>&amp;ldquo;intervenção em nível de microssegundo por ciclo de inferência&amp;rdquo;&lt;/strong> se torna possível, a qual pode ser muito difícil ou acarretar uma alta sobrecarga se feita via LangChain ou Python.&lt;/p>
&lt;hr>
&lt;h2 id="7-segredos-para-ajuste-de-desempenho">7. Segredos para Ajuste de Desempenho
&lt;/h2>&lt;p>Após concluir sua implementação em C++, apresentaremos alguns pontos de verificação para aumentar a velocidade ao limite para uma operação no mundo real.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Otimização de processamento em lote (Batching):&lt;/strong> Ao processar requisições de vários usuários simultaneamente, adicione múltiplas sequências no &lt;code>llama_batch&lt;/code> e chame &lt;code>llama_decode&lt;/code> de uma só vez (Continuous Batching). Isso permite compartilhar os acessos de memória, melhorando dramaticamente o throughput.&lt;/li>
&lt;li>&lt;strong>Ativando a Flash Attention:&lt;/strong>
Configurando &lt;code>ctx_params.flash_attn = true;&lt;/code> nos parâmetros de contexto, você pode acelerar os cálculos da Attention enquanto reduz o uso de memória. Esta é uma configuração obrigatória quando lidando com contextos longos (dezenas de milhares de tokens).&lt;/li>
&lt;li>&lt;strong>Suporte NUMA:&lt;/strong>
Em um ambiente de servidor multi-socket, você pode reduzir a latência de acesso à memória configurando corretamente as configurações NUMA antes do &lt;code>llama_backend_init()&lt;/code>.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-conclusão">8. Conclusão
&lt;/h2>&lt;p>Neste artigo, explicamos em detalhe desde a base matemática do &lt;code>llama.cpp&lt;/code> até a explicação de sua arquitetura, e como construir um motor de inferência customizado fazendo total uso da API em C++.&lt;/p>
&lt;p>O ecossistema Python é extremamente útil para prototipagem, mas em ambientes de produção que exigem implantações em dispositivos de borda, integração em jogos e processamento em tempo real, o controle direto do &lt;code>llama.cpp&lt;/code> baseado em C/C++ mostra um poder esmagador.&lt;/p>
&lt;p>Nós encorajamos fortemente que você tente escrever seu próprio código em C++ e experiencie a alegria de controlar e operar os LLMs livremente em seu ambiente local.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Lista de Links de Referência&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/llama.cpp" target="_blank" rel="noopener"
>llama.cpp Official Repository&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/ggml" target="_blank" rel="noopener"
>ggml - Tensor Library&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://arxiv.org/abs/1706.03762" target="_blank" rel="noopener"
>Attention Is All You Need (Vaswani et al., 2017)&lt;/a>&lt;/li>
&lt;/ul>
&lt;/blockquote></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>