On-prem AI пайплайн для документов: OCR + RAG без облака | AiManual
AiManual Logo Ai / Manual.
27 Мар 2026 Гайд

Полное руководство по созданию on-prem AI пайплайна для документов (OCR + RAG) без облака

Пошаговое руководство по развертыванию локального AI пайплайна для обработки конфиденциальных документов с использованием OCR и RAG. Без облачных API, с открыты

Ваши документы утекают в облака? Пора строить крепость

Контракты, медицинские записи, финансовые отчеты — всё, что должно оставаться внутри компании, постоянно летит на серверы сторонних AI-провайдеров. Каждый раз, когда вы загружаете PDF в облачный OCR или задаете вопрос через API ChatGPT, ваши данные покидают периметр. Звучит как сюжет для отдела кибербезопасности? Так и есть.

В 2026 году проблема не в том, можно ли обрабатывать документы локально. Проблема в том, как сделать это без головной боли, когда у вас нет команды из 10 ML-инженеров. Я собрал пайплайн, который работает на обычном сервере, не требует облачных лицензий и справляется с тысячами страниц в день.

Забудьте про «теоретически возможно». Мы говорим о рабочем конвейере, который я развернул для клиента из финсектора. Их требование было простым: ноль внешних API, ноль данных в интернете, полный контроль над каждым байтом.

Почему облачный RAG для документов — это русская рулетка в 2026 году

Кажется, что проще: взяли OpenAI API, подключили векторную базу, загрузили документы. Работает за пару дней. Пока не начинаешь читать мелкий шрифт в соглашении об обработке данных. Или не получаешь счет за 3 миллиона токенов. Или не обнаруживаешь, что ваш конкурент вдруг узнал о ваших планах слияния.

  • Данные — это новая нефть, а вы ее раздаете. Cloud AI-провайдеры часто оставляют за собой право использовать ваши данные для обучения моделей. Даже с отключенным logging.
  • Юридический ад. GDPR, HIPAA, ФЗ-152 — попробуйте объяснить регулятору, почему медицинская карта пациента лежит на серверах в Калифорнии.
  • Стоимость — это черный ящик. Обработка 10 000 PDF обойдется вам в... кто знает? Ценник меняется каждый месяц, а вы заложили бюджет на год.
  • Зависимость. Отключили интернет? API упал? Ваш бизнес-процесс остановился.

Локальное решение — не про «дешевле». Оно про контроль. Про предсказуемость. Про то, чтобы спать спокойно, зная, где лежат ваши документы. Если вам интересно, как устроена промышленная обработка документов на масштабе, посмотрите историю про 26 ТБ документов в Associa.

Стек технологий: что действительно работает в 2026 году

Не верьте маркетингу. Половина «локальных» решений на самом деле стучится в облако за эмбеддингами или языковой моделью. Наш стек — 100% автономный.

Компонент Инструмент (актуально на март 2026) Альтернатива Зачем нужен
OCR / Извлечение текста Tesseract 6.0 + DocTR (Document Text Recognition) 0.10 PaddleOCR, EasyOCR, коммерческие решения вроде Doc2Me AI Solutions Перевести сканы, фото, PDF в машиночитаемый текст. Для сложных форм нужна гибридная архитектура.
Парсинг и чанкинг LlamaIndex LiteParse 2.3 (обновление 2025 года) Unstructured.io, собственная логика на Python Разбить текст на логические фрагменты (чанки) с сохранением структуры. LiteParse умеет работать с таблицами и заголовками.
Модель эмбеддингов BGE-M3 (BAAI/bge-m3) через Sentence Transformers Nomic AI's nomic-embed-text-v2, Jina Embeddings v3 Превратить текст в числовые векторы для поиска. BGE-M3 на март 2026 — лидер по качеству для мультиязычных данных.
Векторная БД Qdrant 1.9.x (поддержка sparse-dense векторов) ChromaDB (проще), Weaviate (тяжелее) Хранить эмбеддинги и выполнять семантический поиск. Qdrant быстрее на больших объемах.
Языковая модель (LLM) Llama 4 13B (или Qwen2.5 14B) в 4-битной квантованности Mistral AI модели, Phi-4 Отвечать на вопросы по документам, используя найденные чанки. 13-14 миллиардов параметров — оптимальный баланс качества и скорости на серверном GPU.
Оркестрация FastAPI + Celery (или чистое FastAPI для простоты) Airflow, Prefect Связать все компоненты в пайплайн, обеспечить API, очередь задач.
💡
Не гонитесь за самой новой моделью. Llama 4 только что вышла, но Llama 3.1 70B может давать сравнимые результаты, будучи лучше оптимизированной под квантование. Проверяйте benchmarks на ваших данных. Подробнее о выборе архитектуры читайте в полном руководстве по RAG.

Пошаговый план: от голого сервера до работающего ассистента

Здесь нет магии. Только команды, конфиги и неизбежные ошибки, которые я уже совершил за вас. Предполагаем, что у вас есть сервер с Ubuntu 22.04 LTS, 64 ГБ ОЗУ, GPU с 16+ ГБ VRAM (например, RTX 4090 или A10) и здоровое желание разобраться.

1 Готовим среду: контейнеры против голой установки

Docker — ваш друг, но не для GPU-инференса. Для продакшена я рекомендую установить ключевые компоненты на хост, а логику пайплайна упаковать в контейнеры. Так легче обновлять модели и не бороться с драйверами внутри Docker.

# Установка системных зависимостей и Python 3.11
sudo apt update && sudo apt install -y python3.11 python3.11-venv python3.11-dev \
  tesseract-ocr tesseract-ocr-rus tesseract-ocr-eng \
  poppler-utils libgl1-mesa-glx

# Создаем виртуальное окружение
python3.11 -m venv ~/docai_env
source ~/docai_env/bin/activate

# Устанавливаем torch с поддержкой CUDA 12.1 (актуально на 2026)
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121

2 Ядро пайплайна: OCR, который не сломается на плохом скане

Tesseract в одиночку справляется с 80% случаев. Для остальных 20% — комбинация с DocTR (основанным на Vision Transformer). Это дает точность выше 95% даже для рукописных заметок. Если работаете с нелатинскими шрифтами, посмотрите наш разбор проблем арабского OCR.

# Пример гибридного OCR-процессора
import pytesseract
from doctr.models import ocr_predictor
import cv2

class HybridOCR:
    def __init__(self):
        # Загружаем современную модель DocTR (можно кэшировать)
        self.doctr_model = ocr_predictor(det_arch='db_resnet50', reco_arch='crnn_vgg16_bn', pretrained=True)
        
    def extract_text(self, image_path):
        # Первый проход: быстрый Tesseract
        text_tess = pytesseract.image_to_string(image_path, lang='rus+eng')
        if self._confidence_check(text_tess):
            return text_tess
        
        # Второй проход: тяжелая артиллерия DocTR для сложных случаев
        img = cv2.imread(image_path)
        result = self.doctr_model([img])
        full_text = "\n".join([block.value for block in result.pages[0].blocks])
        return full_text
    
    def _confidence_check(self, text):
        # Простая эвристика: если текст короткий и много непонятных символов — плохо
        if len(text.strip()) < 10:
            return False
        # Можно добавить более сложную логику
        return True

3 Чанкинг: самая скучная и самая важная часть

Разбить текст на абзацы — просто. Разбить так, чтобы не потерять смысл и контекст — искусство. Не делайте фиксированные чанки по 500 символов. Это убивает RAG.

# Умный чанкинг с учетом семантических границ
from llama_index.core.node_parser import SemanticSplitterNodeParser
from llama_index.embeddings.huggingface import HuggingFaceEmbedding

# Используем ту же модель эмбеддингов, что и для поиска
embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-m3")

splitter = SemanticSplitterNodeParser(
    buffer_size=1,  # На сколько предложений заглядывать вперед/назад
    breakpoint_percentile_threshold=95,  # Порог для определения границы чанка
    embed_model=embed_model
)

# Предположим, у нас есть документ, извлеченный из PDF
nodes = splitter.get_nodes_from_documents([document])
# Каждый node — это чанк с метаданными (источник, позиция в документе)

Самый частый косяк: чанкинг делается ДО создания эмбеддингов, но с использованием другой модели. В результате границы чанков не соответствуют семантическим кластерам вашей основной модели. Используйте одну и ту же модель или хотя бы одну архитектуру (например, только BGE).

4 Векторная база: запускаем Qdrant и загружаем данные

Qdrant можно запустить одним Docker-образом, но для продакшена лучше нативное размещение. Если ваша коллекция больше 10 миллионов векторов, прочитайте историю про 4 миллиона PDF.

# Запускаем Qdrant сервер (нативная установка через бинарник)
wget https://github.com/qdrant/qdrant/releases/download/v1.9.4/qdrant-x86_64-unknown-linux-gnu.tar.gz
tar -xzf qdrant-*.tar.gz
./qdrant --host 0.0.0.0 --port 6333 &

# Создаем коллекцию с нужными параметрами
curl -X PUT 'http://localhost:6333/collections/docs' \
  -H 'Content-Type: application/json' \
  -d '{
    "vectors": {
      "size": 1024,  # Размерность BGE-M3
      "distance": "Cosine"
    },
    "sparse_vectors": {
      "sparse-text": {
        "index": {
          "full_scan_threshold": 1000
        }
      }
    }
  }'

5 LLM инференс: заставляем Llama 4 работать локально

Скачать модель с Hugging Face — полдела. Заставить ее быстро отвечать — другая история. Используем Ollama или vLLM для эффективной подачи.

# Установка vLLM (оптимизированный сервер инференса)
pip install vllm

# Запуск модели с квантованием AWQ (экономит память и ускоряет)
vllm serve llama-4-13b-instruct --quantization awq --tensor-parallel-size 1 --gpu-memory-utilization 0.9

# Теперь модель доступна на http://localhost:8000
# Код для запроса к локальной LLM в пайплайне RAG
from vllm import SamplingParams
import requests

def query_llama_with_context(question, context_chunks):
    prompt_template = """Ты — ассистент, отвечающий на вопросы по документам. Используй только приведенный контекст.
Контекст: {context}
Вопрос: {question}
Ответ:"""
    
    context = "\n\n".join(context_chunks)
    prompt = prompt_template.format(context=context, question=question)
    
    sampling_params = SamplingParams(temperature=0.1, top_p=0.9, max_tokens=512)
    
    # Отправляем запрос на локальный vLLM сервер
    response = requests.post(
        "http://localhost:8000/v1/completions",
        json={
            "model": "llama-4-13b-instruct",
            "prompt": prompt,
            "sampling_params": sampling_params.to_dict()
        }
    )
    return response.json()["choices"][0]["text"]

Где все ломается: нюансы, которые не пишут в туториалах

Теория гладкая, а практика — это дебаг до 3 ночи. Вот что сломало мне график в двух последних проектах.

  • PDF — это не текст, это зоопарк форматов. Один файл может содержать сканы страниц, текст поверх изображений, заполненные формы. Универсального парсера нет. Придется комбинировать: pdf2image → OCR для сканов, pdfplumber для текстового слоя. Полный гайд по автоматическому пониманию документов раскрывает эту тему.
  • Эмбеддинги «забывают» цифры и имена. Модели вроде BGE плохо кодируют точные совпадения. Решение: гибридный поиск. К семантическому поиску по эмбеддингам добавляйте ключевое слово (BM25) по исходному тексту. Qdrant умеет это из коробки.
  • LLM галлюцинирует, даже с контекстом. Если в retrieved чанках нет ответа, модель начнет выдумывать. Добавляйте в промпт строгие инструкции: «Если ответа нет в контексте, скажи 'Не могу найти информацию'». И проверяйте confidence score у поиска.
  • Графическая память GPU кончается в самый неподходящий момент. 13B модель в FP16 — это 26 ГБ. Плюс эмбеддинг-модель, плюс OCR. Используйте квантование (GGUF, AWQ) и загружайте модели по очереди, если GPU один.
💡
Собирайте метрики с первого дня. Сколько времени занимает обработка одного документа? Какая точность OCR на ваших данных? Как часто LLM возвращает «Не знаю»? Без цифр вы будете оптимизировать вслепую. Взгляните, как собирали метрики в проекте PDIQ на AWS — принципы те же.

Вопросы, которые вы хотели задать, но стеснялись

Насколько мощный сервер нужен для обработки 1000 документов в день?

Все упирается в этап OCR и размер LLM. Для потока в 1000 сканов/PDF средней сложности (10 стр.) хватит: 16-ядерный CPU, 64 ГБ ОЗУ, GPU с 24 ГБ VRAM (например, RTX 4090 или A10). Основная нагрузка — инференс эмбеддинг-модели и LLM. Если документы простые текстовые PDF, можно обойтись без мощной GPU.

Как обновлять модели, если пайплайн работает 24/7?

Синий-зеленое развертывание. Разворачиваете вторую копию пайплайна с новыми моделями, переливайте туда трафик, отключаете старую. Для векторной базы — миграция с созданием новой коллекции и reindexing. Не обновляйте модели на лету в продакшене. Никогда.

Что делать с документами на нескольких языках?

BGE-M3 и подобные мультиязычные модели эмбеддингов справляются хорошо. Для OCR нужно добавлять языковые пакеты Tesseract (например, tesseract-ocr-chi-sim для китайского). LLM тоже должна быть мультиязычной. Llama 4 и Qwen2.5 показывают отличные результаты. Для экзотических языков, как в статье про индийские языки, может потребоваться специализированная модель.

Это все open-source. А есть готовые коммерческие on-prem решения?

Есть, но они либо дорогие, либо недостаточно гибкие. Компании вроде Doc2Me AI Solutions предлагают коробочные решения с поддержкой. Плюс: быстрое развертывание, SLA. Минус: вы заперты в их экосистеме, кастомные доработки сложны, а цена может кусаться. Сборка своего пайплайна дает полную свободу, но требует экспертизы.

И последнее: не делайте это в одиночку

Локальный AI пайплайн — это не DevOps, не ML и не Data Engineering. Это все вместе. Найдите коллегу, который разбирается в ML-моделях, или возьмите консультанта на первые этапы. Самая дорогая ошибка — потратить три месяца на сборку, а потом понять, что выбранная модель эмбеддингов не поддерживает русский язык, или что ваша векторная БД не масштабируется. Начните с маленького прототипа на 100 документах. Добейтесь, чтобы он работал идеально. Потом масштабируйте. И помните: ваши данные теперь остаются дома. Это того стоит.

Подписаться на канал