Ещё пару лет назад разговоры о корпоративном ChatGPT вызывали примерно такую же реакцию, как когда-то разговоры о Kubernetes. Кто-то видел в этом игрушку для энтузиастов, кто-то считал очередным модным словом из презентаций консультантов, а кто-то просто запрещал сотрудникам пользоваться публичными сервисами искусственного интеллекта.
Однако практика показала интересную вещь. Запреты не работают. Разработчики продолжают использовать ChatGPT для генерации кода. Аналитики загружают документы во внешние сервисы. Инженеры просят ИИ объяснить ошибки Terraform или Kubernetes. Данные компании всё равно покидают периметр, просто делают это неуправляемо.
Поэтому вопрос сегодня звучит иначе:
Как построить собственный корпоративный ChatGPT, который останется внутри компании, будет знать внутреннюю документацию и не потребует бюджет уровня покупки дата-центра?
Спойлер: значительно проще, чем кажется.
Как выглядит архитектура
Если убрать маркетинговые названия, архитектура корпоративного ИИ оказывается удивительно простой.
Пользователь
↓
Open WebUI
↓
vLLM
↓
Qwen / DeepSeek
↓
pgvector
↓
Документация компании
Каждый компонент отвечает за свою задачу.
-
Open WebUI - веб-интерфейс, напоминающий ChatGPT.
-
vLLM - высокопроизводительный сервер инференса.
-
Qwen или DeepSeek - непосредственно языковая модель.
-
pgvector - хранение векторных представлений документов.
-
RAG - механизм поиска по внутренним знаниям компании.
Самое интересное заключается в том, что всё это можно развернуть буквально на одном сервере.
Выбираем железо без покупки H100 по цене квартиры
Первый вопрос, который возникает у большинства руководителей:
Нам нужны H100?
Нет.
На практике подавляющему большинству компаний они не нужны.
| Видеокарта | Пользователи | Рекомендуемые модели |
|---|---|---|
| RTX 4090 | 20-50 | Qwen 14B |
| RTX 5090 | 50-100 | DeepSeek 32B |
| L40S | 100-300 | Qwen 32B |
| H100 | 300+ | Llama 70B |
Если вы внедряете корпоративный ИИ впервые, RTX 4090 зачастую оказывается идеальным выбором. Она относительно доступна, обеспечивает достойную производительность и позволяет обслуживать десятки сотрудников одновременно.
Как показывает практика, гораздо чаще компании ошибаются в другую сторону - покупают дорогое оборудование "на вырост", которое потом простаивает без нагрузки.
Ollama - Docker из мира больших языковых моделей
Очень многие считают, что Ollama - это и есть искусственный интеллект. На самом деле это не так.
Ollama не является моделью.
Ollama относится к языковым моделям примерно так же, как Docker относится к приложениям.
Docker:
-
скачивает образы;
-
хранит их;
-
запускает контейнеры;
-
предоставляет единый интерфейс управления.
Ollama делает практически то же самое:
-
скачивает модели;
-
хранит их локально;
-
запускает инференс;
-
предоставляет HTTP API.
Именно поэтому Ollama идеально подходит для пилотных проектов.
Запуск контейнера выглядит следующим образом:
docker run -d \
--name ollama \
--restart unless-stopped \
--gpus all \
-p 11434:11434 \
-v ollama:/root/.ollama \
ollama/ollama
Загрузим модель Qwen:
docker exec -it ollama \
ollama pull qwen3:14b
Проверим её работу:
curl http://localhost:11434/api/generate \
-d '{
"model":"qwen3:14b",
"prompt":"Объясни, что такое Kubernetes"
}'
Если всё прошло успешно, сервер вернёт ответ модели в формате JSON.
Для лабораторий и небольших команд этого уже достаточно. Но как только число пользователей начинает расти, появляются ограничения.
Пока модель отвечает одному пользователю, остальные начинают ждать.
Именно здесь появляется vLLM.
vLLM - почему весь рынок постепенно переходит именно на него
Если Ollama можно сравнить с Docker Desktop, то vLLM больше напоминает полноценный NGINX или Kubernetes для мира инференса.
Основная проблема языковых моделей заключается в неэффективном использовании видеопамяти. Представим обычный сценарий.
Есть сервер с RTX 4090 и десять сотрудников.
При использовании простых механизмов работы с моделью ситуация выглядит примерно так:
Пользователь 1 → ответ модели
Пользователь 2 → ожидание
Пользователь 3 → ожидание
Пользователь 4 → ожидание
...
Каждый новый запрос вынужден ждать завершения предыдущего.
vLLM решает эту проблему благодаря механизму PagedAttention.
Если сильно упростить, видеопамять начинает использоваться по принципу виртуальной памяти операционной системы. Она разбивается на страницы, которые эффективно переиспользуются между запросами.
В результате получается совсем другая картина:
Пользователь 1 ↘
Пользователь 2 → GPU → ответы
Пользователь 3 ↗
Пользователь 4 ↗
Пользователь 5 ↗
На практике это означает, что одна и та же RTX 4090 может обслуживать уже не 5-10 пользователей, а несколько десятков человек одновременно.
Ещё одно важное преимущество vLLM заключается в поддержке OpenAI API. Большинство современных инструментов умеют работать именно с этим интерфейсом.
Для них совершенно неважно, находится ли за API настоящий ChatGPT или локальный Qwen.
Запуск vLLM выглядит следующим образом:
docker run -d \
--name vllm \
--runtime=nvidia \
--gpus all \
-p 8000:8000 \
vllm/vllm-openai:latest \
--model Qwen/Qwen3-14B \
--host 0.0.0.0
Проверим список доступных моделей:
curl http://localhost:8000/v1/models
Попробуем выполнить запрос через OpenAI API:
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model":"Qwen/Qwen3-14B",
"messages":[
{
"role":"user",
"content":"Что такое Kubernetes?"
}
]
}'
Если вы видите ответ модели, значит инфраструктурная часть готова.
Теперь остаётся предоставить пользователям удобный интерфейс.
Open WebUI - собственный ChatGPT за несколько минут
Open WebUI представляет собой веб-интерфейс, который внешне очень напоминает ChatGPT.
Пользователям не придётся изучать curl, терминал или REST API.
Они просто открывают браузер.
Самое приятное заключается в том, что Open WebUI умеет работать с любым сервером, реализующим OpenAI API.
То есть с нашим vLLM он совместим из коробки.
Конечно, можно запускать контейнеры вручную, но любой DevOps-инженер знает: если что-то состоит больше чем из двух контейнеров, рано или поздно появляется docker-compose.
Поднимаем корпоративный ChatGPT одной командой
Ниже приведён минимальный, но вполне рабочий пример.
version: "3.9"
services:
vllm:
image: vllm/vllm-openai:latest
container_name: vllm
runtime: nvidia
command:
- --model
- Qwen/Qwen3-14B
- --host
- 0.0.0.0
ports:
- "8000:8000"
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities:
- gpu
open-webui:
image: ghcr.io/open-webui/open-webui:main
container_name: open-webui
depends_on:
- vllm
environment:
OPENAI_API_BASE_URL: http://vllm:8000/v1
OPENAI_API_KEY: dummy
ports:
- "3000:8080"
postgres:
image: pgvector/pgvector:pg16
container_name: pgvector
environment:
POSTGRES_DB: rag
POSTGRES_USER: rag
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Запускаем платформу:
docker compose up -d
Проверяем состояние контейнеров:
docker compose ps
Результат должен быть примерно таким:
NAME STATUS
vllm running
open-webui running
pgvector running
Проверяем доступность vLLM:
curl http://localhost:8000/v1/models
После этого открываем браузер:
http://localhost:3000
И получаем полноценный корпоративный аналог ChatGPT.
Самое интересное заключается в том, что вся эта платформа запускается буквально одной командой.
Ещё десять лет назад подобная инфраструктура потребовала бы нескольких специализированных команд. Сегодня её способен поднять один DevOps-инженер за вечер.
Но пока это просто локальный ChatGPT. Чтобы он начал приносить бизнесу реальную пользу, ему необходимо научиться работать с внутренними знаниями компании.
Именно здесь появляется RAG.
RAG - почему модель внезапно начинает знать внутренние регламенты
Именно на этом этапе корпоративный ChatGPT перестаёт быть дорогой игрушкой для генерации писем и начинает приносить реальную пользу бизнесу.
Самое распространённое заблуждение звучит примерно так:
Мы загрузим PDF с документацией, и модель всему научится.
К сожалению, это работает не так.
RAG (Retrieval-Augmented Generation) не обучает модель заново. Он работает по совершенно другому принципу.
Представьте опытного инженера. Перед ответом на сложный вопрос он не пытается вспомнить наизусть все регламенты компании. Вместо этого он открывает Confluence, находит нужный документ, читает его и только потом отвечает.
RAG делает ровно то же самое.
Схема выглядит следующим образом:
Вопрос пользователя
↓
Embedding
↓
Векторная БД
↓
Поиск документов
↓
LLM
↓
Ответ
Разница становится очевидной на практике.
Без RAG:
Как восстановить PostgreSQL?
Ответ модели:
Проверьте резервные копии, состояние репликации и журналы транзакций...
Вроде бы всё правильно, но слишком абстрактно.
С RAG ответ выглядит иначе:
Согласно внутреннему регламенту DB-017 необходимо переключить Patroni на replica-02, проверить применение WAL и уведомить группу DBA в течение 15 минут после восстановления сервиса.
Именно здесь появляется настоящая корпоративная ценность.
Подготавливаем PostgreSQL для RAG
Мы уже подняли pgvector через Docker Compose. Теперь превратим его в векторное хранилище.
Подключаемся к базе:
docker exec -it pgvector \
psql -U rag -d rag
Включаем расширение:
CREATE EXTENSION IF NOT EXISTS vector;
Создаём таблицу:
CREATE TABLE documents (
id bigserial PRIMARY KEY,
source text,
content text,
embedding vector(1024)
);
Структура достаточно простая:
-
source - источник документа;
-
content - текстовый фрагмент;
-
embedding - векторное представление текста.
Загружаем документацию
Предположим, что внутренние инструкции находятся в каталоге docs.
Например:
docs/
├── postgresql.md
├── kubernetes.md
├── vpn.md
└── incident.md
Теперь разобьём документы на небольшие фрагменты.
from pathlib import Path
def split_text(text, chunk_size=1000):
return [
text[i:i+chunk_size]
for i in range(0, len(text), chunk_size)
]
Считываем файлы:
documents = []
for file in Path("./docs").glob("*.md"):
text = file.read_text()
for chunk in split_text(text):
documents.append({
"source": file.name,
"content": chunk
})
Следующий шаг - получение эмбеддингов.
from sentence_transformers import SentenceTransformer
model = SentenceTransformer(
"intfloat/multilingual-e5-large"
)
for doc in documents:
doc["embedding"] = (
model.encode(doc["content"])
.tolist()
)
Сохраняем данные:
import psycopg
conn = psycopg.connect(
"dbname=rag user=rag password=secret"
)
cur = conn.cursor()
for doc in documents:
cur.execute(
"""
INSERT INTO documents
(source, content, embedding)
VALUES (%s, %s, %s)
""",
(
doc["source"],
doc["content"],
doc["embedding"]
)
)
conn.commit()
Да, это действительно настолько просто.
Поиск похожих документов
Когда пользователь задаёт вопрос, сначала формируется его эмбеддинг.
После этого выполняется поиск.
Например:
SELECT
source,
content
FROM documents
ORDER BY embedding <-> $1
LIMIT 5;
Именно этот запрос делает всю магию.
Фактически он означает:
Покажи пять фрагментов документации, наиболее похожих на заданный вопрос.
Полученные результаты передаются модели вместе с исходным запросом пользователя.
В итоге ответ формируется уже с учётом внутренних знаний компании.
Именно так обычный ChatGPT превращается в помощника, который знает регламенты, инструкции и особенности вашей инфраструктуры.
Когда Docker Compose перестаёт хватать
Рано или поздно пилотный проект становится популярным.
Количество пользователей растёт.
Появляются требования:
-
обновлять сервис без простоя;
-
ограничивать доступ;
-
подключать мониторинг;
-
использовать отказоустойчивость;
-
интегрироваться с существующей платформой.
И вот здесь появляется Kubernetes.
Если пользователей меньше двадцати, Docker Compose остаётся отличным выбором.
Но когда корпоративным ИИ начинают пользоваться целые подразделения, контейнеры постепенно превращаются в ещё один сервис внутри вашей платформы Kubernetes.
И, пожалуй, именно в этот момент DevOps-инженер впервые понимает, что развёртывание собственного ChatGPT подозрительно напоминает развёртывание обычного бизнес-приложения.
Только вместо PostgreSQL и Java внутри крутится модель на несколько миллиардов параметров.
Переносим корпоративный ChatGPT в Kubernetes
Как только число пользователей начинает расти, Docker Compose постепенно превращается в временное решение. Кто-то просит SSO через Keycloak, служба информационной безопасности хочет сетевые ограничения, а инженеры эксплуатации задают вполне логичный вопрос:
А как мы будем это обновлять без простоя?
Хорошая новость заключается в том, что с точки зрения Kubernetes наш корпоративный ChatGPT - это обычное приложение. Да, внутри работает модель на миллиарды параметров и используется GPU, но принципы остаются теми же.
Начнём с отдельного пространства имён.
apiVersion: v1
kind: Namespace
metadata:
name: corporate-ai
Применяем:
kubectl apply -f namespace.yaml
Секреты и конфигурация
Даже если сейчас вы не используете SSO, привычка выносить чувствительные данные в Secret избавит от многих проблем в будущем.
apiVersion: v1
kind: Secret
metadata:
name: openwebui-secret
namespace: corporate-ai
type: Opaque
stringData:
WEBUI_SECRET_KEY: super-secret-key
Проверяем:
kubectl get secret \
-n corporate-ai
Разворачиваем vLLM
Самое интересное начинается здесь. В отличие от большинства приложений, сервер инференса требует доступ к GPU.
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm
namespace: corporate-ai
spec:
replicas: 1
selector:
matchLabels:
app: vllm
template:
metadata:
labels:
app: vllm
spec:
containers:
- name: vllm
image: vllm/vllm-openai:latest
args:
- --model=Qwen/Qwen3-14B
- --host=0.0.0.0
ports:
- containerPort: 8000
resources:
limits:
nvidia.com/gpu: 1
Обратите внимание на этот фрагмент:
resources:
limits:
nvidia.com/gpu: 1
Именно он сообщает Kubernetes, что контейнеру необходим доступ к видеокарте.
Применяем Deployment:
kubectl apply -f vllm.yaml
Проверяем:
kubectl get pods \
-n corporate-ai
Если всё настроено правильно, Pod перейдёт в состояние Running.
Service для vLLM
Теперь сделаем API доступным внутри кластера.
apiVersion: v1
kind: Service
metadata:
name: vllm
namespace: corporate-ai
spec:
selector:
app: vllm
ports:
- port: 8000
targetPort: 8000
Применяем:
kubectl apply -f service.yaml
Проверяем:
kubectl get svc \
-n corporate-ai
Разворачиваем Open WebUI
Пользователи не должны видеть REST API. Им нужен привычный интерфейс.
apiVersion: apps/v1
kind: Deployment
metadata:
name: open-webui
namespace: corporate-ai
spec:
replicas: 2
selector:
matchLabels:
app: open-webui
template:
metadata:
labels:
app: open-webui
spec:
containers:
- name: open-webui
image: ghcr.io/open-webui/open-webui:main
env:
- name: OPENAI_API_BASE_URL
value: http://vllm:8000/v1
envFrom:
- secretRef:
name: openwebui-secret
ports:
- containerPort: 8080
Обратите внимание, что Open WebUI ничего не знает о локальных моделях.
Для него vLLM выглядит как обычный OpenAI.
Разворачиваем:
kubectl apply -f open-webui.yaml
Публикуем сервис наружу
Создадим Ingress.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: open-webui
namespace: corporate-ai
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
spec:
ingressClassName: nginx
rules:
- host: chat.company.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: open-webui
port:
number: 8080
Применяем:
kubectl apply -f ingress.yaml
Проверяем:
kubectl get ingress \
-n corporate-ai
После настройки DNS пользователи смогут открыть:
https://chat.company.local
И увидеть корпоративный аналог ChatGPT.
Мониторинг: то, о чём вспоминают слишком поздно
Очень часто команды начинают думать о мониторинге только после первой жалобы:
"Почему модель отвечает по минуте?"
К счастью, vLLM экспортирует метрики Prometheus.
Сначала убедимся, что они доступны.
Выполним проброс порта:
kubectl port-forward \
svc/vllm \
8000:8000 \
-n corporate-ai
Проверим метрики:
curl localhost:8000/metrics
Например:
vllm:num_requests_running
vllm:num_requests_waiting
vllm:gpu_cache_usage_perc
vllm:time_to_first_token_seconds
Эти показатели позволяют ответить на важные вопросы:
-
хватает ли GPU;
-
сколько пользователей ожидают ответа;
-
насколько эффективно используется видеопамять;
-
требуется ли масштабирование.
Иными словами, эксплуатация LLM оказывается подозрительно похожа на эксплуатацию любого другого сервиса в Kubernetes.
Безопасность и здравый смысл
Самая опасная ошибка при внедрении корпоративного ИИ - считать, что это просто ещё один чат.
На практике такой сервис очень быстро получает доступ к:
-
внутренней документации;
-
корпоративной Wiki;
-
GitLab;
-
Jira;
-
возможно, даже к производственным системам.
Поэтому стоит соблюдать несколько правил.
-
Используйте SSO через Keycloak или другого провайдера идентификации.
-
Включайте аудит пользовательских запросов.
-
Не передавайте модели секреты и содержимое Vault.
-
Ограничивайте сетевое взаимодействие через NetworkPolicy.
-
Делайте резервные копии базы с документами.
И главное правило:
Если ваш корпоративный ChatGPT одновременно имеет доступ к production-кластеру, Vault и GitLab без ограничений, то это уже не помощник инженера, а очень дорогой способ обновить резюме.
Сколько это стоит
Самый удивительный вывод этой статьи заключается в том, что корпоративный ИИ перестал быть привилегией крупнейших компаний.
| Вариант | Ориентировочная стоимость |
|---|---|
| RTX 4090 + Ollama | ~2500 € |
| RTX 5090 + vLLM | ~4000 € |
| 2×L40S + Kubernetes | ~18000 € |
Для большинства организаций пилотный проект обойдётся дешевле, чем годовые подписки на внешние сервисы для нескольких десятков сотрудников.
Заключение
Построить корпоративный ChatGPT сегодня не сложнее, чем несколько лет назад было поднять собственный GitLab. Самая большая ошибка - считать, что для этого нужны миллионы евро, команда исследователей машинного обучения и стойка с H100.
В действительности всё начинается с одной видеокарты, Docker Compose и желания перестать отправлять внутренние документы во внешние сервисы. Затем появляются RAG, Open WebUI, vLLM и Kubernetes. А дальше корпоративный ИИ постепенно превращается в ещё один сервис вашей платформы.
И, пожалуй, это лучший показатель зрелости технологии. Когда DevOps-инженер начинает относиться к локальной LLM так же спокойно, как к PostgreSQL или Jenkins, искусственный интеллект перестаёт быть модным словом и становится обычным инфраструктурным компонентом.