Strona główna / Artykuły

Projektowanie wieloagentowego narzędzia do znajdowania pracy: pipeline, HyDE oraz możliwości obserwowalności.

Dziewięciostopniowy pipeline LangGraph służący do dopasowywania CV do ofert pracy, z ośmioma opcjami projektowymi dotyczącymi wyszukiwania w HyDE, kierowania modelami, ograniczeń szybkości oraz możliwości obserwacji.

Wydawca: REACTAPP.TOP12 min czytania2781 słów

Źródła: Agentic AI in Practice: A Case Study in Multi-Agent System Design

Agenci, sztuczna inteligencja agencyjna, systemy wieloagentowe: ten termin pojawia się wszędzie, a co tydzień pojawia się kolejny model, framework lub wzorzec orkiestracji. Prompting, RAG, wywoływanie narzędzi, MCP, warstwy pamięci. Ekosystem rozwija się szybciej, niż większość praktyków jest w stanie za nim nadążyć. Pod hałasem trudne pytania pozostają niezmienne:

  • Gdzie należy podzielić problem na elementy rozumowania?
  • Które wywołania należą do LLM, a które nigdy nie powinny być mu powierzone?
  • Jak można potwierdzić, że system robi to, co według nas robi?

Nowa wersja frameworka nie ułatwia tego. Aby postawić sprawę konkretnie, to studium przypadku dotyczy problemu, z którym borykają się miliony ludzi: znajdowania odpowiednich prac w ogromnej ilości ofert. Projektuje się dla tego celu system AI od początku do końca i wykorzystuje ten projekt do odpowiedzi na trzy praktyczne pytania. Co oznacza pojęcie „agent” w kontekście architektury? Kiedy kilka agentów dodaje wartość, a kiedy stanowią jedynie obciążenie? I co sprawia, że system AI jest widoczny, niezawodny i nadaje się do użycia w produkcji?

Pościg za pracą to nie tyle wyszukiwanie

Większość ludzi traktuje poszukiwanie pracy jako zadanie wyszukiwawcze. W rzeczywistości jest to bardziej zadanie dopasowywania. Nikt tak naprawdę nie szuka ofert zawierających określone słowa kluczowe. Podstawowe pytanie jest trudniejsze: biorąc pod uwagę tę wiedzę, umiejętności i kierunek kariery, które oferty są naprawdę odpowiednie?

Portale z ofertami pracy traktują to jak wyszukiwanie. Wpisuje się kilka słów kluczowych, dodaje lokalizację i ma się nadzieję, że pojawią się jakieś istotne wyniki. Rezerum natomiast zawiera informacje o latach doświadczenia, wiedzy specjalistycznej, zaawansowanej znajomości technologii, umiejętnościach przenośnych, rozwoju kariery oraz kontekście, a pole wyszukiwania próbuje zmieścić to wszystko w kilku słowach, zakładając przy tym, że zgodne słowa oznaczają tę samą intencję.

Każdy wie, jak to wygląda:

  • Przewijanie setek ofert na różnych platformach
  • Ocena istotności każdej oferty osobno
  • Natrafianie na duplikaty, wygasłe ogłoszenia i uszkodzone linki
  • Zastanawianie się, czy wybrane role w ogóle były odpowiednie

Nuda nie jest głównym problemem. Prawdziwa luka leży pomiędzy tym, co wskazuje historia kandydata, a tym, czego faktycznie wymaga ogłoszenie, a jej zamknięcie wymaga interpretacji, kontekstu i osądu. Krótko mówiąc, potrzeba do tego rozumowania, w którym modele językowe o dużych możliwościach radzą sobie doskonale. Załóżmy, że system mógłby przeczytać CV, wywnioskować sensowne ścieżki kariery, znaleźć dostępne stanowiska i posortować je według rzeczywistego dopasowania, a nie tylko na podstawie wspólnych słów kluczowych. To właśnie jest problem, dla którego został stworzony ten system.

Proces krok po kroku

Zaczyna się od jednej czynności: przesłania CV. Po tym nikt już nie korzysta z pola wyszukiwania, przewija listy ani nie decyduje, do których stanowisk warto aplikować. System przejmuje kontrolę i wykonuje dziewięć kroków, z których każdy ma określone zadanie.

  1. Agent do analizy CV. Działając jak doświadczony rekruter, przekształca CV w ustrukturyzowany profil zamiast listy słów kluczowych. Profil obejmuje zajmowane stanowiska, umiejętności, obszary specjalizacji, przebieg kariery oraz krótki opis w stylu ATS, który wszystkie późniejsze agenty traktują jako kanoniczny opis kandydata. Model: Claude Sonnet.
  2. Agent do rekomendacji profili. Proponuje dwa lub trzy odpowiednie stanowiska, które pasują do poziomu kandydata, dziedziny i umiejętności, wraz z wariantami zapytań wyszukiwawczych dla każdego z nich. Model: Claude Haiku.
  3. Brama potwierdzenia przez człowieka. To jedyny moment, w którym decyzję podejmuje osoba. Użytkownik przegląda proponowane profile, wybiera ten, który wydaje mu się odpowiedni, opcjonalnie dodaje preferencje dotyczące lokalizacji i doświadczenia, a następnie potwierdza. Cały proces czeka na to potwierdzenie. Nie bierze w tym udziału żaden model – decyzja zapada wyłącznie na podstawie ludzkiego osądu.
  • Szukanie pracy. Dzięki potwierdzonemu profilowi zapytania są wysyłane równolegle do pięciu aktualnych źródeł ofert pracy, co daje około 100 do 150 surowych wyników. Żadne jedno źródło nie zawiera wszystkiego, a działanie ich równolegle zmniejsza opóźnienia przy jednoczesnym poszerzeniu zakresu wyszukiwań. Brak LLM – tylko wywołania API.
  • Walidator URL. Prosta weryfikacja HTTP sprawdza adres URL każdej oferty. Uszkodzone linki, strony 404 oraz przekierowania agregatorów występują częściej, niż się spodziewa się, więc wszystko, co nie zostaje poprawnie rozwiązane, jest odrzucane. Brak LLM.
  • Usuwanie duplikatów. Różne źródła często pokazują te same oferty, dlatego duplikaty (ta sama firma, tytuł i lokalizacja) są usuwane przed rozpoczęciem jakichkolwiek kosztownych kroków. Czysty wprowadzany danych, czysty wynik. Brak LLM – tylko logika działająca w pamięci.
  • Prefiltr semantyczny. Ten etap warto zrozumieć szczegółowo. Wykorzystuje on Hypothetical Document Embeddings (HyDE). Zamiast bezpośrednio porównywać CV z ofertami pracy, system najpierw generuje hipotetyczne opisy stanowisk na podstawie CV, a następnie znajduje rzeczywiste oferty najbliższe pod względem znaczenia tym syntetycznym. Oferty poniżej ustalonego progu podobieństwa są odrzucane przed przeprowadzeniem kosztownego oceniania za pomocą modeli LLM. Uzasadnienie, dlaczego to rozwiązanie działa, a bezpośrednie porównanie nie, znajduje się w punkcie 5 dotyczącym wyboru projektowego poniżej. Modele: Claude Sonnet do generowania opisów, Voyage AI voyage-3 do tworzenia embeddingów.
  • Ranker Agent. LLM porównuje każdy opis stanowiska z pełnym, przetworzonym profilem kandydata i ocenia cztery aspekty: dopasowanie do doświadczenia, pokrycie umiejętności, zgodność z dziedziną oraz wymagania edukacyjne. Wszystko to łączy się w jeden wynik dopasowania, a każdy wynik jest opatrzony uzasadnieniem oraz analizą różnic pomiędzy profilem a wymaganiami, dzięki czemu otrzymujemy wyjaśnienie, a nie tylko uporządkowanie. Model: Claude Haiku.
  • Finalizacja i rejestracja danych do obserwacji. Urankowane wyniki są przekazywane z powrotem do interfejsu, a każda metryka procesu, w tym liczba tokenów, opóźnienie i koszt, jest zapisywana w panelu MLflow w celu późniejszej analizy. Brak użycia LLM.
  • To daje łącznie dziewięć kroków, cztery wywołania LLM, jedną decyzję człowieka oraz całkowity czas wykonywania poniżej trzech minut.

    Mapa technologii

    Na powyższym diagramie każdy główny komponent obecnego stacku AI umieszczony jest w ramach tego procesu. Każdy system stanowi zbiór wyborów, dlatego w kolejnych sekcjach omówiono to, co zostało rozważone, co odrzucono oraz jakie to miało konsekwencje finansowe.

    Osiem decyzji projektowych

    1. LangGraph zamiast CrewAI, AutoGen lub pętli ReAct

    Zwykłymi kandydatami były LangGraph, CrewAI i AutoGen, a w ramach LangGraph istnieje dalszy podział na graf skierowany oraz pętlę ReAct.

    CrewAI kładzie nacisk na autonomiczną współpracę, z agentami odgrywającymi role, które negocjują i delegują zadania między sobą. AutoGen koncentruje się na dialogu wieloagentowym w formie rozmowy. Obie opcje nadają się do zadań o otwartym zakończeniu. Jednocześnie obie powodują dodatkowe obciążenia związane z koordynacją oraz niedeterminizm, który ustalony proces nie może sobie pozwolić na debugowanie.

    Pętle ReAct sprawdzają się, gdy liczba kroków nie jest znana z góry, np. w przypadku modelu językowego przeglądającego internet i nie mogącego przewidzieć, ile wyszukiwań będzie potrzebował. Szukanie pracy nie wygląda w ten sposób – struktura problemu określa kolejne etapy: najpierw analiza, potem rekomendacje, następnie wyszukiwanie, a na końcu filtrowanie; duplikaty usuwa się przed wstawieniem danych. Nic nie jest odkrywane w trakcie wykonywania.

    Graf skierowany idealnie pasuje do tego scenariusza. Każda transycja jest jawna, interwencja człowieka stanowi podstawową funkcję, a stan to wspólny model Pydantic, który każdy węzeł może czytać i zapisywać. Gdy coś się psuje, węzeł, który zawodzi, jest od razu widoczny.

    2. Specjalistyczni agenci zamiast jednego mega-promptu

    Niełatwo oprzeć się pokusie stworzenia jednego dużego promptu, który analizuje CV, proponuje tytuły i oceny, ponieważ jego budowa jest szybsza. Jednak takie rozwiązanie zawodzi w skomplikowany sposób, a błędy się kumulują – błąd w jednym miejscu oznacza błąd we wszystkich. Trudno jest określić, która instrukcja spowodowała złą jakość wyniku, dostosowywanie jednej części niesie ryzyko regresji w innej, a kontekst wypełnia się instrukcjami niezwiązanymi z aktualnym zadaniem.

    Oddzielne agenty unikają tego problemu. Słabą ocenę rankera można sprawdzić, analizując sam prompt rankera. Każdy agent ma swój własny skrypt testowy, dzięki czemu parser można testować pod kątem regresji bez całego procesu. Ponadto różne agenty mogą być przekierowywane do różnych modeli, jak pokazuje wybór projektowy nr 6.

    3. Brama z udziałem człowieka

    Większość poradników dotyczących agentów traktuje ludzką weryfikację jako opcjonalną ulepszenie, coś, co dodaje użytkownikom poczucie zaangażowania. Tutaj brama jest kluczową decyzją architektoniczną.

    System rekomendacyjny proponuje dwa lub trzy tytuły, a profil, który potwierdzi użytkownik, kieruje każdym kolejnym etapem: wyszukiwaniami, filtrami oraz oceną. Pozwól systemowi wybierać automatycznie – błędna decyzja może zepsuć całość, tworząc uporządkowaną listę dla profilu, którego kandydat wcale nie chciał. Żadna inna decyzja w tym procesie nie niesie tak dużego ryzyka, a żadna nie jest lepiej radzona przez człowieka, ponieważ kandydaci znają rzeczy dotyczące swoich preferencji, których parser nie może wydobyć.

    4. Prefiltr przed systemem rankowania

    Dane z rzeczywistego świata nigdy nie są idealne, a wpisy z pięciu API przychodzą z przewidywalnymi problemami:

    • Zepsute linki i błędy 404, spowodowane postami, które wygasły i nigdy nie zostały usunięte
    • Duplikaty, ponieważ ta sama oferta pojawia się jednocześnie z kilku API
    • Przekierowania agregatorów, w których URL prowadzi na stronę główną portalu z ofertami pracy, a nie bezpośrednio na samą ofertę

    To nie są przypadki krawędziowe. To normalny stan danych z zewnętrznych API. Kroki walidacji i usuwania duplikatów służą do oczyszczenia zbioru danych przed wystąpieniem jakichkolwiek kosztownych operacji, dzięki czemu to, co trafia do prefiltrowania semantycznego, jest ważne, unikalne i rzeczywiste.

    Wtedy znaczenie ma koszt. W trakcie różnych rund produkcyjnych narzędzie rankujące stanowi od 70 do 80 procent całkowitych wydatków na LLM. Parser kosztuje stałe 2,7 do 3,0 ₹, niezależnie od liczby zadań przetwarzanych, a narzędzie rekomendujące około 0,30 ₹, również w stałej kwocie. Koszt narzędzia rankującego zmienia się od 3 do 11 ₹ w zależności od liczby zadań, co daje łączny koszt na jedną rundę w przedziale od 6 do 14 ₹. Prefiltr zachowuje tylko te wpisy, które najlepiej pasują do kandydata, dzięki czemu narzędzie rankujące pracuje z podzbiorem o wysokim poziomie sygnału, a nie z hałaśliwym, surowym wynikiem pięciu API zadań.

    5. HyDE zamiast bezpośredniego porównania

    Oczywistym podejściem jest włączenie podsumowania kandydata do systemu ATS i porównanie go z każdym opisem stanowiska za pomocą podobieństwa kosinowego. Jest to proste, szybkie i nie wymaga dodatkowych wywołań modeli językowych. W testach wyniki były rozczarowujące.

    Priyczyną jest niezgodność w przestrzeni embeddingów. Podsumowanie kandydata ma formę opowieści w pierwszej osobie, na przykład „wdrożyłem pipeline’y ML, byłem odpowiedzialny za wdrażanie modeli, współpracowałem z różnymi zespołami”. Opis stanowiska natomiast ma formę listy wymagań w trzeciej osobie, np. „wymagane 3+ lata doświadczenia w ML, umiejętności z PyTorch i dobra komunikacja”. Nawet gdy oba opisywają te same umiejętności, różne style sprawiają, że trafiają one do różnych obszarów, więc bezpośrednie porównanie niedoszacowuje rzeczywistych dopasowań.

    HyDE unika tego problemu, zadając inne pytanie: jak wyglądałby idealny opis stanowiska dla tego kandydata? Model językowy tworzy dwa hipotetyczne opisy na podstawie CV kandydata.

    • JD1 jest uzależniony od konkretnej dziedziny i sformułowany tak, jakby firma z dokładnie tym samym obszarem działalności szukała kandydata o takim doświadczeniu.
    • JD2 skupia się na umiejętnościach przenoszalnych, przedstawionych w taki sposób, jakby specjalistyczna wiedza była drugorzędna, a ogólne kompetencje stanowiły główny element opisu.

    Te syntetyczne opisy znajdują się w tej samej kategorii co te rzeczywiste, ponieważ są to opisy stanowisk, choć jedynie hipotetyczne. Porównywanie ich z rzeczywistymi ofertami umożliwia semantyczne dopasowanie „do tego, co do tego”. Każda rzeczywista oferta trafia wtedy do tego syntetycznego opisu, do którego jest najbliższa. Jeśli jest bliższa JD1, trafia do sekcji 1 – stanowisk w dziedzinie kandydata. Jeśli bliższa JD2, trafia do sekcji 2 – szerszych możliwości.

    Jedna zasada obowiązywała przez cały czas: tylko embeddingi uniwersalne, bez modeli specyficznych dla danej dziedziny. Specyfika dziedziny pochodzi od treści HyDE, którą model LLM włącza do syntetycznych opisów, a nie od wyboru modelu embeddingu. Dzięki temu system może być używany w różnych profesjach.

    6. Różne modele dla różnych agentów

    Nie każde zadanie wymaga takiej samej mocy rozumowania. Parser i generator HyDE kosztują około 2,7–3,0 oraz 0,50 rupii na jedno uruchomienie, przy czym ceny są stałe niezależnie od ilości zadań. Ich jakość wpływa na wszystko, co następuje po nich – słaby parser psuje profil, a słaby hipotetyczny opis zakłóca dopasowanie embeddingu, dlatego Sonnet jest właściwym wyborem.

    Ocena odbywa się dla każdej zadań w narzędziu rankowania, więc to właśnie ta etapa ma rosnące koszty wraz z ilością zadań i już teraz pochłania od 70 do 80 procent budżetu. Bez lepiej ustrukturyzowanych wyników oceny Sonnet powiększyłby ten rachunek mniej więcej trzykrotnie. Haiku radzi sobie z tym zadaniem. Oto sposób routingu:

    7. Jeden plik konfiguracyjny na każdy element do dostosowania

    Systemy agentowe z czasem napotykają problemy z dostosowaniem. Zmiana modelu, dostosowanie progu lub zmiana limitu równoczesności nie powinny oznaczać konieczności przeszukiwania pięciu plików agenta w poszukiwaniu odpowiedniej stałej.

    System ten przechowuje jeden plik YAML, który zawiera informacje o wszystkich parametrach w procesie, dzięki czemu żadne stałe nie są zakodowane bezpośrednio w kodzie agenta, a żadne „magiczne liczby” nie kryją się w instrukcjach. Określa on:

    • Model dla każdego agenta. Zastąpienie Claude Haiku nowszym modelem wymaga tylko jednej edycji w tekście.
  • Ograniczenia liczby tokenów i temperatura są dostosowywane indywidualnie dla każdego agenta. Strukturalna ekstrakcja w parserze wykorzystuje wartość 0,1, aby wyniki były spójne, natomiast system rekomendacji używa wartości 0,4, by nieco zmieniać swoje sugestie tytułów.
  • Ograniczenia konkurencji i szybkości: semaphore_size: 4, batch_size: 4 oraz batch_delay_secs: 2, co zostanie wyjaśnione dalej.
  • 8. Ranking równoległy kształtowany przez ograniczenia szybkości

    Pierwotny system rankowania był sekwencyjny: jedna wywołanie LLM, czekanie, następne zadanie. Przy 40 zadaniami i około 2,5 sekundy na każde wywołanie to łącznie 100 sekund czasu rzeczywistego. Dane z pipeline potwierdzają to – sam system rankowania zajmuje około 95 sekund z typowych 166 sekund całego procesu.

    Wyśłanie wszystkich 40 żądań jednocześnie wydaje się rozwiązaniem, ale wpada w ograniczenia szybkości obsługi Anthropic. Poziom dostępu Tier 1 ogranicza liczbę żądań na minutę, więc 40 do 60 jednoczesnych wywołań natychmiast przekracza te limity i powoduje błędy 429. Najwcześniejsza wersja w produkcji, bez żadnych ograniczeń, zwracała tylko część wyników: zadania od 1 do 70 zostały ocenione, zanim API przestało odpowiadać.

    Rozwiązaniem jest trójkrotny projekt konkurencyjności, kontrolowany w całości z pliku konfiguracyjnego:

    • Semafory (semaphore_size: 4) ograniczają liczbę trwających żądań w danym momencie. Cztery żądania naraz pozostają daleko w granicach limitów Tier 1.
    • Grupowanie (batch_size: 4) umożliwia ocenę zadań w grupach po cztery, przy czym każda grupa kończy pracę przed rozpoczęciem następnej.
    • Odroczenie między grupami (batch_delay_secs: 2) wprowadza dwusekundową przerwę między grupami, aby zapewnić margines bezpieczeństwa przed przekroczeniem limitów.

    Rezultat: 60 zadań w 15 partiach jest przetwarzanych w około 90 do 95 sekund, co stanowi około cztery razy większą szybkość niż w przypadku przetwarzania sekwencyjnego przy tej samej liczbie zadań, przy czym nie dochodzi do przekroczenia limitów.

    Obserwowalność

    System, którego nikt nie może obserwować, to jedynie nadzieja, a nie prawdziwy system. Prawdziwy incydent to tego przykład. Podczas pierwszego pełnego testu produkcyjnego na instancji EC2 brakowało klucza VOYAGE_API_KEY. Prefiltr HyDE cicho pominął proces wstawiania danych i przekazał wszystkie 89 zadań do mechanizmu rankowania, co spowodowało przekroczenie limitu szybkości przy 70. zadaniu i dostarczenie jedynie częściowej listy. Bez możliwości obserwacji zachowanie to wyglądałoby jak losowe, niezrozumiałe zdarzenie. Dzięki obserwowalności ustalenie przyczyny zajęło mniej niż minutę.

    Obserwowalność tutaj działa na dwóch poziomach:

    • LangSmith rejestruje każde wezwanie LLM: dokładny prompt, odpowiedź, czas opóźnienia na poziomie każdego wezwania oraz liczbę tokenów. Zapewnia mikropoziomową widoczność procesu rozumowania i jest wykorzystywany podczas rozwoju w celu wykrycia regresji w promptach, zanim wpłyną one na cały proces.
    • MLflow rejestruje każdy przebieg z informacjami o czasie opóźnienia na poziomie poszczególnych agentów, całkowitym koszcie oraz liczbie tokenów. Jego plik job_audit.json jest najbardziej przydatnym narzędziem diagnostycznym – zawiera pełny zapis każdej operacji przeprowadzonej w ramach procesu: sekcję HyDE, do której trafiła, jej wynik podobieństwa, filtr, który ją odrzucił i powód tego działania, składniki wyniku dopasowania oraz jej ostateczną pozycję.

    Jak wygląda dojrzałość

    Zrośniętość systemu AI nie mierzy się poziomem jego autonomii. Mierzy się natomiast tym, na jak dobrą sprawę ludzie rozumieją, co robi, dlaczego to robi oraz gdzie popełnia błędy. Rozmowy na temat AI o charakterze agencji są zoptymalizowane pod niewłaściwą miarę. Autonomia daje imponującą demonstrację, ale często stanowi słabą cechę inżynieryjną, ponieważ obserwowanie i naprawianie autonomicznego zachowania jest kosztowne.

    Dla każdego, kto dziś buduje system AI, istotne pytania to nie to, na jakim poziomie jest agencji czy ile ma agentów. Są to:

    • Czy można obserwować, co robi na każdym kroku?
    • Czy można wyjaśnić konkretny wynik bez otwierania kodu źródłowego?
    • Czy można go przekalibrować, gdy jego zachowanie ulega odchyleniu?
    • Czy można odróżnić dobre wyniki od ukrytych błędów?

    System, który spełnia wszystkie cztery warunki, to funkcjonalny system ML. Wszystko inne to prototyp z dobrym marketingiem.