Локальные LLM — обзор стека
Выжимка по теории: Ollama, Gemma 4, MCP, RAG, векторные БД и инструменты.
Что такое локальная LLM и зачем
Локальная LLM — языковая модель запущенная на своём железе без обращения к облачным API. Основные причины использовать:
- Приватность — данные не покидают инфраструктуру
- Стоимость — нет платы за токены при постоянной нагрузке
- Офлайн — работает без интернета
- Контроль — можно настраивать параметры inference, квантизацию, контекст
Компромисс: качество локальных моделей заметно ниже чем у Claude Sonnet/Opus или GPT-4, а скорость на CPU-железе намного медленнее чем у облачных сервисов.
Архитектура стека
Полный стек состоит из четырёх независимых слоёв:
┌─────────────────────────────────────┐
│ Интерфейс / клиент │ Open WebUI, Claude Code, API клиент
├─────────────────────────────────────┤
│ MCP серверы RAG + Vector │ опциональные расширения
├─────────────────────────────────────┤
│ Inference сервер │ Ollama, llama.cpp, vLLM
├─────────────────────────────────────┤
│ Модель (веса) │ GGUF / GPTQ / AWQ файлы
└─────────────────────────────────────┘
Каждый слой независим и взаимозаменяем. Можно поменять модель не трогая интерфейс, или поменять vector store не трогая Ollama.
Ollama — inference сервер
Ollama — самый простой способ запустить локальную LLM. Загружает модель, управляет VRAM/RAM, предоставляет OpenAI-совместимый HTTP API на порту 11434.
Что делает Ollama под капотом
- Скачивает модель в формате GGUF с ollama.com или HuggingFace
- При первом запросе загружает веса в память
- Принимает запросы через REST API (
/api/generate,/api/chat) - Выгружает модель из памяти после периода простоя (
KEEP_ALIVE)
Ключевые переменные окружения
| Переменная | Описание | Дефолт |
|---|---|---|
OLLAMA_MAX_LOADED_MODELS | сколько моделей держать в памяти | 1 |
OLLAMA_KEEP_ALIVE | через сколько выгрузить модель | 5m |
OLLAMA_NUM_PARALLEL | параллельных запросов | 1 |
OLLAMA_MODELS | путь к папке с моделями | ~/.ollama |
Форматы квантизации
Квантизация — сжатие весов модели для уменьшения размера и ускорения inference за счёт небольшой потери качества.
| Формат | Размер | Качество | Применение |
|---|---|---|---|
q4_K_M | ~4 бит/параметр | хорошее | оптимальный баланс для CPU |
q8_0 | ~8 бит/параметр | почти полное | если достаточно RAM |
bf16 | 16 бит/параметр | полное | только GPU с большим VRAM |
GPTQ/AWQ | 4-8 бит | близко к полному | GPU-оптимизированные форматы |
Что влияет на скорость inference
Главный фактор — memory bandwidth, а не количество ядер. При генерации каждого токена модель читает все веса из памяти. Поэтому:
- Серверный EPYC с 8-канальным DDR5 (~300 ГБ/с) быстрее десктопного i9 (~38 ГБ/с) в разы
- RTX 4090 (GDDR6X, ~1 ТБ/с) быстрее любого CPU
- H100 в датацентре (HBM3, ~3.35 ТБ/с) быстрее RTX 4090 в 3 раза
Для справки — облачные модели типа Claude работают на TPU/H100 кластерах и выдают 100-300+ токенов/сек при модели на сотни миллиардов параметров.
Модели Gemma 4
Gemma 4 — семейство моделей от Google, выпущенное в апреле 2026. Особенность — наличие edge-версий специально для запуска на ограниченном железе.
Линейка
| Модель | Тип | Размер Q4 | Контекст | Применение |
|---|---|---|---|---|
gemma4:e2b | MoE Edge | ~7.2 ГБ | 128K | Raspberry Pi, мобильные устройства |
gemma4:e4b | MoE Edge | ~9.6 ГБ | 128K | Ноутбуки, мини-ПК |
gemma4:26b | MoE | ~18 ГБ | 256K | Сервер с GPU |
gemma4:31b | Dense | ~20 ГБ | 256K | Сервер с GPU, топ качество |
Что означает MoE (Mixture of Experts)
В обычной (dense) модели при генерации каждого токена задействуются все параметры. В MoE модели параметры разбиты на "экспертов" — специализированные подсети. При каждом токене активируется только часть из них (обычно 2-4 из 8-32).
Результат: вычислительная стоимость соответствует маленькой модели, но качество ближе к большой. Именно поэтому gemma4:e2b называется "Effective 2B" — при inference активно только ~2B параметров, хотя весов хранится больше.
Обратная сторона: MoE требует больше RAM для хранения всех экспертов, даже тех что не активны прямо сейчас.
Суффиксы тегов в Ollama
| Суффикс | Значение |
|---|---|
it | instruction-tuned — для диалога |
q4_K_M | квантизация 4-бит |
q8_0 | квантизация 8-бит |
bf16 | полная точность (только GPU) |
mlx | формат для Apple Silicon |
mxfp8 / nvfp4 | форматы для новых NVIDIA GPU |
RAG — Retrieval-Augmented Generation
RAG — техника которая позволяет модели отвечать на вопросы опираясь на конкретные документы, не зная их содержимое заранее (не через fine-tuning, а через поиск по запросу).
Важное понимание
Модель не обучается на твоих документах. RAG — это умный copy-paste: система находит релевантные куски текста и буквально вставляет их в промпт перед вопросом. Модель видит текст документа так же как видит твой вопрос.
Фаза 1 — индексирование (один раз)
Документ → Чанкинг → Embedding модель → Вектор float[] → Vector Store
-
Чанкинг — документ нарезается на куски (chunk size ~500-1500 токенов) с перекрытием (overlap ~100-200 токенов). Перекрытие нужно чтобы контекст на границах чанков не терялся.
-
Embedding — каждый чанк преобразуется в вектор из сотен или тысяч чисел. Семантически похожие тексты дают близкие векторы в многомерном пространстве. Например "задержка запросов" и "высокое время ответа API" будут близки векторно.
-
Vector Store — векторы сохраняются в специализированной БД (Qdrant, ChromaDB, pgvector) которая умеет быстро искать ближайшие векторы.
Фаза 2 — поиск при каждом запросе
Вопрос → Та же embedding → Поиск top-K похожих → Вставка в промпт → LLM → Ответ
Ключевой момент: запрос и документы должны эмбеддиться одной и той же моделью. Иначе векторы будут в разных пространствах и сравнение не даст смысла.
Итоговый промпт с RAG контекстом
[СИСТЕМНЫЙ ПРОМПТ]
Отвечай на вопросы опираясь на предоставленный контекст.
Если ответа нет в контексте — скажи об этом.
[КОНТЕКСТ]
--- Источник: nginx-setup.md, строки 45-89 ---
Для настройки reverse proxy в Nginx нужно создать...
--- Источник: docker-compose-guide.md, строки 12-34 ---
Сервис open-webui подключается к Ollama через...
[/КОНТЕКСТ]
[ВОПРОС ПОЛЬЗОВАТЕЛЯ]
Как настроить Nginx для Open WebUI?
Где RAG работает плохо
- Табличные данные — плохо ложатся в семантический поиск
- Очень короткие документы — мало контекста для embedding
- Вопросы требующие агрегации по всему документу ("посчитай сколько раз упоминается X")
- Скриншоты и отсканированные PDF без OCR
Выбор embedding модели
Качество поиска напрямую зависит от embedding модели. Для технической документации на русском:
nomic-embed-text— хороший баланс, работает через Ollamamultilingual-e5-large— лучше для смешанного русского/английскогоbge-m3— топ качество для многоязычных задач
Vector Store — варианты
| Хранилище | Особенности | Когда использовать |
|---|---|---|
| Qdrant | быстрый, фильтрация по метаданным, хорошая документация | рекомендуется для production |
| ChromaDB | прост в настройке, embedded режим | для разработки и прототипов |
| pgvector | расширение PostgreSQL | если уже есть Postgres |
| Weaviate | граф + векторы, гибридный поиск | сложные схемы данных |
| OpenSearch | если уже используется для логов | унификация с ELK стеком |
MCP — Model Context Protocol
MCP — открытый стандарт от Anthropic (передан Linux Foundation в декабре 2025) для подключения LLM к внешним инструментам и сервисам через унифицированный интерфейс.
Аналогия: USB-C для AI — один стандарт, к которому подключается что угодно.
Архитектура
LLM клиент (Claude Code / Open WebUI)
↕ JSON-RPC 2.0
MCP сервер (твой Python/TypeScript процесс)
↕ HTTP / socket
Внешний сервис (Graylog, Docker, GitHub, Proxmox...)
Транспорты
- stdio — MCP сервер запускается как subprocess, общение через stdin/stdout. Подходит для локального использования.
- Streamable HTTP — сервер слушает HTTP порт. Нужен для удалённого доступа и интеграции с Open WebUI.
Что модель получает от MCP
MCP сервер экспонирует набор инструментов (tools) — функций с описанием и схемой параметров. Пример:
{
"name": "search_logs",
"description": "Search recent application logs in Graylog. Use when user asks about errors, crashes, slow responses, or any runtime issues in production services.",
"inputSchema": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"},
"time_range": {"type": "integer", "description": "Time range in seconds"}
}
}
}
Как модель решает когда использовать инструмент
Это не if/else логика и не ключевые слова. Модель прошла специальный этап обучения — function calling fine-tuning — где ей показывали тысячи примеров правильного использования инструментов. При каждом запросе она получает список инструментов в системном промпте и самостоятельно решает:
- Есть ли у меня уже достаточно информации для ответа?
- Если нет — какой инструмент поможет получить нужные данные?
- С какими параметрами его вызвать?
Цикл вызова инструмента
1. Пользователь задаёт вопрос
2. Хост собирает промпт: вопрос + список инструментов
3. Модель генерирует JSON вызов инструмента (останавливает генерацию)
4. Хост перехватывает JSON, выполняет реальный запрос к MCP серверу
5. MCP сервер обращается к внешнему сервису, возвращает результат
6. Хост добавляет результат в контекст, снова отправляет в модель
7. Модель генерирует финальный ответ пользователю
8. При необходимости шаги 3-7 повторяются (цепочка вызовов)
Модель не выполняет инструменты сама — она только генерирует описание вызова. Реальное исполнение делает хост (Open WebUI, Claude Code и т.д.).
Качество описания инструмента критично
Описание (description) — единственный способ объяснить модели когда и зачем использовать инструмент. Плохое описание ведёт к неправильным вызовам или игнорированию инструмента.
Плохо:
"description": "get logs"
Хорошо:
"description": "Search recent application logs in Graylog. Use when user asks about errors, crashes, slow responses, high latency, or any runtime issues in production. Returns matching log entries with timestamps."
Готовые MCP серверы
| Сервер | Что умеет |
|---|---|
hashicorp/terraform-mcp-server | документация Terraform Registry, workspace management |
github/github-mcp-server | репозитории, PR, issues, Actions |
docker/docker-mcp-server | контейнеры, логи, stats |
anthropic/postgres-mcp-server | запросы к PostgreSQL |
Для специфичных сервисов (Graylog, Proxmox, MikroTik) — пишешь свой сервер, это ~100-150 строк Python.
MCP vs RAG — в чём разница
Их часто путают, но это принципиально разные вещи:
| RAG | MCP | |
|---|---|---|
| Что делает | ищет по статичным документам | выполняет действия в реальном времени |
| Данные | проиндексированные заранее | актуальные на момент запроса |
| Примеры | документация, runbooks, код | логи, метрики, статус контейнеров |
| Когда нужен | "как настроить X" | "что происходит сейчас с X" |
Они дополняют друг друга: RAG для знаний, MCP для действий.
Open WebUI
Open WebUI — веб-интерфейс для работы с Ollama (и другими LLM). Из коробки включает:
- Управление разговорами и моделями
- Встроенный RAG pipeline (чанкинг, embedding, поиск)
- Knowledge Base — постоянное хранилище документов
- Поддержку MCP серверов через HTTP bridge
- Мультипользовательский режим с ролями
Режимы загрузки документов
В чат напрямую — документ доступен только в текущем разговоре, индексируется на лету.
В Knowledge Base (Workspace → Knowledge) — постоянное хранилище. Документы индексируются один раз, доступны в любом чате через #имя-коллекции. Можно привязать коллекцию к кастомной модели — тогда RAG работает автоматически без ручного указания.
Веб-страницы — начни сообщение с #URL и Open WebUI скачает и проиндексирует страницу на лету.
Поддерживаемые форматы документов
pdf, txt, md, docx, doc, xlsx, xls, pptx, ppt, csv, rst, xml, epub
Для лучшего качества RAG — Markdown и plain text. PDF работает хорошо если не скан. Для расширенного OCR и сложных форматов можно подключить Apache Tika как отдельный контейнер.
Выбор железа
Memory bandwidth — главный параметр
| Железо | Bandwidth | Скорость (14B Q4) |
|---|---|---|
| i9-9900K DDR4 | ~38 ГБ/с | 3-5 т/с |
| i5-12400 DDR4/5 | ~50 ГБ/с | 4-6 т/с |
| EPYC 8-channel DDR5 | ~300 ГБ/с | 15-25 т/с |
| RTX 4090 GDDR6X | ~1 ТБ/с | 40-80 т/с |
| H100 HBM3 | ~3.35 ТБ/с | 100-150 т/с |
Сколько RAM нужно
Модель должна целиком влезть в RAM. Если нет — начнётся своп и скорость упадёт до 0.1-0.5 т/с.
| Свободно RAM | Рекомендуемая модель | Ожидаемая скорость |
|---|---|---|
| 8 ГБ | gemma4:e2b или qwen2.5:7b | 3-5 т/с |
| 16 ГБ | gemma4:e4b или qwen2.5:14b | 4-7 т/с |
| 32 ГБ | qwen2.5:32b | 2-4 т/с |
| 64+ ГБ | gemma4:26b или gemma4:31b | 3-6 т/с |
Варианты деплоя
| Вариант | Стоимость | Скорость | Когда |
|---|---|---|---|
| Локальное железо | уже есть | зависит от железа | попробовать, небольшая команда |
| Hetzner Dedicated (AX серия) | €60-120/мес | 8-15 т/с | постоянная нагрузка, команда |
| Облачный GPU (RunPod) | $0.3-2/час | 40-80 т/с | разовые задачи, эксперименты |
| Свой сервер с GPU | $600-1200 разово | 30-50 т/с | долгосрочно, приватность данных |
Типичный production стек
services:
ollama: # inference сервер
open-webui: # интерфейс + RAG pipeline
qdrant: # vector store для RAG
mcp-server: # кастомные инструменты (опционально)
nginx: # reverse proxy + SSL (если нужен внешний доступ)
Минимальный рабочий вариант для начала — только Ollama + Open WebUI. Qdrant и MCP добавляются по мере необходимости.