Самое сложное в LLM-проекте не языковая модель, а данные и проверки вокруг нее. Как мы сделали поиск ИТ-специалистов по смыслу резюме, а не по совпадению ключевых слов
БизнесМатика - это ИТ-компания на рынке с 2012 года. Мы внедряем проекты на базе языковых моделей (LLM) для компаний среднего и крупного бизнеса.
Один из наших LLM-проектов мы сделали для собственной работы. Это платформа "Телескоп", которая подбирает ИТ-специалистов под запросы клиентов. В ее основе поиск по смыслу. Система сравнивает смысл запроса клиента и смысл резюме, а не совпадение слов в них. Сейчас в ней больше 17 тысяч резюме, и мы подбираем через нее специалистов каждый день.
Дальше расскажу, как это устроено и что требуется, чтобы языковая модель решала рабочую задачу. Если коротко, подключить модель обычно несложно, а основная работа вокруг нее (данные, их проверка, встраивание в работу).
Клиент в запросе и кандидат в резюме часто называют один и тот же опыт разными словами
Клиент описывает живым текстом, кто ему нужен. Например, нужен ведущий разработчик на Python с опытом в финтехе. С другой стороны тысячи резюме из нескольких источников. Это кандидаты от компаний-партнеров, наши собственные специалисты и отклики с публичных площадок. Платформа должна выбрать из этих тысяч те резюме, что отвечают запросу.
Вот где сложность. В запросе стоит «финтех», а подходящий кандидат мог описать тот же опыт как «разрабатывал банковские системы». Поиск по ключевым словам сопоставляет резюме с запросом буквально, по самим словам, поэтому «финтех» и «банковские системы» для него не совпадают. Из-за этого он ошибается в обе стороны. Подходящего кандидата, который описал опыт другими словами, поиск по ключевым словам пропускает. А пустое резюме, где нужное слово стоит формально, без реального опыта за ним, наоборот, считает подходящим. В итоге рекрутер вручную перебирает сотни резюме, где подходящие вперемешку с теми, кто совпал только по словам.
Поэтому сравнивать нужно смысл запроса и смысл резюме, а не слова. Тогда «банковские системы» и «финтех» совпадут по смыслу, и подходящий кандидат не потеряется из-за того, что назвал опыт иначе.
Как поиск по смыслу находит резюме, даже если слова в нем и в запросе разные
Каждый текст, и запрос, и резюме, мы представляем вектором, то есть набором чисел, который отражает смысл текста. Такой набор называют эмбеддингом. Тексты, близкие по смыслу, дают близкие векторы, даже если написаны разными словами. Платформа выбирает те резюме, чей вектор ближе всего к вектору запроса.
Но одного векторного поиска для реальной работы мало. Вокруг него пришлось добавить несколько доработок, без которых он не годится.
Сначала мы отсекаем резюме, которые по смыслу слишком далеки от запроса. Но если отсекать строго, на узкий запрос может не остаться ни одного кандидата. Поэтому в таком случае платформа добирает несколько лучших из тех, что есть. Так у рекрутера на любой запрос есть хотя бы несколько кандидатов, которых он дальше разбирает вручную.
После векторного отбора языковая модель оценивает, насколько кандидат подходит под запрос
Векторный поиск находит резюме, близкие по смыслу, но не оценивает, насколько кандидат подходит на деле. Поэтому несколько резюме с наибольшей близостью к запросу дополнительно разбирает языковая модель. Она сверяет каждого кандидата с требованиями из запроса по шагам. Сначала смотрит роль, затем уровень, затем конкретные требования. Модель выдает балл соответствия, разбор по пунктам (что у кандидата есть из требований, а чего нет) и короткий вывод, стоит ли рассматривать кандидата дальше. Балл соответствия и близость векторов говорят о разном, и рекрутер видит оба. Близость векторов показывает, что резюме вообще про ту же специальность, а балл модели - насколько кандидат закрывает требования запроса.
Отдельно про данные. В поиск по смыслу и в оценку модели уходит только профессиональный профиль. Это роль, уровень, навыки, опыт и образование. Имя, телефон и почта на эти два этапа не передаются.
Под капотом. Эмбеддинги в PostgreSQL и поиск по смыслу в два этапа
Эмбеддинги мы храним и ищем по ним прямо в основной базе данных (PostgreSQL с расширением pgvector), без отдельного векторного хранилища. Так все живет в одной базе. Близость между вектором запроса и векторами резюме мы считаем по косинусной мере.
Поиск по смыслу идет в два этапа. Первый этап быстрый, это сам векторный поиск. Его результат рекрутер видит без задержки. Второй этап, оценка языковой моделью, идет в фоне, по нескольким резюме с наибольшей близостью, чтобы интерфейс не ждал модель.
Близость между запросами и резюме мы пересчитываем при каждом новом запросе или резюме и дополнительно раз в сутки по расписанию, чтобы результаты поиска не устаревали.
Сама языковая модель - это отдельный сменный компонент. Ее можно заменить на другую, и архитектура не изменится. Сложность не в выборе модели, а во всем, что вокруг нее, в хранении, двух этапах поиска и пересчете.
Что нужно, чтобы поиск по смыслу работал на реальном потоке, а не только на демонстрации
Подключить языковую модель можно за несколько дней. А сделать так, чтобы она находила нужных кандидатов на реальном потоке заявок, совсем другая работа. Вот что для этого понадобилось.
Качество резюме и запросов на входе. Модель не умнее текста, который вы ей даете. Резюме и запросы часто приходят в разном виде, поэтому перед поиском мы приводим их к сопоставимому виду. Без этого даже хорошая модель находит не тех кандидатов.
Способ сверить оценки модели с решениями рекрутеров. Многие внедряют модель и не проверяют, совпадают ли ее оценки с тем, как на деле поступают рекрутеры, берут кандидата в работу или отклоняют. Это частая ошибка. У тех, кого берут, медианная оценка модели заметно выше, чем у отклоненных. По нашей шкале это 80 против 65. Это не «точность» в строгом смысле, а признак того, что модель оценивает кандидатов в ту же сторону, что и рекрутер. Без такой сверки вы внедряете модель, не зная, совпадает она с людьми или нет.
Свежесть резюме и запросов. Со временем запросы закрываются, а резюме устаревают. Платформа сама убирает из поиска закрытые запросы и неактуальные резюме, чтобы не показывать их в результатах.
Где еще работает поиск по смыслу, кроме подбора
Если убрать слово «подбор», остается та же задача, что и в подборе. Взять большой объем неструктурированного текста и находить в нем нужное по смыслу запроса, а не по совпадению слов. Тот же поиск по смыслу работает и в других задачах.
- Искать по базе документов и знаний по смыслу вопроса.
- Разбирать входящие документы и раскладывать данные из них по полям.
- Распределять обращения по смыслу, а не по ключевым словам.
Если у вас есть процесс, где много неструктурированного текста и поиск идет по ключевым словам, такой подход стоит попробовать.
С чего начать, если у вас похожая задача
Заработает ли языковая модель в деле, почти не зависит от того, какую модель выбрать. Решают данные, способ их проверки, свежесть данных и встраивание в рабочий поток. Все это мы прошли на собственном продукте.
Если вы хотите встроить языковую модель в свой рабочий процесс и начать с пилота с измеримой метрикой на ваших данных, напишите мне.