Проектирование системы поиска вакансий с участием нескольких агентов: пайплайн, HyDE и возможности наблюдаемости.
Девятиэтапная система LangGraph для соответствия резюме вакансиям, включающая восемь вариантов настройки для поиска в HyDE, маршрутизации моделей, ограничений скорости и возможностей мониторинга.
Источники: Agentic AI in Practice: A Case Study in Multi-Agent System Design
Агенты, искусственный интеллект с агентными возможностями, многокомпонентные системы: такая терминология встречается повсюду, и каждую неделю появляются новые модели, фреймворки или шаблоны оркестрации. Технологии вроде промптинга, RAG, вызова инструментов, MCP и слоев памяти. Экосистема развивается быстрее, чем многие специалисты могут за ней поспевать. Сквозь весь этот шум основные вопросы остаются прежними:
- Как следует разбить проблему на части для пошагового решения?
- Какие операции относятся к LLM, а какие никогда не должны оставаться на его усмотрение?
- Как можно убедиться, что система действительно делает то, что от неё ожидают?
Выпуск новой версии фреймворка не делает эту задачу проще. Чтобы сделать пример более конкретным, в данном исследовании рассматривается проблема, с которой сталкиваются миллионы людей: поиск подходящих вакансий среди огромного количества объявлений. Для решения этой проблемы разрабатывается полноценная система на основе ИИ, с помощью которой отвечаются на три практических вопроса. Что подразумевается под понятием «агент» в архитектурном контексте? Когда несколько агентов приносят пользу, а когда они становятся лишним бременем? И что делает систему ИИ наблюдаемой, надежной и готовой к использованию в производственных целях?
Поиск работы — это не просто поиск
Большинство людей рассматривают поиск работы как задачу поиска. На самом деле это скорее задача сопоставления. Никто на самом деле не ищет объявления, содержащие определенные ключевые слова. Фундаментальный вопрос гораздо сложнее: учитывая опыт, навыки и направление карьеры, какие вакансии действительно подходят?
Порталы вакансий работают по принципу поиска: вы вводите несколько ключевых слов, указываете местоположение и надеетесь найти что-то релевантное. Однако резюме отражает многолетний опыт, специализированные знания, техническую глубину, переносимые навыки, карьерный рост и контекст, а поле поиска заставляет уместить всё это в несколько слов, предполагая, что совпадение слов означает совпадение намерений.
Все знают, как это происходит:
- Пролистывание сотен объявлений на разных платформах
- Оценка релевантности по одному объявлению за раз
- Столкновение с дубликатами, устаревшими объявлениями и сломанными ссылками
- Сомнения в том, были ли выбранные должности действительно подходящими с самого начала
Скука — не главная проблема. Настоящий разрыв заключается между тем, что говорит опыт кандидата, и тем, что на самом деле требуется работодателю, а преодоление этого разрыва требует интерпретации, понимания контекста и умения судить. Короче говоря, для этого нужно логическое мышление, в котором большие языковые модели демонстрируют сильные результаты. Представьте, что система могла бы прочитать резюме, определить разумные карьерные пути, найти вакансии и отсортировать их по степени соответствия, а не по наличию совпадающих ключевых слов. Именно для решения этой проблемы и была создана данная система.
Процесс по шагам
Всё начинается с одного действия: загрузка резюме. После этого никто не пользуется поисковым полем, не прокручивает списки вакансий и не решает, на какие должности стоит подавать заявку. Система берет всё в свои руки и выполняет девять шагов, каждый из которых имеет определённую задачу.
- Агент-анализатор резюме. Действуя как опытный рекрутер, он превращает резюме в структурированный профиль вместо списка ключевых слов. В профиле указываются занимаемые должности, навыки, сферы экспертизы, ход карьеры и краткое описание в стиле ATS, которое все последующие агенты считают каноническим описанием кандидата. Модель: Claude Sonnet.
- Агент-рекомендатор профилей. Он предлагает два-три варианта должностей, соответствующих уровню кандидата, его специализации и навыкам, а также варианты поисковых запросов для каждой из них. Модель: Claude Haiku.
- Этап подтверждения человеком. Это единственный момент, когда решение принимает человек. Пользователь просматривает предложенные профили, выбирает подходящий, по желанию указывает предпочтения по местоположению и уровню опыта, после чего подтверждает выбор. Все остальные этапы ждут до этого момента. В процесс не вовлекаются модели — только человеческое суждение.
Всего это включает девять шагов, четыре вызова ЯЗЫКА, одно решение человека, причем общее время выполнения составляет менее трех минут.
Карта технологий
На приведённой выше диаграмме каждый основной компонент современной стек-архитектуры ИИ показан в рамках этой цепочки обработки. Каждая система представляет собой совокупность выборов, поэтому в следующих разделах рассматривается, что было принято во внимание, что отклонено и какова была связанная с этим стоимость.
Восемь решений по проектированию
1. LangGraph вместо CrewAI, AutoGen или цикла ReAct
Обычными кандидатами были LangGraph, CrewAI и AutoGen; внутри LangGraph существует дальнейшее разделение на ориентированную графу и цикл ReAct.
CrewAI акцентирует внимание на автономном сотрудничестве с использованием агентов, выполняющих роли, которые ведут переговоры и делегируют задачи друг другу. AutoGen ориентирован на диалог между несколькими агентами в формате разговора. Оба варианта подходят для рабочих процессов с открытым исходом. Однако оба также создают дополнительную нагрузку на координацию и неопределённость, которые фиксированная цепочка обработки не может себе позволить отлаживать.
Циклы ReAct особенно эффективны, когда количество шагов неизвестно заранее, как в случае с большой языковой моделью, которая просматривает интернет и не может предсказать, сколько поисков ей понадобится. Поиск работы не похож на это: структура задачи определяет последовательность действий — сначала парсинг, затем рекомендации, потом поиск, после этого фильтрация и только после всего — удаление дубликатов. Ничего не открывается во время выполнения.
Для этого идеально подходит ориентированная графа: каждая переходность явна, вмешательство человека рассматривается как первостепенный элемент, а состояние представляет собой общую модель Pydantic, которую каждый узел может читать и записывать. Когда что-то ломается, неисправный узел становится очевидным.
2. Специализированные агенты вместо одного мегапромпта
Желательно создать один большой промпт, который будет анализировать резюме, предлагать названия и оценки, и это делается быстрее. Однако такой подход приводит к сложным и непредсказуемым сбоям: сбой в одной части влияет на всю систему. Невозможно определить, какая именно инструкция привела к плохому результату, настройка одной части может вызвать проблемы в другой, а контекст заполняется инструкциями, не связанными с текущей задачей.
Отдельные агенты позволяют избежать этого. Низкий результат оценки можно отладить, изучив только промпт для оценки. У каждого агента есть собственный тестовый скрипт, поэтому парсер можно тестировать на наличие регрессий без всей системы. Кроме того, разные агенты могут быть связаны с разными моделями, как показано в пункте 6 проекта.
3. Режим участия человека
В большинстве учебных материалов по агентам проверка человеком рассматривается как необязательная доработка, способ сделать процесс более интересным для пользователей. Здесь же такой режим является ключевым архитектурным решением.
Система рекомендаций предлагает два-три варианта, и профиль, который подтверждает пользователь, определяет все последующие этапы: поиск, фильтрацию и оценку. Если система будет выбирать автоматически, неверный выбор может испортить весь процесс, приведя к списку с рейтингом, который совсем не нужен пользователю. Ни одно другое решение в этой цепочке не несет столь большого риска, и ни одно из них нельзя лучше обработать человеком, поскольку кандидаты знают о своих предпочтениях то, что парсер не может выявить.
4. Предфильтр перед системой ранжирования
Данные из реального мира никогда не бывают идеальными, а записи из пяти API приходят с типичными проблемами:
- Недоступные ссылки и ошибки 404 из-за устаревших записей, которые так и не были удалены
- Дубликаты, поскольку одна и та же вакансия появляется из нескольких API одновременно
- Перенаправления агрегаторов, когда URL ведет на главную страницу биржи труда, а не на саму запись
Это не крайние случаи. Это нормальное состояние данных внешних API. Шаги проверки и удаления дубликатов предназначены для очистки данных до того, как произойдут дорогостоящие операции, так что то, что попадает в семантический предфильтр, является корректным, уникальным и реальным.
Затем важна стоимость. В ходе производственных запусков алгоритм ранжирования составляет от 70 до 80 процентов от общих затрат на использование LLM. Парсер стоит фиксированную сумму в размере 2,7–3,0 рупий независимо от количества обрабатываемых заданий, а рекомендатель — примерно 0,30 рупий, также фиксированную сумму. Стоимость алгоритма ранжирования варьируется от 3 до 11 рупий в зависимости от количества заданий, поступающих к нему, в результате чего общая стоимость одного запуска составляет от 6 до 14 рупий. Предфильтр сохраняет только те записи, которые наиболее соответствуют кандидату, так что алгоритм ранжирования работает с набором данных с высокой значимостью, а не с шумным первоначальным выводом пяти API-заданий.
5. HyDE вместо прямого сравнения
Очевидный подход заключается в встраивании краткого описания кандидата, подготовленного с использованием технологии ATS, и сравнении его со всеми описаниями вакансий с помощью коэффициента косинусного сходства. Этот метод прост, быстр и не требует дополнительных вызовов больших языковых моделей. Однако в ходе тестирования результаты оказались разочаровывающими.
Причиной является несоответствие в пространстве эмбеддингов. Краткое описание кандидата представляет собой повествование от первого лица, например: «Разрабатывал ML-пайплайны, отвечал за развертывание моделей, сотрудничал с разными командами». Описание вакансии же представляет собой список требований от третьего лица, например: «Требуется опыт работы в области ML не менее 3 лет, знание PyTorch и хорошие коммуникативные навыки». Даже когда оба описания касаются одних и тех же навыков, из-за различий в стиле они попадают в разные области пространства эмбеддингов, из-за чего прямое сравнение приводит к заниженной оценке реального соответствия.
HyDE обходит эту проблему, ставя другой вопрос: каким должно быть идеальное описание вакансии для данного кандидата? Большая языковая модель составляет два гипотетических описания на основе резюме кандидата.
- JD1 основан на специфике конкретной отрасли и описывает вакансию так, будто компания из той же сферы деятельности кандидата ищет человека с соответствующим опытом.
- JD2 акцентирует внимание на переносимых навыках, представляя вакансию так, будто профессиональные знания являются второстепенными, а общие способности — главным критерием.
Эти синтетические описания размещаются в том же разделе, что и реальные, поскольку это также описания вакансий, только гипотетические. Сравнение их с реальными объявлениями позволяет провести семантическое сопоставление. Каждое реальное объявление затем относится к тому синтетическому описанию, к которому оно ближе. Если оно ближе к JD1, его помещают в раздел 1 — роли в сфере деятельности кандидата. Если ближе к JD2 — в раздел 2 — более широкие возможности.
Одно ограничение соблюдалось на протяжении всего процесса: использовались только универсальные эмбеддинги, без моделей, специализированных под конкретную область. Специфика области определяется содержимым HyDE, которое большая языковая модель включает в синтетические описания, а не выбором модели эмбеддингов. Это позволяет системе использоваться в разных профессиональных сферах.
6. Разные модели для разных агентов
Не каждая задача требует одинаковой способности к рассуждению. Затраты на парсер и генератор HyDE составляют примерно 2,7–3,0 рупий и 0,50 рупии за один запуск; эти значения не меняются независимо от объема работы. Качество этих инструментов влияет на всё, что следует за ними: слабый парсер портит профиль, а слабое гипотетическое описание нарушает совпадение эмбеддингов, поэтому Sonnet является правильным выбором.
Оценка производится для каждой задачи в системе ранжирования, поэтому именно на этом этапе затраты растут с объемом работы, и он уже поглощает от 70 до 80 процентов бюджета. Без лучше структурированных механизмов оценки система Sonnet увеличит эти расходы примерно в три раза. Система Haiku справляется с этой задачей. Вот способ маршрутизации:
7. Один файл конфигурации на каждый параметр настройки
В агентных системах со временем возникает проблема настройки. Замена модели, ужесточение порогов или изменение лимита одновременных операций не должны требовать поиска нужной константы среди пяти файлов агентов.
Эта система использует один файл формата YAML, в котором заданы все параметры обработки данных; таким образом никакие константы не закодированы прямо в коде агентов, и никакие «волшебные числа» не скрыты в командах. Он регулирует:
- Модель для каждого агента. Замена модели Claude Haiku на более новую осуществляется одной строкой кода.
semaphore_size: 4, batch_size: 4 и batch_delay_secs: 2; подробности рассмотрены ниже.8. Одновременная оценка качества, определяемая лимитами скорости
Изначально процесс оценки качества был последовательным: один вызов большой языковой модели, ожидание, следующая задача. При 40 задачах и времени обработки каждой примерно 2,5 секунды общее время составляло 100 секунд. Данные пайплайна подтверждают это: только процесс оценки занимал около 95 секунд из общего времени выполнения в 166 секунд.
Отправка всех 40 запросов сразу кажется решением, но это приводит к нарушению лимитов скорости обработки у Anthropic. Уровень доступа Tier 1 ограничивает количество запросов в минуту, поэтому 40–60 одновременных запросов сразу превышают эти лимиты и возвращают ошибки 429. В первых версиях продакшена без ограничений на скорость возвращалась лишь часть результатов: оценки для заданий с 1 по 70 были получены до того, как API перестал отвечать.
Решением является концепция параллельной обработки в трех этапах, полностью контролируемая через файл конфигурации:
- Семафор (
semaphore_size: 4) ограничивает количество активных запросов в любой момент времени. Четыре запроса за раз полностью соответствуют лимитам уровня Tier 1. - Группировка запросов (
batch_size: 4) позволяет обрабатывать задания по группам по четыре, причем каждая группа завершается до начала следующей. - Задержка между группами (
batch_delay_secs: 2) вводит двухсекундную паузу между ними, что обеспечивает запас прочности перед лицом внезапного увеличения нагрузки.
Результат: обработка 60 задач в 15 пакетах занимает примерно от 90 до 95 секунд, что в четыре раза быстрее, чем при последовательной обработке при том же количестве задач, причем без превышения лимитов.
Наблюдаемость
Система, которую никто не может наблюдать, — это лишь надежда, а не настоящая система. Настоящий инцидент это демонстрирует. Во время первой полноценной производственной сессии на инстансе EC2 отсутствовал параметр VOYAGE_API_KEY. Предфильтр HyDE незаметно пропустил этап встраивания и переслал все 89 задач ранкеру, из-за чего на 70-й задаче был превышен лимит скорости обработки, и был возвращен только частичный список. При отсутствии наблюдаемости это выглядело бы как случайное, непонятное поведение. С её наличием выявление причины заняло менее минуты.
Наблюдаемость здесь функционирует на двух уровнях:
- LangSmith отслеживает каждый вызов ЯИ: точный промпт, ответ, время задержки и количество токенов за каждый вызов. Он обеспечивает микроуровень прозрачности процесса принятия решений и используется во время разработки для выявления сбоев в промптах до того, как они повлияют на весь процесс обработки.
- MLflow фиксирует каждую работу с информацией о времени задержки для каждого агента, общей стоимости и количестве токенов. Его файл
job_audit.jsonявляется самым полезным инструментом диагностики — это полная запись каждой задачи, прошедшей через процесс: в каком разделе HyDE она оказалась, её показатель сходства, какой фильтр её отфильтровал и почему, компоненты её показателя соответствия и её окончательный ранг.
Как выглядит зрелость
Степень зрелости ИИ-системы не измеряется её автономией. Она определяется тем, насколько хорошо люди понимают, что она делает, почему это делает и где возникают ошибки. Разговоры об агентных ИИ-системах оптимизированы под неверные показатели. Автономность создаёт впечатляющие демо-версии, но часто является плохим инженерным критерием, поскольку наблюдение за автономным поведением и его отладка требуют значительных усилий.
Для тех, кто сегодня создаёт ИИ-системы, важными вопросами являются не степень её агентности или количество в ней агентов. Это следующие вопросы:
- Можно ли наблюдать за тем, что она делает на каждом этапе?
- Можно ли объяснить конкретный результат без просмотра исходного кода?
- Можно ли перенастроить систему, когда её поведение отклоняется?
- Можно ли отличить хорошую работу системы от скрытых сбоев?
Система, проходящая все четыре критерия, — это рабочая система машинного обучения. Всё остальное — это прототип с хорошим маркетингом.