Автор: Александр Казанцев, руководитель отдела документации и контента
В нашей вотчине, отделе документации компании, мы постепенно автоматизируем процессы, чтобы вам, пользователям, предоставить больше полезной информации. За последнее время мы добавили к нашим панелям маркетплейса документацию по их развертыванию, которая собирается по актуальным Ansible-скриптам, или документацию по API, генерируемую по исходному коду Invapi. Если последнее — это временная мера до внедрения нового клиентского API, и процесс еще не закончен (пока нет генерации английской версии, только русской), то статьи по развертыванию пишутся уже в «боевом» режиме.
|
Серверы с GPU NVIDIA Выделенные и виртуальные серверы с графическими картами последних и предыдущих поколений с почасовой оплатой |
Четыре «GPU-пенсионера», но не разбойника
Но прежде чем мы перейдем к самому агенту (точнее, к их связке), немного о железе, которое позволяет нам как автоматизировать документацию, так и поддерживать работу в чат-боте, отвечающих вам в ней. С учетом того, что у нас там параллельно крутятся боты техподдержки Jira, переводчики и «товарищ-майор» (мы так называем модель, которая через MCP-сервер проверяет статьи на соответствие закону о русском языке), мощностей нам стало не хватать. Если до этого у нас за всех отдувалась одна Nvidia A5000, то нужно было выпрашивать хотя бы еще одну видеокарту, но… клиенты имеют больший приоритет, поэтому приходилось довольствоваться тем, что имели (точнее, что нам дали на отдел).
И тут просматривая что у нас в компании есть свободного из ресурсов, нахожу относительно простаивающие GPU. А точнее, NVIDIA TESLA V100 на 16 Гб. Да, эти карты были представлены в 2017 году, и их поддержка самой NVIDIA была прекращена на уровне 538 серии драйверов несколько лет назад (соответственно, и CUDA там будет работать от силы 12.2), и сама карта уступает по скорости в вычислениях типа FP32 более современной A5000 в два раза, но… Мы могли заполучить целых четыре таких карты! А значит, мы могли бы запускать или одну большую модель, которая помещалась бы в 64 Гб суммарной видеопамяти (а она тут HBM2), или каким-то образом можно было распараллелить вычисления на 2 или 4 карты. Новинок, оптимизации, новых драйверов и CUDA мы, увы, не получим, но нам нужны не «шашечки», а ехать.
Последние LLM типа qwen3.5:27b (которую мы используем сейчас) или gemma4:31b с такой же размерностью при размере контекста до 80000–100000 спокойно помещаются в 32 Гб. Значит, нам нужно сделать так, чтобы наша связка Ollama + OpenWebUI (на последнем у нас работают кастомные модели и MCP-сервер) каким-то образом могла все запросы перенаправлять на разные видеокарты.
И такое оказалось возможно. Вот вкратце, что нужно было сделать:
1. Нужно запустить два инстанса Ollama параллельно. У нас это делается двумя systemd-сервисами. Первый инстанс запускается с параметрами использования видеокарт 0 и 1, второй — 2 и 3 и общей директорией для моделей. Плюс такого решения, что при обновлении Ollama ничего делать не надо, всё автоматически перезапускается само. Чтобы они не конфликтовали, запускаем их на разных портах.
Пример ollama.service файла. Ollama2.service отличается только цифрами видеокарт в переменной CUDA_VISIBLE_DEVICES.
[Unit]Description=Ollama ServiceAfter=network-online.target[Service]ExecStart=/usr/local/bin/ollama serveUser=ollamaGroup=ollamaRestart=alwaysRestartSec=3Environment="PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/cuda/bin"Environment="OLLAMA_ORIGINS=*"Environment="OLLAMA_HOST=0.0.0.0:11434"Environment="CUDA_VISIBLE_DEVICES=0,1"Environment="OLLAMA_MODELS=/opt/ollama_shared_models"Environment="HOME=/var/lib/ollama"Environment="OLLAMA_FLASH_ATTENTION=1"Environment="OLLAMA_MAX_QUEUE=1000"Environment="OLLAMA_NUM_PARALLEL=1"Environment="OLLAMA_KEEP_ALIVE=60m"Environment="OLLAMA_MAX_LOADED_MODELS=2"[Install]WantedBy=default.target
2. Установку моделей делаем специальным скриптом. Его задача — установить модель на первом и втором инстансе, ориентируясь на их порты (по факту просто повторяем одну и ту же команду два раза). Небольшой момент: если у вас были модели уже установлены ранее, то директорию с ними нужно будет скопировать в общую.
3. В OpenWebUI прописываем две связки с Ollama. И далее начинается магия, о которой некоторые не знали. Так как модель у нас одна и та же и имеет одно и тоже название на обоих инстансах Ollama, то при запросе через OpenWebUI оболочка сама маршрутизирует задачу на наименее загруженный инстанс.
Вуаля! По итогу мы имеем два потока нейросетевых задач на двух связках по 2×16 Гб V100.
Агенты, которые сами пишут документацию по Ansible-плейбукам
Если вы когда-нибудь пытались поддерживать актуальную документацию для десятков инфраструктурных проектов, вы знаете эту боль: код меняется, а инструкции устаревают ещё до того, как их успеют прочитать. Для нас проблемой были панели из маркетплейса. Вопросы, как устанавливается та или иная панель, возникают от пользователей регулярно, а сама информация устаревает с каждым изменением плейбука.
Поэтому давно хотелось создать систему, которая сама «читает» Ansible плейбуки установки панелей из репозитория и генерирует понятные инструкции для пользователей. Сделать это было решено уже «по-модному», то есть с помощью агентов. Да, тут мы «по-старинке» используем несколько ИИ-агентов со своими системными промптами и общий конвейер-оркестратор для их управления, но есть желание уже позже переписать их все на основе автономного ИИ-агента типа OpenClaw или аналогов и Skills.
Да, без ручной работы, а именно создания конфигурационного файла, описывающего группы панелей, имена их md-файлов и URL репозиториев, не обошлось, и при добавлении или удалении новых панелей в маркетплейс это приходится делать вручную, но это отнимает гораздо меньше времени, чем ручной разбор плейбуков и создание статей документации.
Что умеет этот зверь?
Если коротко: агент забирается в репозиторий, находит нужные файлы, «понимает», что там происходит, и пишет статью в формате Markdown. Но дьявол, как всегда, в деталях. Вместо одного монолитного скрипта я разбил логику на специализированных агентов:
-
RepoScanner — клонирует репозиторий GitLab, фильтрует мусор (тесты, CI/CD, кэш) и находит только релевантные файлы: задачи, шаблоны, docker-compose, переменные.
-
FileSelector — LLM-агент, который решает, какие именно файлы важны для документации. Например, group_vars/all/main.yml он всегда берёт в приоритет.
-
DocGenerator — ИИ, который пишет саму статью по строгому промпту: структура, стиль, запрет на упоминание Ansible (пользователю ведь не важно, как вы это развернули, ему важно, что теперь делать).
-
TranslateIT — LLM-технический переводчик с английского на русский, который не трогает переменные, пути и команды, но аккуратно локализует описания. Это позволяет нам иметь идентичные описания на разных языках. Пока перевод только на русский.
-
QAChecker — ИИ-валидатор, который сравнивает оригинал и перевод, проверяет заголовки, термины и форматирование.
-
Fixer — если QA нашёл «косяки», этот ИИ-агент точечно их исправляет, не переписывая весь текст.
Особенностью нашего маркетплейса является то, что панели могут иметь разные названия или присутствовать только в русской или английских версиях. Поэтому была реализована обработка т.н. «парных» репозиториев. Допустим, у вас есть панель «Self-hosted AI Chatbot» с документацией на английском и её русская локализация «ИИ чат-бот на собственном сервере». В данном случае нам нужен перевод на русский, но название должно быть изменено, и это опять же делается автоматически. Всё это работает без участия человека, но с возможностью вмешательства на любом этапе.
Еще один момент, который доставил проблемы, это ограничения на размер контекста. Чем больше контекст, тем дольше модель обрабатывает запросы. В данной системе реализован динамический расчёт num_ctx:
# Резервируем место под ответ моделиmax_input = max_context - response_reserve# Оцениваем входные токены + 5% запасneeded = int(estimated * 1.05)# Берём минимум из "нужно" и "можно"actual = min(needed, max_input)# Итоговый контекст = ввод + резервnum_ctx = min(actual + response_reserve, max_context)
Это позволяет не «урезать» важные файлы и при этом не вылетать по лимиту окна.
Для повышения надежности также были добавлены:
-
Повторы с экспоненциальной задержкой — если наш ИИ «упал» или сеть моргнула, агент подождёт 2 — 4 — 8 секунд и попробует снова;
-
Логирование ошибок — все проваленные валидации пишутся в validation_errors.json с превью исходника и перевода. Удобно для последующего разбора и исправления ошибок;
Интеграция с GitLab и ночной сборкой
В процессе ежеденой ночной ресборки документации вызывается отдельный скрипт gitlab_monitor.py который опрашивает наш репозиторий и проверяет master-ветки на свежие коммиты за последние 24 часа и, если что-то изменилось, «дёргает» агента с флагом —repo <имя_панели>. Так документация обновляется практически в реальном времени.
Что получилось на выходе?
-
Более 125 репозиториев в конфигурационном файле (панели, базы данных, ML-инструменты, игры). Это еще не все панели, так как часть из них устанавливается как операционные системы, а не с помощью Ansible плейбуков.
-
Автоматическая генерация статей в формате MkDocs.
-
Поддержка двух языков с контролем качества перевода.
-
Минимум ручной работы: добавил плейбук в YAML-конфиг — остальное сделает агент. Но можно запустить и в ручном режиме для отдельного языка, секции или панели.
Вердикт
Да, наш агент не идеален, но он экономит десятки часов рутинной работы и снижает риск рассинхрона между кодом и документацией. Причем это только часть будущей системы (вот почему я думаю, а не переписать ли всё через OpenClaw или Hermes Agent), так как наработки от данной системы дальше пойдут в перевод API и даже в автоматизированную локализацию на французский, турецкий и т. д.
Да, V100 не самая быстрая карта на текущий момент, и, если посмотрите на скрины, процесс создания документации для каждой панели занимает от 3 до 10 минут (зависит от числа файлов в репозитории и числа ошибок, которые нужно поправить), но после первичной генерации у нас в день может быть поправлена 1–2 панели, а то и в неделю, а новые добавляются не так часто.
А как вы автоматизируете документацию? Делитесь опытом в комментариях.
|
Серверы с GPU NVIDIA Выделенные и виртуальные серверы с графическими картами последних и предыдущих поколений с почасовой оплатой |
ссылка на оригинал статьи https://habr.com/ru/articles/1023358/