Advisor: помощник по трудоустройству

в 9:16, , рубрики: ai talent hub, langraph, nlp, qdrant, rag
человек общается с ИИ

человек общается с ИИ

Привет! Меня зовут Гурциев Ричард, я магистрант 1-го курса AI Talent Hub. За первый семестр я с головой погрузился в крутой проект, цель которого — сделать этап трудоустройства проще и удобнее как для работодателей, так и для кандидатов. В этой статье я хочу поделиться своим опытом работы над проектом Advisor🚀

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

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


Содержание:

  1. Данные

  2. RAG

  3. Deploy

Данные

Когда встал вопрос о том, где искать данные, первым на ум пришел HeadHunter (HH) — одна из самых известных и популярных платформ для работы с вакансиями и резюме. Изучив возможности площадки, оказалось, что у HH есть официальный API для получения данных о вакансиях! Но с резюме всё оказалось не так просто: чтобы их собрать, пришлось разработать парсер, так как URL-адрес для резюме был неочевиден. Написав скрипт, который успешно отправлял запросы и извлекал информацию, необходимо было приступать к следующему шагу — структурированию данных.

пример резюме кандидата

пример резюме кандидата

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

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

Определившись с основным контентом необходимо было привести данные к единой структуре. Очевидно, что обрабатывать такие данные вручную не очень хочется. Решением стало внедрение автоматизированной системы, способной быстро и точно анализировать данные. В её основе лежит фреймворк vLLM и модель Qwen/Qwen2.5-7B-Instruct, которая принимая инструкции, довольно неплохо справляется с обработкой естественного языка.

*Инструкция — это текстовый запрос, который передается модели, чтобы получить от нее ответ или выполнить задачу.

Таким образом, собранные резюме/вакансии принимают суммаризированный вид по тем основным полям, которые ранее были указаны.

результат обработки собранных данных

результат обработки собранных данных

После того как данные были собраны и обработаны, следующий ключевой шаг — это их хранение. И тут в игру вступает Qdrant — мощная векторная база данных, которая идеально подходит для хранения данных. Qdrant был выбран по нескольким причинам: он интуитивно понятен в использовании, и его можно легко развернуть в контейнерах. Это обеспечит гибкость и стабильность, необходимое для работы с данных. О процессах, связанных с Qdrant, мы подробно поговорим в блоке RAG.

RAG

Что такое RAG ? Если кратко, то RAG (Retrieval-Augmented Generation) — это форма общения с моделью, при котором ответ на запрос формируется языковой моделью, используя данные из внешнего хранилища, например, Qdrant, Milvus и прочее. Важно, что эти данные извлекаются на основе векторной схожести, что позволяет повысить точность и релевантность сгенерированного ответа. Более подробно можно ознакомиться тут.

Выбор и настройка ретривера (retriever)

Создание RAG начинается с выбора и настройки retriever — компонента, который отвечает за извлечение информации из базы данных.

Для извлечения релевантной информации необходимо было подобрать подходящий алгоритм, который обеспечил бы эффективное извлечение информации из базы, поэтому для поиска подходящего алгоритма было решено взять несколько моделей и рассмотреть их как отдельно, так и совместно. В качестве плотных векторов были выбраны: deepvk/USER-bge-m3, ruRoPEBert-e5-base-2k, rubert-tiny2, multilingual-e5-large и all-MiniLM-L6-v2. Для формирования разряженных векторов был взят bm25.

Проведённые эксперименты для оценки top@10 points показали, что среди алгоритмов поиска, использующих только один вид embeddings, лучшим оказался deepvk/USER-bge-m3. Результаты представлены ниже.

метрика c одним видом эмбеддингов

метрики c одним видом эмбеддингов

Однако хотелось рассмотреть и другие подходы, которые могли повысить полученные метрики.

Fusion Vs Matryoshka

Существует два основных подхода к созданию гибридной поисковой системы: "слияние" и метод "матрёшки". Первый подход предполагает комбинирование результатов, полученных различными методами поиска, исключительно на основе их оценок. Для этого обычно требуется нормализация, так как значения оценок разных методов могут значительно отличаться по диапазону. После нормализации используются показатели релевантности для вычисления итогового балла, который определяет порядок документов. Qdrant имеет встроенную поддержку метода взаимного ранжирования, который является стандартом де-факто в этой области.

взаимное ранговое слияние (изображение было взято отсюда)

взаимное ранговое слияние (изображение было взято отсюда)

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

метрики c методом Fusion

метрики c методом Fusion

Ну что ж, попробуем применить иной подход)

Механизм поиска может выполнять роль механизма повторного ранжирования. Например, можно предварительно отобрать результаты с использованием разреженных векторов, а затем повторно ранжировать их с помощью плотных векторов. Если у вас есть несколько embeddings, то, по принципу матрёшки, можно начать с отбора кандидатов с плотными векторами наименьшей размерности и постепенно уменьшать их количество, повторно ранжируя с помощью более сложных многомерных векторов. Ансамбль таких подходов позволит комбинировать слияние и повторное ранжирование для достижения наилучших результатов.

ранжирование гибридного ансамбля (изображение было взято отсюда)

ранжирование гибридного ансамбля (изображение было взято отсюда)

Остановимся на ансамбле, который объединяет результаты матрёшечных вложений, плотных и разреженных векторов. Для данного алгоритма были выбраны модели на основе результатов 1-го исследования: deepvk/USER-bge-m3, Tochka-AI/ruRoPEBert-e5-base-2k и bm25.

ранжирование методом матрёшки

ранжирование методом матрёшки

Удалось выбить следующие результаты:

ndcg

precision@10

map@10

recall@10

mrr@10

dcg@10

0.991

1.0

0.77

0.77

1.0

4.54

Сравнивая результаты 1-го и 3-го эксперимента стало ясно, что использование метода матрёшки улучшило показатели поиска для MAP@10 и Recall@10, однако привело к незначительному снижению NDCG.

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

Мультиагентная система

После выбора алгоритма поиска мы приступаем к следующему этапу системы RAG — мультиагентным системам.

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

В данной системе используется LangGraph, который позволяет создать графовую сетку, где каждый узел представляет собой агента, выполняющего определенную инструкцию. Более подробно об этом можно ознакомиться тут. Что в итоге получилось ?

графовая сеть

графовая сеть

Графовая сеть начинается с узла classifier, который выполняет классификацию входного текста. Если текст не содержит информации о кандидате или вакансии, то маркой other текст классифицируется и срабатывает узел no_info, возвращая пользователю ответ: "Извините, по вашему запросу нет информации". Если текст не классифицируется как other, то в этом случается срабатывает узел extract, который извлекает из текста сущности для создания суммаризированного резюме или вакансии. Далее узел retriever на основе полученного текста выполняет ранжирование релевантных резюме или вакансий из векторной базы данных, а после узел answer оформляет эти данные в нужном формате и возвращает их пользователю. Как именно пользователь их получает станет ясно в блоке Deploy.

Deploy

Архитектура проекта

Архитектура проекта

Кратко обсудим клиентскую часть, которая состоит из backend и frontend секций. Разберем их поочередно.

Backend

Бэкенд был реализован с использованием FastAPI. С помощью этого фреймворка были созданы два endpoint: POST-запрос для отправки файла с резюме или вакансией, а также GET-запрос для получения всех отобранных кандидатов со стороны RAG.

Frontend

UI проекта

UI проекта
резюме на позицию frontend-разработчик

резюме на позицию frontend-разработчик

UI был разработан с использованием фреймворка Angular. В приложении предусмотрен выбор категории (резюме/вакансия), деятельности (например, frontend, backend и devops) и загрузка файлов формата (.txt, .pdf, .docs). После отправки запроса пользователь через некоторое время получает ранжированный список релевантных вакансий, которые требуют особого внимания кандидата.

Заключение

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

Проект Advisor будет в дальнейшем модифицироваться. Планируется попробовать использовать bert-like модели и обучить их на задачу NER, поскольку это на порядок повысит скорость ответа со стороны RAG системы. Также стоит обратить внимание на vLLM, которая, судя по этой статье, способна увеличить скорость обработки данных.

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

Жду ваши вопросы и замечания!

To be discussed

Что следовало бы доработать или заменить? В чем причина?

Автор: r1char9

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js