Привет! Меня зовут Андрей Старостин, я DS-инженер в аналитической платформе в Авито. В этой статье я расскажу об устройстве и внедрении сервиса-ассистента на основе искусственного интеллекта для упрощения работы с аналитическими данными в нашем продукте M42 внутри Trisigma

Содержание:

О продукте в целом

М42 — это мощный BI-инструмент для продуктовой и бизнес-аналитики, который позволяет получать инсайты без знания Python, SQL или других технических языков.
Вместо сложных запросов пользователи работают с готовыми метриками и разрезами, свободно комбинируя их для решения аналитических задач — быстро, гибко и без участия аналитиков.

Сегодня в М42 доступно более 16 000 метрик, 120+ разрезов и десятки способов агрегировать данные — всё, что нужно, чтобы увидеть полную картину бизнеса.

У инструмента есть два ключевых сегмента пользователей:

  • бизнес-пользователи — маркетологи, продакт-менеджеры, BizDev и категорийные менеджеры.

  • аналитики, для которых М42 стал неотъемлемой частью ежедневной работы.

Уже 62% аналитиков Авито активно используют М42, и 66% из них регулярно строят графики и отчёты. Среди бизнес-пользователей — около половины заходят в М42 на постоянной основе, чтобы решать самые разные задачи: от ежедневного мониторинга ключевых метрик своего продукта или всего бизнеса Авито до получения прогнозов, оценки потенциала инициатив и многого другого.

Семантический слой как основа М42 и ИИ-ассистента

Ранее мы уже рассказывали об устройстве М42 подробно, поэтому особенно заинтересованных приглашаем перейти к статье Влада Божьева «Как мы храним 20000+ метрик и миллиарды комбинаций разрезов в одной таблице» (да-да, мы наводим порядок в метриках, поэтому их количество может сокращаться). 

В рамках же разработки ИИ-ассистента большую роль сыграло то, что инструмент М42 по сути представляет собой продвинутый UI поверх семантического слоя метрик, в который метрики регулярно добавляются в стандартизированном формате. 

Каждая метрика имеет:

  • имя, заданное по определенным семантическим правилам, зафиксированным в глоссарии;

  • описание; 

  • флаг, означающий важность метрики для компании;

  • методологию расчета, описанную в YAML конфиге, и др.

Разрезы для метрик также заведены в семантический слой и имеют:

  • описание;

  • словарь возможных значений;

  • методологию расчета, описанную в YAML конфиге;

  • описание связей между разрезами вида «материнский»  => «дочерний», если это релевантно.

Такое устройство метрик в компании позволяет хранить все ключевые бизнес- сущности в одном месте. Единый формат представления проще для восприятия как людям, так и ИИ-ассистенту.

Тут еще больше контента

16 000+ метрик это реально много — на помощь приходит ИИ-ассистент 

Из-за большого разнообразия бизнес-метрик и широких возможностей визуализации в М42 у пользователей могут возникать сложности с поиском нужной метрики и настройкой параметров при построении графиков. 

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

На помощь приходит сервис m42copilot — ИИ-ассистент, который умеет по текстовому запросу на естественном языке найти нужную метрику или определить параметры визуализации для М42.

Например, запрос может выглядеть так: 

В этом случае ассистент должен определить название метрики («число объявлений»), категорию («Электроника» и ее подкатегории»), временной интервал (первый квартал 2025 года), формат значений метрики (процент изменения относительно прошлой недели), а также формат вывода (таблица). Ассистенту требуется не только правильно выделить слова из запроса, но и поставить им в соответствие реально существующие названия метрик и разрезов, которые могут отличаться от формулировки пользователя. Запрос может содержать жаргонные или транслитерированные названия метрик («баеры с u2i»), аббревиатуры («дау», «arpu»), неточные формулировки разрезов («просмотры в запчастях») — со всем этим ИИ-ассистент должен сопоставить правильное значение.

Другие примеры запросов, на которые должен уметь отвечать ассистент:

Принцип работы ИИ-ассистента

ИИ-ассистент реализован в виде микросервиса на Python, разработанного на платформе Avito PaaS, и имеет 2 основные функциональности:

  • по текстовому запросу пользователя формализовать параметры для дальнейшей отрисовки графика в M42;

  • по текстовому запросу пользователя выводить список релевантных названий бизнес-метрик.

ИИ-ассиcтент основан на взаимодействии с большой языковой моделью (LLM), которая позволяет эффективно решить нашу задачу с помощью указания релевантного запросу контекста в промпте (Retrieval-Augmented Generation, RAG), few-shot примеров с правильными ответами для похожих на запрос случаев, а также структурированного формата вывода (JSON) с указанием перечня допустимых значений для каждого поля.

Обработка запроса на построение графика

Далее приведена общая схема обработки запроса на построение графика. Рассмотрим ее подробнее.

Схема определения параметров графика в ИИ-ассистенте для M42
Схема определения параметров графика в ИИ-ассистенте для M42

Первым шагом при обработке исходного запроса является разделение его на три смысловые части: 

  1. подзапрос с формулировкой основных метрик; 

  2. подзапрос с упоминанием метрики-знаменателя; 

  3. подзапрос с остальными параметрами. 

Метрика-знаменатель используется, когда требуется отобразить отношение одной метрики к другой.

Такое разделение позволяет, во-первых, изолировать логику поиска метрик от разбора параметров (по смыслу это довольно разные сущности), а во-вторых, запустить эти процессы параллельно. Само разделение выполняется запросом к LLM, в котором, помимо описания задачи, приводится набор примеров наподобие таких:

{
   "request": "В каких Вертикалях выше доля контактов из поиска?",
   "response": {
       "main_metric_queries": ["количество контактов из поиска"],
       "denominator_metric_query": "количество любых контактов",
       "remaining_query": "В каких Вертикалях"
    }
}

Логику поиска метрик разберем в следующем разделе. А пока рассмотрим процедуру определения значений разрезов и параметров. 

Мы составляем промпт для языковой модели, в который помещаем инструкции о том, что она выполняет роль бизнес-аналитика, и даем описание разрезов и возможных параметров графика. Кроме того, задается строгая схема ответа в формате json с указанием допустимых значений разрезов и параметров. Такой способ структурированного вывода позволяет добиться корректного формата ответов и в некоторых случаях обойтись без явных инструкций. Например, модель успешно справляется с определением интервалов дат и географических регионов уже по одному наличию в json-схеме полей «start_date» или «region» с перечнем вариантов.

Пример нашей json-схемы приведен далее. Благодаря тому, что задается конкретный список допустимых значений и типов для полей (платформы и вертикали в данном случае), гарантируется, что в этих полях не будет галлюцинаций в процессе генерации ответа от LLM. Модель также не может придумать новых полей, которых нет в схеме.

Такой способ имеет и некоторые ограничения. Например, общее количество перечисляемых значений в полях схемы не может превышать 1000 (для моделей OpenAI), и в целом, чем крупнее схема, тем больше время ответа и количество используемых токенов. То есть внести в нее все подряд точно не получится.

response_format={
   'type': 'json_schema',
   'json_schema': {
       'name': 'avito_bi_schema',
       'description': 'avito bi request schema',
       'strict': True,
       'schema': {
           'type': 'object',
           'properties': {
               'platform': {
                   'type': ['array', 'null'],
                   'items': {'type': 'string', 'enum': platforms},
               },
               'vertical': {
                   'type': ['array', 'null'],
                   'items': {'type': 'string', 'enum': verticals},
               },
               …
            },
            'required': ['platform', 'vertical', …],
            'additionalProperties': False
        }
   }
}

Кроме этого, для эффективного разбора сложных случаев применяется подход RAG few-shot. Few-shot примеры — это техника взаимодействия с большими языковыми моделями, при которой в запросе модели предоставляют несколько примеров правильных решений задачи, прежде чем попросить модель решить новую аналогичную задачу. Такие примеры помогают языковой модели понять структуру задачи, формат ответа или требования к результату, не требуя полноценного обучения.

У нас есть отобранное множество пар запросов и правильных ответов, которые можно подавать в LLM. Однако целесообразнее подавать примеры, наиболее похожие на текущий запрос. В этом состоит известный подход RAG, для реализации которого примеры и сам запрос кодируются в виде векторных представлений (эмбеддингов). Для вычисления эмбеддингов используются модели из репозитория Huggingface, обученные на корпусе русских и английских текстов, например, rubert-mini-frida, и библиотека  sentence-transformers. Для эффективного расчета расстояний между эмбеддингами удобно пользоваться библиотекой Faiss. Схема этого процесса приведена ниже.

Реализация RAG для поиска few-shot примеров
Реализация RAG для поиска few-shot примеров

Поиск метрик

Теперь рассмотрим отдельно логику поиска бизнес-метрик в нашем ИИ-ассистенте. Она во многом похожа на предыдущий раздел, но есть важные особенности. Как уже упоминалось, в нашем продукте рассчитываются и анализируются более 16 тысяч метрик. Каждая метрика описывается ключом (оригинальное неизменяемое название), текущим названием, описанием (более подробный текст) и типом.

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

Поскольку метрик много, их полный перечень не получится задать в json-схеме для структурированного вывода. Поэтому необходим отдельный этап поиска метрик-кандидатов, наиболее подходящих входному запросу, которые затем будут подставляться в промпт для LLM в соответствии с RAG-подходом, упомянутым выше.

Общая схема поиска метрик приведена далее, рассмотрим некоторые ее аспекты.

Схема поиска метрик в ИИ-ассистенте для М42
Схема поиска метрик в ИИ-ассистенте для М42

Генерация кандидатов выполняется несколькими способами:

  • семантический поиск. Используется уже упомянутая схема с эмбеддингами и faiss-индексом, только теперь эмбеддинги считаются по названиям и описаниям всех метрик из реестра. Описания метрик предварительно обработаны LLM для удаления лишних элементов (технические комментарии, ссылки и т.п.).

  • нечеткий лексический поиск. Позволяет найти подходящие метрики-кандидаты, когда пользователь пытается вспомнить отдельные слова из названия или описания метрики (например, для запроса «какие метрики строятся на основе события 6552» будет сложно найти хорошие варианты по эмбеддингам, а по пересечению отдельных слов «событие» и «6552» может получиться). Для этого способа используется библиотека rapidfuzz.

  • точный поиск по названию метрики. Хорошо сработает, если пользователь вводит точное название одной из имеющихся метрик, либо использует транслитерированный вариант (например, по «дау» или «бтц» найдутся метрики «dau» и «btc»).

  • топ популярных. Если ни один из предыдущих способов не сработает, можно передать в LLM список наиболее часто используемых метрик (по истории построенных графиков).

В промпте также описываются общие принципы именования бизнес-метрик, принятые в компании. Например, метрики, связанные с персональными рекомендациями, как правило, имеют суффикс «_u2i», а просмотры объявлений сокращаются до «iv». 

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

Помимо метрик-кандидатов, промпт к LLM также дополняется few-shot примерами – здесь все аналогично подходу, рассмотренному в предыдущем разделе.

После получения ответа от LLM происходит этап постобработки результатов:

  • проверяется валидность структуры ответа и наличие галлюцинаций (придуманных метрик, которых нет в реестре);

  • метрики с признаками архивных или устаревших переносятся в конец списка;

  • отсекается хвост списка за пределами установленных ограничений выдачи.

Жми сюда!

Оптимизация промптов

Отдельный интерес в задачах разработки прикладных ИИ-ассистентов представляет составление основного промпта для языковой модели. Существуют разные приемы и эвристики на этот счет, которые зачастую сводятся к ручному промпт-инжинирингу методом проб и ошибок, однако появились и более технологичные решения. Здесь хотелось бы поделиться опытом использования фреймворка DSPy на примере нашей задачи. 

DSPy — это современный фреймворк для разработки и оптимизации решений на базе LLM, созданный для повышения эффективности промптов и автоматического управления цепочкой рассуждений в сложных ИИ-приложениях. Основная особенность этого фреймворка в том, что он позволяет обучать и оптимизировать промпты с помощью градиентных методов, т.е. делать их дифференцируемыми и автоматически подбирать лучшие варианты для конкретной задачи.

Применение DSPy к задаче настройки ИИ-ассистента на основе RAG может состоять из следующих шагов:

  • Автоматическая генерация и обучение промптов:

    • вместо того чтобы вручную переписывать промпт, достаточно описать высокоуровневую задачу;

    • DSPy создает структуру промпта и автоматически дообучает его на тестовой выборке, улучшая ответы LLM согласно предоставленной метрике качества.

  • Fine-tuning «цепочки рассуждений»:

    • можно разложить сложную задачу на несколько стадий (retrieve -> paraphrase -> answer);

    • DSPy оптимизирует каждый шаг, подбирая лучшие запросы и ответы для максимальной релевантности.

  • Интеграция с Retrieval-Augmented Generation (RAG):

    • DSPy способен обучать и настраивать промпты для связки поиска (Retrieval) и генерации (LLM), делая RAG-пайплайны более точными и устойчивыми.

Приведем небольшой пример с кодом. Вот так может выглядеть упрощенная логика поиска бизнес-метрик на основе RAG и LLM, выполненная в виде DSPy-модуля.

lm = dspy.LM(
    "openai/gpt-4.1", 
    api_key=os.getenv('OPENAI_API_KEY'),       
    api_base=f'{os.getenv('OPENAI_API_URL')}/v1'
)
dspy.configure(lm=lm)

class TrivialRAG(dspy.Module):
    def init(self):
        self.respond = dspy.ChainOfThought(
            dspy.Signature('example_metrics: list[str], query -> metric_names: list[str]',)
        )
        self.retriever = MetricsRetriever(
            metrics_data=metrics_data,   
            embeddings_model_name=<модель эмбеддингов>,
            index_file_name='faiss_index.cache',
        )

    def forward(self, query):
        metrics = self.retriever.get_relevant_elements(query, top_k=20)
        example_metrics = [f"название: {m['metric_name']}, описание: - {m['metric_description']}" for m in metrics]
        return self.respond(example_metrics=example_metrics, query=query)

Этот класс представляет собой базовый блок для решения нашей задачи поиска бизнес-метрик в ИИ-ассистенте: MetricsRetriever отвечает за извлечение списка релевантных метрик, а dspy.ChainOfThought берет на себя работу по вызову LLM. Заметим, что здесь вообще не задается никакой промпт — только верхнеуровневое описание входа и выхода (сигнатура): подаем список примерных метрик и запрос — получаем список названий метрик.

Можно задать некоторую метрику качества, например, top5_accuracy, и посчитать ее на тестовой выборке, как показано ниже. 

class SearchMetricsTopAccuracyMetric(dspy.Module):
    def topkaccuracy(self, pred_metric_names, true_metric_name, k):
        return int(true_metric_name in pred_metric_names[:k])

    def forward(self, example, pred, trace=None):
        return self._topk_accuracy(pred.metric_names, example.metric_name, k=5)

evaluate = dspy.Evaluate(
    devset=devset, 
    metric=SearchMetricsTopAccuracyMetric(), 
    num_threads=24, display_progress=True, display_table=2)

eval_result_before_opt = evaluate(rag)

> Average Metric: 107.00 / 200 (53.5%)

На самом деле, даже такой простой код дает нам достаточно интересные результаты буквально «из коробки». Например, мы можем увидеть:

rag = TrivialRAG()
rag.respond.predict.signature.instructions
> Given the fields example_metrics, query, produce the fields metric_names.

result = rag(query="просмотры айтемов с VAS")
result.metric_names
> ['iv_vas']

res.reasoning
> 'The query "просмотры айтемов с VAS" directly translates to "views of items with VAS." Among the example metrics, the metric "iv_vas" has the description "Количество просмотров айтемов с Vas," which exactly matches the query. Other metrics mention VAS but either refer to ratios, searches, users, or other specific contexts, not the total number of views. Therefore, "iv_vas" is the most relevant metric.'

То есть модуль dspy.ChainOfThought находит нужную метрику по запросу, на основе промпта, полученного из нашей  сигнатуры, и дает вполне внятное объяснение своих действий.

Теперь самое интересное: попробуем оптимизировать этот дефолтный промпт средствами DSPy.

tp = dspy.MIPROv2(
    metric=SearchMetricsTopAccuracyMetric(), 
    auto="medium", num_threads=24
) 
optimized_rag = tp.compile(
    rag, 
    trainset=trainset, 
    max_bootstrapped_demos=2, max_labeled_demos=2
)
eval_result_after_opt = evaluate(optimized_rag)
> Average Metric: 120.00 / 200 (60.0%)

 Что здесь происходит: DSPy автоматизирует подбор промптов, инструкций и примеров для нашего RAG-а на основе метрики и данных из тренировочного набора.

Модуль оптимизации MIPROv2 перебирает варианты промпта и, выполняя вызовы к LLM, сравнивает их между собой, чтобы вернуть версию пайплайна с максимальным  значением метрики для нашего trainset. Можно заметить, что качество поиска после оптимизации улучшилось на 12%.

Посмотрим, каким стал промпт после оптимизации:

optimized_rag.respond.predict.signature.instructions

> You are given a list of example metrics, each with a technical metric name and a description, as well as a user’s natural language query. Your task is to identify and select the metric names from the provided list that best match the user’s query. 
For your output:
1. Reason step by step to explain your selection process, justifying which metric(s) you selected, how their names and descriptions match the query intent, and why you excluded others.
2. Return a list of the most relevant metric names.
Think carefully about synonyms, abbreviations, and the business context of the query when matching to metric descriptions. The reasoning should be transparent and help a business user or analyst understand how you mapped the query to metric names.
Format your response to include:
- Reasoning: <your detailed explanation>
- Metric Names: [<selected metric names>]

Видно, что DSPy составил достаточно толковый промпт, отталкиваясь лишь от формальной сигнатуры, тестовых примеров и метрики. Вообще, фреймворк содержит множество разных оптимизаторов и хорошие туториалы, поэтому за подробностями стоит обратиться к документации.

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

Сравнение LLM

Помимо выбора архитектуры, подбора примеров и промпта, нам, очевидно, надо сравнить и языковые модели, с которыми может общаться наш ИИ-ассистент.

Опираясь на 570 тестовых поисковых запросов из нашего бенчмарка (см. далее), было проведено сравнение нескольких популярных LLM от OpenAI, DeepSeek, Anthropic, Qwen и xAI на примере задачи поиска бизнес-метрик.

Сравнение проводилось по нескольким метрикам качества:

  • доля верных определений параметров запроса на график (по совокупности всех поддерживаемых параметров и разрезов);

  • доля верных ответов для топ-1 и топ-5 выдачи при запросе на поиск метрик;

  • среднее времени ответа LLM для поиска метрик;

  • цена за токены. 

 Результаты приведены в таблице:

LLM

text-to-plot all params accuracy

top1 search accuracy

top5 search accuracy

ср. время ответа при поиске

цена за 1М токенов

gpt-4.1

0.5

0.75

0.85

1.96

$2.00 / $8.00

gpt-4.1-mini

0.33

0.62

0.72

1.59

$0.40 / $1.60

gpt-o3

0.47

0.72

0.85

13.28

$2.00 / $8.00

gpt-5

0.52

0.72

0.84

13.2

$1.25 / $10.00

grok-4-fast

0.41

0.71

0.84

5.97

$0.21 / $0.52

qwen3-235b

0.12

0.63

0.75

9.12

$0.18 / $0.54

qwen3-480b-a35b

0.16

0.70

0.80

1.10

$0.38 / $1.53

deepseek-V3

0.19

0.72

0.83

3.18

$1.40 / $5.60

claude-sonnet-4-all

0.51

0.71

0.86

9.96

$2.10 / $10.50

Можно заметить, что модели qwen3-480b и deepseek-V3 показали хорошие результаты в задаче поиска метрик. Однако в задаче обработки запросов на визуализацию их показатели значительно хуже из-за большой вариативности текстов запросов и значений извлекаемых параметров. Критически важным фактором успеха в этой задаче оказалось эффективное использование JSON-схемы структурированного вывода, с которым лучше всего справились gpt-модели, например, gpt-4.1.

Оценка качества работы ассистента

Оценка качества работы нашего ИИ-ассистента выполнялась двумя способами.

Бенчмарк

Первый способ оценки качества — это проверка ответов ассистента на заранее собранном и размеченном валидационном наборе (голден-сете). Такие наборы собирались отдельно для задачи анализа запросов на построение графиков и для задачи поиска метрик. Они получились небольшими (225 и 570 примеров соответственно), поскольку тщательная разметка и проверка требуют кропотливой ручной работы.

На собранных датасетах считались точность и полнота для отдельных разрезов и параметров в запросах на построение графиков, а также доля верных ответов среди топ-1, топ-3 и топ-5 поисковой выдачи для задачи поиска метрик.

По отдельным разрезам, таким как «вертикали», «категории», «платформы», «параметры агрегации» и «форматы отображения», точность/полнота получились в пределах 0.7-0.95. Доля верных ответов ассистента для комбинации из 5 основных разрезов составила 0.58, а для всех доступных —- 0.5. Основную сложность представляют разрезы, схожие по названию и значениям — например, среди них есть «логическая категория», «категория» и «подкатегория», что запутывает LLM особенно в случае нечетко сформулированных запросов.

В задаче поиска метрик ИИ-ассистент показал долю случаев с релевантными ответами для топ-5 выдачи около 0.85, для топ-1 — 0.75. 

Сбор обратной связи 

Вторым способом оценки качества был сбор фидбека от пользователей после внедрения ИИ-ассистента в интерфейс продукта М42. Пользователи могли оставлять лайки и дизлайки по результатам выполнения своих запросов, а также указывать, что было определено неверно. За 2 месяца использования было собрано около 550 реакций с соотношением 2:1 в пользу лайков.

Основная причина дизлайков состоит в том, что ассистент на данный момент поддерживает не все доступные в M42 виды разрезов для построения графиков.

Результаты внедрения

За первые два месяца после запуска сотрудники Авито сделали около 2 000 запросов к ИИ-ассистенту в М42. И результаты уже заметны:

  • графики строятся на 50 % быстрее. Мы сравнили, сколько времени уходит на построение графика вручную — от открытия метрик до появления визуализации — и через ассистента. Разница впечатляет: с помощью ИИ всё получается в два раза быстрее.

  • в некоторых случаях поиск метрик становится в десятки раз быстрее. Один из пользователей пишет: «ИИ ассистент нашел данные с первого запроса. Я их несколько месяцев назад искал почти час. Фантастика!»

  • инструмент стал популярнее. Проникновение выросло на 1,5 % — то есть к М42 пришли новые пользователи, которые раньше им не пользовались, но начали взаимодействовать с ним благодаря ассистенту.

Эти данные показывают, что новая функциональность действительно помогает людям активнее работать с продуктом и сокращать время, затраченное на поиск объектов и накликивание графиков.

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

Кликни здесь и узнаешь

Планы развития

В дальнейшем мы планируем развивать ИИ-ассистент по следующим направлениям:

  • увеличение числа поддерживаемых разрезов и повышение точности их определения;

  • диалоговый режим работы с возможностью дополнения предыдущих запросов;

  • расширение сценариев взаимодействия с ассистентом (например, ответы на вопросы по устройству метрик, интерпретация графиков).

Подробнее о Trisigma можно прочитать здесь, а если хотите вместе с нами адаптироваться в мире стремительно развивающихся технологий — присоединяйтесь к командам. Свежие вакансии есть на нашем карьерном сайте.

Комментарии (0)