Как мы научили таск‑трекер и корпоративную wiki понимать вопросы на человеческом языке — и сэкономили сотни часов в год

от автора

Всем привет! На связи Валерий Калинин и Олег Кудинов, мы представляем команду сопровождения тестовых стендов приемочного тестирования Московской Биржи. В этой статье расскажем, как сделали поиск по внутренней документации в таск-трекере и корпоративной wiki на порядок быстрее, не написав ни единой строчки кода бэкенда.

Проблематика

Наше корпоративное пространство в wiki разрослось до десятков тысяч страниц, а поиск нужной информации стал иногда представлять из себя квест. Проблема заключается в том, что в wiki есть встроенный поиск, но он не понимает суть поискового запроса. Напишешь «как настроить интеграцию с Kafka» — получишь страницы, где слова «интеграция» и «Kafka» встречаются, но не обязательно вместе и не обязательно в нужном контексте.

Вроде бытовые мелочи, но есть большие интеграционные процессы, которые проходят через множество ИТ-систем. Для того, чтобы узнать подробности, как они работают целиком, нужно внимательно изучить документацию. К тому же команды меняются: разработчик приходит на готовый процесс «на поддержку», не успев поучаствовать в его создании, и пока еще не глубоко погружен. Экспертиза фиксируется в документации, но порой документация растёт быстрее, чем люди успевают в ней ориентироваться. А это очень важно, например, при разборе инцидентов на проде, когда счёт идёт на минуты.

Или вот еще один кейс от команды E2E-тестирования. У коллег есть ежедневные дежурства по анализу отчётов регресс-тестов. По итогам анализа заводятся тикеты и перед этим нужно проверить, нет ли дублей. Обычный поиск таск-трекера ищет по жёсткому совпадению, а у них тикеты часто содержат почти одинаковые стектрейсы, которые отличаются только переменными данными — UID, датами, трейд-кодами. Сложности начались, когда за 4 года работы команды количество решённых задач превысило 9000. В итоге ребята ежедневно тратили время на ручной поиск дублей, а это по 10 мин на каждый поиск. Ниже расскажем, как мы сэкономили ребятам несколько десятков часов монотонной работы.

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

Пример поиска в корпоративной wiki

Пример поиска в корпоративной wiki

Архитектурный стек

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

Движок автоматизации— open-source low-code платформа для создания workflow-автоматизаций. Уже из коробки имеет сотни готовых интеграций и простой интерфейс для взаимодействия с LLM и поддержку мульти-агентных систем.

Ключевое для нас: open-source low-code платформа разворачивается полностью self-hosted. Именно так она и используется в Московской Бирже — никаких внешних API-запросов с нашими данными.

Low-code платформа в нашей системе:
— оркестрирует весь пайплайн (загрузка → чанкинг → эмбеддинг → поиск → ответ);
— взаимодействует с API wiki-платформ, LLM и базами данных;
— позволяет визуально строить и отлаживать сложные цепочки без написания кода.

Второй ключевой инструмент — векторная СУБД. Хранит эмбеддинги документов и выполняет семантический поиск по близости векторов. В отличие от полнотекстового поиска, она:
— находит смысловые совпадения, а не только точные вхождения слов;
— поддерживает фильтрацию по метаданным (автор, дата, пространство в wiki);
— возвращает результаты с оценкой релевантности;
— горизонтально масштабируется.
Именно векторная СУБД позволяет задать вопрос «где описан порядок эскалации инцидентов?» и получить нужную страницу, даже если в ней нет слова «эскалация».

Векторная БД

Векторная БД

LLM используется для понимания запросов и генерации ответов.

Языковая модель решает две задачи:
1. Понять запрос пользователя и преобразовать его в форму, удобную для векторного поиска.
2. Сформулировать ответ на основе найденных чанков документации, добавив ссылки на источники.
Модель работает внутри периметра Московской Биржи — данные не уходят во внешние сервисы.

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

Хранение данных в PostgreSQL

Хранение данных в PostgreSQL

Решение

Воркфлоу в low-code платформе

Воркфлоу в low-code платформе

Для наглядности на изображении проиллюстрированы действия в первом воркфлоу.

Мы использовали 2 промежуточные таблицы postgres для того, чтобы в первую собирать id нужных страниц, по которым будет работать поиск. Во вторую таблицу уже записывали контекст страницы и использовали её для проверок (пройденные LLM-кой страницы, загруженные в векторную БД и т.д.).  Этого можно не делать, но на пространстве в 10000+ страниц при работе воркфлоу возможны разного рода коллизии и проверки id по таблицам помогают продолжать работу с того места, где случилась ошибка.

0 этап

Собираем список необходимых страниц пространства, из которых будем с помощью LLMполучать контекст. Мы делали это скриптом на python, который обходит все подстраницы пространства и записывает id страницы в БД postgres.

1 этап (синяя подложка на воркфлоу)

С помощью стандартной ноды берём id страниц из первой БД и проверяем, обрабатывалась она или нет. Если нет, то группой нод получаем её содержимое http-запросом в API wiki, подчищаем от лишнего форматирования и превращаем в markdown. Самые длинные страницы мы обрезали, чтобы они влезали в контекстное окно LLM. Далее простым промптом просим LLM выделить из страницы контекст по стандартной форме и сформировать несколько тегов ключевых слов, описывающих эту статью. После чего грузим всё во вторую БД.

2 этап. Жёлтая подложка

Получившуюся таблицу мы просматривали вручную и выборочно проверяли некоторые строки. Убедившись, что всё ок, проставили скриптами галки true в колонку validate и запустили с помощью ручного триггера и стандартной ноды для работы postgres обход всех строк таблицы с проставленной галкой validate=true и loaded=false. Дальше с помощью стандартного для такой задачи набора нод (embeding, splitter) загружаем необходимые данные в векторную БД, формируя базу для контекстного поиска.

3 этап. Зелёная подложка

Тут реализован модуль общения с ботом. Всё стандартно, триггер чата обращается в агент с LLM-моделью, у которого в качестве инструмента есть получившееся шагом ранее хранилище. Количество выборки и формат ответа регулируется промптом.

Общение в чате реализовано через простой веб-интерфейс. На той же машине, что и low-code платформа, развернут локальный веб-сервер, отдающий идущую из коробки страницу чата low-code платформы.

Как мы реализовали аналогичное решение для таск-трекера

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

Штатный поиск по таск-трекеру работал так же, как и по wiki. Нужно помнить точные keyword. Немного ошибся, выбрал синоним или сокращение — и нужную задачу найти уже не получится.

Наше решение работало по той же схеме:
1.       python скрипт разбирает все задачи в пространстве и складывает содержимое в postgres БД;
2.       embedding перегружает в векторную базу и оттуда уже выдается чат-боту;
3.       чат-бот помогает тестировщикам искать по сути ФЗ, не утруждая себя вспоминать дословные формулировки.

Поиск по таск-трекеру

Поиск по таск-трекеру

Подводные камни

·       Несколько раз падало из-за невозможности обработать LLM-кой запросы, поэтому и пришли к версии с 2-мя таблицами и retry на всех важных нодах.
·       Так же следует заранее подумать о данных, которые вам необходимо индексировать. Если там  есть обязательные поля (например, названия проектов на странице автора) и вы хотите гарантированно получать их в ответе на свой поисковый запрос — стоит их заранее разметить как метаданные для векторной БД и записывать как metadata.key  для точного поиска.
· Обновление индексов в векторной базе – из коробки через low-code платформу специальной нодой обновить метаданные конкретной записи нельзя. Если вам требуется периодически изменять страницы в wiki и изменять соответствующие векторы, потребуется хранить id страницы как метаданные metadata.key и уже по ним искать в векторной базе id записи и уже по нему – обращением в api векторной базы обновлять или удалять запись.

Что мы в итоге получили

·       Поиск по смыслу, а не по словам.
Запросы в стиле «как откатить деплой на стенде» находят нужную документацию, какими бы словами она ни была написана. Сотрудники тратят меньше времени на поиск информации.
·       Система не требует точной формулировки.
Опечатка, синоним, смешение латиницы и кириллицы — раньше это затрудняло поиск. Снижается риск потери знаний в командах, а также снижается порог входа для новых сотрудников.
·       Для того конкретного кейса для команды E2E 
Поиск дубля тикета стал в 10 раз быстрее. До внедрения дежурный тратил на поиск дубля среди 9000+ тикетов около 10 минут — и делал это 1-2 раза за рабочий день. После внедрения тот же поиск занимает минуту. Это дало команде 50+ часов сэкономленного времени в год. И таких кейсов можно найти несколько у каждой команды.
·       Все данные остаются внутри периметра компании.
Low-code платформа, LLM и базы данных развёрнуты self-hosted, ни один запрос и ни один фрагмент документации не уходит во внешние сервисы. Отсутствуют интеграционные риски с внешними API.
· Переиспользование коллекций.
Коллекции векторной БД можно выгружать и передавать смежным командам — не нужно переиндексировать одно и то же дважды.

Мы только в начале пути. В ближайшее время планируем:

·       расширить покрытие на другие источники внутренней документации;
·       добавить возможность задавать вопросы с уточнениями (диалоговый режим);
·       улучшить качество чанкинга с учётом структуры страниц wiki (заголовки, таблицы, блоки кода);
·       настроить аналитику запросов, чтобы понимать, что сотрудники ищут чаще всего.

Если у вас растёт корпоративная база знаний и стандартный поиск перестаёт справляться — контекстный поиск на базе LLM и векторных баз данных решает задачу.
При этом не обязательно писать бэкенд с нуля: low-code платформа позволяет собрать весь пайплайн, а данные можно оставить внутри периметра.

Стек low-code платформа + векторная СУБД + PostgreSQL + LLM оказался практичным выбором: каждый инструмент делает своё, они хорошо интегрируются друг с другом, и вся система прозрачна для отладки.

Если есть вопросы по архитектуре или хотите поделиться своим опытом — пишите в комментариях.

ссылка на оригинал статьи https://habr.com/ru/articles/1061242/