Локальный переводчик CLI на Gemma 3: QLoRA, Docker, сравнение 1B/4B моделей | AiManual
AiManual Logo Ai / Manual.
21 Фев 2026 Гайд

Как создать локальный переводчик команд CLI на Gemma 3: тонкая настройка QLoRA, тесты на Docker и сравнение 1B/4B моделей

Пошаговый гайд по созданию локального переводчика Docker команд с помощью тонкой настройки Gemma 3 1B и 4B через QLoRA. Тесты скорости, сравнение точности 76% v

Почему Docker-команды переводят хуже всего

Запускаете контейнер в изолированной среде без интернета? Нужно быстро перевести команду из документации, но Google Translate превращает docker run --mount type=bind,src=$(pwd),dst=/app в бессмысленный набор слов? Я тоже сталкивался с этим.

Облачные переводчики ломаются на техническом сленге, флагах командной строки, путях файлов. Особенно когда дело касается Docker — там своя логика, свои паттерны. Решение? Обучить модель понимать именно этот язык.

На 21.02.2026 Gemma 3 от Google — одна из самых сбалансированных моделей для локального запуска. Новые версии 1B и 4B специально оптимизированы для инференса на CPU и слабом железе.

Что у нас получится в итоге

CLI-утилита, которая берет английскую Docker-команду и выдает русский перевод с объяснением каждого флага. Работает полностью локально, без единого запроса в интернет. Идеально для:

  • Обучения новичков Docker
  • Быстрого перевода документации в офлайн-режиме
  • Интеграции в CI/CD пайплайны с изолированным доступом
  • Создания собственной базы знаний команд
💡
Если вам интересны другие кастомизированные версии Gemma 3, посмотрите статью про 20 финтюнов Gemma 3 от DavidAU. Там собраны модели с улучшенными reasoning-способностями и снятыми ограничениями.

1 Готовим датасет: какие команды и как собирать

Первая ошибка — пытаться взять все команды подряд. Docker CLI огромен, но 80% работы покрывают 20% команд. Собираем структурированный датасет:

{
  "instruction": "Translate Docker command to Russian with explanations",
  "input": "docker run -d --name nginx -p 8080:80 -v /data:/usr/share/nginx/html nginx:alpine",
  "output": "Запустить контейнер в фоновом режиме (-d) с именем 'nginx' (--name), пробросить порт 8080 хоста на 80 контейнера (-p), подключить том с хоста /data в контейнер /usr/share/nginx/html (-v), использовать образ nginx:alpine"
}

Ключевые моменты:

  • Берем реальные команды из популярных туториалов, официальной документации
  • Обязательно включаем compose-файлы (docker-compose up -d)
  • Добавляем команды управления сетями, томами, образами
  • Для каждой команды — четкое объяснение каждого флага

Мой датасет на 21.02.2026 содержит 1250 пар «команда-объяснение». Этого достаточно для качественного финтюна даже маленькой модели.

2 Выбор модели: Gemma 3 1B против 4B — что брать

Здесь большинство ошибается дважды. Либо берут слишком большую модель (и потом мучаются со скоростью), либо слишком маленькую (и получают мусор на выходе).

Параметр Gemma 3 1B Gemma 3 4B
Размер (4-bit) ~0.7 GB ~2.5 GB
Скорость на CPU (токенов/сек) 45-55 18-25
Точность в моих тестах 76% 94%
Минимальная RAM 4 GB 8 GB
Время обучения QLoRA 25 минут 1.5 часа

Выбор простой: если нужна максимальная скорость на слабом железе — 1B. Если важна точность и вы готовы пожертвовать скоростью — 4B. Лично я выбрал 4B, потому что 76% точности — это когда каждая четвертая команда переводится с ошибкой. Неприемлемо для production.

Не берите Gemma 3 270B для этой задачи. Да, она умнее. Но даже в 4-bit квантовании она займет 15+ GB памяти, а скорость будет 2-3 токена в секунду на CPU. Это как стрелять из пушки по воробьям.

3 Тонкая настройка через QLoRA: настройки, которые работают

QLoRA (Quantized Low-Rank Adaptation) — это магия 2025-2026 годов. Позволяет дообучить большую модель, изменяя всего 1-2% весов. Экономия памяти в 10 раз, скорость обучения выше.

Вот конфиг, который я выбил методом проб и ошибок:

from transformers import TrainingArguments
from peft import LoraConfig

# Конфиг LoRA - не меняйте эти параметры без причины
lora_config = LoraConfig(
    r=16,           # Rank - увеличивать только если качество низкое
    lora_alpha=32,  # Alpha - обычно в 2 раза больше r
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

# Параметры обучения
training_args = TrainingArguments(
    output_dir="./gemma-3-4b-docker-translator",
    num_train_epochs=3,           # Больше 3 - overfitting гарантирован
    per_device_train_batch_size=4,
    gradient_accumulation_steps=2,
    warmup_steps=50,
    logging_steps=25,
    save_steps=100,
    eval_steps=100,
    evaluation_strategy="steps",
    learning_rate=2e-4,           # Для QLoRA ставьте выше обычного
    fp16=True,                    # Обязательно для современных GPU
    gradient_checkpointing=True,  # Экономит память
    optim="paged_adamw_8bit",    # Только так для QLoRA
    report_to="none",            # Отключаем wandb/tensorboard
    save_total_limit=2
)

Почему именно такие параметры? r=16 — золотая середина между качеством и размером адаптера. Увеличивать до 32 или 64 стоит только если у вас огромный датасет (10k+ примеров). Для наших 1250 примеров 16 более чем достаточно.

target_modules — здесь важно не пропустить ключевые слои. В Gemma 3 архитектура немного отличается от Llama, но эти проекции работают стабильно.

💡
Если вы работаете в среде с ограниченным доступом в интернет, вам пригодится статья про локальные LLM против интернет-цензуры. Там подробно разбирается, как настроить окружение для полностью офлайн-работы.

4 Инференс на CPU: оптимизация скорости и памяти

Обученная модель — это только половина дела. Вторая половина — заставить ее быстро работать на обычном процессоре. Особенно если у вас нет GPU.

Используем llama.cpp — на 21.02.2026 это версия 0.16.3 с поддержкой Gemma 3 и новыми оптимизациями:

# Конвертируем модель в формат GGUF
python convert_hf_to_gguf.py \
    --model ./gemma-3-4b-docker-translator \
    --outfile ./gemma-3-4b-docker-translator.Q4_K_M.gguf \
    --outtype q4_k_m  # Лучший баланс качество/размер

# Квантование до 4-bit для экономии памяти
./quantize \
    ./gemma-3-4b-docker-translator.f16.gguf \
    ./gemma-3-4b-docker-translator.Q4_K_M.gguf \
    Q4_K_M

# Запуск инференса
./main -m ./gemma-3-4b-docker-translator.Q4_K_M.gguf \
    -p "Translate: docker compose down -v --rmi all" \
    -n 256 \
    -t 8 \
    --temp 0.1 \
    --repeat-penalty 1.1

Ключевые флаги для скорости:

  • -t 8 — используем 8 потоков CPU (ставьте по количеству физических ядер)
  • --temp 0.1 — низкая температура для детерминированных переводов
  • --repeat-penalty 1.1 — штраф за повторения, чтобы модель не зацикливалась

На моем Intel i7-12700K Gemma 3 4B выдает 22-25 токенов в секунду. Для переводчика команд этого более чем достаточно — большинство команд укладываются в 50-100 токенов.

5 Создаем CLI-утилиту: обертка на Python

Работать через ./main неудобно. Создаем простую утилиту на Python:

#!/usr/bin/env python3
import subprocess
import sys
import json

class DockerTranslator:
    def __init__(self, model_path: str):
        self.model_path = model_path
        self.template = """Translate Docker command to Russian with explanations:
Command: {command}
Translation: """
    
    def translate(self, command: str) -> str:
        prompt = self.template.format(command=command)
        
        # Вызов llama.cpp через subprocess
        cmd = [
            "./main",
            "-m", self.model_path,
            "-p", prompt,
            "-n", "256",
            "-t", "8",
            "--temp", "0.1",
            "--repeat-penalty", "1.1",
            "--silent-prompt"
        ]
        
        result = subprocess.run(cmd, capture_output=True, text=True)
        output = result.stdout.strip()
        
        # Вырезаем только ответ модели
        if "Translation:" in output:
            translation = output.split("Translation:", 1)[1].strip()
            return translation
        return output

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: docker-translate 'docker run ...'")
        sys.exit(1)
    
    translator = DockerTranslator("./gemma-3-4b-docker-translator.Q4_K_M.gguf")
    command = " ".join(sys.argv[1:])
    result = translator.translate(command)
    print(f"📦 Команда: {command}")
    print(f"🇷🇺 Перевод: {result}")

Теперь работаем просто:

$ docker-translate 'docker run -it --rm ubuntu bash'
📦 Команда: docker run -it --rm ubuntu bash
🇷🇺 Перевод: Запустить интерактивный контейнер (-it) с автоматическим удалением после завершения (--rm), использовать образ ubuntu, выполнить команду bash

Тестируем: какие команды ломают модель

После обучения провел стресс-тест. 200 команд, которых не было в датасете. Результаты:

Тип команды Gemma 3 4B (точность) Проблемы
Простые run команды 98% Нет
Сети и volumes 92% Иногда путает --network и --net
Docker Compose 89% Сложные флаги вроде --profile
Build с кэшем 85% --no-cache, --pull понимает не всегда
Swarm/Orchestration 76% Специфичные флаги требуют дообучения

Вывод: модель отлично справляется с повседневными задачами. Сложные orchestration-команды требуют расширения датасета. Но для 95% разработчиков этого более чем достаточно.

Не пытайтесь заставить модель переводить команды с pipe (|) или сложной bash-логикой. Это не переводчик bash, а переводчик Docker CLI. Для сложных скриптов лучше разбивать на части.

Деплой в Docker: ирония в квадрате

Самая забавная часть — упаковываем Docker-переводчик в Docker-контейнер. Метауровень достигнут.

FROM ubuntu:22.04

# Устанавливаем зависимости для llama.cpp
RUN apt-get update && apt-get install -y \
    build-essential \
    cmake \
    git \
    python3 \
    python3-pip \
    && rm -rf /var/lib/apt/lists/*

# Клонируем и собираем llama.cpp
RUN git clone https://github.com/ggerganov/llama.cpp && \
    cd llama.cpp && \
    mkdir build && cd build && \
    cmake .. -DLLAMA_CUBLAS=OFF && \
    make -j$(nproc)

# Копируем модель и скрипты
COPY gemma-3-4b-docker-translator.Q4_K_M.gguf /app/model.gguf
COPY docker-translate.py /app/docker-translate.py
COPY entrypoint.sh /app/entrypoint.sh

RUN chmod +x /app/entrypoint.sh

WORKDIR /app
ENTRYPOINT ["/app/entrypoint.sh"]

entrypoint.sh — простой скрипт, который запускает нашу утилиту:

#!/bin/bash
cd /app
python3 docker-translate.py "$@"

Собираем и запускаем:

docker build -t docker-translator .
docker run --rm docker-translator \
    'docker logs --tail 100 -f container_name'

Получаем перевод команды для просмотра логов внутри контейнера, который переводит Docker-команды. Круг замкнулся.

💡
Для более глубокого понимания оптимизации llama.cpp под разное железо рекомендую статью «Аргументы llama.cpp: от слепого копирования команд к осознанной настройке». Там разобраны все флаги и их влияние на производительность.

Что делать, если хочется больше

Проект работает, но всегда есть куда расти. Вот что можно улучшить:

  • Добавить контекст — модель не знает, переводите вы для новичка или для эксперта. Можно добавить префикс «Explain for beginner:» или «Brief explanation:»
  • Поддержка других CLI — тот же подход работает для kubectl, git, aws-cli. Нужно только собрать датасет
  • Интеграция с IDE — плагин для VS Code, который переводит команды прямо в терминале
  • Обратный перевод — с русского на английский. Полезно, когда ищешь команду в документации

Самое главное — начать с малого. Не пытайтесь создать универсальный переводчик всех команд сразу. Docker CLI — отличная отправная точка: команды структурированы, документация богатая, сообщество большое.

Через неделю после запуска моего переводчика в команде из 15 разработчиков, 3 джуниора перестали задавать вопросы «что делает этот флаг?». Они просто прогоняли команду через переводчик. Экономия времени — 20-30 минут в день на человека. Умножьте на зарплату — получается существенно.

Локальные LLM в 2026 году — это не игрушки для энтузиастов. Это рабочие инструменты, которые решают конкретные бизнес-задачи. Переводчик Docker-команд — лишь один пример из сотен возможных. Следующий на очереди — переводчик ошибок из логов. Но это уже другая история.