<?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/es/tags/llm/</link><description>Recent content in LLM on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>es</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 11:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/es/tags/llm/index.xml" rel="self" type="application/rss+xml"/><item><title>Guía de uso de llama.cpp e introducción a la personalización en C++</title><link>http://kenji.blog/es/p/llama-cpp-cxx-customization/</link><pubDate>Fri, 11 Sep 2026 11:00:00 +0900</pubDate><guid>http://kenji.blog/es/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 Guía de uso de llama.cpp e introducción a la personalización en C++" />&lt;p>En los últimos años, la evolución de los Grandes Modelos de Lenguaje (LLM) ha sido asombrosa, y su ámbito de aplicación se expande día a día. Sin embargo, para ejecutar modelos con miles o decenas de miles de millones de parámetros en un entorno local, normalmente se requiere una GPU de gama alta con una enorme cantidad de VRAM. Quien ha derribado este &amp;ldquo;muro de hardware&amp;rdquo; y ha hecho posible la inferencia práctica de LLMs en PCs y Macs comunes, e incluso en dispositivos como Raspberry Pi, es &lt;strong>llama.cpp&lt;/strong>.&lt;/p>
&lt;p>En este artículo, no nos limitaremos a explicar cómo usar la herramienta de línea de comandos, sino que profundizaremos detalladamente para ingenieros en la arquitectura de su tecnología base &lt;code>ggml&lt;/code>, el trasfondo matemático de los Transformers y la cuantización, así como la forma de integrar y personalizar LLMs en aplicaciones propias utilizando la API de C++.&lt;/p>
&lt;hr>
&lt;h2 id="1-visión-general-de-llamacpp-y-ggml">1. Visión general de llama.cpp y ggml
&lt;/h2>&lt;p>&lt;code>llama.cpp&lt;/code> es un motor de inferencia de LLM ligero escrito en C/C++ desarrollado por Georgi Gerganov. Originalmente nació con el objetivo de ejecutar rápidamente el modelo LLaMA de Meta en Apple Silicon (M1/M2 Mac), pero en la actualidad soporta diversas arquitecturas y modelos.&lt;/p>
&lt;p>Su mayor característica es que es &lt;strong>una implementación pura en C/C++ sin dependencias externas&lt;/strong>. No requiere ecosistemas gigantescos como Python o PyTorch, y dado que se puede compilar como un único archivo ejecutable, su despliegue es sumamente sencillo.&lt;/p>
&lt;p>El corazón de este &lt;code>llama.cpp&lt;/code> es la biblioteca de operaciones con tensores &lt;strong>ggml&lt;/strong>. ggml está diseñada desde cero para optimizar al máximo las operaciones matriciales de aprendizaje automático en CPU (y algunas GPU).&lt;/p>
&lt;h3 id="11-por-qué-llamacpp-es-rápido">1.1 ¿Por qué llama.cpp es rápido?
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>Uso de mapeo de memoria (mmap)&lt;/strong>: Al cargar los pesos del modelo en memoria, se utiliza la función &lt;code>mmap&lt;/code> del sistema operativo, evitando cargar todo en la RAM y logrando un inicio rápido y un uso eficiente de la memoria.&lt;/li>
&lt;li>&lt;strong>Optimización exhaustiva de instrucciones SIMD&lt;/strong>: Se aprovechan los conjuntos de instrucciones específicos de la CPU como AVX2, AVX-512, ARM NEON y Apple AMX, acelerando exponencialmente la multiplicación de matrices.&lt;/li>
&lt;li>&lt;strong>Cuantización (Quantization)&lt;/strong>: Comprime los pesos de números de punto flotante de 16 bits (FP16) a enteros de 4, 5 u 8 bits, eliminando los cuellos de botella del ancho de banda de la memoria (se explicará en detalle más adelante).&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="2-trasfondo-matemático-transformer-y-cuantización-quantization">2. Trasfondo matemático: Transformer y Cuantización (Quantization)
&lt;/h2>&lt;p>Para comprender profundamente llama.cpp, es necesario conocer las fórmulas matemáticas que calcula y cómo aproxima dichos cálculos.&lt;/p>
&lt;h3 id="21-proceso-de-inferencia-del-transformer">2.1 Proceso de inferencia del Transformer
&lt;/h3>&lt;p>Modelos como LLaMA adoptan una arquitectura de decodificador Transformer de tipo autorregresivo (Auto-regressive). El núcleo de la generación de texto es el mecanismo de &lt;strong>Self-Attention&lt;/strong>.&lt;/p>
&lt;p>Para una matriz de estado oculto de entrada $X \in \mathbb{R}^{N \times d}$, la consulta $Q$ (Query), la clave $K$ (Key) y el valor $V$ (Value) se calculan mediante el producto con matrices de pesos.&lt;/p>
$$
Q = X W_Q, \quad K = X W_K, \quad V = X W_V
$$
&lt;p>Aquí, la salida de la Attention se define de la siguiente manera:&lt;/p>
$$
\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V
$$
&lt;p>En el bucle de inferencia de llama.cpp, el cuello de botella es el producto de estas enormes matrices $W_Q, W_K, W_V$ o la matriz de pesos de la red prealimentada (FFN) con el vector $X$ (en la fase de generación, como se procesa token por token, $N=1$), es decir, &lt;strong>GEMV (General Matrix-Vector Multiplication)&lt;/strong>.&lt;/p>
&lt;h3 id="22-fundamentos-matemáticos-de-la-cuantización">2.2 Fundamentos matemáticos de la Cuantización
&lt;/h3>&lt;p>En la inferencia donde el ancho de banda de acceso a memoria se convierte en el cuello de botella, la cuantización, que representa los parámetros de peso con un número reducido de bits, es indispensable. Explicaremos el principio básico de la cuantización por bloques (por ejemplo, &lt;code>Q4_K&lt;/code> o &lt;code>Q4_0&lt;/code>) ampliamente utilizada en llama.cpp.&lt;/p>
&lt;p>Por ejemplo, consideremos un bloque $w = [w_1, w_2, \dots, w_B]$ de longitud $B$ (generalmente 32 o 64) que es parte de la matriz de pesos FP16 $W$. Este bloque se aproxima a un entero de 4 bits $q_i \in [-8, 7]$ y un único factor de escala $\Delta$ (FP16 o FP32).&lt;/p>
$$
w_i \approx \Delta \times q_i
$$
&lt;p>$\Delta$ se determina en base al valor absoluto máximo dentro del bloque.&lt;/p>
$$
\Delta = \frac{\max_i |w_i|}{7}
$$
&lt;p>Al calcular el producto punto $y = w \cdot x$ utilizando los pesos cuantizados, si cuantizamos el vector de entrada $x$ de la misma manera como $x_i \approx \Delta_x \times q_{x, i}$, tenemos:&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 convierte en &lt;strong>aritmética puramente entera&lt;/strong>, y se puede calcular en paralelo a una velocidad altísima utilizando instrucciones SIMD. Este es el truco matemático por el cual llama.cpp logra velocidades sorprendentes en CPU.&lt;/p>
&lt;hr>
&lt;h2 id="3-arquitectura-y-flujo-de-inferencia">3. Arquitectura y flujo de inferencia
&lt;/h2>&lt;p>Para comprender el funcionamiento interno de llama.cpp, el siguiente diagrama de Mermaid muestra la arquitectura de todo el sistema y el flujo de datos.&lt;/p>
&lt;div class="mermaid">graph TD
A["Entrada del usuario (String)"] --> B["Tokenizer de llama.cpp"]
B --> C["IDs de tokens (Array de int32)"]
C --> D["Buffer de contexto (KV Cache)"]
D --> E["Grafo de computación de ggml"]
E --> F["Capas del Transformer"]
subgraph "Motor ggml"
F --> G["Self-Attention (RoPE)"]
G --> H["Red Neuronal Prealimentada (FFN)"]
H --> F
end
F --> I["Logits (Tamaño del Vocabulario)"]
I --> J["Muestreador (Temperature, Top-K, Top-P)"]
J --> K["ID del token seleccionado"]
K --> L["Detokenizer de llama.cpp"]
L --> M["Cadena de salida"]
K -. "Bucle autorregresivo" .-> D&lt;/div>
&lt;p>La generación de texto es un bucle autorregresivo donde, cada vez que se emite un token, este se añade a la KV Cache como la siguiente entrada y pasa nuevamente por el grafo de computación.&lt;/p>
&lt;hr>
&lt;h2 id="4-configuración-del-entorno-y-método-de-compilación">4. Configuración del entorno y método de compilación
&lt;/h2>&lt;p>Antes de integrar llama.cpp en un proyecto C++, primero intentemos compilar el código fuente.&lt;/p>
&lt;h3 id="41-clonar-el-repositorio">4.1 Clonar el repositorio
&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-compilación-usando-cmake">4.2 Compilación usando CMake
&lt;/h3>&lt;p>Para integrarlo como un proyecto C++ en otras aplicaciones, usar CMake es lo más estándar. Al habilitar los aceleradores (backends) específicos de la plataforma, se puede acelerar el cálculo.&lt;/p>
&lt;p>&lt;strong>Solo CPU (Compilación básica):&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>Al usar una GPU de NVIDIA (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>Al 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>Si la compilación es exitosa, se generarán archivos ejecutables como &lt;code>llama-cli&lt;/code> en el directorio &lt;code>build/bin/&lt;/code> y la biblioteca &lt;code>llama&lt;/code> (así como la biblioteca &lt;code>ggml&lt;/code>) para enlazar a través de la API de C++ descrita a continuación.&lt;/p>
&lt;hr>
&lt;h2 id="5-introducción-a-la-personalización-en-c-uso-de-la-api-de-llamacpp">5. Introducción a la personalización en C++: Uso de la API de llama.cpp
&lt;/h2>&lt;p>A partir de aquí, explicaremos el tema principal: el control de llama.cpp desde código en C++.
Para integrar un LLM en tu propia aplicación (por ejemplo, motores de juegos, aplicaciones de escritorio, sistemas integrados, etc.), más allá de usar la herramienta de línea de comandos, es necesario llamar directamente a la API de C++.&lt;/p>
&lt;p>llama.cpp proporciona principalmente una interfaz en lenguaje C a través del archivo de cabecera &lt;code>llama.h&lt;/code>. Esta interfaz también se utiliza cuando se llama desde C++.&lt;/p>
&lt;h3 id="51-inclusiones-y-configuraciones-mínimas-necesarias">5.1 Inclusiones y configuraciones mínimas necesarias
&lt;/h3>&lt;p>Al usar llama.cpp en tu propio proyecto, incluye lo siguiente:&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 el manejo de errores
&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-carga-del-modelo-e-inicialización-del-contexto">5.2 Carga del modelo e inicialización del contexto
&lt;/h3>&lt;p>Primero, cargamos un archivo de modelo en formato &lt;code>.gguf&lt;/code> y reservamos el contexto (espacio de memoria y KV cache) para la inferencia.&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. Inicialización del backend (Configuración del entorno para 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. Obtener la configuración por defecto de los parámetros del 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 capas a descargar en la 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. Carga del 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. Configuración de los parámetros del 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">// Tamaño máximo de contexto (número 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="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 hilos de CPU utilizados para la inferencia
&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. Creación del 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">// ... Procesamiento subsiguiente
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="53-tokenización-de-la-solicitud-tokenization">5.3 Tokenización de la solicitud (Tokenization)
&lt;/h3>&lt;p>Los LLMs no entienden el texto directamente, sino que lo procesan como una secuencia de IDs enteros (tokens). Es necesario convertir la cadena de entrada en 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: ¿Cuál es la capital de Japón?&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">// Tamaño del buffer con un margen extra
&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">// Si añadir o no tokens especiales (BOS: Begin of Sequence, etc.) al principio
&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">// Convertir la cadena en un 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">// Lógica necesaria para reasignar y reintentar si el buffer es insuficiente (omitido por simplicidad)
&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-bucle-de-inferencia-y-muestreo">5.4 Bucle de inferencia y muestreo
&lt;/h3>&lt;p>Construiremos un bucle que introduce tokens en el modelo, obtiene la distribución de probabilidades (Logits) del siguiente token, realiza el muestreo y determina el siguiente 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 generar
&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 la estructura para la evaluación por lotes (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">// Añadir los tokens del prompt al 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 emitir los logits (resultados de la predicción) solo en el último token del 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">// Primera evaluación (alimentar el modelo con el 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">// Longitud de contexto actual
&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">// Inicialización del contexto del muestreador (configuración de 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 semilla (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. Muestreo: Predecir el siguiente token basado en el contexto actual
&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. Terminar el bucle si el token es EOS (End of Sequence)
&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 el token a una cadena (texto) para mostrarlo
&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 el token recién generado como el siguiente 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_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. Evaluación del modelo (Actualizar la KV cache y predecir lo siguiente)
&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">// Limpieza (Cleanup)
&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 un bucle de inferencia personalizado utilizando la API básica de llama.cpp.
Utiliza la estructura &lt;code>llama_batch&lt;/code> para gestionar el grupo de tokens y &lt;code>llama_decode&lt;/code> para ejecutar el pase hacia adelante (forward pass) de la red neuronal.&lt;/p>
&lt;hr>
&lt;h2 id="6-caso-de-personalización-avanzada-manipulación-de-logits-y-control-de-penalizaciones-en-c">6. Caso de personalización avanzada: Manipulación de Logits y control de penalizaciones en C++
&lt;/h2>&lt;p>Para no limitarse a la simple generación de texto y, en su lugar, forzar un formato de salida específico (por ejemplo, solo JSON) o evitar la aparición de ciertas palabras prohibidas, manipulamos directamente los &lt;strong>Logits&lt;/strong> en C++ antes del muestreo.&lt;/p>
&lt;p>Se puede obtener el array de puntuaciones en bruto (los valores antes de convertirse en probabilidades) justo antes de que el modelo emita cada 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;/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">// Obtener el array de logits en bruto después de la inferencia y antes de realizar el muestreo
&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 prohibidos (por ejemplo, 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">// Establecer la probabilidad de aparición de los tokens prohibidos a 0 (Logit a 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>De esta manera, al interactuar directamente con la API de C++, se hace posible una &lt;strong>&amp;ldquo;intervención a nivel de micro o milisegundos en cada ciclo de inferencia&amp;rdquo;&lt;/strong>, lo cual sería difícil de lograr o tendría una gran sobrecarga (overhead) si se hiciera a través de LangChain o Python.&lt;/p>
&lt;hr>
&lt;h2 id="7-los-secretos-del-ajuste-de-rendimiento-performance-tuning">7. Los secretos del ajuste de rendimiento (Performance Tuning)
&lt;/h2>&lt;p>Después de completar la implementación en C++, presentamos algunos puntos de control para llevar la velocidad al límite en un entorno de producción.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Optimización del procesamiento por lotes (Batching):&lt;/strong> Cuando se procesan simultáneamente peticiones de múltiples usuarios, se puede incluir múltiples secuencias en el &lt;code>llama_batch&lt;/code> y llamar a &lt;code>llama_decode&lt;/code> a la vez (Continuous Batching). Esto permite compartir el acceso a la memoria y aumentar dramáticamente el rendimiento (throughput).&lt;/li>
&lt;li>&lt;strong>Habilitación de Flash Attention:&lt;/strong>
Configurando &lt;code>ctx_params.flash_attn = true;&lt;/code> en los parámetros de contexto, se puede reducir el uso de memoria a la vez que se acelera el cálculo de Attention. Es una configuración indispensable cuando se manejan contextos largos (decenas de miles de tokens).&lt;/li>
&lt;li>&lt;strong>Soporte NUMA:&lt;/strong>
En entornos de servidor de múltiples sockets, realizar una configuración NUMA adecuada antes de &lt;code>llama_backend_init()&lt;/code> permite reducir la latencia de acceso a la memoria.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-conclusión">8. Conclusión
&lt;/h2>&lt;p>En este artículo, hemos detallado desde el trasfondo matemático de &lt;code>llama.cpp&lt;/code> y la explicación de su arquitectura, hasta cómo construir un motor de inferencia personalizado aprovechando la API de C++.&lt;/p>
&lt;p>El ecosistema de Python es muy útil para prototipos, pero en entornos de producción que requieren despliegue en dispositivos edge, integración en juegos y procesamiento en tiempo real, el control directo basado en C/C++ de &lt;code>llama.cpp&lt;/code> muestra un poder abrumador.&lt;/p>
&lt;p>Te animamos a que escribas código C++ por ti mismo y experimentes la diversión de controlar un LLM libremente en tu entorno local.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Enlaces de referencia&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/llama.cpp" target="_blank" rel="noopener"
>Repositorio Oficial de llama.cpp&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>【Último en 2026】Guía completa para ejecutar LLM locales en un entorno Windows</title><link>http://kenji.blog/es/p/local-llm-windows-2026/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/es/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 【Último en 2026】Guía completa para ejecutar LLM locales en un entorno Windows" />&lt;h1 id="1-introducción-por-qué-llm-locales-en-windows-ahora">1. Introducción: ¿Por qué LLM locales en Windows ahora?
&lt;/h1>&lt;p>En 2026, la evolución de la IA generativa y los Grandes Modelos de Lenguaje (LLM) muestra un cambio de paradigma importante: desde servicios API gigantes en la nube hasta &amp;ldquo;LLM locales&amp;rdquo; que se ejecutan en PCs personales y entornos on-premise. Aunque las IA en la nube como GPT-5 de OpenAI o Claude 3.5 de Anthropic son extremadamente potentes, no todas las empresas o individuos pueden enviar todos sus datos a la nube. Desde el punto de vista de la privacidad, seguridad, latencia y los costes sostenibles a largo plazo, la demanda de LLM locales ha crecido explosivamente como nunca antes.&lt;/p>
&lt;p>Especialmente en el entorno Windows, la evolución del ecosistema de LLM locales es notable. Hasta hace unos años, el sentido común dictaba que &amp;ldquo;el desarrollo y la ejecución de IA significaba Linux&amp;rdquo;, pero en 2026 Windows se ha transformado en una plataforma de IA extremadamente potente y accesible.&lt;/p>
&lt;p>Este artículo, basado en las últimas tendencias tecnológicas de 2026, proporciona una guía completa para construir, operar y optimizar un LLM local en un entorno Windows. Cubriremos exhaustivamente desde una configuración simple con Ollama para principiantes, hasta una optimización extrema usando llama.cpp para usuarios avanzados, además de profundizar en el enfoque matemático del cálculo de VRAM, una comprensión profunda de la arquitectura y el fine-tuning local.&lt;/p>
&lt;h2 id="11-tendencias-tecnológicas-que-rodean-a-los-llm-locales-en-2026">1.1 Tendencias tecnológicas que rodean a los LLM locales en 2026
&lt;/h2>&lt;p>Las principales tendencias que conforman el ecosistema actual de los LLM locales son las siguientes:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Adopción total del formato GGUF&lt;/strong>: El GGUF (GPT-Generated Unified Format), que integra metadatos y tensores en un solo archivo, se ha convertido en el estándar de facto. Esto permite que con solo descargar un archivo desde Hugging Face, se pueda ejecutar en cualquier entorno.&lt;/li>
&lt;li>&lt;strong>Democratización de la arquitectura MoE (Mixture of Experts)&lt;/strong>: Se han lanzado numerosos modelos MoE de pequeña escala pero de alto rendimiento, que al activar solo ciertos expertos durante la inferencia, logran un rendimiento comparable al de modelos gigantes mientras mantienen bajo el uso de computación en PCs de consumo.&lt;/li>
&lt;li>&lt;strong>Abstracción y optimización avanzadas de los motores de inferencia&lt;/strong>: Herramientas como Ollama, LM Studio y AnythingLLM se han perfeccionado, eliminando la necesidad de que los usuarios se preocupen por dependencias complejas como la instalación de controladores CUDA. Además, el soporte nativo de FlashAttention 3 en Windows ha mejorado drásticamente la velocidad de inferencia.&lt;/li>
&lt;li>&lt;strong>Utilización de NPU y el auge de las PC Windows Copilot+&lt;/strong>: Incluso en laptops sin GPU, la tecnología para ejecutar pequeños LLM (SLM: Small Language Models) con bajo consumo energético utilizando la NPU (Neural Processing Unit) integrada ha alcanzado una etapa práctica.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="2-requisitos-de-hardware-y-preparación-del-so">2. Requisitos de hardware y preparación del SO
&lt;/h1>&lt;p>Para ejecutar un LLM local a una velocidad práctica (más de 15-30 tokens por segundo), la selección del hardware es lo más importante.&lt;/p>
&lt;h2 id="21-configuración-de-hardware-recomendada">2.1 Configuración de hardware recomendada
&lt;/h2>&lt;p>Con la evolución de los PC con IA, las especificaciones requeridas también están cambiando.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>SO&lt;/strong>: Windows 11 Pro (24H2 o posterior). Indispensable para utilizar las funcionalidades completas de WSL2, la gestión avanzada de memoria y las últimas API de DirectML.&lt;/li>
&lt;li>&lt;strong>CPU&lt;/strong>: Intel Core Ultra serie 200 o superior, o AMD Ryzen serie 9000 o superior. Si se utiliza la inferencia por CPU de forma combinada, es esencial una comunicación de memoria de gran ancho de banda.&lt;/li>
&lt;li>&lt;strong>RAM&lt;/strong>: Mínimo 32 GB, recomendado 64 GB o más. El ancho de banda de la memoria principal (MB/s) se convierte en el cuello de botella decisivo durante la inferencia por CPU o la descarga (offloading). Una memoria rápida como DDR5-6000 o superior es ideal.&lt;/li>
&lt;li>&lt;strong>GPU&lt;/strong>: NVIDIA RTX serie 4000/5000. Lo más importante en los LLM locales no es el rendimiento de cálculo, sino la &amp;ldquo;capacidad de VRAM&amp;rdquo;.
&lt;ul>
&lt;li>&lt;strong>Entrada&lt;/strong>: RTX 4060 Ti (versión de 16 GB) - La mejor relación calidad-precio. Ideal para modelos de clase 8B a 14B.&lt;/li>
&lt;li>&lt;strong>Gama media&lt;/strong>: RTX 4070 Ti SUPER (16 GB) / RTX 4080 SUPER (16 GB)&lt;/li>
&lt;li>&lt;strong>Gama alta&lt;/strong>: RTX 4090 (24 GB) / RTX 5090 (32 GB) - Necesaria para ejecutar modelos cuantizados de clase 30B a 70B.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Almacenamiento&lt;/strong>: NVMe SSD PCIe Gen4 o Gen5. Reduce drásticamente el tiempo de carga de modelos de decenas de GB.&lt;/li>
&lt;/ul>
&lt;h2 id="22-configuración-de-wsl2-windows-subsystem-for-linux-2">2.2 Configuración de WSL2 (Windows Subsystem for Linux 2)
&lt;/h2>&lt;p>Aunque muchas herramientas GUI funcionan de forma nativa en Windows, WSL2 es muy útil para el desarrollo con Python, la compilación de las últimas herramientas y el fine-tuning LoRA que veremos más adelante. En los entornos modernos de Windows 11, simplemente instalando el controlador NVIDIA en el host, la GPU (CUDA) se puede utilizar de forma transparente desde WSL2.&lt;/p>
&lt;p>Abre PowerShell con privilegios de administrador y ejecuta lo siguiente:&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"># Instalación de WSL2 y el último Ubuntu&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"># Actualización del 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>Después de la instalación, ejecuta &lt;code>nvidia-smi&lt;/code> dentro de la terminal de WSL2. Si la GPU se reconoce correctamente, ha sido un éxito.&lt;/p>
&lt;hr>
&lt;h1 id="3-arquitectura-del-llm-local-y-mecanismo-de-inferencia">3. Arquitectura del LLM local y mecanismo de inferencia
&lt;/h1>&lt;p>Comprender cómo el modelo genera texto en un entorno local y su estructura interna es extremadamente útil para la resolución de problemas y la optimización.&lt;/p>
&lt;p>El siguiente diagrama Mermaid muestra la ruta de inferencia típica de un LLM local.&lt;/p>
&lt;div class="mermaid">graph TD
User["Entrada del usuario (Prompt)"] --> Tokenizer["Tokenizador (Tokenizer)"]
Tokenizer --> Embedding["Capa de incrustación (Embedding)"]
subgraph "Bloque Transformer (x Capas)"
Embedding --> Attn["Auto-atención (Self-Attention)"]
Attn --> KVCache["Caché KV (Retención Key/Value)"]
Attn --> FFN["Red feed-forward (FFN)"]
end
FFN --> Logits["Cálculo de logits (Logits)"]
Logits --> Sampler["Muestreador (Temperature, Top-K, Top-P)"]
Sampler --> OutputToken["Token de salida"]
OutputToken --> |"Generación autorregresiva"| Tokenizer
OutputToken --> Decoder["Detokenizador (Detokenizer)"]
Decoder --> FinalOutput["Texto de salida final"]&lt;/div>
&lt;h2 id="31-dos-fases-prefill-y-decode">3.1 Dos fases: Prefill y Decode
&lt;/h2>&lt;p>La generación de texto por parte de un LLM se divide en dos fases con diferentes características computacionales:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Fase de Prefill (Procesamiento del prompt)&lt;/strong>: Fase en la que todo el prompt introducido se procesa y comprende a la vez. Dado que es posible el cálculo paralelo, la capacidad de cálculo de la GPU (FLOPS) está directamente relacionada con la velocidad. Si el prompt es largo, esta fase puede tardar varios segundos.&lt;/li>
&lt;li>&lt;strong>Fase de Decode (Generación de tokens)&lt;/strong>: Fase en la que se predice un token a la vez y se pasa a la siguiente entrada (autorregresiva). Dado que el cálculo paralelo está limitado en esta fase, el ancho de banda de la VRAM (Memory Bandwidth) de la GPU se convierte en un cuello de botella decisivo.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="4-cálculo-del-consumo-de-vram-y-comprensión-matemática-del-tamaño-del-modelo">4. Cálculo del consumo de VRAM y comprensión matemática del tamaño del modelo
&lt;/h1>&lt;p>Para determinar correctamente &amp;ldquo;qué modelos pueden ejecutarse en mi PC&amp;rdquo;, es necesario comprender la fórmula para calcular la VRAM. Cuando ocurre un fallback hacia la memoria del sistema (RAM) debido a la falta de VRAM, la velocidad de inferencia se ralentiza de 10 a 100 veces.&lt;/p>
&lt;h2 id="41-vram-base-según-el-tamaño-de-los-parámetros">4.1 VRAM base según el tamaño de los parámetros
&lt;/h2>&lt;p>Esta es la cantidad de memoria requerida para cargar los pesos (weights) del modelo en la VRAM.
Se calcula usando el tamaño del modelo $P$ (número de parámetros, unidad: 1000 millones = 1B) y el número de bytes por parámetro $B$.&lt;/p>
$$
V_{base} = P \times B \quad \text{(GB)}
$$
&lt;p>Por ejemplo, al cargar un modelo de parámetros 8B (8 mil millones) en FP16 (punto flotante de media precisión, 16 bits = 2 bytes):&lt;/p>
$$
V_{base} = 8 \times 2 = 16 \text{ GB}
$$
&lt;p>En otras palabras, incluso con una GPU de 16 GB de VRAM, se llega casi al límite solo con cargar el modelo.&lt;/p>
&lt;h2 id="42-la-magia-de-la-cuantización-quantization">4.2 La magia de la cuantización (Quantization)
&lt;/h2>&lt;p>Aquí es donde entra en juego la &amp;ldquo;cuantización&amp;rdquo;. Al reducir la precisión de los parámetros, el tamaño del modelo se reduce drásticamente. En el caso más común de la cuantización de 4 bits (ej: Q4_K_M), el promedio es de aproximadamente 0.55 bytes por parámetro.&lt;/p>
$$
V_{base\_4bit} = 8 \times 0.55 = 4.4 \text{ GB}
$$
&lt;p>Gracias a esto, si se tienen 16 GB de VRAM, se puede ejecutar un modelo 8B con mucho margen.&lt;/p>
&lt;h2 id="43-cálculo-de-la-caché-kv-versión-compatible-con-gqa">4.3 Cálculo de la caché KV (Versión compatible con GQA)
&lt;/h2>&lt;p>Durante la inferencia, la &amp;ldquo;caché KV&amp;rdquo;, que retiene el contexto pasado, consume VRAM. En los modelos más recientes como Llama 3, se adopta GQA (Grouped Query Attention) para ahorrar memoria.&lt;/p>
&lt;p>El consumo de la caché KV $V_{kv}$ (en gigabytes) se expresa mediante la siguiente fórmula matemática:&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, se puede calcular fácilmente usando el número de cabezales (heads) de Key y Value $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>Donde:&lt;/p>
&lt;ul>
&lt;li>$b$: Tamaño del lote (normalmente 1 para uso personal y local)&lt;/li>
&lt;li>$s$: Longitud de la secuencia (longitud del contexto, ej: 8192)&lt;/li>
&lt;li>$l$: Número de capas (ej: 32)&lt;/li>
&lt;li>$h_{kv}$: Número de cabezales KV (ej: 8)&lt;/li>
&lt;li>$d$: Número de dimensiones por cabezal (ej: 128)&lt;/li>
&lt;li>$B_{kv}$: Número de bytes de la caché KV (2 para FP16)&lt;/li>
&lt;/ul>
&lt;p>Ejemplo de cálculo (Llama 3 8B, contexto 8192, caché 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>Tenga en cuenta que cuanto mayor sea la longitud del contexto $s$, la VRAM requerida aumentará de forma lineal.&lt;/p>
&lt;hr>
&lt;h1 id="5-práctica-1-configuración-más-rápida-y-corta-usando-ollama">5. Práctica 1: Configuración más rápida y corta usando Ollama
&lt;/h1>&lt;p>Una vez entendida la teoría, ejecutemos un LLM en el entorno Windows.
En 2026, la herramienta más amigable para el usuario es &amp;ldquo;Ollama&amp;rdquo;. Proporciona una CLI intuitiva tipo Docker.&lt;/p>
&lt;h2 id="51-instalación-y-ejecución">5.1 Instalación y ejecución
&lt;/h2>&lt;ol>
&lt;li>Descarga el instalador para Windows desde el &lt;a class="link" href="https://ollama.com/" target="_blank" rel="noopener"
>sitio web oficial de Ollama&lt;/a> y ejecútalo.&lt;/li>
&lt;li>Abre PowerShell e introduce el siguiente comando. Aquí usaremos &lt;code>llama3:8b&lt;/code>, que soporta 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>En la primera ejecución, se descargará el modelo. Una vez finalizado, podrás interactuar directamente en la terminal.&lt;/p>
&lt;h2 id="52-creación-de-una-ia-personalizada-mediante-modelfile">5.2 Creación de una IA personalizada mediante Modelfile
&lt;/h2>&lt;p>Puedes crear fácilmente una IA con una personalidad específica. Crea un &lt;code>Modelfile&lt;/code> en cualquier ubicación.&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">Eres un ingeniero de software senior muy talentoso.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Al responder a las preguntas de los usuarios, debes incluir siempre ejemplos de código y responder de forma lógica y 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>Ejecuta el siguiente comando para compilar y ejecutar tu propio 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;/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-uso-desde-aplicaciones-externas-editores-de-ia">5.3 Uso desde aplicaciones externas (Editores de IA)
&lt;/h2>&lt;p>Ollama expone un punto de conexión de la API compatible con OpenAI en &lt;code>http://localhost:11434&lt;/code>.
Simplemente configurando esta URL en los ajustes de backend de extensiones de VS Code como Cursor o Continue.dev y especificando un modelo como &lt;code>SeniorDev&lt;/code>, obtendrás un potente asistente de programación local y gratuito.&lt;/p>
&lt;hr>
&lt;h1 id="6-práctica-2-ajuste-de-rendimiento-extremo-con-llamacpp">6. Práctica 2: Ajuste de rendimiento extremo con llama.cpp
&lt;/h1>&lt;p>Si quieres probar opciones como una gestión detallada de la memoria o los últimos formatos (EXL2, cuantización IQ, etc.) lo antes posible, interactúa directamente con el motor central, &lt;code>llama.cpp&lt;/code>.&lt;/p>
&lt;h2 id="61-pasos-para-compilar-llamacpp">6.1 Pasos para compilar llama.cpp
&lt;/h2>&lt;p>En un entorno Windows, lo mejor es compilar desde el código fuente utilizando CUDA Toolkit y 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 para CUDA y compilar&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-inicio-avanzado-en-modo-servidor">6.2 Inicio avanzado en modo servidor
&lt;/h2>&lt;p>Utiliza el ejecutable &lt;code>llama-server.exe&lt;/code> compilado para alojar el 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>: Descarga (offload) todas las capas posibles a la VRAM de la GPU.&lt;/li>
&lt;li>&lt;code>--flash-attn&lt;/code>: Habilita FlashAttention 3, logrando una mejora en la velocidad de inferencia y una reducción en el consumo de VRAM por parte de la caché KV.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="7-interfaz-gráfica-gui-construcción-de-lm-studio-y-rag-local">7. Interfaz gráfica (GUI): Construcción de LM Studio y RAG local
&lt;/h1>&lt;p>Si no te sientes cómodo con la línea de comandos o si deseas realizar RAG (Generación Aumentada por Recuperación) de manera intuitiva, puedes usar una GUI.&lt;/p>
&lt;h2 id="71-lm-studio">7.1 LM Studio
&lt;/h2>&lt;p>LM Studio es una excelente aplicación que integra la búsqueda y descarga de modelos, verificación previa de los requisitos del sistema y una interfaz de chat. Simplemente con presionar el botón &amp;ldquo;Local Server&amp;rdquo; en la aplicación, se levantará una API compatible con OpenAI.&lt;/p>
&lt;h2 id="72-arquitectura-rag-usando-anythingllm">7.2 Arquitectura RAG usando AnythingLLM
&lt;/h2>&lt;p>Este es un diagrama de la arquitectura de un entorno RAG para cargar documentos internos o notas personales.&lt;/p>
&lt;div class="mermaid">graph LR
Document["Documentos (PDF, MD)"] --> Chunking["División en fragmentos (Chunking)"]
Chunking --> EmbedModel["Modelo de incrustación (Embedding)"]
EmbedModel --> VectorDB["Base de datos vectorial"]
UserQuery["Consulta del usuario"] --> EmbedQuery["Incrustación de la consulta"]
EmbedQuery --> VectorDB
VectorDB --> |"Búsqueda de similitud"| RetrievedDocs["Extracción de documentos relevantes"]
UserQuery --> PromptBuilder["Generador de prompts"]
RetrievedDocs --> PromptBuilder
PromptBuilder --> LocalLLM["LLM local"]
LocalLLM --> Answer["Respuesta final"]&lt;/div>
&lt;p>Si usas la versión de escritorio de AnythingLLM (Windows), simplemente configurando Ollama (LLM y Embedding) desde la pantalla de configuración y utilizando la VectorDB local (LanceDB), esta arquitectura se completará en minutos. Así nace una IA privada que no envía ningún dato al exterior.&lt;/p>
&lt;hr>
&lt;h1 id="8-fine-tuning-en-windows-wsl2-lora">8. Fine-tuning en Windows WSL2 (LoRA)
&lt;/h1>&lt;p>Si además de ejecutarlo localmente quieres que el modelo sea más inteligente con tus propios datos, es posible realizar fine-tuning mediante LoRA (Low-Rank Adaptation). En 2026, utilizando la biblioteca &amp;ldquo;Unsloth&amp;rdquo;, se puede completar el entrenamiento de un modelo 8B en unas pocas horas en un entorno WSL2 de Windows, incluso con 16 GB de VRAM.&lt;/p>
&lt;p>Ejecuta lo siguiente dentro de Ubuntu en WSL2 para preparar el entorno:&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>Unsloth optimiza los núcleos CUDA al extremo, y en comparación con la biblioteca estándar de Hugging Face, la velocidad de entrenamiento es aproximadamente el doble, mientras que el consumo de VRAM se reduce a la mitad. Al abrir un Jupyter Notebook y cargar un conjunto de datos (formato JSONL), el entrenamiento de varias épocas es posible incluso en una RTX 4060 Ti con 12 GB-16 GB de VRAM.&lt;/p>
&lt;hr>
&lt;h1 id="9-resolución-de-problemas-de-rendimiento">9. Resolución de problemas de rendimiento
&lt;/h1>&lt;p>Estos son los problemas más frecuentes a los que te puedes enfrentar y sus soluciones.&lt;/p>
&lt;h3 id="1-la-velocidad-de-inferencia-es-extremadamente-lenta-1-2-tokenss">1. La velocidad de inferencia es extremadamente lenta (1-2 tokens/s)
&lt;/h3>&lt;p>&lt;strong>Causa&lt;/strong>: El modelo no cabe en la VRAM y se está descargando (offloading) a la memoria del sistema (RAM).
&lt;strong>Solución&lt;/strong>: Verifica la &amp;ldquo;Memoria dedicada de la GPU&amp;rdquo; en el Administrador de tareas. Si se ha alcanzado el límite, reduce el tamaño del contexto (&lt;code>-c&lt;/code>) o utiliza un modelo con cuantización de menos bits (como Q4_K_M).&lt;/p>
&lt;h3 id="2-error-de-cuda-out-of-memory">2. Error de &amp;ldquo;CUDA out of memory&amp;rdquo;
&lt;/h3>&lt;p>&lt;strong>Causa&lt;/strong>: La VRAM se ha agotado por completo. Esto ocurre especialmente cuando la interacción se prolonga y la caché KV aumenta de tamaño.
&lt;strong>Solución&lt;/strong>: Limita intencionadamente el valor de &lt;code>num_ctx&lt;/code> en el caso de Ollama, o de &lt;code>-c&lt;/code> en el caso de llama.cpp a un número menor.&lt;/p>
&lt;h3 id="3-la-generación-en-japonés-u-otro-idioma-es-extraña">3. La generación en japonés (u otro idioma) es extraña
&lt;/h3>&lt;p>&lt;strong>Causa&lt;/strong>: Incompatibilidad en la plantilla del prompt, o el modelo no es compatible.
&lt;strong>Solución&lt;/strong>: Asegúrate de usar un modelo que contenga &lt;code>Instruct&lt;/code> en su nombre y verifica que la herramienta tenga seleccionada la plantilla correcta especificada por el creador del modelo, como el formato ChatML o Llama3.&lt;/p>
&lt;hr>
&lt;h1 id="10-conclusión-y-perspectivas-de-futuro">10. Conclusión y perspectivas de futuro
&lt;/h1>&lt;p>En 2026, la construcción de un LLM local en un entorno Windows ya no es un privilegio reservado para unos pocos ingenieros. Gracias a la estandarización del formato GGUF, la aparición de ecosistemas sofisticados como Ollama o LM Studio y las optimizaciones de hardware como FlashAttention, cualquier persona puede obtener fácilmente un entorno de IA de nivel empresarial.&lt;/p>
&lt;p>Aprovecha los siguientes puntos explicados en este artículo:&lt;/p>
&lt;ol>
&lt;li>Elegir lógicamente el tamaño del modelo y el nivel de cuantización óptimos para las especificaciones de tu PC utilizando el &lt;strong>cálculo matemático de la VRAM&lt;/strong>.&lt;/li>
&lt;li>Construir el entorno lo más rápido posible con &lt;strong>Ollama&lt;/strong> y mejorar drásticamente la productividad vinculándolo con un editor de IA.&lt;/li>
&lt;li>Extraer el rendimiento límite del hardware mediante el control avanzado de parámetros en &lt;strong>llama.cpp&lt;/strong>.&lt;/li>
&lt;li>Construir un sistema RAG local y seguro para manejar datos confidenciales con &lt;strong>AnythingLLM&lt;/strong>.&lt;/li>
&lt;li>Fomentar tu propia IA personalizada con conocimientos especializados aprovechando &lt;strong>Unsloth (WSL2)&lt;/strong>.&lt;/li>
&lt;/ol>
&lt;p>La &amp;ldquo;democratización&amp;rdquo; de la IA ya no es una palabra de moda; es un sistema real que funciona en tu escritorio de Windows. Libérate de los costes de uso de API en la nube y los riesgos de filtración de información, e ingresa hoy mismo al poderoso y libre mundo de la IA privada.&lt;/p></description></item></channel></rss>