На связи удалённо · офис завтра с 09:00

Серверы и 1С

Свой ИИ в закрытом контуре: когда облако под запретом

ИИ-помощник по внутренним документам без облака: собрали стенд на своих серверах — видеокарты в ESXi, Ollama и поиск по базе знаний на PostgreSQL.

Клиенты всё чаще спрашивают одно и то же: можно ли сделать ИИ-помощника, который знает внутренние регламенты, инструкции и документы компании? Сотрудник спрашивает «как оформить возврат поставщику?» и получает ответ со ссылкой на нужный пункт регламента, а не на статью из интернета.

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

Технически проще всего было бы подключить ChatGPT или Claude через API. Но мы сразу поставили себе то же условие, которое ставят службы безопасности наших клиентов: ни один документ не покидает периметр. Ни в облако, ни в чужой дата-центр, ни «только для обработки». Значит, всё — от модели до базы знаний — должно работать на своём железе, в закрытом контуре, без выхода в интернет.

Главное, что нужно понять про локальные модели

Когда говорят «запустить нейросеть у себя», обычно думают о мощности: процессоры, ядра, гигагерцы. На самом деле главное ограничение — объём видеопамяти. Модель должна целиком поместиться в память видеокарты, иначе её части начнут ездить через шину, и скорость упадёт в десятки раз.

Прикинуть можно на пальцах. Модель с 35 миллиардами параметров в сжатом формате (квантизация 4 бита) занимает около 20 ГБ. Плюс память на контекст — тот самый текст документов, который модель держит «в голове», пока отвечает. Поэтому карта на 24 ГБ — это минимум, с которого начинается разговор о серьёзных моделях, а карта на 10 ГБ подходит для моделей поменьше и вспомогательных задач.

Железо

Стенд мы собирали из того, что реально доступно небольшой компании. Основа — серверы Huawei 2288H V5 с быстрыми NVMe-массивами. Вычисления — видеокарты NVIDIA: RTX 3090 Ti на 24 ГБ под тяжёлые модели и RTX 3080 на 10 ГБ под вспомогательные задачи. Это потребительские карты, а не серверные ускорители за миллионы, и в этом весь смысл: при разумном бюджете получить достаточно памяти для моделей уровня 30+ миллиардов параметров.

Цена этого решения — инженерная работа. Потребительская видеокарта в сервере — это вопросы питания, охлаждения и, главное, виртуализации.

Самое трудное: пробросить видеокарту в виртуальную машину

На серверах стоит гипервизор VMware ESXi 8.0.3, а модели работают в виртуальных машинах на Ubuntu. Чтобы виртуальная машина получила видеокарту целиком и без потерь в скорости, используется проброс устройства (PCI passthrough). На серверных картах это работает из коробки. На потребительских — после нескольких настроек, о которых нигде не написано в одном месте.

На стороне сервера: в BIOS включаем поддержку 64-битного адресного пространства для устройств (Above 4G Decoding). Без неё карта с 24 ГБ памяти просто не помещается в адресное пространство, которое отводится устройствам.

На стороне ESXi: Host → Manage → Hardware → PCI Devices, отмечаем видеокарту для проброса и перезагружаем хост. Пробрасывать нужно обе функции карты — сам графический процессор и встроенный в него аудиоконтроллер HDMI.

На стороне виртуальной машины: загрузка через EFI, полное резервирование оперативной памяти (Reserve all guest memory — без этого проброс не включится) и несколько расширенных параметров:

pciPassthru.use64bitMMIO     = "TRUE"
pciPassthru.64bitMMIOSizeGB  = "64"
hypervisor.cpuid.v0          = "FALSE"

Размер окна MMIO считается от суммарной видеопамяти проброшенных карт, округлённой вверх до степени двойки. Параметр hypervisor.cpuid.v0 скрывает от драйвера, что он работает в виртуальной машине: старые драйверы NVIDIA для потребительских карт отказывались работать в виртуалке с ошибкой Code 43. Современные драйверы к этому относятся спокойно, но параметр не мешает.

Внутри виртуальной машины

Драйвер NVIDIA, Docker и NVIDIA Container Toolkit, который позволяет контейнерам видеть видеокарту:

sudo ubuntu-drivers install
# репозиторий NVIDIA Container Toolkit подключается по официальной инструкции
sudo apt install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

# проверка: контейнер должен увидеть карту
docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi

Если последняя команда показала табличку с вашей видеокартой, всё остальное — дело техники.

Мотор: Ollama

Модели запускает Ollama — сервер, который загружает модель в видеопамять и отвечает на запросы по HTTP. Две карты с разным объёмом памяти мы не объединяем в одну: на каждой своя копия Ollama со своим набором моделей. Тяжёлая модель живёт на 24 ГБ, распознавание и вспомогательные задачи — на 10 ГБ:

services:
  ollama-main:
    image: ollama/ollama:<версия>        # фиксированная версия, не latest
    container_name: ollama-main
    restart: unless-stopped
    environment:
      - OLLAMA_KEEP_ALIVE=30m            # не выгружать модель сразу после ответа
      - OLLAMA_NUM_PARALLEL=2            # сколько запросов обрабатывать одновременно
      - OLLAMA_FLASH_ATTENTION=1         # экономия памяти на длинном контексте
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              device_ids: ["0"]          # RTX 3090 Ti
              capabilities: [gpu]
    volumes:
      - ./ollama-main:/root/.ollama
    ports:
      - "127.0.0.1:11434:11434"          # только локально!

  ollama-aux:
    image: ollama/ollama:<версия>
    container_name: ollama-aux
    restart: unless-stopped
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              device_ids: ["1"]          # RTX 3080
              capabilities: [gpu]
    volumes:
      - ./ollama-aux:/root/.ollama
    ports:
      - "127.0.0.1:11435:11434"

Обратите внимание на 127.0.0.1 в портах. В примерах из интернета почти всегда пишут просто "11434:11434", и это открывает Ollama на всю сеть. А у Ollama нет никакой авторизации: любой, кто дотянулся до порта, может задавать вопросы модели, загружать и удалять модели. В закрытом контуре, который строился ради безопасности, это была бы дыра посреди периметра. Доступ к моделям получают только наши сервисы на той же машине.

Фиксированная версия образа вместо latest — по той же логике: обновление должно быть решением, а не сюрпризом после перезапуска контейнера.

Память компании: RAG на PostgreSQL

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

Базой знаний служит PostgreSQL с расширением pgvector. Документы режутся на фрагменты по смысловым границам — разделам и пунктам, а не по количеству символов, — и для каждого фрагмента считается вектор, числовой «отпечаток смысла»:

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE chunks (
    id         bigserial PRIMARY KEY,
    doc        text NOT NULL,          -- название документа
    section    text,                   -- раздел или пункт
    body       text NOT NULL,          -- сам фрагмент
    embedding  vector(1024) NOT NULL
);

CREATE INDEX ON chunks USING hnsw (embedding vector_cosine_ops);

Поиск — это запрос «найди фрагменты, ближайшие по смыслу к вопросу»:

import requests, psycopg

OLLAMA = "http://127.0.0.1:11435"

def embed(text: str) -> list[float]:
    r = requests.post(f"{OLLAMA}/api/embed", json={"model": "bge-m3", "input": text})
    return r.json()["embeddings"][0]

def find_context(question: str, k: int = 5):
    vec = str(embed(question))
    with psycopg.connect("dbname=kb") as db:
        return db.execute(
            "SELECT doc, section, body FROM chunks "
            "ORDER BY embedding <=> %s::vector LIMIT %s",
            (vec, k),
        ).fetchall()

Поля doc и section здесь не для красоты. В ответе модель обязана указать, из какого документа и пункта она взяла информацию. Это главная защита от «галлюцинаций»: если ответ нельзя подтвердить ссылкой на регламент, сотрудник это видит сразу.

Глаза и уши

Часть знаний компании хранится не в тексте, а в схемах и сканах. Для них мы подключили визуальную модель MiniCPM-V 2.6: она разбирает схемы и изображения и превращает их в текст, который потом попадает в ту же базу знаний.

А чтобы вопрос можно было наговорить голосом, добавили локальное распознавание речи на Faster-Whisper — тоже без единого обращения во внешний мир:

from faster_whisper import WhisperModel

model = WhisperModel("large-v3", device="cuda", compute_type="float16")
segments, _ = model.transcribe("vopros.ogg", language="ru", vad_filter=True)
question = " ".join(s.text.strip() for s in segments)

Параметр vad_filter отрезает тишину и шум, и распознавание коротких голосовых сообщений заметно ускоряется.

Дирижёр

Над всем этим работает оркестратор Hermes Agent. Он решает, какую модель позвать для какой задачи, ходит в базу знаний, собирает ответ и следит за очередью. Когда стенд перестал справляться с нагрузкой, мы обновили его до версии v0.20.6 и подключили второй рабочий сервер с двумя дополнительными видеокартами. Оркестратор раздаёт задачи между серверами сам, и добавление мощности не требует перестраивать систему.

Основную работу с базой знаний выполняют модели Qwen 35B и Gemma 26B, визуальные задачи — MiniCPM-V.

Честно о границах

Локальные модели не заменяют лучшие облачные модели во всём. В сложных рассуждениях, длинных цепочках логики и творческих задачах облако пока сильнее. Но для задачи «найди в наших документах и ответь со ссылкой» локальная модель с хорошей базой знаний справляется уверенно, отвечает за секунды и не отправляет за периметр ни одного байта. А для компаний с коммерческой тайной или персональными данными это часто единственный допустимый вариант.

Что из этого вынести

Свой ИИ в закрытом контуре — это реально и без бюджета дата-центра. Но это не «скачать программу», а инфраструктурный проект: подбор железа под объём видеопамяти, виртуализация с пробросом карт, безопасная публикация моделей, база знаний с поиском по смыслу и честная проверка ответов. Все грабли из этой статьи мы собрали на своём стенде, чтобы клиенты на них не наступали. Если вы думаете о собственном ИИ в закрытом контуре, поможем оценить, какое железо нужно под ваши задачи, и собрать систему — от выбора серверов до интерфейса для сотрудников.

Ещё проекты

Серверы и 1С

Zabbix тревожит сервер 1С: ложная тревога и настоящая настройка памяти SQL

Серверы клиентов у нас под мониторингом Zabbix: он пишет в Telegram, когда что-то идёт не так. Один из серверов 1С стал регулярно присылать предупреждение «Memory Pages/sec is too high (over 1000 for 5m)» со значениями около 4000.

Серверы и 1С

Медицинская система только по секретной ссылке: обратный прокси с ежемесячной ротацией токена

Медицинская организация пользуется облачной медицинской информационной системой (МИС). Вендор системы умеет ограничивать доступ по IP-адресу, но у клиники несколько площадок, сотрудники работают и из дома, и с мобильных устройств, а провайдеры меняют адреса.

Позвонить

Сайт использует cookie: для работы форм, отзывов с Яндекс.Карт и Яндекс.Метрики — чтобы понимать, что улучшить. Подробнее