<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Local AI on kenji.blog</title><link>http://kenji.blog/ru/tags/local-ai/</link><description>Recent content in Local AI on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ru</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 16:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/ru/tags/local-ai/index.xml" rel="self" type="application/rss+xml"/><item><title>Как быстрее всего настроить TinyLLaMA в локальной (on-premises) среде</title><link>http://kenji.blog/ru/p/tinyllama-on-premises-fast-tuning-guide/</link><pubDate>Fri, 11 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/ru/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 Как быстрее всего настроить TinyLLaMA в локальной (on-premises) среде" />&lt;h2 id="1-введение-почему-именно-сейчас-tinyllama-и-локальная-среда">1. Введение: Почему именно сейчас TinyLLaMA и локальная среда?
&lt;/h2>&lt;p>Эволюция больших языковых моделей (LLM) идет с невероятной скоростью, и вместе с этим количество параметров моделей продолжает разрастаться до сотен миллиардов. Хотя сверхгигантские модели, такие как GPT-4 и Claude 3, обладают непревзойденной производительностью, вычислительные затраты на инференс и обучение, а также проблемы безопасности и конфиденциальности данных при использовании внешних API стали серьезным препятствием для бизнеса. В частности, при работе с высококонфиденциальными внутренними данными компании или личной информацией, отправка данных в публичные API LLM в облаке часто недопустима с точки зрения соблюдения нормативных требований (таких как GDPR, APPI и др.).&lt;/p>
&lt;p>Именно поэтому в центре внимания оказались &lt;strong>малые языковые модели (SLM: Small Language Models)&lt;/strong> и &lt;strong>локальная эксплуатация в on-premises среде&lt;/strong>. Среди них «&lt;strong>TinyLLaMA&lt;/strong>» при компактном размере всего 1.1B (1,1 миллиарда) параметров была предварительно обучена на огромном наборе данных объемом около 3 триллионов токенов, демонстрируя поразительную производительность по сравнению с моделями того же класса.&lt;/p>
&lt;p>В этой статье мы представляем полное руководство по файнтюнингу (тонкой настройке) TinyLLaMA в локальной среде (на локальном сервере или рабочей станции) «максимально быстро и эффективно» для ваших собственных специализированных задач. Мы всесторонне рассмотрим всё: от математических основ до новейших технологий оптимизации и конкретного кода реализации на PyTorch.&lt;/p>
&lt;hr>
&lt;h2 id="2-архитектура-и-особенности-tinyllama">2. Архитектура и особенности TinyLLaMA
&lt;/h2>&lt;p>TinyLLaMA следует архитектуре LLaMA (Large Language Model Meta AI), разработанной компанией Meta. При ограничении количества параметров до 1.1B она использует тот же технологический стек, что и LLaMA 2, что обеспечивает ей чрезвычайно высокую совместимость в экосистеме.&lt;/p>
&lt;h3 id="основные-компоненты-архитектуры">Основные компоненты архитектуры
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>RMSNorm (Root Mean Square Normalization):&lt;/strong>
Это метод нормализации, который опускает вычитание среднего значения из традиционного вычисления LayerNorm, тем самым повышая эффективность вычислений. Это увеличивает пропускную способность при сохранении стабильности обучения.&lt;/li>
&lt;li>&lt;strong>Функция активации SwiGLU:&lt;/strong>
В сети прямого распространения (Feed Forward Network, FFN) вместо традиционных ReLU или GELU используется SwiGLU. Математически это выражается следующим образом:
$$ \text{SwiGLU}(x, W, V) = \text{Swish}(xW) \otimes (xV) $$
Здесь $\otimes$ обозначает поэлементное произведение (произведение Адамара), а функция Swish — это $\text{Swish}(z) = z \cdot \sigma(\beta z)$. Это значительно повышает выразительность.&lt;/li>
&lt;li>&lt;strong>RoPE (Rotary Position Embedding):&lt;/strong>
Это метод, сочетающий преимущества абсолютного и относительного позиционного кодирования. Он обладает высокой обобщающей способностью даже при увеличении длины последовательности.&lt;/li>
&lt;li>&lt;strong>Grouped Query Attention (GQA):&lt;/strong>
Это промежуточный подход между Multi-Head Attention (MHA) и Multi-Query Attention (MQA), который значительно увеличивает скорость инференса и экономит пропускную способность памяти за счет группировки голов ключей (key) и значений (value).&lt;/li>
&lt;/ol>
&lt;p>Следующая диаграмма Mermaid показывает общий поток данных TinyLLaMA и структуру блока Transformer.&lt;/p>
&lt;div class="mermaid">graph TD
A["Входной текст"] --> B["Токенизатор (BPE)"]
B --> C["Слой Embedding"]
C --> D["Блоки Transformer (x22 слоя для TinyLLaMA)"]
D --> E["RMSNorm (Финальный)"]
E --> F["Линейная проекция (Размер словаря)"]
F --> G["Выходные вероятности (Softmax)"]
subgraph "Анатомия блока Transformer"
D1["Входное скрытое состояние"] --> D2["RMSNorm"]
D2 --> D3["Grouped Query Attention (GQA)"]
D3 --> D4["Остаточное сложение (Residual Add)"]
D4 --> D5["RMSNorm"]
D5 --> D6["SwiGLU FFN"]
D6 --> D7["Остаточное сложение (Residual Add)"]
D7 --> D8["Выход на следующий слой"]
D1 -.-> D4
D4 -.-> D7
end&lt;/div>
&lt;hr>
&lt;h2 id="3-прорыв-в-файнтюнинге-lora-и-qlora">3. Прорыв в файнтюнинге: LoRA и QLoRA
&lt;/h2>&lt;p>Для выполнения полного файнтюнинга параметров в локальной среде, даже для модели 1.1B, требуются десятки гигабайт видеопамяти (VRAM) для хранения состояний оптимизатора и градиентов. Для эффективного обучения с ограниченными ресурсами необходимы методы &lt;strong>PEFT (Parameter-Efficient Fine-Tuning)&lt;/strong>, такие как «&lt;strong>LoRA&lt;/strong>» и её квантованное расширение «&lt;strong>QLoRA&lt;/strong>».&lt;/p>
&lt;h3 id="31-математические-основы-lora-low-rank-adaptation">3.1 Математические основы LoRA (Low-Rank Adaptation)
&lt;/h3>&lt;p>LoRA — это метод, который фиксирует (замораживает) предварительно обученную матрицу весов и аппроксимирует обновление весов ($\Delta W$) как произведение двух небольших матриц низкого ранга.&lt;/p>
&lt;p>Пусть предварительно обученные веса равны $W_0 \in \mathbb{R}^{d \times k}$. При полном файнтюнинге обновляется сама $W_0$ до $W_0 + \Delta W$, но в LoRA матрица обновлений $\Delta W$ разлагается следующим образом:&lt;/p>
$$ \Delta W = B \times A $$
&lt;p>Здесь $B \in \mathbb{R}^{d \times r}$, $A \in \mathbb{R}^{r \times k}$, а $r$ — это гиперпараметр, называемый рангом (Rank), который является очень маленьким значением (обычно 8, 16, 32 и т.д.), удовлетворяющим условию $r \ll \min(d, k)$.&lt;/p>
&lt;p>Вычисление прямого прохода выглядит следующим образом:&lt;/p>
$$ h = W_0 x + \Delta W x = W_0 x + B A x $$
&lt;p>В начальном состоянии матрица $A$ инициализируется случайным образом с нормальным (гауссовым) распределением, а матрица $B$ инициализируется нулевой матрицей. В результате $\Delta W$ в начале обучения равна нулю, и мы можем начать обучение, полностью сохраняя выходные данные базовой модели.&lt;/p>
&lt;div class="mermaid">graph LR
X["Входной вектор x"] --> W0["Замороженные предварительно обученные веса (W_0)"]
X --> A["Обучаемая матрица LoRA A (r x k)"]
A --> B["Обучаемая матрица LoRA B (d x r)"]
W0 --> Add["Сложение векторов"]
B --> Add
Add --> Y["Выходной вектор h"]&lt;/div>
&lt;h3 id="32-инновационность-qlora-quantized-lora">3.2 Инновационность QLoRA (Quantized LoRA)
&lt;/h3>&lt;p>QLoRA развивает подход LoRA дальше, квантуя базовую модель $W_0$ с 4-битной точностью (NormalFloat 4, NF4) и загружая её в память. Это кардинально снижает потребление VRAM.&lt;/p>
&lt;p>В QLoRA интегрированы три ключевые технологии:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Квантование 4-bit NormalFloat (NF4):&lt;/strong> Теоретически оптимальный тип данных, оптимизированный для весов, распределенных по нормальному закону.&lt;/li>
&lt;li>&lt;strong>Двойное квантование (Double Quantization):&lt;/strong> Квантование самих констант квантования (масштабных коэффициентов) для дополнительной экономии памяти.&lt;/li>
&lt;li>&lt;strong>Paged Optimizers:&lt;/strong> Механизм, использующий функцию объединенной памяти (unified memory) NVIDIA для временной выгрузки состояний оптимизатора в оперативную память CPU (RAM) при нехватке VRAM.&lt;/li>
&lt;/ol>
&lt;p>Благодаря этому тюнинг, который обычно требует от 16 до 24 ГБ VRAM, может быть легко выполнен даже на потребительских GPU (таких как RTX 3060 12GB или RTX 4070).&lt;/p>
&lt;hr>
&lt;h2 id="4-требования-к-оборудованию-и-настройка-в-локальной-среде">4. Требования к оборудованию и настройка в локальной среде
&lt;/h2>&lt;p>Требования к оборудованию для тюнинга TinyLLaMA (1.1B) с помощью QLoRA очень низки.&lt;/p>
&lt;h3 id="рекомендуемые-характеристики-оборудования">Рекомендуемые характеристики оборудования
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>GPU:&lt;/strong> NVIDIA RTX 3060 (12GB), RTX 3090/4090 (24GB) или NVIDIA A10G/A100 и т.д. Минимальный объем VRAM для работы — 8 ГБ, но для увеличения размера батча рекомендуется от 12 ГБ и выше.&lt;/li>
&lt;li>&lt;strong>CPU:&lt;/strong> Современный процессор с 8 и более ядрами (Intel Core i7/i9, AMD Ryzen 7/9).&lt;/li>
&lt;li>&lt;strong>RAM:&lt;/strong> Не менее 32 ГБ (важно при использовании Paged Optimizers как место для выгрузки из VRAM).&lt;/li>
&lt;li>&lt;strong>Накопитель:&lt;/strong> NVMe SSD (для ускорения загрузки датасетов и сохранения модели).&lt;/li>
&lt;/ul>
&lt;h3 id="настройка-программной-среды">Настройка программной среды
&lt;/h3>&lt;p>Процедура настройки предполагается для среды Ubuntu 22.04 LTS. Мы будем использовать Python 3.10 или новее.&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"># Создание и активация виртуальной среды&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"># Установка PyTorch (для 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"># Установка библиотек, связанных с трансформерами&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-методы-оптимизации-для-самого-быстрого-тюнинга">5. Методы оптимизации для самого быстрого тюнинга
&lt;/h2>&lt;p>Для завершения тюнинга «максимально быстро» недостаточно просто запустить скрипт, необходимо комбинировать следующие методы оптимизации.&lt;/p>
&lt;h3 id="51-flash-attention-2">5.1 Flash Attention 2
&lt;/h3>&lt;p>Стандартный механизм внимания (Attention) имеет временную и пространственную сложность $O(N^2)$ для длины последовательности $N$. Flash Attention 2 оптимизирует доступ к памяти между SRAM и HBM (High Bandwidth Memory) GPU, устраняя узкое место ввода-вывода (IO) без сокращения вычислений, что в разы увеличивает скорость обучения и кардинально снижает потребление памяти.&lt;/p>
&lt;h3 id="52-gradient-checkpointing-чекпойнтинг-градиентов">5.2 Gradient Checkpointing (Чекпойнтинг градиентов)
&lt;/h3>&lt;p>Это метод, при котором в VRAM сохраняются не все промежуточные активации, вычисленные при прямом проходе, а лишь некоторые из них; остальные пересчитываются при обратном проходе, когда это необходимо. Время вычислений увеличивается примерно на 20%, но потребление памяти значительно сокращается, что позволяет установить больший размер батча (batch size) и в итоге повысить общую пропускную способность.&lt;/p>
&lt;h3 id="53-обучение-со-смешанной-точностью-mixed-precision-training-и-bfloat16">5.3 Обучение со смешанной точностью (Mixed Precision Training) и Bfloat16
&lt;/h3>&lt;p>Для максимального использования тензорных ядер (Tensor Cores) GPU вычисления при обучении выполняются в &lt;code>bfloat16&lt;/code> (Brain Floating Point). По сравнению с &lt;code>float16&lt;/code> длина бита экспоненты у него такая же, как у &lt;code>float32&lt;/code>, поэтому риск переполнения и потери значимости (overflow/underflow) крайне низок, что делает обучение стабильным.&lt;/p>
&lt;hr>
&lt;h2 id="6-практика-код-файнтюнинга-tinyllama-с-помощью-qlora">6. Практика: Код файнтюнинга TinyLLaMA с помощью QLoRA
&lt;/h2>&lt;p>Теперь давайте разберем скрипт PyTorch для самого быстрого тюнинга, который включает в себя все вышеупомянутые оптимизации. Здесь мы будем использовать &lt;code>SFTTrainer&lt;/code> из библиотеки Hugging Face &lt;code>trl&lt;/code> (Transformer Reinforcement Learning).&lt;/p>
&lt;h3 id="61-подготовка-набора-данных-и-загрузка-модели">6.1 Подготовка набора данных и загрузка модели
&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. Указание модели и токенизатора&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. Настройка 4-битного квантования для 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"># Вычисления производятся в 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. Загрузка модели (Включение 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;Loading model...&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"># Ключ к максимальной скорости&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. Загрузка токенизатора&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"># Устанавливаем right для предотвращения багов при обучении 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-применение-адаптера-lora-и-форматирование-набора-данных">6.2 Применение адаптера LoRA и форматирование набора данных
&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. Подготовка к k-bit обучению и включение чекпойнтинга градиентов&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. Настройка 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"># Ранг&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"># Масштабный коэффициент&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"># Ориентация на все линейные слои улучшает производительность&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"># Пример вывода: 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. Загрузка набора данных (В качестве примера используется японский датасет инструкций)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># На практике здесь загружается локальный приватный JSONL файл и т.д.&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"> Форматирует строку в соответствии с форматом ChatML или шаблоном промпта
&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-выполнение-обучения">6.3 Выполнение обучения
&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. Настройка аргументов обучения&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"># Увеличьте, если есть свободная VRAM&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"># Эффективный размер батча = 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"># Экономия VRAM с помощью 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"># Обучение со смешанной точностью (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 шагов для тестирования. В реальности указывайте количество эпох&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. Запуск обучения с помощью 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"># Настройте в соответствии с ожидаемой длиной входа&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;Starting training...&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. Сохранение адаптера 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;Training complete and model saved.&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-оценка-производительности-и-устранение-неполадок">7. Оценка производительности и устранение неполадок
&lt;/h2>&lt;p>Вот частые проблемы и их решения при запуске обучения в локальной среде.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Возникает ошибка OOM (Out Of Memory):&lt;/strong>
&lt;ul>
&lt;li>Уменьшите &lt;code>per_device_train_batch_size&lt;/code> до &lt;code>1&lt;/code>.&lt;/li>
&lt;li>Увеличьте &lt;code>gradient_accumulation_steps&lt;/code>, чтобы сохранить эффективный размер батча.&lt;/li>
&lt;li>Сократите &lt;code>max_seq_length&lt;/code> с &lt;code>2048&lt;/code> до &lt;code>1024&lt;/code> или &lt;code>512&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Loss (Потеря) не снижается или расходится:&lt;/strong>
&lt;ul>
&lt;li>Возможно, скорость обучения (&lt;code>learning_rate&lt;/code>) слишком высока. Попробуйте снизить её с &lt;code>2e-4&lt;/code> до примерно &lt;code>5e-5&lt;/code>.&lt;/li>
&lt;li>Если используется Float16 вместо Bfloat16, возможно, происходит потеря значимости градиента (underflow). Проверьте наличие &lt;code>bf16=True&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>При инференсе генерируются непонятные символы:&lt;/strong>
&lt;ul>
&lt;li>Убедитесь, что &lt;code>padding_side=&amp;quot;right&amp;quot;&lt;/code> настроен правильно. Также необходимо проверить, соответствует ли формат датасета (специальные токены вроде &lt;code>&amp;lt;|im_start|&amp;gt;&lt;/code>) формату базовой модели при предварительном обучении.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-развертывание-модели-deployment-после-тюнинга">8. Развертывание модели (Deployment) после тюнинга
&lt;/h2>&lt;p>После завершения тюнинга сохраняется не &amp;ldquo;вся базовая модель&amp;rdquo;, а только &amp;ldquo;&lt;strong>адаптер LoRA (веса разницы)&lt;/strong>&amp;rdquo; размером от нескольких до десятков мегабайт. Для быстрого инференса эти веса LoRA необходимо слить (merge) с исходной базовой моделью и экспортировать как единую модель.&lt;/p>
&lt;h3 id="скрипт-слияния-модели">Скрипт слияния модели
&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"># Загрузка модели и адаптера в формате 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"># Слияние и сохранение весов&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="запуск-сверхбыстрого-сервера-инференса-с-помощью-vllm">Запуск сверхбыстрого сервера инференса с помощью vLLM
&lt;/h3>&lt;p>Для максимизации скорости инференса (токенов в секунду) при развертывании в локальной среде настоятельно рекомендуется использовать &lt;strong>vLLM&lt;/strong> или &lt;strong>TGI (Text Generation Inference)&lt;/strong> вместо стандартного &lt;code>pipeline&lt;/code> от Hugging Face. vLLM использует технологию PagedAttention для предотвращения фрагментации памяти GPU и кардинально увеличивает пропускную способность при параллельных запросах.&lt;/p>
&lt;p>Следующая диаграмма Mermaid показывает пайплайн от обучения до развертывания сервера инференса.&lt;/p>
&lt;div class="mermaid">graph TD
A["Сырые приватные данные"] --> B["Предобработка и форматирование (JSONL)"]
B --> C["Файнтюнинг QLoRA (SFTTrainer)"]
C --> D["Веса адаптера LoRA (.safetensors)"]
D --> E["Слияние с базовой TinyLLaMA 1.1B"]
E --> F["Слитая модель (Merged Model)"]
F --> G["Развертывание через сервер vLLM"]
G --> H["Конечная точка API / UI (например, Чат-бот)"]&lt;/div>
&lt;p>Запуск API-сервера с использованием vLLM выполняется всего одной командой:&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>Теперь в вашей локальной среде развернута конечная точка, совместимая с OpenAI API, что позволяет безопасно и быстро использовать локальный ИИ.&lt;/p>
&lt;hr>
&lt;h2 id="9-заключение">9. Заключение
&lt;/h2>&lt;p>В этой статье мы рассмотрели методы максимально быстрого и экономичного с точки зрения памяти файнтюнинга в локальной среде легкой, но высокопроизводительной модели «TinyLLaMA» с 1.1B параметров.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>LoRA / QLoRA&lt;/strong> делают возможным полноценный тюнинг LLM даже на потребительских GPU.&lt;/li>
&lt;li>Использование &lt;strong>Flash Attention 2&lt;/strong> и &lt;strong>Gradient Checkpointing&lt;/strong> позволяет предельно оптимизировать время обучения и потребление VRAM.&lt;/li>
&lt;li>Развертывание с помощью &lt;strong>vLLM&lt;/strong> обеспечивает высокую пропускную способность даже в рабочей (production) среде.&lt;/li>
&lt;/ul>
&lt;p>Эксплуатация локальной LLM в on-premises среде не только защищает конфиденциальность данных, но и становится мощнейшим инструментом для создания по низким затратам специализированного ИИ, адаптированного для конкретных областей (юриспруденция, медицина, внутренние правила компании и т.д.). Пожалуйста, используйте это руководство для создания вашей собственной специализированной версии TinyLLaMA.&lt;/p></description></item><item><title>Разработка небольших ИИ-моделей (таких как TinyLLaMA) на C++</title><link>http://kenji.blog/ru/p/cpp-small-ai-model-tinyllama-dev-guide/</link><pubDate>Fri, 11 Sep 2026 14:00:00 +0900</pubDate><guid>http://kenji.blog/ru/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 Разработка небольших ИИ-моделей (таких как TinyLLaMA) на C++" />&lt;h1 id="руководство-по-разработке-небольших-ии-моделей-таких-как-tinyllama-на-c">Руководство по разработке небольших ИИ-моделей (таких как TinyLLaMA) на C++
&lt;/h1>&lt;p>В последние годы стремительно растет интерес к запуску больших языковых моделей (LLM) в локальных средах. В частности, небольшие модели, такие как TinyLLaMA (1,1 млрд параметров), могут осуществлять вывод с практической скоростью даже на периферийных устройствах с ограниченными ресурсами и обычных ноутбуках (включая среды Windows). В то время как разработка с использованием Python и PyTorch является мейнстримом, для достижения максимальной производительности и экономии памяти де-факто стандартом становится комбинация C++ и основанной на C тензорной библиотеки &amp;ldquo;ggml&amp;rdquo;.&lt;/p>
&lt;p>В этой статье будет представлено очень подробное пошаговое руководство по разработке для создания механизма вывода с нуля (или глубокого понимания внутренней структуры существующего llama.cpp) для загрузки TinyLLaMA и генерации текста с использованием C++.&lt;/p>
&lt;hr>
&lt;h2 id="1-почему-c-и-ggml">1. Почему C++ и ggml?
&lt;/h2>&lt;p>На этапе обучения ИИ Python имеет подавляющее преимущество благодаря своей гибкости и богатой экосистеме. Однако на этапах развертывания и &amp;ldquo;вывода&amp;rdquo; (Inference) C++ становится мощным выбором по следующим причинам:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Снижение накладных расходов&lt;/strong>: Можно полностью исключить глобальную блокировку интерпретатора (GIL) и накладные расходы времени выполнения Python.&lt;/li>
&lt;li>&lt;strong>Эффективность памяти и выделение арены&lt;/strong>: Поскольку выделение и освобождение памяти можно контролировать вручную, предотвращаются непредсказуемые всплески, вызванные сборкой мусора.&lt;/li>
&lt;li>&lt;strong>Прямой доступ к оборудованию&lt;/strong>: Можно напрямую вызывать встроенные функции SIMD (Intrinsics), такие как AVX-512, AVX2, ARM NEON, чтобы максимально использовать вычислительную мощность процессора.&lt;/li>
&lt;li>&lt;strong>Отсутствие зависимостей&lt;/strong>: ggml — это библиотека C/C++ с нулевыми зависимостями (Zero dependencies), которую можно легко собрать даже в среде MSVC на Windows, если есть компилятор.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="2-общий-обзор-архитектуры">2. Общий обзор архитектуры
&lt;/h2>&lt;p>Общий поток конвейера вывода показан на диаграмме Mermaid ниже. Это серия процессов, начиная с введенного пользователем текста и заканчивая генерацией следующего токена.&lt;/p>
&lt;div class="mermaid">graph TD
A["Введенный пользователем текст"] --> B["Токенизатор BPE"]
B --> C["Массив ID токенов"]
C --> D["Поиск в слое Embedding"]
D --> E["Блоки Transformer"]
E --> F["RMSNorm"]
F --> G["Слой LM Head"]
G --> H["Массив логитов"]
H --> I["Модуль Sampler"]
I --> J["ID следующего токена"]
J --> K["Детокенизатор"]
K --> L["Фрагмент выходного текста"]
J -.-> |"Добавить в контекст"| C&lt;/div>
&lt;p>Поскольку это авторегрессионная модель, выведенный токен снова добавляется в контекст и циркулирует как входные данные для прогнозирования следующего токена (пунктирная линия на диаграмме).&lt;/p>
&lt;hr>
&lt;h2 id="3-формат-модели-и-отображение-памяти-mmap">3. Формат модели и отображение памяти (mmap)
&lt;/h2>&lt;p>Самым большим препятствием при работе с весами гигантских нейронных сетей являются дисковый ввод-вывод и потребление памяти. В реализации на C++ это решается с помощью &lt;strong>отображения памяти (mmap)&lt;/strong>.&lt;/p>
&lt;h3 id="31-механизм-отображения-памяти-и-реализация-в-windows">3.1 Механизм отображения памяти и реализация в Windows
&lt;/h3>&lt;p>С помощью mmap содержимое файла можно напрямую отобразить в виртуальное адресное пространство процесса.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Zero-copy (Нулевое копирование)&lt;/strong>: Данные считываются непосредственно с диска в страничный кэш ядра, и лишнее копирование в пользовательское пространство не происходит.&lt;/li>
&lt;li>&lt;strong>Загрузка по требованию (Page Fault)&lt;/strong>: В тот момент, когда процессор фактически обращается к этому адресу памяти, происходит ошибка страницы (page fault), и в физическую память загружается только необходимый фрагмент (обычно 4 КБ).&lt;/li>
&lt;/ul>
&lt;p>В среде Windows вместо POSIX &lt;code>mmap&lt;/code> используются API Win32 &lt;code>CreateFileMapping&lt;/code> и &lt;code>MapViewOfFile&lt;/code>.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant OS["ОС Windows"]
participant RAM["Физическая память"]
participant App["Приложение C++"]
App->>OS: "CreateFileMapping / MapViewOfFile"
OS-->>App: "Указатель адреса виртуальной памяти"
App->>App: "Чтение тензорных данных по указателю"
OS->>RAM: "Ошибка страницы / Загрузка страницы с диска"
RAM-->>App: "Данные готовы для вычислений SIMD"&lt;/div>
&lt;h3 id="32-бинарная-структура-формата-gguf">3.2 Бинарная структура формата GGUF
&lt;/h3>&lt;p>&lt;strong>GGUF (GPT-Generated Unified Format)&lt;/strong>, преобразованный из таких форматов, как &lt;code>.safetensors&lt;/code> на Hugging Face, является идеальным форматом для вывода. Он имеет строгую бинарную структуру, как показано ниже:&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>: Номер версии формата.&lt;/li>
&lt;li>&lt;strong>Tensor Count &amp;amp; Metadata Count&lt;/strong>: Количество тензоров и количество пар ключ-значение метаданных.&lt;/li>
&lt;li>&lt;strong>Metadata (Key-Value Pairs)&lt;/strong>: Ключи с префиксом длины строки и типизированные значения.&lt;/li>
&lt;li>&lt;strong>Tensor Info&lt;/strong>: Имя каждого тензора, количество измерений, тип данных (FP16, Q4_K и т.д.) и позиция смещения в файле.&lt;/li>
&lt;li>&lt;strong>Padding&lt;/strong>: Заполнение (padding), вставляемое для того, чтобы тензорные данные были выровнены по определенной границе (обычно 32 или 64 байта). Это важно для быстрого доступа к памяти с помощью инструкций SIMD (особенно AVX).&lt;/li>
&lt;li>&lt;strong>Tensor Data&lt;/strong>: Массив выровненных фактических данных весов.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="4-математические-основы-tinyllama-и-алгоритмы-c">4. Математические основы TinyLLaMA и алгоритмы C++
&lt;/h2>&lt;p>TinyLLaMA включает в себя несколько продвинутых архитектурных хитростей для повышения эффективности. Мы объясним математические выражения, необходимые для их правильной реализации на C++.&lt;/p>
&lt;h3 id="41-rmsnorm-нормализация-среднеквадратичного-значения">4.1 RMSNorm (Нормализация среднеквадратичного значения)
&lt;/h3>&lt;p>Затраты на вычисления снижаются за счет отказа от центрирования по среднему значению из LayerNorm и выполнения только масштабирования дисперсии.&lt;/p>
$$ \text{RMSNorm}(x) = \frac{x}{\sqrt{\frac{1}{d}\sum_{i=1}^{d} x_i^2 + \epsilon}} \odot \gamma $$
&lt;p>Где $d$ — количество измерений, а $\gamma$ — обученный тензор масштабирования.
При реализации на C++ сначала быстро вычисляется сумма квадратов массива с помощью &lt;code>_mm256_fmadd_ps&lt;/code> из AVX2 и оптимизируется путем умножения на обратный квадратный корень (например, инструкция &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>Это метод, который применяет информацию о позиции токена в виде вращения в тензорном пространстве. Его можно рассматривать как вращение на комплексной плоскости, и к соседней паре измерений $(x_1, x_2)$ вектора $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>Где $m$ — абсолютный индекс позиции токена, а $\theta$ — предварительно вычисленная базовая частота. В ggml это выполняется параллельно просто путем добавления оператора &lt;code>ggml_rope&lt;/code> во время построения графа вывода.&lt;/p>
&lt;h3 id="43-grouped-query-attention-gqa">4.3 Grouped-Query Attention (GQA)
&lt;/h3>&lt;p>В обычном Multi-Head Attention (MHA) количество голов для Query, Key и Value одинаково. Однако TinyLLaMA использует &lt;strong>Grouped-Query Attention (GQA)&lt;/strong>, чтобы радикально снизить пропускную способность памяти и потребление кэша KV.&lt;/p>
$$ \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{Q K^T}{\sqrt{d_k}}\right) V $$
&lt;p>В GQA несколько голов Query совместно используют одну голову Key/Value. В реализации C++ перед выполнением матричного умножения &lt;code>ggml_mul_mat&lt;/code> требуется операция широковещательной рассылки (broadcast) тензора KV в соответствии с количеством Query.&lt;/p>
&lt;h3 id="44-функция-активации-swiglu">4.4 Функция активации SwiGLU
&lt;/h3>&lt;p>В слоях Feed-Forward Network (FFN) вместо GELU используется SwiGLU.&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>В вычислительном графе это выражается путем объединения оператора &lt;code>ggml_silu&lt;/code> и &lt;code>ggml_mul&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="5-построение-вычислительного-графа-и-управление-памятью-с-помощью-ggml">5. Построение вычислительного графа и управление памятью с помощью ggml
&lt;/h2>&lt;p>ggml использует подход &amp;ldquo;Define-and-Run&amp;rdquo; (определи и запусти), при котором строится статический вычислительный граф для вывода, а затем вычисляется (evaluate).&lt;/p>
&lt;h3 id="51-ggml_context-и-распределитель-арены-arena-allocator">5.1 ggml_context и распределитель арены (Arena Allocator)
&lt;/h3>&lt;p>Самая уникальная особенность ggml — это &amp;ldquo;выделение арены&amp;rdquo; (arena allocation), которое вообще не выполняет динамическое выделение памяти (&lt;code>malloc&lt;/code> или &lt;code>new&lt;/code>) внутри цикла вывода.
При инициализации выделяется огромная непрерывная область памяти (арена), и указатель этой области увеличивается (increment) каждый раз при вызове &lt;code>ggml_new_tensor&lt;/code> и т.д. Когда один шаг вывода завершен, достаточно сбросить указатель выделения в исходное положение, и выделение памяти для следующего шага вывода мгновенно завершается.&lt;/p>
&lt;h3 id="52-конкретный-пример-построения-графа">5.2 Конкретный пример построения графа
&lt;/h3>&lt;p>Для каждого шага вывода в памяти собирается следующий вычислительный граф.&lt;/p>
&lt;div class="mermaid">graph TD
A["Входные ID токенов"] --> B["Поиск Embed"]
B --> C["ggml_rms_norm"]
C --> D["Проекции Q / K / V"]
D --> E["Позиционное ggml_rope"]
E --> F["Сохранение в кэш KV"]
E --> G["Загрузка из кэша KV"]
G --> H["Self Attention"]
H --> I["Масштабирование и Softmax"]
I --> J["Вывод Attention"]
J --> K["Выходная проекция"]
K --> L["Добавление Residual"]&lt;/div>
&lt;hr>
&lt;h2 id="6-квантование-quantization-и-оптимизация-windows--simd">6. Квантование (Quantization) и оптимизация Windows / SIMD
&lt;/h2>&lt;p>Если обрабатывать TinyLLaMA (1.1B) в формате FP16, потребуется около 2,2 ГБ памяти, но с помощью 4-битного квантования (например, Q4_K) её можно радикально сжать примерно до 600 МБ.&lt;/p>
&lt;h3 id="61-архитектура-блочного-квантования">6.1 Архитектура блочного квантования
&lt;/h3>&lt;p>ggml не квантует весь тензор единообразно, а делает это по «блокам».
В формате &lt;code>Q4_0&lt;/code> 32 значения FP16 объединяются в один блок.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Масштабный коэффициент (Scale factor)&lt;/strong>: 1 значение FP16 (2 байта)&lt;/li>
&lt;li>&lt;strong>Квантованные данные&lt;/strong>: 32 4-битных значения (16 байт)
Это сводит к минимуму влияние локальных выбросов.&lt;/li>
&lt;/ul>
&lt;h3 id="62-ускорение-скалярного-произведения-с-помощью-avx2">6.2 Ускорение скалярного произведения с помощью AVX2
&lt;/h3>&lt;p>При сборке для новейших процессоров x86 в среде Windows использование флагов компилятора, таких как &lt;code>/arch:AVX2&lt;/code>, обеспечивает обработку SIMD в следующем потоке:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Загрузка&lt;/strong>: Загрузка 4-битных квантованных данных из памяти в 256-битный регистр AVX.&lt;/li>
&lt;li>&lt;strong>Распаковка&lt;/strong>: Развертывание 4-битных значений в Int8 или Int16 с помощью битовых масок и операций сдвига.&lt;/li>
&lt;li>&lt;strong>Деквантование (Обратное квантование)&lt;/strong>: Умножение на масштабный коэффициент для преобразования в число с плавающей запятой.&lt;/li>
&lt;li>&lt;strong>Операция FMA&lt;/strong>: Параллельное выполнение операций умножения с накоплением (multiply-add) со значениями активации с помощью &lt;code>_mm256_fmadd_ps&lt;/code> (Fused Multiply-Add).&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="7-детали-реализации-кэша-kv">7. Детали реализации кэша KV
&lt;/h2>&lt;p>В авторегрессионной генерации «кэш KV» является важной функцией для пропуска вычисления Key и Value для прошлых токенов.&lt;/p>
&lt;p>Ключевые моменты при реализации на C++:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Предварительное выделение тензора&lt;/strong>: Инициализируйте огромный тензор для кэша KV на максимальную длину контекста (например, 2048 токенов) (рекомендуется FP16).&lt;/li>
&lt;li>&lt;strong>Копирование со смещением&lt;/strong>: Когда выполняются вычисления для позиции токена $N$, векторы K и V, полученные на этом шаге, сохраняются в $N$-й строке тензора кэша KV с помощью &lt;code>ggml_cpy&lt;/code> и т.д.&lt;/li>
&lt;li>&lt;strong>Создание представления (view) во время Attention&lt;/strong>: При вычислении Attention создается «представление» (view), указывающее только на часть токенов от 0 до $N$, которое передается в матричное умножение.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-токенизатор-bpe-и-декодирование">8. Токенизатор BPE и декодирование
&lt;/h2>&lt;p>Входная строка обрабатывается как последовательность байтов UTF-8 и сравнивается с заранее определенным словарем. В C++ для ускорения поиска по словарю реализуются алгоритмы с использованием &lt;strong>Trie-дерева (префиксного дерева)&lt;/strong> или очереди с приоритетом.&lt;/p>
&lt;p>Из логитов (logits), выводимых из LM Head, вероятности масштабируются с использованием параметра Temperature, кандидаты сужаются с помощью методов Top-K или Top-P (Nucleus Sampling), а затем случайные числа используются для определения конечного следующего токена.&lt;/p>
&lt;hr>
&lt;h2 id="9-настройка-проекта-c-среда-windows--powershell">9. Настройка проекта C++ (среда 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"># Настройки оптимизации и флага AVX2 для 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>Пример команды сборки в 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-заключение">10. Заключение
&lt;/h2>&lt;p>Реализация механизма вывода для небольших ИИ-моделей, таких как TinyLLaMA, с нуля с использованием C++ и ggml — это отличная возможность раскрыть черный ящик глубокого обучения и оценить красоту низкоуровневого управления аппаратным обеспечением. Давайте прокладывать путь в будущее периферийного ИИ (Edge AI), в полной мере наслаждаясь сутью системного программирования, такой как загрузка без копирования с использованием отображения памяти, оптимизация SIMD и создание кэша KV.&lt;/p></description></item><item><title>【Введение в реализацию RAG】Как заставить локальный ИИ читать ваши документы</title><link>http://kenji.blog/ru/p/rag-local-ai-implementation-guide/</link><pubDate>Fri, 11 Sep 2026 13:00:00 +0900</pubDate><guid>http://kenji.blog/ru/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 【Введение в реализацию RAG】Как заставить локальный ИИ читать ваши документы" />&lt;h1 id="введение">Введение
&lt;/h1>&lt;p>В последние годы развитие больших языковых моделей (LLM) поражает воображение: множество ИИ, во главе с ChatGPT и Claude, проникают в нашу жизнь и работу. Однако у обычных LLM есть очевидная слабость: они знают только &amp;ldquo;публичную информацию на момент обучения&amp;rdquo;. Естественно, они не могут ответить на вопросы, касающиеся &amp;ldquo;приватных документов&amp;rdquo;, таких как внутренние правила компании, личные заметки или неопубликованные проектные материалы. Если попытаться заставить их ответить, возрастает риск генерации правдоподобной лжи, не соответствующей действительности (галлюцинаций).&lt;/p>
&lt;p>В связи с этим сегодня в мире взрывными темпами распространяется технологическая архитектура &lt;strong>RAG (Retrieval-Augmented Generation: генерация с дополненной выборкой)&lt;/strong>. Использование RAG позволяет динамически предоставлять LLM собственные знания из внешней базы данных, на основе которых можно генерировать точные и обоснованные ответы.&lt;/p>
&lt;p>Кроме того, при работе с корпоративными данными или личной конфиденциальной информацией передача данных в облачные API, такие как OpenAI, часто недопустима с точки зрения политики безопасности. Именно здесь возникает потребность в создании &amp;ldquo;Локального RAG&amp;rdquo; в сочетании с &lt;strong>локальным ИИ&lt;/strong> (LLM, полностью работающей на вашем ПК или локальном сервере).&lt;/p>
&lt;p>В этой статье мы подробно рассмотрим все: от базовой теории RAG до конкретных методов реализации локального RAG с использованием Python, математической основы (механизм векторного поиска) и продвинутых методов запуска системы в рабочую среду.&lt;/p>
&lt;hr>
&lt;h1 id="1-общая-архитектура-rag">1. Общая архитектура RAG
&lt;/h1>&lt;p>RAG — это не единая модель ИИ, а системная архитектура, в которой взаимодействуют несколько компонентов. Она условно делится на две фазы: &amp;ldquo;фаза поглощения (загрузка данных)&amp;rdquo; и &amp;ldquo;фаза поиска и генерации&amp;rdquo;.&lt;/p>
&lt;p>Следующая диаграмма Mermaid показывает общую картину системы RAG.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "Фаза поглощения (Предварительная подготовка)"
Doc["Собственные документы (PDF, TXT и т.д.)"] --> Loader["Загрузчик документов"]
Loader --> Splitter["Разделение текста (Чанкинг)"]
Splitter --> EmbedModel1["Модель встраивания (Embedding)"]
EmbedModel1 --> VectorDB["Векторная база данных"]
end
subgraph "Фаза вывода (При запросе пользователя)"
User["Вопрос пользователя (Запрос)"] --> EmbedModel2["Модель встраивания (Embedding)"]
EmbedModel2 --> QueryVector["Вектор запроса"]
QueryVector --> Search["Поиск по сходству (Векторный поиск)"]
VectorDB --> Search
Search --> Context["Извлечение связанных фрагментов (Контекст)"]
User --> PromptBuilder["Построение промпта"]
Context --> PromptBuilder
PromptBuilder --> LocalLLM["Локальная LLM"]
LocalLLM --> Answer["Генерация окончательного ответа"]
end&lt;/div>
&lt;h2 id="фаза-поглощения-предварительная-подготовка">Фаза поглощения (Предварительная подготовка)
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>Загрузка документов&lt;/strong>: Загрузка неструктурированных данных, таких как PDF, Word, текстовые файлы и т.д.&lt;/li>
&lt;li>&lt;strong>Чанкинг (разделение текста)&lt;/strong>: Разделение длинных текстов на осмысленные фрагменты (чанки) для того, чтобы они поместились в ограничение на ввод LLM (контекстное окно) и для повышения точности поиска.&lt;/li>
&lt;li>&lt;strong>Эмбеддинг (векторизация)&lt;/strong>: Передача разделенных чанков в модель встраивания (Embedding Model) и преобразование их в массивы чисел (векторы) размерностью от сотен до тысяч.&lt;/li>
&lt;li>&lt;strong>Сохранение в базу данных&lt;/strong>: Сохранение преобразованных векторов и связывание их с исходными текстовыми данными в векторной базе данных (Vector DB).&lt;/li>
&lt;/ol>
&lt;h2 id="фаза-вывода-во-время-выполнения">Фаза вывода (Во время выполнения)
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>Векторизация запроса&lt;/strong>: Векторизация вопроса пользователя с использованием той же модели встраивания, что и при предварительной подготовке.&lt;/li>
&lt;li>&lt;strong>Поиск по сходству&lt;/strong>: Расчет сходства между вектором запроса и векторами документов в базе данных для получения нескольких наиболее семантически близких (релевантных) фрагментов текста.&lt;/li>
&lt;li>&lt;strong>Построение промпта&lt;/strong>: Объединение полученных связанных текстов в качестве &amp;ldquo;контекста (фоновых знаний)&amp;rdquo; с вопросом пользователя для создания промпта ввода в LLM.&lt;/li>
&lt;li>&lt;strong>Генерация ответа&lt;/strong>: Получив расширенный промпт, LLM генерирует ответ на основе предоставленной контекстной информации.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="2-глубокое-понимание-векторного-поиска-и-встраиваний-embeddings">2. Глубокое понимание векторного поиска и встраиваний (Embeddings)
&lt;/h1>&lt;p>В основе RAG лежит &amp;ldquo;векторный поиск (семантический поиск)&amp;rdquo;. В отличие от традиционного поиска по ключевым словам (например, BM25), который основан на точном совпадении и частоте слов, векторный поиск основан на &amp;ldquo;смысловом сходстве&amp;rdquo;. Например, даже если используются разные слова, такие как &amp;ldquo;собака&amp;rdquo; и &amp;ldquo;щенок&amp;rdquo;, &amp;ldquo;ПК&amp;rdquo; и &amp;ldquo;компьютер&amp;rdquo;, они будут найдены, если их значения близки.&lt;/p>
&lt;h2 id="что-такое-модель-встраивания-embedding-model">Что такое модель встраивания (Embedding Model)?
&lt;/h2>&lt;p>Модель встраивания — это нейронная сеть, которая принимает на вход текст на естественном языке и выводит плотный вектор (Dense Vector) фиксированной длины. Обычные модели (например, &lt;code>text-embedding-3-small&lt;/code> или модель с открытым исходным кодом &lt;code>multilingual-e5-large&lt;/code>) отображают текст в векторы вещественных чисел размерностью 384 или 1024.&lt;/p>
&lt;p>В этом многомерном пространстве (скрытом пространстве) они обучены так, что чем ближе по смыслу предложения, тем меньше расстояние между ними в координатном пространстве.&lt;/p>
&lt;h2 id="математическая-основа-расчета-сходства-косинусное-сходство">Математическая основа расчета сходства: Косинусное сходство
&lt;/h2>&lt;p>Когда векторная база данных ищет связанные документы, наиболее часто используемой метрикой расстояния является &lt;strong>косинусное сходство (Cosine Similarity)&lt;/strong>. В отличие от евклидова расстояния (абсолютного расстояния в пространстве), косинусное сходство фокусируется на &amp;ldquo;угле между двумя векторами&amp;rdquo;. Поскольку оно менее подвержено влиянию длины предложения (нормы вектора), оно очень хорошо подходит для расчета сходства текстов.&lt;/p>
&lt;p>В виде формулы косинусное сходство между векторами $\mathbf{A}$ и $\mathbf{B}$ выглядит следующим образом:&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}$ обозначает скалярное произведение (Dot Product).&lt;/li>
&lt;li>$\|\mathbf{A}\|$ обозначает L2-норму (длину) вектора $\mathbf{A}$.&lt;/li>
&lt;li>$n$ — это размерность вектора.&lt;/li>
&lt;/ul>
&lt;p>Косинусное сходство принимает значения от -1 до 1.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Ближе к 1&lt;/strong>: направления двух векторов почти совпадают (очень схожи по смыслу)&lt;/li>
&lt;li>&lt;strong>Ближе к 0&lt;/strong>: два вектора перпендикулярны (не связаны)&lt;/li>
&lt;li>&lt;strong>Ближе к -1&lt;/strong>: два вектора указывают в противоположные стороны (противоположные по смыслу)&lt;/li>
&lt;/ul>
&lt;p>Современные векторные БД (Chroma, FAISS, Qdrant и т.д.) используют алгоритм приближенного поиска ближайших соседей (ANN), называемый HNSW (Hierarchical Navigable Small World), который оптимизирован для поиска документов с высоким косинусным сходством среди миллионов векторных данных за миллисекунды.&lt;/p>
&lt;hr>
&lt;h1 id="3-технологический-стек-для-создания-локального-rag">3. Технологический стек для создания локального RAG
&lt;/h1>&lt;p>Для создания полностью локального RAG, не зависящего от облака, мы будем использовать экосистему с открытым исходным кодом. Ниже представлен рекомендуемый технологический стек.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Языковая модель (LLM)&lt;/strong>
&lt;ul>
&lt;li>Инструмент: &lt;code>Ollama&lt;/code> или &lt;code>Llama.cpp&lt;/code>&lt;/li>
&lt;li>Модель: легкие и высокопроизводительные открытые модели, такие как &lt;code>Llama-3-8B-Instruct&lt;/code>, &lt;code>Gemma-2-9B-It&lt;/code>, &lt;code>Qwen2-7B-Instruct&lt;/code>. Для задач на японском языке подходят модели, настроенные на японский язык, такие как &lt;code>Llama-3-ELYZA-JP-8B&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Модель встраивания (Embedding)&lt;/strong>
&lt;ul>
&lt;li>Модель: &lt;code>intfloat/multilingual-e5-large&lt;/code> или &lt;code>BAAI/bge-m3&lt;/code>. При локальном запуске обычно их скачивают с Hugging Face и запускают с помощью Sentence-Transformers.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Векторная база данных (Vector DB)&lt;/strong>
&lt;ul>
&lt;li>&lt;code>ChromaDB&lt;/code>: основана на Python, очень проста в настройке. Идеально подходит для локальной разработки.&lt;/li>
&lt;li>&lt;code>FAISS&lt;/code>: высокоскоростная библиотека векторного поиска, разработанная Meta.&lt;/li>
&lt;li>&lt;code>Qdrant&lt;/code> / &lt;code>Milvus&lt;/code>: для более масштабных проектов и рабочих сред.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Фреймворк оркестрации&lt;/strong>
&lt;ul>
&lt;li>&lt;code>LangChain&lt;/code>: фактический стандарт для связывания (Chain) компонентов.&lt;/li>
&lt;li>&lt;code>LlamaIndex&lt;/code>: фреймворк для подключения данных, специально ориентированный на RAG.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>В этот раз мы реализуем систему, используя самую простую в освоении комбинацию: &lt;strong>LangChain + ChromaDB + Ollama + HuggingFaceEmbeddings&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="4-учебное-руководство-по-реализации-создание-полного-локального-rag-на-python">4. Учебное руководство по реализации: Создание полного локального RAG на Python
&lt;/h1>&lt;p>Начиная с этого момента, мы будем создавать локальный RAG, написав фактический код на Python. Пожалуйста, предварительно установите Ollama на свой ПК и запустите его в фоновом режиме. Также загрузите модель в Ollama (например: &lt;code>ollama run llama3&lt;/code>).&lt;/p>
&lt;h2 id="шаг-1-установка-необходимых-библиотек">Шаг 1: Установка необходимых библиотек
&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="шаг-2-обзор-кода-реализации">Шаг 2: Обзор кода реализации
&lt;/h2>&lt;p>Ниже представлен полный Python-скрипт для загрузки PDF-файла, его векторизации и ответов на вопросы с помощью локальной LLM.&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. Загрузка документов&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;Загрузка документов...&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"># Укажите путь к PDF, который нужно загрузить&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. Разделение на чанки (Text Splitting)&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="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"># Максимальное количество символов в одном чанке&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"># Количество перекрывающихся символов между чанками (предотвращает потерю контекста)&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;Разделено на &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"> чанков.&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. Инициализация модели встраивания (Local HuggingFace Model)&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="nb">print&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="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"># Используйте &amp;#39;cuda&amp;#39; или &amp;#39;mps&amp;#39;, если есть 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. Создание векторной базы данных (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;Создание векторной базы данных...&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"># Создание ретривера (поисковика). Настройка на получение топ-3 связанных документов&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. Инициализация локальной LLM (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;Подключение к локальной 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 class="c1"># Предварительно загрузите модель, например, с помощью &amp;#39;ollama pull llama3&amp;#39;&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. Определение шаблона промпта&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;Вы - превосходный ассистент, хорошо разбирающийся в правилах и внутренней информации компании.
&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">Если ответ не может быть найден в контексте, не стройте догадок и честно ответьте «Я не могу найти ответ в предоставленной информации».
&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">【Контекст】
&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">【Вопрос】
&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">【Ответ】:
&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. Создание цепочки 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"># Настройка возврата источников информации&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. Выполнение вопроса&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;Расскажите об условиях оплаты транспортных расходов при удаленной работе.&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">Вопрос: &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;【Ответ】&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;【Использованные источники】&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;- Страница &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;неизвестно&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="объяснение-ключевых-моментов-кода">Объяснение ключевых моментов кода
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>RecursiveCharacterTextSplitter&lt;/strong>:
Это наиболее рекомендуемый разделитель для естественного языка. Он пытается разделить текст в порядке: абзац (&lt;code>\n\n&lt;/code>), строка (&lt;code>\n&lt;/code>), точка (&lt;code>。&lt;/code>), чтобы разделить текст таким образом, чтобы он уместился в заданный &lt;code>chunk_size&lt;/code>, сохраняя при этом смысловые блоки насколько это возможно. Установив &lt;code>chunk_overlap&lt;/code>, вы предотвращаете потерю информации на границах контекста.&lt;/li>
&lt;li>&lt;strong>HuggingFaceEmbeddings&lt;/strong>:
&lt;code>intfloat/multilingual-e5-large&lt;/code> — это очень мощная многоязычная модель встраивания с открытым исходным кодом. Вы можете векторизовать текст оффлайн в локальной памяти, не используя облачные API (например, &lt;code>text-embedding-ada-002&lt;/code> от OpenAI).&lt;/li>
&lt;li>&lt;strong>ChromaDB&lt;/strong>:
Она работает в оперативной памяти или локальном хранилище (на базе SQLite), поэтому вам не нужно настраивать сложный сервер базы данных. Указав &lt;code>persist_directory&lt;/code>, вы можете пропустить процесс векторизации при повторном выполнении и загрузить базу данных с диска.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="5-продвинутые-методы-rag-advanced-rag-techniques">5. Продвинутые методы RAG (Advanced RAG Techniques)
&lt;/h1>&lt;p>Базовая система RAG (Naive RAG), созданная в приведенном выше руководстве, также будет работать, но если в рабочей среде требуется высокая точность ответов, необходимо внедрить следующие продвинутые методы.&lt;/p>
&lt;h2 id="51-гибридный-поиск-hybrid-search">5.1 Гибридный поиск (Hybrid Search)
&lt;/h2>&lt;p>Векторный поиск хорошо справляется с пониманием &amp;ldquo;смысла&amp;rdquo;, но он может плохо справляться со строгим поиском по ключевым словам, таким как &amp;ldquo;определенные имена собственные&amp;rdquo;, &amp;ldquo;номера моделей продуктов&amp;rdquo; и &amp;ldquo;идентификаторы сотрудников&amp;rdquo;.
Следовательно, параллельно выполняя &lt;strong>семантический поиск&lt;/strong> (с помощью векторного поиска) и &lt;strong>поиск по ключевым словам&lt;/strong> (с использованием алгоритмов типа BM25), а затем оценивая и объединяя результаты обоих подходов (используя методы типа Reciprocal Rank Fusion, RRF), можно радикально сократить количество пропусков в поиске.&lt;/p>
&lt;h2 id="52-повторное-ранжирование-re-ranking">5.2 Повторное ранжирование (Re-ranking)
&lt;/h2>&lt;p>Векторный поиск работает быстро, но он не обязательно оценивает точную контекстную релевантность. Общий конвейер для повышения точности поиска выглядит следующим образом:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Начальный поиск (First-stage Retrieval)&lt;/strong>: Широкий и поверхностный поиск из векторной БД, извлечение примерно 20–30 связанных чанков.&lt;/li>
&lt;li>&lt;strong>Повторная оценка (Re-ranking)&lt;/strong>: Использование другой, более &amp;ldquo;тяжелой&amp;rdquo; модели машинного обучения, называемой Cross-Encoder (например, &lt;code>bge-reranker&lt;/code>), для подачи пар запроса пользователя и извлеченного чанка и пересчета баллов семантической релевантности.&lt;/li>
&lt;li>&lt;strong>Отбор&lt;/strong>: Только верхние 3–5 с наивысшими баллами передаются в промпт LLM в качестве окончательного контекста.&lt;/li>
&lt;/ol>
&lt;p>Этот метод предотвращает передачу нерелевантной шумовой информации в LLM и может значительно повысить точность (Precision) ответов.&lt;/p>
&lt;div class="mermaid">graph LR
Query["Запрос"] --> VSearch["Векторный поиск (топ 20)"]
VSearch --> Reranker["Модель реранкера (Cross-Encoder)"]
Query --> Reranker
Reranker --> TopK["Высокоточные топ 3"]
TopK --> LLM["Генерация LLM"]&lt;/div>
&lt;h2 id="53-семантический-чанкинг-и-поиск-родительского-документа">5.3 Семантический чанкинг и поиск родительского документа
&lt;/h2>&lt;p>Существует метод под названием &amp;ldquo;Semantic Chunking&amp;rdquo; (Семантический чанкинг), который использует ИИ для обнаружения изменений в смысле предложений и разделяет текст на их основе, а не механически разбивает текст на фиксированное количество символов.
Кроме того, существует метод &amp;ldquo;Parent Document Retriever&amp;rdquo; (Поиск родительского документа), в котором векторизация выполняется на очень маленьких единицах (например, предложениях) для высокоточного поиска, но при передаче в LLM передается &amp;ldquo;исходный большой абзац (родительский документ)&amp;rdquo;, содержащий это предложение, что обеспечивает LLM достаточным контекстом.&lt;/p>
&lt;hr>
&lt;h1 id="6-проблемы-и-решения-при-эксплуатации-локального-rag">6. Проблемы и решения при эксплуатации локального RAG
&lt;/h1>&lt;p>При создании и эксплуатации RAG в локальной среде существуют специфические препятствия.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Нехватка VRAM (видеопамяти)&lt;/strong>:
Чтобы запустить локальную LLM с практичной скоростью (десятки токенов в секунду), вам необходимо загрузить модель в VRAM вашего GPU. Для работы модели класса 8B в формате fp16 (16-битная плавающая запятая) требуется около 16 ГБ VRAM, но с использованием технологии &lt;strong>квантования (Quantization)&lt;/strong> (сжатие до 4 или 8 бит, например, в форматах GGUF или AWQ), ее можно заставить работать достаточно быстро даже на 8 ГБ VRAM (например, на стандартном игровом ПК). Llama.cpp и Ollama поддерживают эти форматы квантования из коробки.&lt;/li>
&lt;li>&lt;strong>Ограничение контекстного окна&lt;/strong>:
Если объем полученного контекста слишком велик, он может превысить лимит ввода LLM (лимит токенов) или модель может &amp;ldquo;забыть&amp;rdquo; среднюю часть информации (феномен Lost in the middle). Важно настраивать количество извлекаемых чанков и тщательно отбирать их с помощью вышеупомянутых технологий реранжирования.&lt;/li>
&lt;li>&lt;strong>Управление свежестью данных&lt;/strong>:
Если исходные документы обновляются, соответствующие векторы документов в векторной базе данных также должны быть обновлены или удалены (операции CRUD). Поскольку ChromaDB поддерживает обновление на основе идентификаторов документов, практично управлять хеш-значениями файлов и настраивать пакетную обработку для синхронизации только изменений.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="заключение">Заключение
&lt;/h1>&lt;p>RAG (Retrieval-Augmented Generation) — это мощная парадигма, которая превращает ИИ из обычного универсального ассистента в вашего «персонального эксперта» или «эксперта, специализирующегося на ваших внутренних задачах».&lt;/p>
&lt;p>Мы увидели, что даже с высокими требованиями к конфиденциальности, не позволяющими использовать облачные сервисы, можно относительно легко создать полноценную среду «локального RAG», комбинируя элементы экосистемы с открытым исходным кодом, такие как Ollama, LangChain и ChromaDB.&lt;/p>
&lt;p>Основываясь на математическом понимании векторных пространств и продвинутых подходах, таких как разделение текста и реранжирование, рассмотренных в этой статье, попробуйте разработать собственную оригинальную систему ИИ, используя свои данные. Скорость эволюции локального ИИ поразительна, и система, которую вы построили сегодня, может быть мгновенно обновлена по производительности завтра, просто заменив ее на еще более умную легкую модель.&lt;/p>
&lt;hr>
&lt;p>&lt;em>В этом блоге мы продолжим публиковать подробные статьи о технологиях ИИ и RAG. Если у вас есть какие-либо вопросы или отзывы, пожалуйста, оставьте их в разделе комментариев.&lt;/em>&lt;/p></description></item><item><title>【2026 год: Последняя версия】Полное руководство по запуску локальных LLM в среде Windows</title><link>http://kenji.blog/ru/p/local-llm-windows-2026/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/ru/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 【2026 год: Последняя версия】Полное руководство по запуску локальных LLM в среде Windows" />&lt;h1 id="1-введение-почему-именно-сейчас-локальные-llm-на-windows">1. Введение: Почему именно сейчас локальные LLM на Windows?
&lt;/h1>&lt;p>По состоянию на 2026 год эволюция генеративного ИИ и больших языковых моделей (LLM) демонстрирует серьезный сдвиг парадигмы — от гигантских облачных API-сервисов к «локальным LLM», работающим на персональных ПК или в локальной среде (on-premise). Облачные ИИ, такие как GPT-5 от OpenAI или Claude 3.5 от Anthropic, очень мощны, но компании и частные лица не могут отправлять абсолютно все свои данные в облако. С точки зрения конфиденциальности, безопасности, задержек, а также долгосрочной и устойчивой стоимости, спрос на локальные LLM сейчас высок как никогда.&lt;/p>
&lt;p>В частности, экосистема локальных LLM для среды Windows переживает поразительное развитие. Еще несколько лет назад здравый смысл подсказывал, что «разработка и запуск ИИ означает Linux», но в 2026 году Windows превратилась в очень мощную и удобную платформу для ИИ.&lt;/p>
&lt;p>В этой статье представлено полное руководство по созданию, развертыванию и оптимизации локальных LLM в среде Windows с учетом последних технологических тенденций 2026 года. Мы детально и всесторонне рассмотрим всё: от простой настройки для новичков с помощью Ollama до экстремальной оптимизации для продвинутых пользователей с использованием llama.cpp, а также глубокого понимания архитектуры, математического подхода к расчету VRAM и локального файнтюнинга.&lt;/p>
&lt;h2 id="11-технологические-тенденции-в-сфере-локальных-llm-в-2026-году">1.1 Технологические тенденции в сфере локальных LLM в 2026 году
&lt;/h2>&lt;p>Основные тенденции, формирующие текущую экосистему локальных LLM, следующие:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Полное распространение формата GGUF&lt;/strong>: Формат GGUF (GPT-Generated Unified Format), объединяющий метаданные и тензоры в один файл, стал абсолютным стандартом де-факто. Теперь достаточно скачать один файл с Hugging Face, чтобы запустить его в любой среде.&lt;/li>
&lt;li>&lt;strong>Демократизация архитектуры MoE (Mixture of Experts)&lt;/strong>: Выпущено множество небольших, но высокопроизводительных моделей MoE. Активируя при выводе (инференсе) лишь часть «экспертов», они достигают производительности, сопоставимой с гигантскими моделями, при этом снижая вычислительную нагрузку на потребительские ПК.&lt;/li>
&lt;li>&lt;strong>Высокий уровень абстракции и оптимизации движков вывода&lt;/strong>: Такие инструменты, как Ollama, LM Studio и AnythingLLM, стали настолько совершенными, что пользователям больше не нужно беспокоиться о сложных зависимостях, вроде установки драйверов CUDA. Кроме того, нативная поддержка FlashAttention 3 для Windows привела к резкому увеличению скорости инференса.&lt;/li>
&lt;li>&lt;strong>Использование NPU и развитие Windows Copilot+ PC&lt;/strong>: Технология запуска небольших LLM (SLM: Small Language Models) с низким энергопотреблением на ноутбуках без GPU с использованием встроенного NPU (Neural Processing Unit) достигла стадии практического применения.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="2-требования-к-аппаратному-обеспечению-и-подготовка-ос">2. Требования к аппаратному обеспечению и подготовка ОС
&lt;/h1>&lt;p>Чтобы локальная LLM работала с приемлемой скоростью (от 15 до 30+ токенов в секунду), самое важное — правильно выбрать аппаратное обеспечение.&lt;/p>
&lt;h2 id="21-рекомендуемая-конфигурация-оборудования">2.1 Рекомендуемая конфигурация оборудования
&lt;/h2>&lt;p>С развитием ИИ-ПК меняются и системные требования.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>ОС&lt;/strong>: Windows 11 Pro (24H2 или новее). Необходимо для полноценного использования функций WSL2, продвинутого управления памятью и работы с новейшим API DirectML.&lt;/li>
&lt;li>&lt;strong>CPU&lt;/strong>: Серия Intel Core Ultra 200 или выше, либо серия AMD Ryzen 9000 или выше. Если параллельно используется инференс на CPU, жизненно необходима высокоскоростная связь с памятью.&lt;/li>
&lt;li>&lt;strong>RAM&lt;/strong>: Минимум 32 ГБ, рекомендуется 64 ГБ или больше. Пропускная способность основной памяти (МБ/с) становится решающим узким местом при инференсе на CPU или переносе (offload) вычислений. В идеале использовать высокоскоростную память DDR5-6000 или выше.&lt;/li>
&lt;li>&lt;strong>GPU&lt;/strong>: Серия NVIDIA RTX 4000/5000. В локальных LLM наиболее важна не вычислительная мощность, а «объем VRAM».
&lt;ul>
&lt;li>&lt;strong>Начальный уровень&lt;/strong>: RTX 4060 Ti (версия 16 ГБ) — лучшее соотношение цены и качества. Идеально подходит для моделей класса 8B–14B.&lt;/li>
&lt;li>&lt;strong>Средний уровень&lt;/strong>: RTX 4070 Ti SUPER (16 ГБ) / RTX 4080 SUPER (16 ГБ)&lt;/li>
&lt;li>&lt;strong>High-end&lt;/strong>: RTX 4090 (24 ГБ) / RTX 5090 (32 ГБ) — необходимы для запуска квантованных моделей класса 30B–70B.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Накопитель&lt;/strong>: NVMe SSD PCIe Gen4 или Gen5. Резко сокращает время загрузки моделей объемом в десятки гигабайт.&lt;/li>
&lt;/ul>
&lt;h2 id="22-настройка-wsl2-windows-subsystem-for-linux-2">2.2 Настройка WSL2 (Windows Subsystem for Linux 2)
&lt;/h2>&lt;p>Хотя многие инструменты с графическим интерфейсом работают в Windows нативно, WSL2 очень удобен для разработки на Python, компиляции новейших инструментов и файнтюнинга LoRA, о котором пойдет речь ниже. В последних версиях среды Windows 11 достаточно установить драйвер NVIDIA на хосте, чтобы прозрачно использовать GPU (CUDA) из WSL2.&lt;/p>
&lt;p>Откройте 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;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"># Установка WSL2 и последней версии 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"># Обновление ядра&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>После установки выполните команду &lt;code>nvidia-smi&lt;/code> в терминале WSL2. Если GPU распознан корректно — установка прошла успешно.&lt;/p>
&lt;hr>
&lt;h1 id="3-архитектура-локальных-llm-и-механизм-вывода-инференса">3. Архитектура локальных LLM и механизм вывода (инференса)
&lt;/h1>&lt;p>Понимание внутренней структуры того, как модель генерирует текст в локальной среде, очень полезно для устранения неполадок и оптимизации.&lt;/p>
&lt;p>Следующая диаграмма Mermaid показывает типичный конвейер инференса локальной LLM.&lt;/p>
&lt;div class="mermaid">graph TD
User["Пользовательский ввод (Промпт)"] --> Tokenizer["Токенизатор (Tokenizer)"]
Tokenizer --> Embedding["Слой встраивания (Embedding)"]
subgraph "Transformer Block (x Layers)"
Embedding --> Attn["Механизм внутреннего внимания (Self-Attention)"]
Attn --> KVCache["KV-кэш (Хранение Key/Value)"]
Attn --> FFN["Сеть прямой связи (FFN)"]
end
FFN --> Logits["Вычисление логитов (Logits)"]
Logits --> Sampler["Сэмплер (Temperature, Top-K, Top-P)"]
Sampler --> OutputToken["Выходной токен"]
OutputToken --> |"Авторегрессионная генерация"| Tokenizer
OutputToken --> Decoder["Детокенизатор (Detokenizer)"]
Decoder --> FinalOutput["Итоговый сгенерированный текст"]&lt;/div>
&lt;h2 id="31-две-фазы-prefill-и-decode">3.1 Две фазы: Prefill и Decode
&lt;/h2>&lt;p>Генерация текста LLM разделена на две фазы с различными вычислительными характеристиками.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Фаза Prefill (Обработка промпта)&lt;/strong>: Фаза, в которой весь введенный промпт обрабатывается и понимается за один раз. Поскольку возможны параллельные вычисления, вычислительная мощность GPU (FLOPS) напрямую влияет на скорость. Если промпт длинный, эта фаза может занять несколько секунд.&lt;/li>
&lt;li>&lt;strong>Фаза Decode (Генерация токенов)&lt;/strong>: Фаза, в которой предсказывается по одному токену за раз, и результат передается на следующий вход (авторегрессия). Поскольку параллельные вычисления на этом этапе ограничены, пропускная способность VRAM (Memory Bandwidth) становится решающим узким местом.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="4-расчет-потребления-vram-и-математическое-понимание-размера-модели">4. Расчет потребления VRAM и математическое понимание размера модели
&lt;/h1>&lt;p>Чтобы правильно определить, «какая модель будет работать на моем ПК», необходимо понимать формулу расчета VRAM. Если из-за нехватки VRAM происходит откат (фолбэк) к системной памяти (RAM), скорость вывода падает в 10–100 раз.&lt;/p>
&lt;h2 id="41-базовый-объем-vram-на-основе-размера-параметров">4.1 Базовый объем VRAM на основе размера параметров
&lt;/h2>&lt;p>Это объем памяти, необходимый для загрузки весов модели в VRAM.
Он рассчитывается с использованием размера модели $P$ (количество параметров, единица измерения: 1 миллиард = 1B) и количества байт на 1 параметр $B$.&lt;/p>
$$
V_{base} = P \times B \quad \text{(ГБ)}
$$
&lt;p>Например, при загрузке модели с 8B (8 миллиардами) параметров в формате FP16 (полуточные числа с плавающей запятой, 16 бит = 2 байта):&lt;/p>
$$
V_{base} = 8 \times 2 = 16 \text{ ГБ}
$$
&lt;p>Другими словами, даже на GPU с 16 ГБ VRAM вы достигнете предела уже только при загрузке модели.&lt;/p>
&lt;h2 id="42-магия-квантования-quantization">4.2 Магия квантования (Quantization)
&lt;/h2>&lt;p>Вот здесь в игру вступает «квантование». Снижая точность параметров, размер модели кардинально уменьшается. В случае наиболее распространенного 4-битного квантования (например, Q4_K_M), на один параметр приходится в среднем около 0.55 байта.&lt;/p>
$$
V_{base\_4bit} = 8 \times 0.55 = 4.4 \text{ ГБ}
$$
&lt;p>Таким образом, имея 16 ГБ VRAM, вы сможете запускать модель 8B с достаточным запасом памяти.&lt;/p>
&lt;h2 id="43-расчет-kv-кэша-с-поддержкой-gqa">4.3 Расчет KV-кэша (с поддержкой GQA)
&lt;/h2>&lt;p>Во время вывода (инференса) «KV-кэш», предназначенный для сохранения прошлого контекста, потребляет VRAM. В последних моделях, таких как Llama 3, для экономии памяти применяется GQA (Grouped Query Attention).&lt;/p>
&lt;p>Потребление KV-кэша $V_{kv}$ (в гигабайтах) выражается следующей формулой:&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>Упростив это, мы можем произвести вычисления с помощью количества голов Key и 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>Где:&lt;/p>
&lt;ul>
&lt;li>$b$: Размер батча (обычно 1 для локального индивидуального использования)&lt;/li>
&lt;li>$s$: Длина последовательности (длина контекста, например: 8192)&lt;/li>
&lt;li>$l$: Количество слоев (например: 32)&lt;/li>
&lt;li>$h_{kv}$: Количество голов KV (например: 8)&lt;/li>
&lt;li>$d$: Размерность на одну голову (например: 128)&lt;/li>
&lt;li>$B_{kv}$: Количество байт KV-кэша (2 для FP16)&lt;/li>
&lt;/ul>
&lt;p>Пример расчета (Llama 3 8B, контекст 8192, кэш FP16):
$V_{kv} = 2 \times 1 \times 8192 \times 32 \times 8 \times 128 \times 2 \div 10^9 \approx 1.07 \text{ ГБ}$&lt;/p>
&lt;p>Обратите внимание, что чем больше длина контекста $s$, тем больше необходимо VRAM, и этот рост линеен.&lt;/p>
&lt;hr>
&lt;h1 id="5-практика-1-самая-быстрая-и-короткая-настройка-с-использованием-ollama">5. Практика 1: Самая быстрая и короткая настройка с использованием Ollama
&lt;/h1>&lt;p>Теперь, поняв теорию, давайте действительно запустим LLM в среде Windows.
По состоянию на 2026 год, самым удобным инструментом является «Ollama». Он предоставляет интуитивно понятный CLI в стиле Docker.&lt;/p>
&lt;h2 id="51-установка-и-запуск">5.1 Установка и запуск
&lt;/h2>&lt;ol>
&lt;li>Скачайте и запустите установщик для Windows с &lt;a class="link" href="https://ollama.com/" target="_blank" rel="noopener"
>официального сайта Ollama&lt;/a>.&lt;/li>
&lt;li>Откройте PowerShell и введите следующую команду. Здесь мы используем &lt;code>llama3:8b&lt;/code>.&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>При первом запуске произойдет загрузка модели. По завершении вы сможете вести диалог прямо в терминале.&lt;/p>
&lt;h2 id="52-создание-собственного-ии-с-помощью-modelfile">5.2 Создание собственного ИИ с помощью Modelfile
&lt;/h2>&lt;p>Вы можете легко создать ИИ с определенной персоной. Создайте файл &lt;code>Modelfile&lt;/code> в любом месте.&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">Вы — выдающийся старший инженер-программист (Senior Software Engineer).
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">На вопросы пользователя всегда отвечайте логично и кратко, обязательно приводя примеры кода.
&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>Используйте следующие команды для сборки и запуска вашей собственной модели:&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-использование-из-внешних-приложений-ии-редакторов">5.3 Использование из внешних приложений (ИИ-редакторов)
&lt;/h2>&lt;p>Ollama открывает API-эндпоинт, совместимый с OpenAI, по адресу &lt;code>http://localhost:11434&lt;/code>.
В настройках бэкенда таких расширений для VS Code, как Cursor или Continue.dev, просто укажите этот URL и имя модели (например, &lt;code>SeniorDev&lt;/code>), чтобы получить мощного локального помощника по программированию абсолютно бесплатно.&lt;/p>
&lt;hr>
&lt;h1 id="6-практика-2-экстремальная-настройка-производительности-с-помощью-llamacpp">6. Практика 2: Экстремальная настройка производительности с помощью llama.cpp
&lt;/h1>&lt;p>Если вы хотите получить доступ к детальному управлению памятью или быстро опробовать новейшие форматы (такие как EXL2 или IQ квантование), то стоит использовать основной движок &lt;code>llama.cpp&lt;/code> напрямую.&lt;/p>
&lt;h2 id="61-процесс-сборки-llamacpp">6.1 Процесс сборки llama.cpp
&lt;/h2>&lt;p>В среде Windows лучше всего собирать из исходного кода, используя CUDA Toolkit и 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"># Конфигурация и компиляция с поддержкой 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-продвинутый-запуск-в-режиме-сервера">6.2 Продвинутый запуск в режиме сервера
&lt;/h2>&lt;p>Используйте собранный &lt;code>llama-server.exe&lt;/code> для хостинга модели.&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>: Переносит на VRAM GPU все возможные слои (максимально возможное количество).&lt;/li>
&lt;li>&lt;code>--flash-attn&lt;/code>: Включает FlashAttention 3, что повышает скорость инференса и снижает потребление VRAM KV-кэшем.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="7-gui-фронтенды-lm-studio-и-создание-локального-rag">7. GUI фронтенды: LM Studio и создание локального RAG
&lt;/h1>&lt;p>Если вы не любите командную строку или хотите интуитивно выполнять RAG (Генерация с дополненной выборкой), воспользуйтесь графическими интерфейсами.&lt;/p>
&lt;h2 id="71-lm-studio">7.1 LM Studio
&lt;/h2>&lt;p>LM Studio — это отличное приложение, которое объединяет поиск моделей, их загрузку, предварительную проверку системных требований и пользовательский интерфейс для чата в одном месте. Просто нажав кнопку &amp;ldquo;Local Server&amp;rdquo; в приложении, вы запускаете API, совместимый с OpenAI.&lt;/p>
&lt;h2 id="72-архитектура-rag-с-использованием-anythingllm">7.2 Архитектура RAG с использованием AnythingLLM
&lt;/h2>&lt;p>Вот схема архитектуры среды RAG для чтения внутренних корпоративных документов или личных заметок.&lt;/p>
&lt;div class="mermaid">graph LR
Document["Документ (PDF, MD)"] --> Chunking["Разделение на чанки"]
Chunking --> EmbedModel["Модель встраивания (Embedding)"]
EmbedModel --> VectorDB["Векторная база данных"]
UserQuery["Запрос пользователя"] --> EmbedQuery["Встраивание запроса"]
EmbedQuery --> VectorDB
VectorDB --> |"Поиск по сходству"| RetrievedDocs["Извлеченные релевантные документы"]
UserQuery --> PromptBuilder["Генератор промпта"]
RetrievedDocs --> PromptBuilder
PromptBuilder --> LocalLLM["Локальная LLM"]
LocalLLM --> Answer["Итоговый ответ"]&lt;/div>
&lt;p>Используя десктопную версию AnythingLLM (для Windows), достаточно указать Ollama (как LLM и Embedding) на экране настроек и настроить использование локальной векторной БД (LanceDB), и эта архитектура будет готова за несколько минут. Так рождается приватный ИИ, который совершенно не отправляет данные наружу.&lt;/p>
&lt;hr>
&lt;h1 id="8-файнтюнинг-на-windows-в-wsl2-lora">8. Файнтюнинг на Windows в WSL2 (LoRA)
&lt;/h1>&lt;p>Если вы хотите не только локально запускать модели, но и обучать их на своих собственных данных, чтобы сделать умнее, вы можете использовать файнтюнинг с помощью LoRA (Low-Rank Adaptation). По состоянию на 2026 год, благодаря библиотеке под названием &amp;ldquo;Unsloth&amp;rdquo;, обучение 8B-модели в среде Windows WSL2 с 16 ГБ VRAM завершается всего за несколько часов.&lt;/p>
&lt;p>Выполните следующее в Ubuntu под 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>Unsloth доводит оптимизацию ядер CUDA до предела, так что скорость обучения примерно удваивается, а потребление VRAM снижается вдвое по сравнению со стандартными библиотеками Hugging Face. Просто запустите Jupyter Notebook, загрузите свой набор данных (в формате JSONL), и вы сможете выполнить несколько эпох обучения даже на RTX 4060 Ti с VRAM от 12 ГБ до 16 ГБ.&lt;/p>
&lt;hr>
&lt;h1 id="9-устранение-проблем-с-производительностью-troubleshooting">9. Устранение проблем с производительностью (Troubleshooting)
&lt;/h1>&lt;p>Часто возникающие проблемы и способы их решения.&lt;/p>
&lt;h3 id="1-скорость-вывода-крайне-низкая-1-2-tokenss">1. Скорость вывода крайне низкая (1-2 tokens/s)
&lt;/h3>&lt;p>&lt;strong>Причина&lt;/strong>: Модель не помещается в VRAM и выгружается (offload) в системную память (RAM).
&lt;strong>Решение&lt;/strong>: Проверьте параметр «Выделенная память графического процессора» в Диспетчере задач. Если он достиг предела, уменьшите размер контекста (&lt;code>-c&lt;/code>) или используйте квантованную модель с меньшим битрейтом (например, Q4_K_M).&lt;/p>
&lt;h3 id="2-ошибка-cuda-out-of-memory">2. Ошибка &amp;ldquo;CUDA out of memory&amp;rdquo;
&lt;/h3>&lt;p>&lt;strong>Причина&lt;/strong>: VRAM полностью исчерпан. В основном возникает, когда диалог затягивается, и KV-кэш разрастается.
&lt;strong>Решение&lt;/strong>: Намеренно ограничьте значение &lt;code>num_ctx&lt;/code> в Ollama или &lt;code>-c&lt;/code> в llama.cpp, сделав его меньше.&lt;/p>
&lt;h3 id="3-странная-генерация-на-японском-или-другом-языке">3. Странная генерация на японском (или другом) языке
&lt;/h3>&lt;p>&lt;strong>Причина&lt;/strong>: Несоответствие шаблона промпта или неподдерживаемая модель.
&lt;strong>Решение&lt;/strong>: Убедитесь, что вы используете модель, содержащую слово &lt;code>Instruct&lt;/code> в названии, и что в инструменте выбран правильный шаблон, указанный автором модели (например, формат ChatML или Llama3).&lt;/p>
&lt;hr>
&lt;h1 id="10-заключение-и-перспективы-на-будущее">10. Заключение и перспективы на будущее
&lt;/h1>&lt;p>В 2026 году развертывание локальных LLM в среде Windows больше не является привилегией лишь избранных инженеров. Благодаря формату GGUF, ставшему стандартом де-факто, появлению продуманных экосистем, таких как Ollama и LM Studio, а также аппаратной оптимизации, включая FlashAttention, каждый может легко получить ИИ-среду корпоративного уровня.&lt;/p>
&lt;p>Пожалуйста, воспользуйтесь ключевыми моментами, описанными в этой статье:&lt;/p>
&lt;ol>
&lt;li>Используйте &lt;strong>математические расчеты VRAM&lt;/strong>, чтобы логически выбрать размер модели и уровень квантования, оптимальные для характеристик вашего ПК.&lt;/li>
&lt;li>Используйте &lt;strong>Ollama&lt;/strong> для максимально быстрой настройки среды и интегрируйте её с ИИ-редакторами для резкого повышения производительности.&lt;/li>
&lt;li>Раскройте предельные возможности оборудования с помощью продвинутого контроля параметров в &lt;strong>llama.cpp&lt;/strong>.&lt;/li>
&lt;li>Создайте безопасную локальную систему RAG для работы с конфиденциальными данными с помощью &lt;strong>AnythingLLM&lt;/strong>.&lt;/li>
&lt;li>Используйте &lt;strong>Unsloth (WSL2)&lt;/strong>, чтобы вырастить собственного персонализированного ИИ, обладающего вашими экспертными знаниями.&lt;/li>
&lt;/ol>
&lt;p>«Демократизация» ИИ — это больше не модное словечко, а реальная система, работающая на вашем рабочем столе Windows. Освободитесь от затрат на облачные API и рисков утечки информации, и прямо сейчас сделайте шаг в свободный и мощный мир приватного ИИ.&lt;/p></description></item></channel></rss>