
Привет, это Андрей Мелихов, ведущий разработчик интерфейсов в Yandex Cloud. Я работаю в команде DataLens — BI‑системы для визуализации больших наборов данных на дашбордах и графиках.
В прошлом году в DataLens появился чат‑интерфейс: пользователь общается с ИИ‑ассистентом, который строит графики, пишет формулы и решает аналитические задачи. В рамках работы над этим продуктом, который получил имя Нейроаналитик, мы пошли не совсем очевидным для многих путём и перераспределили ответственность между командами фронтенда и бэкенда. В статье хочется поделиться этим опытом: внутри вы найдёте демо‑проект в репозитории, чтобы самим увидеть нашу идею изнутри.
ИИ, бэкендеры и фронтендеры
Подключение LLM к продукту — задача, с которой сегодня сталкиваются многие команды. Обычно за неё берётся бэкенд. Мы выбрали другой подход: первый этап интеграции с моделью взяла на себя фронтенд‑команда и считаем, что у такого подхода есть конкретные преимущества.
Важная ремарка. Под фронтендерами мы (как минимум наша команда DataLens) понимаем скорее фуллстек‑инженеров с уклоном в UX и JavaScript/TypeScript. В нашей зоне ответственности как браузерный, так и серверный код на node.js, собственные CI/CD‑пайплайны и DevOps, обслуживающий задачи фронтенда. Но интерфейсы нам всё же ближе, чем данные.
Итак, типичный сценарий: бэкенд интегрирует LLM, поднимает эндпоинты, а фронтенд подключается к ним и рисует красивый интерфейс чата. Рабочая схема, но возникает вопрос о распределении ответственности. Действительно ли вся интеграция с моделью должна лежать на бэкенде?
Фронтенд‑команды обладают собственной технической экспертизой: умеют строить BFF (бэкенд для фронтенда), могут напрямую взаимодействовать с API, и именно они проектируют интерфейс. А в ИИ‑продукте интерфейс — не менее важная часть, чем модель. Помимо этого, у фронтенда есть конкретные преимущества на этапе интеграции:
-
Данные уже под рукой. В современных интерфейсах сходятся данные из множества бэкендов. Если нужно построить ИИ‑инструмент поверх — контекст уже на клиенте, и дозапросить нужное несложно.
-
Быстрые итерации. Когда команда ищет подходящую нишу для ИИ в продукте, скорость экспериментов критична. Фронтенд позволяет быстро проверять гипотезы без изменений в основном бэкенде.
-
Меньше координации на старте. BFF на Node.js — это привычная инфраструктура. Подключился к совместимому API и можно двигаться, не блокируя другие команды.
Это не значит, что бэкенду здесь нечего делать — с развитием продукта неизбежно появляются задачи, которые должны решаться на сервере. Но начать можно силами фронтенда, и результат будет вполне продуктовым.
Архитектура: как это устроено
В выбранной архитектуре между клиентом и LLM добавляется слой BFF, например на Node.js или Bun, хотя конкретная технология не принципиальна — аналогичное решение можно реализовать и на Python, если фронтенд‑команда готова поддерживать решения на других языках. Это важно, так как классический BFF занимается подготовкой view‑ориентированных данных и находится в зоне ответственности команды разработки фронтенда.
В нашем случае этот слой берёт на себя в том числе и взаимодействие с моделью. Существующий бэкенд остаётся без изменений — интеграция на первом этапе фактически переносится в зону ответственности фронтенд‑команды.

Схема привычна с точки зрения фронтенд‑разработчика — по сути, просто появляется дополнительный бэкенд. В периметре BFF находятся ключи доступа, реализуется работа с rate limiting и CORS, настраивается мониторинг и логирование. Таким образом, логика взаимодействия с API LLM переносится на сервер — на тот бэкенд, который «бэкенд для фронтенда».
Чтобы показать, как это выглядит на практике, я собрал демо‑проект на GitHub — монорепозиторий с сервером на Express и клиентом на React. Интерфейс реализует упрощённую BI‑систему: слева дашборд, справа — ИИ‑ассистент. Сценарий использования: пользователь запрашивает, скажем, топ-5 продуктов: ассистент обращается к функции getChartData, получает данные и формирует ответ на их основе.

Прототип я собрал, конечно, с помощью ИИ. Сначала составил план в Superpowers, затем код‑ассистент всё это реализовал, я проверил результат и подключил Gravity UI для отрисовки интерфейса. В итоге получилось рабочее приложение с простой кодовой базой, которую можно изучить в репозитории.
Цель этого примера — показать, что для фронтенд‑разработчика, знакомого с Express, реализация базовой интеграции с LLM не представляет особой сложности. А дальше уже можно наращивать: тулинг, контекст, продвинутые сценарии.
Что же нам нужно для того, чтобы реализовать интеграцию с LLM в реальном продукте?
Четыре компонента интеграции
Для добавления ИИ в продукт фронтенд‑разработчику понадобятся четыре вещи:
-
UI‑кит — компоненты для чат‑интерфейса.
-
API SDK — библиотека для общения с LLM.
-
Тулинг — механизм, позволяющий модели вызывать функции и получать данные.
-
Контекст — данные и состояние приложения, которые передаются модели вместе с запросом.
Разберём каждый.
UI-кит
Антон Непша сделал хороший обзор UI‑китов для создания ИИ‑агентов: там и AI Elements от Vercel, и опенсорс‑решения вроде Assistant UI, prompt‑kit, shadcn‑chatbot‑kit.
Правда, не все одинаково удобны. Решение от Vercel, например, при ближайшем знакомстве мне показалось перегруженным: много слоёв абстракции, проблемы совместимости с опенсорс‑моделями и в целом недостаточная гибкость. При выборе инструмента важна не только функциональность, но и сложность интеграции.
Мы используем AIKit от команды Gravity UI. У него проработанный визуал, корректная отрисовка ответов, встроенная история вызовов — и не нужно вручную подключать обработку маркдауна или расширения вроде GFM для таблиц. Кстати, мой коллега Илья Ломтев уже писал о нём на Хабре.
Сейчас AIKit внедряется во все продукты Yandex Cloud, включая консоль и SourceCraft. Это значит, что он будет активно развиваться — в нём появится функциональность, нужная разным командам.

Конечно же, в моём демо доступна версия с AIKit — она заметно симпатичнее. Эта версия лежит в отдельной ветке.
API SDK
Когда OpenAI предложили модель доступа через API, это стало поворотным моментом. Локальное развёртывание LLM оказалось слишком дорогим — и появился единый сетевой интерфейс, на основе которого разработчики стали строить продукты.
Сегодня провайдеров и моделей множество, но хорошая новость в том, что большинство ориентируется на совместимость с OpenAI API. Поддержан OpenAI API и в Yandex AI Studio — про это, конечно же, тоже есть статья на Хабре. Смена baseURL позволяет использовать Mistral, Groq, Fireworks, Ollama, Together, xAI и другие платформы. Для разработчика это означает: один клиент — много моделей.
Стоит отметить: помимо OpenAI API, рынок снова присматривается к поддержке Anthropic API — во многом благодаря популярности Claude Code и желанию провайдеров привлечь его пользователей. Но в остальном OpenAI API доминирует.
Во многих туториалах сразу предлагают использовать LangChain. Инструмент мощный — есть реализации на Python, JavaScript/TypeScript, Java, Go,.NET. Но начинать с него, на мой взгляд, не стоит. Это очень высокоуровневая абстракция, которая скрывает слишком много. Дебажить её непросто — часто требуются отдельные инструменты вроде LangSmith для трассировки.
Начинать с LangChain — как изучать веб‑разработку с React. Сначала стоит понять, как всё работает на уровне API, а LangChain (или аналоги) подключить, когда проект разрастётся.
Давайте возьмём OpenAI SDK для Node.js. Минимальный пример:
import OpenAI from "openai";
const openai = new OpenAI({ apiKey, baseURL });
const completion = await openai.chat.completions.create({
messages: [
{ role: "system", content: "Ты очень умный ассистент." },
{ role: "user", content: "Что умеют большие языковые модели?" }
],
model: "gpt://<идентификатор_каталога>/yandexgpt/latest",
});
console.log(completion.choices[0]);
Создаём клиент, передаём массив сообщений, system задаёт поведение модели, user содержит запрос. Вся коммуникация строится как цепочка сообщений — на этом и основан Chat Completions API.
Ответ API включает usage с количеством токенов (полезно для логирования и контроля затрат) и choices с результатом. Забираем текст, отображаем в интерфейсе — чат готов.
Но без тулинга такая система — просто красивая обёртка над генерацией текста. Модель ничего не знает о данных в вашем продукте.
Тулинг
Тулинг — это механизм, позволяющий модели запрашивать информацию из приложения. Без него чат остаётся «голым» генератором текста. С тулингом система превращается в агента, способного взаимодействовать с данными.
В 2023 году OpenAI добавили в API возможность передавать модели список доступных функций. Теперь модель может явно сообщить: «Хочу вызвать вот эту функцию с такими параметрами». Аналогичный подход используется в MCP — разработчик описывает инструменты, а модель учится их вызывать.
Как это выглядит на практике? В параметре tools передаём описание доступных функций:
const completion = await openai.chat.completions.create({
messages: [
{ role: "system", content: "Ты аналитик." },
{ role: "user", content: "Проанализируй дашборд с чартами: цены, магазины, доходность" }
],
tools,
});
Описание инструмента — это JSON, где указано название функции, её назначение и параметры. Например: «У тебя есть функция getChartData, которая принимает массив ID чартов и возвращает их данные».
В ответ модель возвращает массив tool_calls — список функций, которые хочет вызвать:
[
{
"id": "chatcmpl-tool-087c7a6c...",
"type": "function",
"function": {
"name": "getChartData",
"arguments": "{"chartIds": ["цены", "магазины", "доходность"]}"
}
}
]
Дальше — дело разработчика. Вызываем реальную функцию, получаем данные и возвращаем результат модели в сообщении с ролью tool:
{
role: "tool",
tool_call_id: "chatcmpl-tool-087c7a6c...",
content: JSON.stringify([
{ chartId: "цены", описание: "средний чек 500р" },
{ chartId: "магазины", описание: "Два магазина, один другого хуже" },
{ chartId: "доходность", описание: "Никакая" }
])
}
Полный массив сообщений, который уходит модели на следующем шаге:
messages: [
{ role: "system", content: "Ты аналитик." },
{ role: "user", content: "Проанализируй дашборд со ..." },
{ role: "assistant", content: null, tool_calls: [...] },
{ role: "tool", tool_call_id: "chatcmpl-tool-...", content: "..." },
]
Получив данные, модель формирует осмысленный ответ. Объём зависит от модели — она может ограничиться парой предложений или развернуть полноценный анализ даже на скудных данных. Но не стоит питать иллюзий: модель — не калькулятор. Ей нельзя отдавать вычисления на откуп, и для полноценной аналитики понадобится серьёзная обвязка из тулинга.
Responses API: что дальше
OpenAI представили новый Responses API и предлагают постепенно переходить к нему от Chat Completions. По их словам, предыдущий API был спроектирован и развёрнут в крайне сжатые сроки, но быстро стал настолько востребованным, что лёг в основу значительной части современных интеграций с LLM. Буквально, в пятницу задизайнили, а во вторник она была доступна по всему миру. И вот уже все завязаны на этот API.
Эволюция OpenAI API отражает то, как менялись потребности разработчиков:
-
Первое поколение — простая схема «запрос → ответ».
-
Второе поколение — Chat Completions, адаптированный под диалог.
-
Третье поколение — Responses API, заточенный под агентные сценарии.
Responses API встраивает в себя RAG, function calling, поиск — всё, что раньше приходилось собирать вручную. Для фронтенд‑разработчика это упрощает жизнь ещё сильнее: нужен BFF на Express, обращение к API, а остальная магия — внутри.
Правда, есть нюанс доверия: передача данных стороннему провайдеру означает, что информация хранится вне вашего периметра. Для продуктовых решений это не всегда приемлемо. Но концепция «агентность по умолчанию» набирает обороты и упрощает порог входа.
Контекст
Если отправить модели два сообщения по отдельности — сначала представиться, потом спросить «как меня зовут?» — она не ответит. У LLM нет памяти. Она опирается только на то, что передано в текущем запросе.
Поэтому в каждом обращении нужно отправлять историю переписки. Но на практике одной истории чата мало. Для нормальной работы ИИ‑функциональности в продукте модели нужен более широкий контекст.
Проблема в том, что контекстное окно ограничено: 128–256 тысяч токенов, у некоторых моделей — до миллиона. Но даже при большом окне модели не всегда эффективно используют весь объём — они фокусируются на части переданных данных. Возникает инженерная задача: какие фрагменты передавать, а какие отбросить?
Если рассматривать DataLens Editor, то значимым контекстом становится не только история чата.

Модели нужно знать о коде пользователя, о результатах выполнения, об ошибках в консоли. Всё это живёт на клиенте. И это территория фронтенда — бэкенд до этих данных не добирается.
Вот что делает управление контекстом BI‑системы сложной задачей:
-
Данные могут быть огромными. Микротаблицу в нашем простом примере легко уложить в контекст. В реальности данные разбиты на страницы, и передать их целиком зачастую невозможно.
-
Модели плохо считают. Если дать LLM большой массив чисел и попросить посчитать среднее — нет гарантий, что модель учтёт все данные. Точные вычисления нужно делать на стороне приложения.
-
Контекст быстро растёт. С каждым сообщением и каждым вызовом инструмента объём передаваемых данных увеличивается.
Степень участия бэкенда зависит от архитектуры. Если основная логика на сервере — часть задач можно делегировать ему. Однако клиентский контекст — код, состояние интерфейса, результаты выполнения — доступен только фронтенд‑слою. Поэтому даже при классической архитектуре фронтенд‑разработчикам приходится самостоятельно управлять этим объёмом информации. В крупных приложениях контекста становится особенно много, и его обработка превращается в отдельную инженерную задачу.
С развитием продукта неизбежно появляются задачи, которые нужно решать на бэкенде: фоновые длительные операции, взаимодействие с клиентом через API. Но реализовать их на бэкенде (будь то Python или Node.js) будет значительно проще, если в качестве работающего примера перед глазами уже есть полезная фича на клиенте.
Работы хватит всем
Базовая интеграция складывается из четырёх компонентов — интерфейс, SDK, тулинг, контекст — и уже этого достаточно, чтобы получить работающее приложение. При этом сама область работы с LLM остаётся новой и быстро развивающейся.
Здесь хватает серьёзных инженерных задач: управление клиентским контекстом и его размером, проектирование удобных ИИ‑интерфейсов, работа со стримингом и function calling. Форматы взаимодействия тоже продолжают меняться: ещё недавно все сидели в IDE, а сейчас набирают популярность консольные агенты. Всё это указывает на то, что пространство для работы в этой области только расширяется.
Фронтенд‑команда может взять на себя интеграцию с LLM и получить продуктовый результат с понятной архитектурой, знакомым стеком и готовыми SDK. А по мере роста продукта подключатся и бэкендеры — для фоновых операций, масштабирования и более глубокой интеграции.
Мы всё ещё в начале пути и не знаем, куда всё повернёт завтра. Интерфейсы меняются, модели становятся мощнее, а то, что вчера казалось экспериментом, сегодня уже в продакшене. На этом этапе неважно где, главное делать — пробовать, ломать, проверять гипотезы. Инструменты для этого уже есть, порог входа ниже, чем кажется, и работы действительно хватит всем.
Если вам интересны подходы к работе в наших командах, заглядывайте в Inside Yandex Cloud, где мы делимся опытом и рассказываем, какие технологии применяем при создании облачной платформы. Будем рады ответить на вопросы.
Автор: melikhov-dev


