Искусственный интеллект · ISPsystem · BILLmanager · LLM · Angular · SSE · ReactJS · Разработка27 сентября в 04:02 · 4 мин

Архитектура ИИ-ассистента BILLmanager: адаптеры, SSE через POST и инкрементальный рендеринг

Компания ISPsystem представила детальный разбор реализации ИИ-ассистента для своей платформы BILLmanager. Разработчики описали архитектуру системы, позволяющей клиентам интегрировать различные языковые модели (LLM), реализовать потоковую передачу данных через специфичный протокол SSE (используя POST-запросы) и обеспечить мгновенную отрисовку Markdown-контента без perceptible задержек при генерации.

# Что внутри ИИ-ассистента BILLmanager

Компания ISPsystem, известная своими решениями для управления интернет-сервисами (ISP), недавно опубликовала технический обзор своего проекта по внедрению искусственного интеллекта в платформу BILLmanager. Цель разработки заключалась в автоматизации рутинных задач пользователей, ускорении поиска информации в документации и снижению нагрузки на службу поддержки. Система не просто предоставляет готового чат-бота, а предлагает гибкую платформу, где администраторы могут настраивать логику обработки запросов и подключать собственные провайдеры LLM.

Гибкая система адаптеров для LLM

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

Интерфейс адаптера определяет базовые методы для получения ответа: обычный запрос и потоковый (streaming). Для передачи информации о статусе отмены операций используется механизм AbortSignal, что позволяет адаптеру корректно завершать генерацию при прерывании пользователем. Кроме того, система предусматривает возможность передачи произвольных параметров (additionalParams), необходимых для настройки температуры генерации, выбора модели и других тонких настроек, которые могут варьироваться от провайдера к провайдцу.

В качестве примера приводится реализация адаптера для произвольных API, совместимых со стандартами OpenAI. Такой код занимает всего несколько десятков строк и использует нативный JavaScript для отправки POST-запросов, что упрощает процесс интеграции и уменьшает зависимость от внешних библиотек. Пользователи могут создавать свои собственные адаптеры, размещая файлы в указанной директории, что делает систему масштабируемой без необходимости обновления основного программного кода.

Реализация потоковой передачи через POST и SSE

Передача текстового ответа в реальном времени является критически важной функцией для чат-интерфейсов. Обычно для этого используется WebSocket, но команда ISPsystem opted за более легковесное решение — Server-Sent Events (SSE). Однако стандартный браузерный API EventSource поддерживает только HTTP-метод GET, что создает ограничения при необходимости передачи сложного запроса (промпта, выбора модели, токенов авторизации).

Для решения этой проблемы разработчики реализовали SSE поверх HTTP-запроса POST. Это позволяет отправлять весь необходимый контекст в теле запроса, избегая проблем с длиной URL-адреса. На серверной стороне используется декоратор NestJS для создания эндпоинта, который возвращает наблюдаемую последовательность событий. Клиентская часть анализирует заголовок Content-Type: text/event-stream и обрабатывает поступающие фрагменты данных, складывая их в единый текст ответа.

Этот подход решает две основные задачи: позволяет передавать большие объемы данных в запросе (избегая лимитов на длину URI) и упрощает серверную реализацию, так как не требует сложной двухсторонней коммуникации, характерной для WebSockets. Весь формат событий (заголовки, данные, завершение) полностью соответствует спецификации SSE, обеспечивая совместимость с любым современным клиентом.

Инкрементальный рендеринг Markdown в Angular

Отображение ответов от языковой модели требует корректной обработки форматирования, которое обычно передается в Markdown. Простая конвертация Markdown в HTML и вставка через атрибут innerHTML не дает достаточного контроля над стилизацией и функциональностью элементов (например, подсветкой синтаксиса в блоках кода).

Команда применила подход на основе абстрактного синтаксического дерева (AST). С помощью библиотеки unified с плагинами remark-parse и remark-gfm текст Markdown преобразуется в дерево объектов. Затем это дерево мопируется (преобразуется) в компоненты Angular, используя директивы и сервисы для маппинга типов узлов (заголовки, списки, кодовые блоки) на соответствующие UI-элементы.

Ключевым вызовом стала оптимизация процесса при потоковой передаче. При генерации ответа текст растет постепенно. Если бы систему нужно было перепарсить весь накопленный текст после каждого нового символа, это привело бы к значительным задержкам и блокировке главного потока, особенно для длинных сообщений.

Для решения этой проблемы была реализована стратегия инкрементального рендеринга. Поскольку новые фрагменты текста всегда добавляются в конец документа, парсер может оптимизировать процесс обновления AST, перестраивая только концевые узлы дерева. Это позволяет интерфейсу обновляться плавно, без видимых лагов, даже при генерации объемных ответов. Такой подход аналогичен тем, что используются в современных IDE для быстрого отрисовки кода.

Ограничения и безопасность

Несмотря на высокую гибкость, система имеет четкие границы для обеспечения стабильности и экономии ресурсов. Поскольку использование LLM оплачивается по потреблению токенов, ISPsystem внедрил механизмы лимитирования:

* Количество сообщений: Ограничено числом запросов в сутки (пересчет по UTC). * Длина сообщения: Установка предельного размера для входных данных. * Глубина истории: Ограничение количества предыдущих диалогов, передаваемых в контекст. * Параллелизм: Разрешен только один активный запрос к ИИ на одного пользователя одновременно.

Также важен аспект безопасности и идентификации. Доступ к виджету и к API адаптеров строго привязан к сеансу авторизации в BILLmanager. Использование куки платформы позволяет однозначно идентифицировать пользователя, предотвращая доступ к функциям ИИ от незарегистрированных лиц или ботов. В случае превышения лимитов сервер возвращает четкую ошибку с указанием времени сброса блокировки, что дает пользователю полную прозрачность использования ресурсов.

Первоисточники

Habr AI ↗
← Вернуться в эфир