Головна / Статті

Розробка багатоагентного пошуку роботи: конвеєр, HyDE та можливості спостереження.

Дев’ятиетапний підхід LangGraph для підбору резюме до вакансій, що включає вісім варіантів налаштувань щодо пошуку в HyDE, маршрутизації моделей, обмежень швидкості та можливостей моніторингу.

Видавець: REACTAPP.TOP12 хв читання2781 слів

Джерела: Agentic AI in Practice: A Case Study in Multi-Agent System Design

Агенти, агентні ШІ, багатоагентні системи: цей термінологічний запас є всюди, і щотижня з’являється нова модель, фреймворк чи шаблон оркестрації. Промптування, RAG, виклик інструментів, MCP, шари пам’яті. Екосистема розвивається швидше, ніж більшість фахівців можуть за нею встигати. Попри весь цей шум, основні запитання залишаються незмінними:

  • Де слід розділити проблему на окремі етапи міркувань?
  • Які виклики належать до LLM, а які ніколи не слід залишати на його розсуд?
  • Як можна переконатися, що система робить те, що вважається?

Випуск нової версії фреймворку не робить це простішим. Щоб зробити все конкретнішим, у цьому кейс-стаді використовується проблема, з якою стикаються мільйони людей: пошук відповідних робочих місць серед величезної кількості оголошень. Для її вирішення розроблено повністю автоматизовану систему на основі ШІ, яка допомагає відповісти на три практичні запитання. Що означає термін «агент» у архітектурному контексті? Коли кілька агентів додають цінність, а коли вони є тягарем? І що робить систему ШІ прозорою, надійною та придатною для використання в реальних умовах?

Пошук роботи — це не справжній пошук

Більшість людей сприймають пошук роботи як завдання пошуку. Насправді це більше схоже на завдання підбору. Ніхто насправді не шукає оголошення, які містять певні ключові слова. Основне запитання складніше: враховуючи цей досвід, ці навички та напрямок кар’єри, які вакансії є справді підходящими?

Портали з вакансіями працюють за принципом пошуку. Ви вводите кілька слів, вказуєте місце розташування та сподіваєтесь знайти щось корисне. Однак резюме відображає роки досвіду, знання в певній галузі, технічну глибину, навички, які можна перенести на іншу роботу, кар’єрний ріст та контекст, а поле пошуку змушене уміщати все це в кілька слів, припускаючи, що збіг слів означає збіг намірів.

Усі знають, як це відбувається:

  • Перегляд сотень оголошень на кількох платформах
  • Оцінка релевантності кожного окремого оголошення
  • Зустріч з дублікатами, закінченими оголошеннями та пошкодженими посиланнями
  • Запитання, чи були обрані саме ті посади, які потрібні

Нудність — це не головна проблема. Справжня прогалина полягає між тим, що свідчить досвід кандидата, та тим, що насправді потрібно роботодавцю, а її подолання вимагає інтерпретації, контексту та судження. Коротко кажучи, це потребує логічного мислення, у чому сильні моделі великих мов. Уявімо, що система може прочитати резюме, визначити логічні кар’єрні шляхи, знайти вакансії та ранжувати їх за справжньою придатністю, а не за збігом ключових слів. Саме для вирішення цієї проблеми була створена ця система.

Процес, крок за кроком

Він починається з однієї дії: завантаження резюме. Після цього ніхто не торкається поля пошуку, не прокручує списки та не вирішує, на які посади варто подавати заявку. Система бере все під контроль та виконує дев’ять кроків, кожен з яких має чітке завдання.

  1. Агент-аналізатор резюме. Діючи як досвідчений кадровик, він перетворює резюме на структурований профіль замість списку ключових слів. Цей профіль включає посади, які обіймав кандидат, навички, сфери експертизи, хід кар’єри та короткий опис у стилі ATS, який усі наступні агенти використовують як канонічний опис кандидата. Модель: Claude Sonnet.
  2. Агент-рекомендатор профілів. Він пропонує два-три потенційні посадові титули, які відповідають рівню, галузі та навичкам кандидата, разом із варіантами запитів для пошуку для кожного з них. Модель: Claude Haiku.
  3. Етап людського підтвердження. Це єдине місце, де людина приймає рішення. Користувач переглядає запропоновані профілі, обирає той, який здається найкращим, за бажанням додає уподобання щодо місця розташування та рівня досвіду, та підтверджує вибір. Усі наступні етапи чекають на це рішення. У процесі не беруть участі жодні моделі — лише людський осуд.
  • Пошук роботи. З підтвердженим профілем одночасно відбуваються запити до п’яти активних джерел роботи, що повертає приблизно від 100 до 150 первинних оголошень. Жодне окреме джерело не містить усього, тому паралельна обробка зменшує затримки та розширює спектр пошуку. Використовуються лише API-запити, без ШІ.
  • Валідатор URL. Проста перевірка через HTTP перевіряє URL кожного оголошення. Неактивні посилання, сторінки 404 та перенаправлення агрегаторів зустрічаються частіше, ніж можна було б очікувати, тож усе, що не підтверджується коректно, відкидається. Без ШІ.
  • Усунення дублікатів. Різні джерела часто повертають однакові вакансії, тому дублікати (одна й та сама компанія, посада та місце розташування) видаляються ще до початку дорогих операцій. Чистий вхід, чистий вихід. Без ШІ, лише логіка в пам’яті.
  • Семантичний попередній фільтр. Цей етап варто розуміти детально. Він використовує гіпотетичні вбудовування документів (HyDE). Замість прямого порівняння резюме з вакансіями система спочатку генерує гіпотетичні описи посад на основі резюме, а потім знаходить справжні вакансії, які за значенням найбільше наближені до цих синтетичних. Вакансії, які не досягають мінімального порогу схожості, видаляються ще до проведення дорогого оцінювання за допомогою LLM. Причини, чому цей підхід ефективний, а пряме порівняння — ні, описані у пункті 5 нижче. Моделі: Claude Sonnet для генерації описів, Voyage AI voyage-3 для створення вбудовувань.
  • Агент Ranker. Штучний інтелект порівнює кожен опис посади з повним проаналізованим профілем кандидата та оцінює чотири аспекти: відповідність досвіду, перетин навичок, узгодженість з галуззю та вимоги до освіти. Ці показники об’єднуються в єдиний бал відповідності, причому до кожного балу додається пояснення та аналіз розбіжностей між профілем та вимогами, тож результат — це пояснення, а не просто порядок ранжування. Модель: Claude Haiku.
  • Остаточне формування результатів та журналування даних. Результати ранжування повертаються у інтерфейс користувача, а кожен показник виконання, включаючи кількість токенів, затримку та витрати, записується у панель керування MLflow для подальшого аналізу. Штучний інтелект не використовується.
  • Це означає дев’ять кроків, чотири виклики штучного інтелекту, одне людське рішення та загальний час виконання менше трьох хвилин.

    Карта технологій

    На наведеній вище діаграмі кожен основний компонент сучасної стеку ШІ розміщений у межах цього конвеєра обробки даних. Кожна система є сукупністю виборів, тому у наступних розділах розглядається, що було взято до уваги, що було відхилено та яка це коштувала.

    Вісім рішень щодо дизайну

    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 та порівняти його з кожним описом вакансії за допомогою косинусової схожості. Це просто, швидко та не вимагає додаткових запитів до ШІ. Однак у тестуванні результати виявилися розчаровуючими.

    Причиною є неузгодженість у просторі ембеддингів. Резюме кандидата має вигляд оповіді від першої особи, щось на кшталт „реалізував алгоритми машинного навчання, керував розгортанням моделей, співпрацював з різними командами“. Опис вакансії — це перелік вимог у третій особі, наприклад „необхідно 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 на новішу модель — це зміна всього в одному рядку.
  • Ліміти токенів та параметр температури налаштовуються окремо для кожного агента. Для структурованого вилучення даних у парсері використовується значення 0.1, щоб результати залишалися послідовними, тоді як система рекомендацій використовує 0.4, щоб трохи змінювати пропоновані заголовки.
  • Ліміти конкурентності та швидкості: 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 вона потрапила, її показник схожості, який фільтр її відхилив та чому, складові показника придатності та її кінцеве місце в рейтингу.

    Як виглядає зрілість

    Рівень зрілості системи ШІ не вимірюється її автономністю. Його вимірюють тим, наскільки добре люди розуміють, що вона робить, чому це робить та де виникають проблеми. Розмови про агентні системи ШІ оптимізовані під неправильну метрику. Автономність створює вражаючу демонстрацію, але часто є поганою інженерною характеристикою, оскільки спостереження за автономною поведінкою та її виправлення є складними та дорогими.

    Для кожного, хто сьогодні створює систему ШІ, корисними є не питання про те, наскільки вона агентна чи скільки у неї агентів. Це такі питання:

    • Чи можете ви спостерігати за тим, що вона робить на кожному кроці?
    • Чи можете ви пояснити певний результат без перегляду вихідного коду?
    • Чи можете ви переналаштувати її, коли її поведінка відхиляється?
    • Чи можете ви розрізнити хорошу продуктивність від прихованої несправності?

    Система, яка пройшла всі чотири критерії, — це функціональна система машинного навчання. Усе інше — це прототип із гарною маркетинговою стратегією.