Wróć do katalogu
Season 48 20 Odcinki 1h 19m 2026

LangChain v1.0 Orchestration Framework

Wersja 1.2 — Edycja 2026. Szczegółowy kurs audio na temat frameworka orkiestracji LangChain v1.0. Buduj niezawodne, wieloagentowe aplikacje AI ze standaryzowanym wywoływaniem narzędzi, ustrukturyzowanymi danymi wyjściowymi, walidacją human-in-the-loop i zaawansowaną inżynierią kontekstu.

Orkiestracja LLM Frameworki AI/ML Systemy wieloagentowe
LangChain v1.0 Orchestration Framework
Teraz odtwarzane
Click play to start
0:00
0:00
1
Era orkiestracji
Analizujemy, dlaczego LangChain ewoluował z prostego wrappera do pełnoprawnego frameworka orkiestracji. Poznasz historię rozwoju aplikacji LLM i dowiesz się, jak wydanie wersji v1.0 standaryzuje interakcje z modelami.
3m 59s
2
Zunifikowana abstrakcja agenta
Zagłębiamy się w kluczową funkcję create_agent, która unifikuje wcześniejsze abstrakcje LangChain. Dowiesz się, jak pętla ReAct działa pod spodem, zarządzając wnioskowaniem modelu i wykonywaniem narzędzi.
3m 45s
3
Standaryzacja bałaganu
Badamy, jak LangChain standaryzuje interakcje z modelami różnych dostawców. Dowiesz się, jak inicjalizować modele czatu i płynnie przełączać się między OpenAI, Anthropic i Google.
3m 27s
4
Uniwersalny język modeli LLM
Rozkładamy na czynniki pierwsze podstawową jednostkę kontekstu w LangChain: Messages. Dowiesz się, jak strukturyzować wiadomości typu System, Human, AI oraz Tool, aby budować solidne historie konwersacji.
3m 40s
5
Wyposażanie agentów w narzędzia
Odkrywamy, jak nadać modelom możliwość działania za pomocą dekoratora @tool. Dowiesz się, jak type hints i docstrings są automatycznie konwertowane na precyzyjne schematy JSON dla modelu.
4m 08s
6
Wstrzykiwanie kontekstu narzędzi
Zagłębiamy się w przekazywanie informacji w czasie działania (runtime) bezpośrednio do narzędzi, bez ujawniania ich modelowi LLM. Dowiesz się, jak używać parametru ToolRuntime do bezpiecznych konfiguracji z wstrzykiwaniem zależności.
3m 34s
7
Persystencja na poziomie wątku
Zajmujemy się pamięcią krótkotrwałą i sposobami utrzymania historii konwersacji. Dowiesz się, jak podłączyć checkpointers do swojego agenta, aby umożliwić pauzowanie, wznawianie i zapamiętywanie konwersacji.
3m 48s
8
Kompresja kontekstu za pomocą Middleware
Odkrywamy, jak zapobiec awariom modelu spowodowanym długimi konwersacjami. Dowiesz się, jak używać SummarizationMiddleware do automatycznej kompresji starych wiadomości i oszczędzania tokenów.
3m 51s
9
Gwarantowane formaty danych
Omawiamy, jak wymusić na modelach językowych zwracanie ścisłych, przewidywalnych struktur danych. Poznasz różnicę między ProviderStrategy a ToolStrategy przy generowaniu modeli Pydantic.
3m 56s
10
Przechwytywanie pętli agenta
Wprowadzamy paradygmat middleware, dający chirurgiczną kontrolę nad wykonywaniem agenta. Dowiesz się, jak używać hooków typu wrap-style i node-style do przechwytywania wywołań modelu.
3m 21s
11
Dynamiczna inżynieria kontekstu
Zagłębiamy się w inżynierię kontekstu poprzez dynamiczne generowanie promptów systemowych. Dowiesz się, jak używać middleware do modyfikowania instrukcji na podstawie roli i środowiska obecnego użytkownika.
4m 14s
12
Bezpieczne AI z deterministycznymi zabezpieczeniami
Zabezpieczamy naszych agentów przed wyciekami danych za pomocą wbudowanego middleware. Dowiesz się, jak zastosować PIIMiddleware, aby automatycznie redagować poufne informacje, zanim dotrą do modelu.
3m 26s
13
Wstrzymywanie w celu zatwierdzenia przez człowieka
Badamy wykonywanie narzędzi wysokiego ryzyka, dodając człowieka do pętli decyzyjnej. Dowiesz się, jak zatrzymać działanie agenta, aby zatwierdzić, edytować lub odrzucić wrażliwe akcje.
4m 15s
14
Informacje zwrotne od agenta w czasie rzeczywistym
Zagłębiamy się w strumieniowanie, aby drastycznie poprawić doświadczenie użytkownika. Dowiesz się, jak interpretować stream modes, aby wyświetlać tokeny LLM na żywo wraz z niestandardowymi aktualizacjami wykonywania narzędzi.
3m 43s
15
Persystencja między sesjami
Odkrywamy pamięć długotrwałą, aby budować agentów, którzy naprawdę znają swoich użytkowników. Dowiesz się, jak używać magazynów LangGraph do zapisywania dokumentów JSON w zupełnie różnych konwersacjach.
3m 37s
16
Paradygmat wieloagentowy
Wyjaśniamy, dlaczego pojedynczy agenci zawodzą, i wprowadzamy architekturę Subagents. Dowiesz się, jak główny agent nadzorujący koordynuje subagentów jako izolowane okna kontekstowe, aby zapobiec nadmiarowi tokenów.
4m 12s
17
Agenci sterowani stanem
Badamy, jak agenci mogą dynamicznie zmieniać swoje zachowanie. Poznasz wzorzec Handoffs do przekazywania kontroli oraz wzorzec Skills do ładowania wyspecjalizowanych promptów na żądanie.
3m 53s
18
Niestandardowe przepływy pracy i rutery
Wychodzimy poza standardową pętlę agenta. Dowiesz się, jak używać LangGraph do budowania niestandardowych architektur routingu, łącząc deterministyczną logikę z niedeterministycznym wnioskowaniem agentowym.
4m 32s
19
Komunikacja Agent-to-Agent
Odkrywamy endpoint LangSmith A2A. Dowiesz się, jak rozproszeni agenci wdrożeni na zupełnie różnych serwerach mogą natywnie konwersować przy użyciu protokołu A2A RPC od Google.
5m 19s
20
Przyszłość to MCP
Patrzymy w przyszłość z Model Context Protocol, który standaryzuje sposób dostępu agentów do zewnętrznych narzędzi. Dowiesz się, jak łączyć zdalne serwery MCP ze swoim agentem przy użyciu standardowych transports.
5m 11s

Odcinki

1

Era orkiestracji

3m 59s

Analizujemy, dlaczego LangChain ewoluował z prostego wrappera do pełnoprawnego frameworka orkiestracji. Poznasz historię rozwoju aplikacji LLM i dowiesz się, jak wydanie wersji v1.0 standaryzuje interakcje z modelami.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 1 z 20. Zbudowanie prototypu agenta AI jest niezwykle proste, ale stworzenie takiego, który będzie wystarczająco niezawodny, aby wdrożyć go na produkcję, jest niezwykle trudne. Przepaść między fajnym weekendowym demo a aplikacją klasy enterprise jest ogromna. Sposobem na zasypanie tej przepaści jest to, co nazywamy Erą Orkiestracji. Po pierwsze, wyjaśnijmy bardzo powszechne nieporozumienie. Ludzie często mylą LangChain z dostawcą modeli. LangChain nie trenuje, nie hostuje ani nie serwuje dużych modeli językowych. To warstwa orkiestracji, która znajduje się bezpośrednio nad tymi modelami. Pomyśl o tym jak o centrum sterowania, które zarządza tym, jak twoja aplikacja komunikuje się z dowolnym modelem, którego zdecydujesz się użyć. Aby zrozumieć, dlaczego warstwa orkiestracji jest niezbędna, musimy przyjrzeć się temu, jak ewoluowała ta technologia. Jeszcze w 2022 roku interakcja z modelem językowym była prosta. Wysyłałeś stringa i w odpowiedzi otrzymywałeś stringa. Proste chainy promptów w zupełności wystarczały, aby załatwić sprawę. Nie potrzebowałeś ciężkiego frameworka do zarządzania prostym workflow typu text-in, text-out. Mogłeś łatwo napisać skrypt, w którym output z promptu A był po prostu wklejany do promptu B. Ale teraz, gdy przechodzimy przez rok 2025 i patrzymy w stronę 2026, ten krajobraz wygląda zupełnie inaczej. Modele nie przetwarzają już tylko zwykłego tekstu. Przyjmują i generują złożone bloki multimodalne. Pojedyncza interakcja może obejmować routing promptu użytkownika, wyzwolenie zewnętrznego tool calla, przetworzenie obrazu i zwrócenie ustrukturyzowanego bloku danych. Model może zwrócić request o odpytanie bazy danych tuż obok tekstowego podsumowania. Jeśli kod twojej aplikacji musi ręcznie sprawdzać każdą pojedynczą odpowiedź, aby ustalić, czy jest to string, tool call, czy plik obrazu, twój codebase szybko stanie się kruchym, niemożliwym do utrzymania bałaganem. Oto kluczowy wniosek. Przekazanie dokładnie właściwego kontekstu do modelu w idealnym momencie jest znacznie trudniejsze niż po prostu wybór najpotężniejszego modelu na rynku. Możesz podmienić go na najinteligentniejszy dostępny silnik wnioskowania, ale jeśli otrzyma on chaotyczne, nieustandaryzowane dane, cała interakcja zakończy się błędem. Właśnie dlatego, przy okazji wydania wersji 1.0, LangChain ewoluował z prostej biblioteki do chainów w ustandaryzowaną warstwę orkiestracji. Zapewnia standardowy format wiadomości, który działa spójnie u wszystkich głównych dostawców modeli. Zamiast pisać customową logikę parsowania dla każdego osobnego API, używasz jednolitej struktury. Standaryzując format wiadomości, LangChain gwarantuje, że tool call od jednego dostawcy wygląda w twoim kodzie dokładnie tak samo, jak tool call od konkurencyjnego dostawcy. Definiujesz sekwencję, w której wiadomość użytkownika wchodzi na wejście, warstwa orkiestracji ją normalizuje, wysyła do modelu, przechwytuje multimodalną odpowiedź i tłumaczy tę odpowiedź z powrotem na standardowy format, którego twoja aplikacja może faktycznie użyć. Logikę aplikacji piszesz raz, a warstwa orkiestracji zajmuje się tłumaczeniem. Sam model nie jest już całą aplikacją, jest jedynie silnikiem wnioskowania, a to warstwa orkiestracji decyduje, czy ten silnik faktycznie rozwiązuje twój problem biznesowy. Jeśli chcesz pomóc nam w dalszym tworzeniu tych odcinków, możesz wesprzeć nasz podcast, wyszukując DevStoriesEU na Patreonie. To wszystko w tym odcinku. Dzięki za wysłuchanie i koduj dalej!
2

Zunifikowana abstrakcja agenta

3m 45s

Zagłębiamy się w kluczową funkcję create_agent, która unifikuje wcześniejsze abstrakcje LangChain. Dowiesz się, jak pętla ReAct działa pod spodem, zarządzając wnioskowaniem modelu i wykonywaniem narzędzi.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 2 z 20. A co, gdybyś mógł zamienić cały swój złożony reasoning loop na jeden, dziesięciolinijkowy function call? Spędzasz godziny pisząc własne parsery i pętle while, tylko po to, żeby model językowy niezawodnie wywołał funkcję. Unified Agent Abstraction to architektura, która zdejmuje to z twoich barków. Żeby zrozumieć, dlaczego to takie ważne, musimy wyjaśnić pewne zamieszanie wokół starszych wersji frameworka. W wersjach zero kropka x, developerzy musieli przedzierać się przez labirynt specyficznych klas agentów. Miałeś conversational agents, zero-shot agents i skomplikowane, customowe chainy. Jeśli aktualizujesz swój kod, możesz o tym wszystkim zapomnieć. Unified Agent Abstraction całkowicie zastępuje wszystkie stare chainy i legacy agents. Zapewnia jeden przejrzysty, ustandaryzowany entry point poprzez funkcję o nazwie create agent. Ta funkcja służy do zarządzania pętlą ReAct. ReAct to skrót od Reason and Act. Kiedy użytkownik zadaje złożone pytanie, model językowy nie może po prostu wykonać kodu. Musi przeanalizować problem, zdecydować się na akcję, wygenerować tekst z żądaniem tej akcji, a następnie poczekać na observation, zanim będzie mógł ponownie podjąć reasoning. Ręczna obsługa tego cyklu jest żmudna. Musisz sparsować tekst wygenerowany przez model, zmapować go na lokalną funkcję, wykonać tę funkcję, sformatować output, przekazać go z powrotem do modelu i ocenić, czy zadanie jest zakończone. Funkcja create agent ukrywa ten cały orchestration process za abstrakcją. Przejdźmy przez prostą implementację z użyciem toola do sprawdzania pogody. Najpierw definiujesz swojego konkretnego toola, na przykład funkcję o nazwie get weather, która przyjmuje nazwę miasta. Następnie inicjalizujesz wybrany model językowy. Wtedy wkracza abstrakcja. Wywołujesz funkcję create agent i przekazujesz jej trzy argumenty. Przekazujesz swój model językowy, listę zawierającą twojego toola get weather oraz system prompt, który dyktuje reguły dla agenta. To pojedyncze wywołanie zwraca wykonywalny obiekt agenta. Na koniec wywołujesz ten obiekt z user query, pytając o aktualną pogodę w Londynie. Oto kluczowa rzecz, jeśli chodzi o execution flow. Kiedy wywołujesz agenta, uruchamiasz pętlę ReAct. Agent wysyła query i opisy tooli do modelu. Model decyduje, że potrzebuje danych w czasie rzeczywistym i zwraca ustandaryzowany tool call. Abstrakcja agenta automatycznie przechwytuje ten call. Wykonuje twojego toola get weather z argumentem London, pobiera wynikowe dane o temperaturze i przekazuje je z powrotem do modelu jako nowe observation. Model ewaluuje te dane, zdaje sobie sprawę, że ma odpowiedź na user query i generuje ostateczną odpowiedź. Nie napisałeś ani jednej pętli i nie napisałeś żadnego output parsera. Dostarczyłeś jedynie toole, model i instrukcje. Siła Unified Agent Abstraction tkwi w ustanowieniu ścisłej granicy architektonicznej. Całkowicie izoluje mechanikę reasoning cycle, pozwalając ci poświęcić cały wysiłek inżynieryjny na udoskonalanie jakości twoich tooli i przejrzystości promptów. To wszystko w tym odcinku. Dzięki za wysłuchanie i twórz dalej!
3

Standaryzacja bałaganu

3m 27s

Badamy, jak LangChain standaryzuje interakcje z modelami różnych dostawców. Dowiesz się, jak inicjalizować modele czatu i płynnie przełączać się między OpenAI, Anthropic i Google.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 3 z 20. Różni dostawcy modeli mają bardzo różne API, co oznacza, że wypróbowanie nowego modelu zazwyczaj zmusza cię do przepisania połowy aplikacji. W efekcie utykasz u jednego dostawcy tylko dlatego, że techniczny koszt zmiany jest zbyt wysoki. Standaryzacja tego bałaganu to dokładnie to, o czym jest ten odcinek. Zanim przejdziemy do mechaniki tego, jak LangChain to rozwiązuje, warto wyjaśnić pewne częste nieporozumienie. Jeśli pracowałeś z wczesnymi modelami językowymi, prawdopodobnie znasz starsze klasy LLM, które przyjmują pojedynczy, surowy string jako input. Nowoczesne modele chatowe są inne. Wymagają one ściśle ustrukturyzowanej sekwencji wiadomości, gdzie każda wiadomość ma przypisaną konkretną rolę, taką jak system, human lub AI. Wszystko, o czym teraz mówimy, dotyczy tych nowoczesnych modeli chatowych, a nie starszych modeli typu text completion. Kiedy budujesz aplikację, hardcodowanie konkretnego dostawcy tworzy natychmiastowy vendor lock-in. Aby przełamać tę zależność, LangChain wprowadza jedną funkcję typu factory o nazwie init chat model. Pomyśl o niej jak o uniwersalnym translatorze do inicjalizowania klientów AI. Zamiast importować osobną klasę dla OpenAI, kolejną dla Anthropic i jeszcze inną dla Google, polegasz wyłącznie na tej jednej funkcji. Oto kluczowa sprawa. Funkcja init chat model używa prostej składni typu string, aby wiedzieć, co zbudować. Podajesz string sformatowany jako nazwa dostawcy, po której następuje dwukropek, a następnie konkretna wersja modelu. Weźmy na przykład agenta działającego obecnie na modelu GPT-5 od OpenAI. Inicjalizujesz swój model, po prostu przekazując string openai dwukropek gpt-5. Załóżmy teraz, że Anthropic wypuszcza nowy model, który lepiej radzi sobie z generowaniem kodu, a ty chcesz go przetestować. Ponieważ użyłeś funkcji init chat model, nie ruszasz logiki swojego agenta. Nie importujesz nowej paczki klienta. Po prostu zmieniasz ten jeden string inicjalizujący na anthropic dwukropek claude-sonnet-4-6. LangChain dynamicznie rozwiązuje ten string i ładuje odpowiednią klasę integracji pod spodem. To załatwia sprawę samego modelu, ale dostawcy różnią się też w kwestii ustawień konfiguracji. Jedno API może oczekiwać parametru o nazwie max sampled tokens, podczas gdy inne oczekuje max length. Funkcja init chat model rozwiązuje ten problem, przyjmując standardowe parametry. Kiedy inicjalizujesz swój model, możesz przekazać argumenty takie jak temperature czy max tokens bezpośrednio do funkcji. Jeśli ustawisz temperature na zero przecinek dwa, a max tokens na tysiąc, LangChain mapuje te ogólne terminy na dokładne klucze w payloadzie, wymagane przez dostawcę, którego podałeś w swoim stringu. Konfigurujesz swój model raz, używając standardowej terminologii, a framework tłumaczy to dla docelowego API. Oddzielając kod aplikacji od specyficznych dla dostawcy szczegółów implementacji, zyskujesz architektoniczną zwinność, co pozwala ci oceniać konkurencyjne modele w kilka sekund, a nie dni. To wszystko w tym odcinku. Dzięki za wysłuchanie i buduj dalej!
4

Uniwersalny język modeli LLM

3m 40s

Rozkładamy na czynniki pierwsze podstawową jednostkę kontekstu w LangChain: Messages. Dowiesz się, jak strukturyzować wiadomości typu System, Human, AI oraz Tool, aby budować solidne historie konwersacji.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 4 z 20. Jeśli nadal przekazujesz zwykłe stringi do swoich modeli językowych, mocno ograniczasz swoje aplikacje. Zwykłe stringi gubią kontekst. Nie potrafią bezpiecznie przechowywać referencji do obrazków, wyników tool execution, ani odrębnych ról w interakcji. Aby to rozwiązać, LangChain używa ustandaryzowanych obiektów message, które działają jak uniwersalny język dla LLM-ów. Message w LangChain to struktura danych zawierająca konkretną rolę, payload i opcjonalne metadata. Różni providerzy API inaczej obsługują role w konwersacji i multimodalne inputy w swoich surowych API. LangChain ukrywa te różnice za abstrakcją, wprowadzając cztery odrębne klasy. Pierwsza z nich to SystemMessage. Ten obiekt ustala reguły ogólne, personę lub ścisłe ograniczenia dla interakcji. Kolejna to HumanMessage, reprezentująca prompt użytkownika lub wrzucone pliki. Następnie mamy AIMessage, która przechowuje wygenerowaną odpowiedź modelu. Na koniec jest ToolMessage. Ten obiekt służy do przekazywania wyników wykonania zewnętrznej funkcji z powrotem do modelu, czysto oddzielając surowy input użytkownika od wygenerowanych przez system danych faktycznych. Orkiestrujesz konwersacje, przekazując do modelu array tych obiektów message. Możesz ręcznie zbudować ten array, aby ukształtować output. Najpierw tworzysz listę i wstawiasz SystemMessage, przypisując modelowi rolę eksperta od poezji o ściśle określonym formacie. Następnie appendujesz HumanMessage z prośbą o haiku na temat migracji bazy danych. I tu jest kluczowa sprawa. Wcale nie musisz czekać, aż model wygeneruje kolejną odpowiedź. Możesz ręcznie zinstancjonować AIMessage i wstrzyknąć ją do arraya zaraz po prompcie od człowieka, umieszczając w niej konkretną linijkę początkową. Kiedy przekażesz ten cały array do modelu, zinterpretuje on wstrzykniętą AIMessage jako swoje własne wcześniejsze zachowanie. Płynnie będzie kontynuował haiku dokładnie od twojego punktu startowego, trzymając się struktury, którą mu narzuciłeś. Kiedy w końcu otrzymasz AIMessage z powrotem od modelu, musisz wyciągnąć z niej to, co faktycznie wygenerował. Developerzy rutynowo mylą surowy atrybut content ze sparsowanym payloadem. Każdy obiekt message ma właściwość content. Jednak ten surowy atrybut content bezpośrednio odzwierciedla to, co zwrócił konkretny provider LLM. W zależności od providera modelu i promptu, może to być prosty text string, albo mocno zagnieżdżona lista dictionary, zawierająca mieszane chunki tekstu, URL-e obrazków i identyfikatory tooli. Ręczne parsowanie tego sprawia, że twój kod staje się niesamowicie kruchy. Zamiast czytać surowy content, powinieneś użyć właściwości content blocks. Właściwość content blocks to ściśle typowana, ustandaryzowana reprezentacja payloadu message'a w LangChain. Kiedy czytasz z content blocks, LangChain tłumaczy odpowiedź specyficzną dla danego providera na jednolitą listę obiektów typu block. Możesz bezpiecznie iterować po tej liście. Najpierw sprawdzasz, czy block to text block, a jeśli tak, wyciągasz text payload. Następnie sprawdzasz, czy to tool call block, i wyciągasz argumenty. Zbudowanie logiki parsowania wokół ustandaryzowanej właściwości content blocks to jedyny sposób, aby upewnić się, że twoja aplikacja pozostanie całkowicie odseparowana od zmieniających się formatów odpowiedzi poszczególnych providerów modeli. To wszystko w tym odcinku. Dzięki za wysłuchanie i koduj dalej!
5

Wyposażanie agentów w narzędzia

4m 08s

Odkrywamy, jak nadać modelom możliwość działania za pomocą dekoratora @tool. Dowiesz się, jak type hints i docstrings są automatycznie konwertowane na precyzyjne schematy JSON dla modelu.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 5 z 20. Agent AI bez dostępu do świata zewnętrznego to po prostu generator tekstu. Aby przekształcić go w system, który faktycznie wykonuje pracę, musisz dać mu ręce do pracy. Dzisiaj porozmawiamy o wyposażaniu agentów w toolsy, a konkretnie o użyciu dekoratora at-tool. Tool w LangChain to pomost między silnikiem wnioskowania modelu językowego a twoimi systemami zewnętrznymi. Istnieje tu jednak powszechne, błędne przekonanie. Wielu programistów zakłada, że model językowy w jakiś sposób analizuje logikę wewnątrz ich funkcji w Pythonie, aby dowiedzieć się, jak jej użyć. Tak nie jest. Model językowy nigdy nie widzi twojego kodu w Pythonie. Widzi jedynie schema opisujące funkcję. Aby stworzyć toola, piszesz standardową funkcję w Pythonie i umieszczasz dekorator at-tool bezpośrednio nad nią. Ten dekorator robi coś kluczowego. Analizuje sygnaturę twojej funkcji, wyciąga jej nazwę, czyta type hinty dla każdego parametru i parsuje docstring. Bierze wszystkie te metadane i pakuje je w ustrukturyzowany format, który model językowy jest w stanie faktycznie przeczytać. Ponieważ model czyta tylko to wygenerowane schema, precyzja w twoim kodzie jest krytyczna. Spójrzmy na pewien scenariusz. Załóżmy, że piszesz funkcję o nazwie search database. Jeśli dasz jej słaby docstring, który mówi tylko: przeszukuje bazę danych, i całkowicie pominiesz type hinty, model językowy leci na ślepo. Nie wie, jaka to baza danych i nie wie, jakie argumenty przekazać. Może spróbować przekazać pełne zdanie z konwersacji jako search query, powodując crash twojej funkcji w Pythonie podczas jej wykonywania. Oto kluczowa sprawa. Kiedy używasz dekoratora at-tool, musisz pisać swoje docstringi dla modelu językowego, a nie dla programisty. Zamiast niejasnego opisu, piszesz jasną instrukcję, na przykład: przeszukuje bazę klientów po adresie email, aby pobrać historię rozliczeń. Następnie dodajesz ścisłe type hinty do swoich parametrów wejściowych. Określasz, że argument email musi być stringiem. Możesz nawet dodać opis do samego argumentu. Każda informacja o typie, którą dodajesz, daje modelowi językowemu węższe granice tego, co wolno mu wygenerować. Kiedy przekazujesz tego nowo udekorowanego toola agentowi, agent czyta szczegółowe schema, zanim zrobi cokolwiek innego. Gdy użytkownik pyta o zwrot pieniędzy dla klienta, agent skanuje swoje dostępne toolsy i rozpoznaje, że tool search database idealnie pasuje na podstawie twojego precyzyjnego docstringu. Dzięki twojemu ścisłemu type hintowi, wie dokładnie, jak sformatować argument. Wyciąga string email z promptu użytkownika, zatrzymuje generowanie tekstu i wyrzuca tool call. LangChain przechwytuje ten tool call. Bierze string email wygenerowany przez model, przekazuje go do twojej funkcji w Pythonie i wykonuje kod. Twoja funkcja gada z bazą danych, pobiera historię rozliczeń i oddaje surowe dane prosto do LangChain. LangChain następnie przekazuje te dane z powrotem do agenta jako obserwację. Agent wznawia swój proces myślenia, ale teraz ma prawdziwe dane, które właśnie mu dostarczyłeś. Zdolność modelu językowego do działania jest całkowicie uzależniona od jakości sygnatury twojej funkcji. Traktuj swoje docstringi i type hinty jako ścisłe ograniczenia inżynieryjne, ponieważ dla modelu językowego są to jedyne instrukcje, jakie istnieją. To wszystko w tym odcinku. Dzięki za wysłuchanie i buduj dalej!
6

Wstrzykiwanie kontekstu narzędzi

3m 34s

Zagłębiamy się w przekazywanie informacji w czasie działania (runtime) bezpośrednio do narzędzi, bez ujawniania ich modelowi LLM. Dowiesz się, jak używać parametru ToolRuntime do bezpiecznych konfiguracji z wstrzykiwaniem zależności.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 6 z 20. Jeśli polegasz na modelu językowym, żeby poprawnie przekazać token uwierzytelniający albo tożsamość użytkownika do toola bazodanowego, narażasz się na potężną lukę w zabezpieczeniach. Model nie wie, kim jest obecny użytkownik i na pewno nie powinieneś mu ufać, że sam to zgadnie. Potrzebujesz sposobu na przekazanie wrażliwych danych z backendu bezpośrednio do twoich tooli, całkowicie omijając model. To jest dokładnie to, co rozwiązuje Injecting Tool Context. Kiedy budujesz toola, niektóre argumenty są przeznaczone do wygenerowania przez model, jak na przykład search string czy zakres dat. Inne argumenty są przeznaczone stricte dla twojej infrastruktury backendowej. I tutaj wkracza obiekt ToolRuntime. Pozwala on wstrzyknąć statyczną konfigurację do toola dokładnie w momencie jego wykonania. Możesz pomyśleć, że wystarczy przekazać słownik konfiguracyjny jako zwykły argument toola i powiedzieć w prompcie, żeby go zignorował. Nie rób tego. Kiedy definiujesz parametr o nazwie config lub runtime w funkcji swojego toola, LangChain traktuje je jako zarezerwowane słowa kluczowe. Celowo ukrywa je w schemacie toola, który jest wysyłany do modelu językowego. Model nigdy ich nie widzi. Widzi tylko te argumenty, za których dostarczenie jest odpowiedzialny. Oznacza to, że model nie może wyhalucynować fałszywej konfiguracji ani próbować obejść twoich granic bezpieczeństwa. Rozważmy konkretny scenariusz. Budujesz toola get account info dla aplikacji bankowej. Ten tool wymaga user ID, żeby pobrać właściwe rekordy z bazy danych. Jeśli to model dostarcza to ID, sprytny prompt injection mógłby oszukać model i zmusić go do zażądania danych zupełnie innego klienta. Zamiast tego, projektujesz funkcję swojego toola tak, żeby przyjmowała dwa argumenty. Pierwszy to typ konta, który dostarczy model. Drugi to argument o nazwie runtime. W głównym kodzie twojej aplikacji, zanim tool zostanie wywołany, wypełniasz ten obiekt runtime. Dokładniej mówiąc, używasz właściwości runtime dot context. Bezpośrednio w tym kontekście umieszczasz prawdziwe, uwierzytelnione user ID osoby wysyłającej request. Możesz też umieścić tam aktywne połączenie z bazą danych albo adres regionalnego endpointu. Model analizuje request użytkownika i decyduje się wywołać toola get account info. Patrzy na schemat, widzi, że musi podać typ konta i zwraca słowo savings. Nie zwraca niczego więcej. LangChain przechwytuje to wywołanie. Pobiera typ konta z modelu, płynnie łączy go z runtime context z twojego backendu i wykonuje funkcję w Pythonie. Wewnątrz funkcji wyciągasz user ID z kontekstu i bezpiecznie uruchamiasz swoje zapytanie do bazy danych. Ten mechanizm daje ci bezpieczne dependency injection. Możesz wstrzyknąć wszystko, czego twój tool potrzebuje do działania, a o czym model nie ma prawa wiedzieć. Klucze API dla zewnętrznych usług bilingowych, ścieżki w systemie plików czy identyfikatory tenantów w architekturze multi-tenant – to wszystko powinno znaleźć się w runtime context. Oto kluczowy wniosek. Ukrycie argumentów konfiguracyjnych za runtime context gwarantuje, że twój model działa wyłącznie jako logiczny router, podczas gdy kod twojej aplikacji zachowuje absolutną, bezkompromisową kontrolę nad dostępem do danych i bezpieczeństwem wykonania. Dzięki za spędzenie ze mną tych kilku minut. Do usłyszenia następnym razem, trzymaj się.
7

Persystencja na poziomie wątku

3m 48s

Zajmujemy się pamięcią krótkotrwałą i sposobami utrzymania historii konwersacji. Dowiesz się, jak podłączyć checkpointers do swojego agenta, aby umożliwić pauzowanie, wznawianie i zapamiętywanie konwersacji.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 7 z 20. Bez pamięci każda interakcja z twoim agentem AI przypomina scenę z filmu 50 pierwszych randek. Model startuje z czystą kartą, zapominając wszystko, o czym rozmawialiście kilka sekund temu. Rozwiązaniem jest Thread-Level Persistence. Duże modele językowe są całkowicie stateless. Przetwarzają tekst i zwracają tekst, nie zachowując absolutnie niczego pomiędzy requestami. Aby podtrzymać rozmowę, agent potrzebuje sposobu na zapisywanie i odczytywanie poprzednich interakcji. W kontekście pojedynczej aktywnej sesji, ogarniamy to za pomocą pamięci krótkotrwałej, która jest zarządzana jako część state'u agenta i zapisywana przy użyciu checkpointerów. Ludzie często myślą, że pamięć w AI to jakaś wewnętrzna funkcja modelu, dzięki której sieć neuronowa magicznie cię pamięta. Wcale tak nie jest. Pamięć to po prostu historia wiadomości. Thread-Level Persistence oznacza po prostu wzięcie bieżącej listy wiadomości, zapisanie jej w bazie danych po każdym kroku i wrzucenie jej z powrotem do prompta, zanim model zobaczy kolejny input. Checkpointer zarządza tym automatycznie, więc nie musisz ręcznie pisać logiki zapisu i odczytu. W LangGraph, state jest zapisywany per thread. Thread reprezentuje jedną ciągłą sesję. Żeby to włączyć, potrzebujesz checkpointera. Do developmentu i testowania możesz użyć In Memory Saver. Kiedy kompilujesz graf swojego agenta, przekazujesz ten obiekt savera jako argument checkpointer. Ta integracja mówi agentowi, że na koniec egzekucji każdego node'a, musi zrobić snapshot swojego obecnego state'u i przekazać go do savera. State zawiera wszystko, co zdefiniowałeś w swoim grafie, czyli zazwyczaj bieżącą listę wiadomości. Spójrzmy na konkretny scenariusz. Kompilujesz swojego agenta z In Memory Saver. Teraz chcesz wywołać agenta. Zamiast po prostu przekazywać wiadomość użytkownika, przekazujesz też obiekt konfiguracyjny zawierający konkretny thread ID. Użyjmy stringa o wartości conversation one. Wysyłasz wiadomość: mam na imię Bob. Agent ją odbiera, generuje uprzejme powitanie i kończy działanie. W tle, checkpointer zapisuje zaktualizowany state, który teraz zawiera wiadomość mówiącą, że masz na imię Bob, zaindeksowaną pod conversation one. Później wywołujesz agenta po raz drugi. Wysyłasz nową wiadomość z pytaniem: jak mam na imię. Co kluczowe, przekazujesz dokładnie ten sam obiekt konfiguracyjny z thread ID conversation one. I tu jest kluczowa sprawa. Zanim agent przekieruje twoje nowe pytanie do modelu, checkpointer przechwytuje ten proces. Szuka conversation one w In Memory Saver. Pobiera snapshot state'u z twojej poprzedniej tury, ładuje zapisaną historię wiadomości i dodaje twoje nowe pytanie na końcu. Model językowy otrzymuje pełny kontekst historyczny, widzi poprzednią wiadomość, w której się przedstawiłeś, i poprawnie odpowiada, że masz na imię Bob. Gdybyś zmienił thread ID na conversation two i zapytał o swoje imię, checkpointer poszukałby tego nowego ID, nie znalazłby żadnego istniejącego state'u i zainicjowałby nową, pustą listę wiadomości. Agent nie miałby pojęcia, kim jesteś. Thread ID to jedyny klucz, który wiąże sekwencję izolowanych, stateless wywołań modelu w spójną sesję pamięci krótkotrwałej. Checkpointer abstrahuje powtarzalną pracę związaną z zarządzaniem tablicami wiadomości i odpytywaniem baz danych, gwarantując, że twój agent może wznowić pracę dokładnie tam, gdzie ją przerwał, o ile podasz prawidłowy thread ID. Dzięki za wysłuchanie — do usłyszenia następnym razem.
8

Kompresja kontekstu za pomocą Middleware

3m 51s

Odkrywamy, jak zapobiec awariom modelu spowodowanym długimi konwersacjami. Dowiesz się, jak używać SummarizationMiddleware do automatycznej kompresji starych wiadomości i oszczędzania tokenów.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 8 z 20. Im dłużej trwa rozmowa, tym bardziej duży model językowy rozprasza się nieaktualnymi informacjami. Tracisz na dokładności, płacąc jednocześnie wyższe koszty tokenów przy każdej turze. Kompresja kontekstu za pomocą middleware'u rozwiązuje dokładnie ten problem. W miarę jak historia czatu rośnie, w końcu dobijasz do limitu context window swojego modelu. Nawet zanim osiągniesz ten twardy limit, przekazywanie tysięcy tokenów ze starej rozmowy obniża wydajność. Rozwiązaniem jest SummarizationMiddleware w LangChain. Zamiast po prostu ucinać stare wiadomości, kompresuje je do jednego bloku podsumowania. Dzięki temu zachowujesz semantyczne znaczenie rozmowy bez ogromnego narzutu tokenów. Krąży powszechne błędne przekonanie o tym, jak to działa. Ludzie często zakładają, że główny agent musi sam wykonać to podsumowanie. Wcale nie musi i tak naprawdę nie powinien. Chcesz, aby twój główny agent działał na najmądrzejszym, najbardziej potężnym modelu, żeby radzić sobie ze złożoną logiką. Podsumowanie to znacznie prostsze zadanie. Przypisujesz mniejszy, tańszy model do SummarizationMiddleware wyłącznie do tego zadania. Konfiguracja middleware'u wymaga zdefiniowania dwóch głównych parametrów. Pierwszym z nich jest trigger. Trigger mówi middleware'owi, kiedy ma wkroczyć do akcji. Możesz ustawić trigger tak, aby aktywował się, gdy całkowita liczba tokenów w konwersacji dobije do 4000. Drugim parametrem jest warunek keep. Mówi on middleware'owi, ile najnowszego kontekstu ma zostawić w całkowitym spokoju. Możesz ustawić wartość keep na 20, co oznacza, że 20 najnowszych wiadomości pozostanie nietkniętych. Oto jak ten logic flow wygląda w praktyce. Twój użytkownik rozmawia z głównym agentem. Rozmowa się rozrasta. W kolejnej turze całkowita historia wiadomości przekracza próg 4000 tokenów. Zanim główny agent w ogóle zobaczy nowy user input, SummarizationMiddleware przechwytuje request. Skanuje historię i identyfikuje wszystko, co jest starsze niż 20 najnowszych wiadomości. Bierze ten starszy fragment rozmowy i przekazuje go do twojego wyznaczonego, mniejszego modelu. Załóżmy, że skonfigurowałeś middleware do korzystania z gpt-4.1-mini. Ten mniejszy model czyta stare wiadomości i generuje zwięzły akapit podsumowujący to, o czym dyskutowano. Następnie middleware nadpisuje array z historią. Zastępuje wszystkie te stare, pojedyncze wiadomości jednym system message, zawierającym nowe podsumowanie. Jeśli istniało już starsze podsumowanie z poprzedniego cyklu kompresji, middleware dołącza je do promptu, dzięki czemu nowe podsumowanie aktualizuje bieżącą narrację. Ostateczny pakiet wysłany do twojego głównego agenta jest wysoce zoptymalizowany. Zawiera on nową wiadomość z podsumowaniem, po której następuje 20 nieskompresowanych, najnowszych wiadomości, a na końcu najnowszy user input. Oto kluczowy wniosek. Główny agent nigdy nie zdaje sobie sprawy, że historia została skompresowana w tle. Otrzymuje po prostu czyste, wysoce trafne context window. Zachowujesz długoterminowe znaczenie semantyczne czatu, utrzymujesz skupienie modelu i drastycznie obniżasz koszty tokenów w każdej kolejnej turze. Jeśli uważasz te odcinki za pomocne i chcesz wesprzeć program, wyszukaj DevStoriesEU na Patreonie. To wszystko w tym odcinku. Dzięki za wysłuchanie i buduj dalej!
9

Gwarantowane formaty danych

3m 56s

Omawiamy, jak wymusić na modelach językowych zwracanie ścisłych, przewidywalnych struktur danych. Poznasz różnicę między ProviderStrategy a ToolStrategy przy generowaniu modeli Pydantic.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 9 z 20. Tworzenie oprogramowania opartego na parsowaniu odpowiedzi w języku naturalnym za pomocą wyrażeń regularnych to tykająca bomba. Prosisz model językowy o prosty obiekt danych, a on zwraca ci idealne dane, z tą różnicą, że na początku dodaje uprzejme powitanie i opakowuje całość w markdown. Twój parser natychmiast się wywala. Gwarantowane formaty danych to sposób na trwałe rozwiązanie tego problemu. Structured output wymusza na modelu językowym zwracanie informacji dokładnie w taki sposób, jakiego oczekuje twoja aplikacja. Przekształca to nieprzewidywalne generowanie tekstu w niezawodne obiekty w kodzie. Wyobraź sobie system, który przetwarza przychodzące wiadomości do supportu. Użytkownik wysyła chaotyczny, nieustrukturyzowany akapit, narzekając na problem z logowaniem, ale gdzieś w tekście ukrywa swoje imię, e-mail i numer telefonu. Potrzebujesz tych trzech danych, żeby odpalić wyszukiwanie w bazie. Zamiast pisać skomplikowany prompt, błagając model o poprawne sformatowanie odpowiedzi, definiujesz standardowy model w Pydantic. Tworzysz klasę o nazwie ContactInfo i definiujesz name, email i phone jako wymagane pola. Następnie po prostu przekazujesz tę schemę Pydantic do parametru response format w konfiguracji twojego modelu językowego. Nie musisz podawać przykładów ani pisać własnych skryptów do walidacji. To jest najważniejsza część. Kiedy przekazujesz tę schemę Pydantic, LangChain automatycznie określa najbardziej niezawodny sposób, żeby ją wymusić. Robi to, po cichu wybierając między dwiema różnymi ścieżkami wykonania. Najpierw sprawdza, czy twój wybrany model językowy ma oficjalną funkcję structured output wbudowaną w swoje API. Jeśli tak, LangChain automatycznie wybiera Provider Strategy. Ta strategia wypycha twoją schemę bezpośrednio do providera, wykorzystując jego natywne ograniczenia po stronie serwera, żeby zagwarantować format outputu. Ale sprzęt się zmienia, a modele bywają podmieniane. Jeśli zdecydujesz się użyć innego modelu, któremu brakuje natywnego structured output, LangChain wykryje ten brak. Automatycznie robi fallback do Tool Strategy. Pod spodem tłumaczy twoją schemę ContactInfo na sygnaturę funkcji. Informuje model o fake'owym toolu, który do uruchomienia wymaga dokładnie pól name, email i phone. Model próbuje wywołać ten tool i robiąc to, generuje dokładnie te ustrukturyzowane argumenty, których potrzebujesz. Kod twojej aplikacji w ogóle nie musi się zmieniać, żeby dostosować się do tej podmiany. Po zakończeniu operacji, developerzy często szukają swoich danych w niewłaściwym miejscu. Możesz zakładać, że output jest zwracany jako surowy tekst, który wciąż musisz sparsować. To nie jest surowy tekst. LangChain przechwytuje payload i tworzy dla ciebie instancję obiektu Pydantic. Umieszcza ten w pełni zwalidowany obiekt Pythona bezpośrednio w stanie twojej aplikacji. Znajdziesz go przechwyconego w kluczu structured response twojego słownika stanu. Po prostu odwołujesz się do tego klucza i natychmiast masz swój obiekt ContactInfo, z polami type-safe gotowymi do przekazania do reszty aplikacji. Przenosząc ciężar walidacji schemy z własnej logiki parsowania do warstwy frameworku, twoje integracje modeli językowych stają się tak przewidywalne, jak standardowe wywołanie API. Dzięki za wysłuchanie — do usłyszenia następnym razem.
10

Przechwytywanie pętli agenta

3m 21s

Wprowadzamy paradygmat middleware, dający chirurgiczną kontrolę nad wykonywaniem agenta. Dowiesz się, jak używać hooków typu wrap-style i node-style do przechwytywania wywołań modelu.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 10 z 20. Jeśli twój agent failuje po cichu na produkcji, często wynika to z tego, że nie śledzisz, co dzieje się między krokami jego reasoning loop. Model crashuje, loop się przerywa, a ty zostajesz z niekompletnym runem. Przechwycenie agent loopa za pomocą customowego middleware to sposób na odzyskanie kontroli. Kiedy agent odpala cykl ReAct, ciągle przekazuje kontrolę tam i z powrotem do modelu językowego. Middleware dostarcza hooki, żeby odpalić twoją logikę dokładnie wtedy, kiedy jej potrzebujesz podczas tej wymiany. Będziesz używać dwóch głównych typów hooków: node-style hooks i wrap-style hooks. Częstym błędem jest traktowanie ich zamiennie. Node-style hooks odpalają się sekwencyjnie. Wrap-style hooks tak naprawdę otaczają wykonanie kodu i potrafią łapać wyjątki. Node-style hooks używają dekoratorów o nazwach before model i after model. Kiedy podpinasz hook before model do funkcji, framework wykonuje twoją logikę w całości, i dopiero wtedy triggeruje API modelu językowego. Kiedy model odpowie, odpala się hook after model. Te hooki są świetne do logowania dokładnego promptu wysłanego do API, wstrzykiwania kontekstu, albo wycinania złych znaków z końcowego outputu. Ale ponieważ odpalają się ściśle sekwencyjnie, nie dają żadnej ochrony przed awariami. Jeśli API modelu językowego rzuci timeout, twój hook after model nigdy się nie wykona. Błąd propaguje w górę i crashuje cały agent loop. I to jest ta najważniejsza część. Jeśli musisz obsłużyć niestabilność, używasz wrap-style hook. Dekorator do tego to wrap model call. Wrap hook całkowicie otacza wykonanie modelu. Twoja funkcja się odpala, robi jakiś setup, a potem jawnie przekazuje kontrolę do modelu. Ponieważ twój customowy kod wrappuje właściwe wywołanie sieciowe, możesz wrzucić to wykonanie w standardowe struktury obsługi błędów. Wyobraź sobie budowanie middleware'u wrap model call, żeby obsłużyć API rate limits za pomocą exponential backoff retry loop. Piszesz funkcję udekorowaną przez wrap model call. Wewnątrz tej funkcji tworzysz retry loop. Wrzucasz komendę, która przekazuje kontrolę do modelu, w blok try. Jeśli model odpowie sukcesem, łapiesz response, zwracasz go, i loop się kończy. Jeśli model rzuci błędem, twój blok catch go przechwytuje. Zamiast crashować agenta, twój blok catch triggeruje pauzę. Wyliczasz krótki delay, czekasz, a potem pozwalasz, żeby loop spróbował wywołać to jeszcze raz, podwajając delay za każdym razem. Agent orchestrator nigdy nie widzi tych błędów. Middleware łapie wyjątki, zarządza logiką retry w izolacji, i płynnie przekazuje udany response z powrotem do głównego ReAct loop, kiedy w końcu się uda. Node-style hooks przygotowują inputy i formatują outputy, ale wrap-style hooks chronią wykonanie. To tyle na dzisiaj. Do usłyszenia następnym razem!
11

Dynamiczna inżynieria kontekstu

4m 14s

Zagłębiamy się w inżynierię kontekstu poprzez dynamiczne generowanie promptów systemowych. Dowiesz się, jak używać middleware do modyfikowania instrukcji na podstawie roli i środowiska obecnego użytkownika.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 11 z 20. Głównym powodem, dla którego twój agent zawodzi, wcale nie jest to, że model bazowy jest głupi. Chodzi o to, że przekazałeś mu zły kontekst do zadania. Jeśli twój system traktuje superusera i gościa dokładnie tak samo, twoja aplikacja jest ślepa na rzeczywistość. Żeby to naprawić, stosujemy Dynamic Context Engineering. Najpierw wyjaśnijmy powszechne nieporozumienie dotyczące tego, jak budowane są prompty. Dynamiczny kontekst to nie jest bazowy system prompt, który piszesz, gdy początkowo definiujesz swojego agenta w kodzie. Ten początkowy system prompt jest całkowicie statyczny. Dynamic Context Engineering to proces modyfikowania tego promptu w locie, zaledwie milisekundy przed faktycznym wywołaniem modelu. Context engineering polega na przekazaniu modelowi językowemu dokładnie tych reguł, których potrzebuje dla konkretnego użytkownika w danym momencie, i niczego więcej. Jeśli spróbujesz upchnąć każdą możliwą regułę w jeden potężny, statyczny prompt — mówiąc modelowi, jak ma działać, gdy użytkownik to admin, jak ma działać, gdy to viewer, i jak ma działać, jeśli jest wtorek — marnujesz tokeny i dezorientujesz model. Zamiast tego, chcesz dynamicznie wstrzykiwać tylko te reguły, które mają znaczenie w danym momencie. W LangChain obsługuje się to za pomocą specjalnego dekoratora o nazwie dynamic underscore prompt. Umieszczasz ten dekorator nad zdefiniowaną przez siebie funkcją w Pythonie. Kiedy twoja aplikacja otrzymuje zapytanie i odpala chain, LangChain pauzuje. Szuka dowolnej funkcji opakowanej w ten dekorator i wykonuje ją przed komunikacją z modelem. Wewnątrz udekorowanej funkcji potrzebujesz sposobu, żeby dowiedzieć się, co aktualnie się dzieje. I tu właśnie odczytujesz dane z request dot runtime dot context. Ten obiekt context to w zasadzie słownik. Przechowuje wszystkie metadane na żywo przekazane do chaina podczas jego wywołania. Możesz tam wrzucić co tylko chcesz z backendu swojej aplikacji, na przykład user ID, stany sesji, feature flagi czy poziomy dostępu. Spójrzmy na konkretny scenariusz. Piszesz funkcję o nazwie context aware prompt i opakowujesz ją dekoratorem dynamic prompt. Wewnątrz tej funkcji odczytujesz rolę użytkownika z runtime context. Sprawdzasz tę rolę. Jeśli użytkownik to admin, twoja funkcja dokleja konkretny blok tekstu do system promptu, mówiąc modelowi językowemu, że ma pełne uprawnienia do zwracania destrukcyjnych poleceń. Jeśli użytkownik to viewer, twoja funkcja dokleja inny blok tekstu, dając ścisłe instrukcje, że model musi zwracać wyłącznie podsumowania read-only i nigdy nie może sugerować zmian w konfiguracji. Teraz wyciągasz drugą informację z runtime context, czyli stan środowiska. Sprawdzasz, czy środowisko jest ustawione na produkcję. Jeśli tak, twoja funkcja dokleja poważne ostrzeżenie o bezpieczeństwie na samym końcu system promptu, żądając od modelu podwójnego sprawdzenia outputu pod kątem bezpieczeństwa. Jeśli środowisko to tylko staging, całkowicie pomijasz dodawanie tego ostrzeżenia. I tu jest kluczowa sprawa. Twoja funkcja bierze statyczny bazowy prompt, dokleja reguły dla admina lub viewera, dorzuca ostrzeżenie na produkcji, jeśli to konieczne, i zwraca ostateczny string. LangChain bierze ten w pełni złożony string i wysyła go do modelu językowego. Model językowy nigdy nie wie, że prompt został posklejany z kawałków. Widzi po prostu bardzo szczegółowy, idealnie skrojony zestaw instrukcji. Robiąc to, utrzymujesz swoje system prompty lekkie, dokładne i w pełni adekwatne do bieżącego requestu. Przestajesz liczyć na to, że model zgadnie, które reguły mają zastosowanie, i zaczynasz egzekwować dokładnie te reguły, które są wymagane dla obecnego stanu twojej aplikacji. Chciałbym poświęcić chwilę, żeby podziękować ci za słuchanie — to bardzo nam pomaga. Miłego dnia!
12

Bezpieczne AI z deterministycznymi zabezpieczeniami

3m 26s

Zabezpieczamy naszych agentów przed wyciekami danych za pomocą wbudowanego middleware. Dowiesz się, jak zastosować PIIMiddleware, aby automatycznie redagować poufne informacje, zanim dotrą do modelu.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 12 z 20. Pojedynczy log z czatu zawierający niezredagowany numer karty kredytowej może natychmiast naruszyć zgodność całej twojej aplikacji. Nie możesz polegać na tym, że model językowy grzecznie zignoruje wrażliwe dane, a proszenie modelu o cenzurowanie samego siebie jest powolne i nieprzewidywalne. I tu do gry wchodzi Safe AI z deterministycznymi guardrailami. Deterministyczne guardraile to zahardkodowane kontrole oparte na regułach. Opierają się na przewidywalnych wzorcach i logice, takich jak wyrażenia regularne czy stałe algorytmy, zamiast prosić kolejny model językowy o ocenę tekstu. Ponieważ omijają wywołanie sieciowe do AI, wykonują się w milisekundach i praktycznie nic nie kosztują. Jeśli budujesz na produkcję, ta deterministyczna warstwa jest obowiązkowa dla bezpieczeństwa. We frameworku implementujesz to używając PII Middleware. Częstym błędem, który popełniają developerzy, jest próba filtrowania wrażliwych informacji po fakcie, poprzez skanowanie outputu modelu. Ale żeby chronić prywatność użytkownika, PII Middleware jest zaprojektowany tak, aby przechwytywać surową wiadomość dokładnie w momencie, gdy użytkownik klika wyślij. Przetwarza tekst zanim wywołanie modelu w ogóle się rozpocznie. Konfigurujesz to zachowanie jawnie, ustawiając parametr apply to input na true. Przejdźmy przez scenariusz z agentem obsługi klienta. Zestresowany użytkownik wysyła wiadomość, że jego konto jest zablokowane, podaje swój prywatny adres email, a następnie wkleja cały szesnastocyfrowy numer karty kredytowej, aby zweryfikować zakup. Jeśli twój kod przekaże ten surowy string do zewnętrznego dostawcy AI, naruszasz podstawowe zasady compliance danych. Potrzebujesz strategii na zneutralizowanie tekstu, a middleware daje ci trzy wbudowane akcje: block, redact i mask. Jeśli użyjesz strategii block, middleware działa jak twarda ściana. W momencie, gdy wykryje format karty kredytowej, rzuca błąd i całkowicie przerywa chain. Request jest natychmiast odrzucany. Jeśli wybierzesz strategię redact, middleware chirurgicznie usuwa konkretne dane i wstawia czysty placeholder. Prywatny adres email jest całkowicie wymazany ze stringa i zastąpiony słowem email w nawiasach. Model językowy nadal czyta spójne zdanie i rozumie, że podano email, ale rzeczywistych danych już nie ma. Trzecia strategia to mask. Maskowanie zachowuje bezpieczną część oryginalnych danych. Middleware zastępuje pierwsze dwanaście cyfr karty kredytowej gwiazdkami, zostawiając odsłonięte tylko cztery ostatnie cyfry. Jest to bardzo skuteczne, gdy twój backend musi zweryfikować konto bez ujawniania pełnych danych finansowych. Zaimplementowanie tego wymaga skonfigurowania middleware'u zanim uruchomi się twój chain. Tworzysz instancję PII Middleware i przekazujesz mu listę docelowych encji. W tym przypadku określasz email i kartę kredytową. Następnie przypisujesz wybrane strategie do tych encji, na przykład wybierając redact dla emaila i mask dla karty. Na koniec podpinasz ten komponent middleware do swojego głównego chaina, upewniając się, że ustawiłeś parametr apply to input. W momencie, gdy użytkownik wysyła swoją wiadomość, deterministyczne reguły czyszczą tekst, a AI otrzymuje tylko zdezynfekowany prompt. Oto kluczowy wniosek. Najbezpieczniejszym sposobem na obsługę wrażliwych danych osobowych w dowolnej architekturze generatywnego AI jest zagwarantowanie, że model językowy w ogóle ich nie zobaczy. To wszystko w tym odcinku. Dzięki za wysłuchanie i buduj dalej!
13

Wstrzymywanie w celu zatwierdzenia przez człowieka

4m 15s

Badamy wykonywanie narzędzi wysokiego ryzyka, dodając człowieka do pętli decyzyjnej. Dowiesz się, jak zatrzymać działanie agenta, aby zatwierdzić, edytować lub odrzucić wrażliwe akcje.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 13 z 20. Autonomiczny agent jest niezwykle potężny, aż do momentu, gdy autonomicznie wyśle maila z wersją roboczą twoich danych finansowych do niewłaściwego klienta. Niektóre akcje są po prostu zbyt ryzykowne, żeby je wykonać bez nadzoru człowieka. Właśnie dlatego używamy Pausing for Human Approval. Agenty automatycznie uruchamiają toolsy na podstawie promptów od użytkownika. Takie zachowanie jest idealne do odczytu danych, ale staje się niebezpieczne przy akcjach destrukcyjnych lub nieodwracalnych. Potrzebujemy sposobu na zapauzowanie execution, zapytanie człowieka, czy akcja jest bezpieczna, a następnie na resume lub abort. Zanim omówimy mechanikę, musimy wyjaśnić częsty punkt awarii. Inżynierowie czasami konfigurują interrupts, a potem zastanawiają się, dlaczego agent po prostu crashuje lub się restartuje. Musisz mieć włączony checkpointer. Nie możesz zapauzować agenta, jeśli nie potrafi on zapamiętać, w którym miejscu skończył. Cała pamięć agenta i jego obecny progres muszą zostać zapisane w persistence layer, podczas gdy czeka on na odpowiedź człowieka. Brak checkpointera oznacza brak pauzy. Z aktywnym persistence, możesz bezpiecznie obsługiwać tool execution używając Human In The Loop Middleware. Wyobraź sobie setup, w którym twój agent ma dwa toolsy: search tool i delete database tool. Chcesz, żeby agent mógł swobodnie wyszukiwać, ale absolutnie nie chcesz, żeby robił drop tabel bez pozwolenia. Kiedy konfigurujesz ten middleware, ustawiasz argument o nazwie interrupt on. Przekazujesz mu konkretne nazwy toolsów, które wymagają nadzoru. W naszym scenariuszu konfigurujesz interrupt on, żeby monitorował tylko delete database tool. Search tool jest ignorowany przez middleware i wykonuje się natychmiast, gdy tylko agent go wywoła. Jednak kiedy agent zdecyduje, że musi użyć delete database tool, middleware przechwytuje ten request. Pauzuje graph, zapisuje obecny state do twojego checkpointera i całkowicie zatrzymuje execution. Graph jest teraz zawieszony w persistence layer, czekając na interwencję człowieka. Operator analizuje oczekujący tool call i ma trzy sposoby na odpowiedź dla middleware. Pierwszy typ decyzji to approve. Człowiek patrzy na parametry wygenerowane przez agenta, zgadza się, że są poprawne, i wysyła komendę approve. Graph się budzi i wykonuje usunięcie dokładnie tak, jak agent pierwotnie zaplanował. Drugi typ decyzji to reject. Operator widzi, że agent próbuje usunąć zły target i wysyła reject. Tool się nie wykonuje. Zamiast tego agent otrzymuje obserwację wskazującą, że akcja została zablokowana przez człowieka. Agent następnie procesuje ten feedback i może spróbować innego podejścia albo poprosić użytkownika o doprecyzowanie. A oto kluczowa sprawa. Trzecia opcja to edit. Czasami agent ma w większości rację, ale robi drobny błąd, na przykład uderza w środowisko production zamiast staging. Zamiast całkowicie odrzucać akcję i zmuszać agenta do ponownego przeanalizowania problemu, operator może bezpośrednio zmodyfikować tool input parameters. Człowiek zmienia środowisko docelowe na staging i wysyła poprawiony call. Agent robi resume i wykonuje akcję używając zmodyfikowanych parametrów, płynnie ruszając dalej. Używając tego middleware, chronisz swój system przed niebezpiecznymi błędami. Pausing for human approval nie tylko zapobiega katastrofom, ale też przekształca twojego agenta z nieprzewidywalnego bytu w nadzorowanego współpracownika, który może bezpiecznie obsługiwać operacje o wysokiej stawce. To wszystko w tym odcinku. Dzięki za wysłuchanie i budujcie dalej!
14

Informacje zwrotne od agenta w czasie rzeczywistym

3m 43s

Zagłębiamy się w strumieniowanie, aby drastycznie poprawić doświadczenie użytkownika. Dowiesz się, jak interpretować stream modes, aby wyświetlać tokeny LLM na żywo wraz z niestandardowymi aktualizacjami wykonywania narzędzi.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 14 z 20. Użytkownikom nie przeszkadza czekanie dziesięciu sekund na złożoną odpowiedź, o ile pokażesz im, co mózg robi przez te dziesięć sekund. Pusty ekran sprawia wrażenie zepsutej aplikacji. Rozwiązaniem problemu odczuwalnego opóźnienia jest Real-Time Agent Feedback. Aby naprawić problem pustego ekranu, LangChain udostępnia parametr o nazwie stream mode podczas uruchamiania twojego agenta lub grafu. Kontroluje on dokładnie, jakie dane agent odsyła przez połączenie podczas swojego działania. Pierwszym trybem, który musisz znać, jest messages mode. Obsługuje on klasyczny efekt pisania. Streamuje surowe tokeny z modelu językowego w miarę ich generowania. Jeśli model pisze akapit, twoja aplikacja odbiera fragmenty tekstu jeden po drugim, co pozwala na płynną aktualizację interfejsu użytkownika zamiast czekania na cały blok tekstu. Ludzie często mylą streamowanie tokenów końcowej odpowiedzi ze streamowaniem pośredniego rozumowania. To zupełnie różne rzeczy. Jeśli twój agent zdecyduje się wywołać search tool, generowanie tokenów się zatrzymuje. Model językowy czeka na zakończenie działania toola. Jeśli ten tool działa przez pięć sekund, twój interfejs użytkownika zawiesza się na pięć sekund. Sam messages mode nie mówi użytkownikowi, co agent faktycznie robi w tle. Pokazuje tylko to, co mówi model językowy. Aby rozwiązać problem milczącego toola, używasz custom mode. Custom mode pozwala twoim toolom i wewnętrznym nodom emitować własne aktualizacje statusu w czasie rzeczywistym bezpośrednio do streamu. Aby to zaimplementować, używasz narzędzia LangChain o nazwie get stream writer. Wywołujesz tę funkcję wewnątrz kodu swojego toola. Daje ci to obiekt writera, którego możesz użyć do emitowania customowych eventów z powrotem do klienta w dowolnym momencie działania toola. Pomyśl o wolnym toolu do sprawdzania pogody. Twój agent otrzymuje prompt z prośbą o prognozę i decyduje się wywołać weather tool. Wewnątrz funkcji w Pythonie dla tego toola, pobierasz stream writer. Kiedy tool zaczyna odpytywać wolne, zdalne API, używasz writera, aby wyemitować customowy event ze statusem takim jak Acquired data. Twój frontend natychmiast odbiera ten customowy event i wyświetla loading spinner z tym tekstem. Użytkownik wie, że agent pracuje. Kiedy zdalne API zwróci dane, tool kończy działanie, a model językowy odzyskuje kontrolę. Pobiera surowe dane pogodowe, formułuje przyjazną dla człowieka odpowiedź, a messages stream rusza ponownie, wypisując na ekranie ostateczną prognozę. Oto kluczowa sprawa. Nie musisz wybierać tylko jednego trybu. Możesz przekazać listę zawierającą zarówno messages, jak i custom do parametru stream mode. LangChain automatycznie przeplecie tokeny modelu językowego i logi twojego customowego toola w jeden ciągły feed. Twój frontend po prostu sprawdza typ eventu, gdy ten nadejdzie. Jeśli jest to custom event, aktualizujesz wskaźnik statusu. Jeśli jest to message event, doklejasz token do dymka czatu. Odczuwalne opóźnienie spada do zera, ponieważ system cały czas mówi do użytkownika. Jeśli chcesz pomóc w tworzeniu kolejnych odcinków, możesz wesprzeć podcast, wyszukując DevStoriesEU na Patreon. Dzięki za wysłuchanie, udanego kodowania!
15

Persystencja między sesjami

3m 37s

Odkrywamy pamięć długotrwałą, aby budować agentów, którzy naprawdę znają swoich użytkowników. Dowiesz się, jak używać magazynów LangGraph do zapisywania dokumentów JSON w zupełnie różnych konwersacjach.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 15 z 20. Żeby zbudować prawdziwie spersonalizowanego asystenta, musi on pamiętać, że wolisz krótkie odpowiedzi, nawet jeśli powiedziałeś mu to trzy tygodnie temu w zupełnie innym czacie. Jeśli polegasz wyłącznie na standardowej pamięci konwersacji, ta preferencja znika w momencie rozpoczęcia nowego wątku. Mechanizmem, który zapobiega tej amnezji, jest Cross-Session Persistence z wykorzystaniem paradygmatu Store. Wielu programistów myli checkpointer ze storem. Oto różnica. Checkpointer zarządza krótkoterminowym statem. Zapamiętuje pojedynczy wątek konwersacji. Kiedy użytkownik tworzy nowy czat, checkpointer zaczyna z czystą kartą. Store przekracza te granice wątków. Pozwala twoim agentom na globalne zapisywanie i pobieranie informacji we wszystkich interakcjach z konkretnym użytkownikiem. W swojej istocie, pamięć długoterminowa w LangChain to po prostu hierarchiczny key-value store. Przechowuje on dokumenty JSON. Hierarchia opiera się na namespace'ach. Namespace to sekwencja stringów, która działa dokładnie tak samo jak ścieżka do folderu na twoim komputerze. Jeśli chcesz przechować dane profilu, możesz użyć namespace'a zawierającego string "users", po którym następuje identyfikator użytkownika. Wewnątrz tego namespace'a przechowujesz elementy. Każdy element wymaga unikalnego klucza w postaci stringa oraz dictionary reprezentującego wartość JSON. I tu robi się ciekawie. Toole komunikują się z tym storem bezpośrednio poprzez runtime context. Nigdy nie przekazujesz store'a ręcznie przez twój graph state. Weźmy na przykład customowy tool o nazwie save user info. Jego zadaniem jest przechwycenie preferencji języka mówionego. Podczas setupu inicjalizujesz swoją aplikację z wykorzystaniem store'a, na przykład in-memory store do lokalnego testowania. Wewnątrz logiki twojego toola, uzyskujesz dostęp do instancji store'a bezpośrednio ze wstrzykniętej konfiguracji runtime'u. Wyciągasz identyfikator użytkownika z obecnego contextu. Następnie wywołujesz metodę put na storze. Podajesz tuplę namespace'a zawierającą słowo "users" i user ID. Definiujesz klucz, na przykład "language preference", i na koniec przekazujesz JSON dictionary zawierające wartość, powiedzmy "Spanish". Store zapisuje ten dokument. Kilka tygodni później użytkownik zaczyna zupełnie nową konwersację. State wątku jest pusty. Ale ponieważ agent ma dostęp do toola do pobierania danych, może wywołać metodę get na runtime storze, używając dokładnie tego samego namespace'a i klucza. Pobiera dokument JSON, odczytuje preferencję i natychmiast odpowiada po hiszpańsku. Oddzielenie krótkoterminowego contextu konwersacji od długoterminowej pamięci faktów sprawia, że twoja aplikacja pozostaje lekka. Checkpointer nie puchnie od lat historii użytkownika, a state pozostaje czysty. Store ładuje tylko te konkretne dokumenty JSON, które agent jawnie zdecyduje się pobrać. Traktowanie contextu i persistence jako dwóch całkowicie odrębnych systemów to jedyny sposób na niezawodne skalowanie agenta. Checkpointer przechowuje teraźniejszość, a store przeszłość. To wszystko na dziś. Dzięki za wysłuchanie — idź zbudować coś fajnego.
16

Paradygmat wieloagentowy

4m 12s

Wyjaśniamy, dlaczego pojedynczy agenci zawodzą, i wprowadzamy architekturę Subagents. Dowiesz się, jak główny agent nadzorujący koordynuje subagentów jako izolowane okna kontekstowe, aby zapobiec nadmiarowi tokenów.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 16 z 20. Kiedy twój pojedynczy agent AI zaczyna zawodzić z powodu własnej, ogromnej listy tooli i konkurujących ze sobą instrukcji, wrzucenie mu większego context window nie rozwiąże problemu. Czas przestać pisać monolityczny skrypt i zacząć zatrudniać zespół. I tu właśnie wkracza paradygmat multi-agent. Budujemy systemy multi-agentowe, ponieważ pojedyncze agenty uderzają w poznawczą ścianę. Daj agentowi trzydzieści tooli, pięć stron system promptów i długą historię konwersacji, a straci on focus. Zrobi zły tool call albo zapomni o ograniczeniach. Podejście multi-agentowe rozbija to na mniejsze części. Umożliwia to rozproszony development, w którym różne zespoły zarządzają różnymi agentami. Pozwala na równoległą egzekucję. A co najważniejsze, wymusza ścisłą izolację kontekstu. Dzisiaj skupimy się na konkretnej architekturze, czyli wzorcu Subagents. Polega to na tym, że główny agent, tak zwany supervisor, deleguje zadania do wyspecjalizowanych subagentów. Ludzie często mylą supervisora z prostym routerem. Router to po prostu statyczna funkcja, która patrzy na zapytanie i wysyła je jedną, z góry ustaloną ścieżką. Supervisor to aktywny, myślący agent. Utrzymuje stan konwersacji, decyduje, których subagentów wywołać w kolejnych turach i syntetyzuje ich odpowiedzi. I tu jest kluczowa sprawa. Subagenci zapewniają idealną izolację kontekstu. Kiedy supervisor prosi subagenta o zrobienie czegoś, subagent startuje z całkowicie czystym context window. Ma tylko te konkretne instrukcje i toole, których potrzebuje do swojego zadania. Subagent może popełniać błędy, robić tool call trzy razy i zapełniać swój własny scratchpad, próbując znaleźć odpowiedź. Supervisor nigdy nie widzi tego bałaganu. Dostaje tylko ostateczny, wyczyszczony wynik. To chroni twojego głównego agenta przed context bloat i zapobiega halucynacjom. Aby połączyć supervisora z subagentami, opakowujesz subagentów jako toole. W LangChain można to zrobić na dwa sposoby. Pierwsza metoda to tool-per-agent. Dajesz supervisorowi konkretny tool dla każdego subagenta. Jeśli masz pięciu subagentów, supervisor ma pięć tooli. Druga metoda to single-dispatch tool. W tym przypadku supervisor dostaje dokładnie jeden tool, nazwany na przykład delegate task. Ten tool wymaga dwóch inputów: nazwy docelowego agenta i opisu zadania. Weźmy pod uwagę scenariusz single-dispatch. Masz głównego agenta, agenta od researchu i agenta od pisania. Użytkownik prosi o złożony raport rynkowy. Główny agent decyduje, że najpierw potrzebuje danych. Robi tool call do single-dispatch tool, przekazując agenta od researchu jako target i zapytanie rynkowe jako payload. Agent od researchu odpala się w swoim własnym, odizolowanym kontekście, przeszukuje sieć, parsuje dokumenty i zwraca akapit z podsumowaniem. Główny agent otrzymuje ten tekst. Następnie główny agent ponownie wywołuje dispatch tool, tym razem targetując agenta od pisania, przekazując podsumowanie researchu i instrukcje formatowania. Agent od pisania tworzy draft końcowego raportu i zwraca go do głównego agenta, który dostarcza go użytkownikowi. Możesz wykonywać te podzadania na różne sposoby, w zależności od twoich potrzeb. Możesz odpalać subagentów synchronicznie, gdzie supervisor czeka, aż agent od researchu skończy, zanim podejmie jakąkolwiek inną akcję. Jeśli masz niezależne zadania, takie jak zrobienie researchu trzech różnych konkurentów, możesz odpalić subagentów asynchronicznie. Supervisor dispatchuje wszystkie trzy zadania naraz, wykonują się one równolegle, a supervisor czeka na zwrot ze wszystkich, zanim przejdzie dalej. Grupowanie zadań w subagentów to nie tylko organizacja twojego kodu, to ścisła kontrola nad tym, co model językowy jest zmuszony trzymać w pamięci w danym momencie. To wszystko w tym odcinku. Dzięki za wysłuchanie i buduj dalej!
17

Agenci sterowani stanem

3m 53s

Badamy, jak agenci mogą dynamicznie zmieniać swoje zachowanie. Poznasz wzorzec Handoffs do przekazywania kontroli oraz wzorzec Skills do ładowania wyspecjalizowanych promptów na żądanie.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 17 z 20. Nie musisz z góry ładować do mózgu swojego agenta każdego możliwego scenariusza. Wrzucenie pięćdziesięciu stron instrukcji w jeden system prompt sprawia tylko, że twój model jest zagubiony, wolny i drogi. Musisz go tylko nauczyć, jak poprosić o odpowiednią instrukcję, gdy przyjdzie na to czas. To główny mechanizm działania State-Driven Agents. State-driven agents działają w oparciu o prostą zasadę. Zachowanie agenta zmienia się dynamicznie w zależności od aktualnego stanu aplikacji. Obsługujemy to za pomocą dwóch głównych wzorców, którymi są Skills i Handoffs. Oba wzorce opierają się na toolsach do aktualizacji zmiennych stanu, które z kolei decydują o tym, co wydarzy się dalej w workflow. Przyjrzyjmy się najpierw wzorcowi Skills. W tym wzorcu chodzi o stopniowe odkrywanie wiedzy. Zamiast dawać agentowi wszystkie instrukcje na starcie, dajesz mu tool. Kiedy agent uzna, że potrzebuje więcej informacji do rozwiązania problemu, wywołuje ten tool. Tool się wykonuje, ale robi coś więcej niż tylko zwrócenie stringa do modelu. Aktualizuje konkretną zmienną stanu w twojej aplikacji. Twoja warstwa orkiestracji monitoruje ten stan. Kiedy wykryje zmianę, dynamicznie wstrzykuje nowy zestaw instrukcji lub możliwości do system promptu agenta na samą następną turę. Weźmy na przykład standardowego agenta obsługi klienta. Początkowo jego jedynym zadaniem jest zorientowanie się, czego chce klient. Użytkownik pyta o zepsuty produkt. Agent wywołuje tool, aby zebrać ID gwarancji. Wykonanie tego toola aktualizuje zmienną stanu, wskazując, że proces reklamacji jest aktywny. Aplikacja odczytuje ten nowy stan i dynamicznie ładuje do promptu wyspecjalizowany skill zwrotu pieniędzy. Ten skill może zawierać konkretne zasady przetwarzania zwrotów i dostęp do bezpiecznej bazy danych magazynu. Możliwości agenta ewoluowały w połowie konwersacji, napędzane wyłącznie przez aktualizację stanu. A co, jeśli wymagane zadanie jest zbyt skomplikowane dla początkowego agenta, nawet z nowymi skillami? Wtedy wkracza wzorzec Handoff. Handoffy również używają toolsów do aktualizacji stanu, ale zamiast ładować nowe instrukcje do obecnego agenta, zmiana stanu przekazuje kontrolę zupełnie innemu agentowi. Wróćmy do naszego scenariusza. Agent wsparcia zbiera ID gwarancji, ale zamiast samemu przetwarzać zwrot, wywołuje handoff tool. Ten tool aktualizuje zmienną routingu w stanie, zmieniając aktywnego agenta z bota do triażu na agenta specjalistę, zaprojektowanego wyłącznie do zwrotów o wysokiej wartości. Warstwa orkiestracji widzi tę zmianę stanu i kieruje kolejny krok workflow do specjalisty. To właśnie w tym punkcie przejścia rzeczy często się psują. Przy robieniu handoffu między agentami, nowy agent potrzebuje kontekstu konwersacji. Wielu developerów próbuje wyczyścić historię, przekazując nowemu agentowi tylko surowe wiadomości użytkownika. Nie rób tego. Podczas handoffu między agentami, musisz dołączyć wiadomość AI zawierającą właściwy tool call, który zainicjował handoff, oraz wynikową wiadomość Tool, która potwierdza, że handoff miał miejsce. Jeśli wyrzucisz tool call i wiadomość Tool z message array, historia konwersacji się psuje. Nowy model traci logiczny ciąg zdarzeń. Nie będzie wiedział, jak się tam znalazł, i prawdopodobnie powtórzy pytania, na które użytkownik już odpowiedział. Zawsze przekazuj nieprzerwaną historię wiadomości. Oto kluczowy wniosek. Stan to nie tylko pasywny magazyn pamięci, ale control plane, który dokładnie dyktuje, co twój system jest w stanie zrobić w każdej danej milisekundzie. To wszystko w tym odcinku. Dzięki za odsłuch i buduj dalej!
18

Niestandardowe przepływy pracy i rutery

4m 32s

Wychodzimy poza standardową pętlę agenta. Dowiesz się, jak używać LangGraph do budowania niestandardowych architektur routingu, łącząc deterministyczną logikę z niedeterministycznym wnioskowaniem agentowym.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 18 z 20. Czasami nie chcesz, aby agent AI swobodnie decydował, co zrobić dalej. Chcesz po prostu, aby wykonał ścisły, deterministyczny flowchart. Custom workflows i routery dają ci dokładnie taki poziom kontroli. Kiedy polegasz wyłącznie na standardowym agent loopie, ufasz, że model językowy sam wymyśli każdy kolejny krok. Może przeszukać bazę danych, zorientować się, że potrzebuje więcej danych, poszukać jeszcze raz i w końcu odpowiedzieć. To potężne narzędzie, ale bywa nieprzewidywalne i często działa wolno. Custom workflows w LangGraph pozwalają ci wyrwać się z tego loopa. To ty rysujesz mapę. Możesz płynnie łączyć deterministyczną logikę, jak odpalanie konkretnych skryptów do pobierania danych, z niedeterministycznym rozumowaniem agenta. Zamykasz model językowy w ścisłej sekwencji zdarzeń. Zanim go zbudujemy, musimy wyjaśnić częste mylenie routera z supervisorem. Supervisor aktywnie orkiestruje wieloetapową konwersację. Obserwuje, jak agenci rozmawiają, decyduje, kto mówi następny, i zarządza dialogiem w czasie. Router działa inaczej. Router to po prostu krok klasyfikacji. Patrzy na input, decyduje, którą ścieżką powinien pójść workflow, routuje dane i na tym jego rola się kończy. Może być stateless lub stateful, ale nie jest menedżerem konwersacji. Spójrzmy na konkretny scenariusz. Budujesz narzędzie typu knowledge base oparte na wielu źródłach. Użytkownik zadaje pytanie, a odpowiedź może być zakopana w pull requestach na GitHubie, wątkach na Slacku, albo tu i tu. Nie chcesz, żeby pojedynczy agent w ciemno zgadywał, gdzie szukać. Chcesz mieć ustrukturyzowany workflow. Najpierw tworzysz node routujący. Przekazujesz query użytkownika do modelu językowego i prosisz go o zwrócenie prostej listy miejsc docelowych. Jeśli query dotyczy niedawnego bugfixa, model może zwrócić słowa GitHub i Slack. I to jest kluczowy moment. Nie musisz wybierać tylko jednej ścieżki. Możesz odpalić wielu agentów dokładnie w tym samym czasie, używając Send API. W LangGraph, zamiast zwracać pojedynczy kolejny krok z twojej logiki warunkowej, twoja funkcja routująca zwraca listę komend Send. Każda komenda paruje docelowy node z konkretnymi danymi, których on potrzebuje. Graf widzi wiele komend Send i automatycznie wykonuje wszystkie te docelowe node'y równolegle. Nazywa się to fanning out. Podczas fan-outu, workflow trafia na twoje node'y agentów. W custom workflow, wywołanie agenta jest proste. Agent to po prostu proces typu runnable, wykonywany wewnątrz standardowej funkcji node'a. Node Slacka odbiera query, odpala dedykowanego agenta Slacka do przeszukania kanałów, wyciąga kontekst i zwraca go do ogólnego state'u grafu. Node GitHuba robi dokładnie to samo w tym samym czasie dla repozytoriów kodu. Izolowanie tych agentów wewnątrz konkretnych node'ów daje pewność, że robią tylko to, do czego zostały stworzone. Na koniec wszystkie te równoległe gałęzie muszą się połączyć. Robisz fan-in. Tworzysz node syntezujący, który czeka, aż równolegli agenci skończą pracę. Odczytuje ogólny state grafu, bierze kontekst zebrany ze Slacka i kontekst z GitHuba, przekazuje je oba do końcowego modelu językowego i generuje jedną, czystą odpowiedź dla użytkownika. Prawdziwa siła custom workflows polega na opakowaniu nieprzewidywalnej natury dużych modeli językowych w przewidywalną niezawodność standardowego software'owego routingu. To tyle w tym odcinku. Do usłyszenia następnym razem!
19

Komunikacja Agent-to-Agent

5m 19s

Odkrywamy endpoint LangSmith A2A. Dowiesz się, jak rozproszeni agenci wdrożeni na zupełnie różnych serwerach mogą natywnie konwersować przy użyciu protokołu A2A RPC od Google.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 19 z 20. Co się dzieje, gdy agent zbudowany w Pythonie musi natywnie komunikować się z agentem zbudowanym przez zupełnie inny zespół, działającym na zupełnie innym serwerze? Jeśli polegasz na hardcodowanych wewnętrznych wywołaniach funkcji, twój system wysypuje się w momencie przekroczenia granicy sieci. Rozwiązaniem jest komunikacja Agent-to-Agent. Agent-to-Agent, czyli A2A, to protokół komunikacyjny, który umożliwia działanie prawdziwie rozproszonych systemów wieloagentowych. Pozwala agentom hostowanym na zupełnie różnych serwerach na utrzymywanie ciągłej konwersacji bez konieczności współdzielenia tego samego codebase'u ani lokalnej przestrzeni pamięci. Zamiast pakować wszystko w jedną, ogromną aplikację, routujesz requesty przez sieć. Komunikacja ściśle opiera się na zdefiniowanym formacie endpointu: slash a2a slash, a po nim assistant ID. Każdy agent uczestniczący w tej rozproszonej sieci wystawia dokładnie tę ścieżkę endpointu. Gdy jeden agent potrzebuje pomocy od drugiego, wysyła tam request HTTP POST. Payload wysyłany na ten endpoint jest ustrukturyzowany jako standardowa wiadomość JSON-RPC. Aby zachować spójność konwersacji podczas wielu przeskoków sieciowych i na różnych serwerach, protokół używa w swoim payloadzie dwóch odrębnych identyfikatorów. Developerzy czasami je mylą, więc zdefiniujmy ich granice. Pierwszy to Context ID. Context ID odpowiada za ogólną ciągłość wątku. Reprezentuje całą nadrzędną historię konwersacji, od pierwszego promptu do końcowego outputu. Drugi to Task ID. Task ID identyfikuje konkretny request lub krok w ramach tej pojedynczej tury. Context ID obejmuje całą sesję. Task ID zmienia się za każdym razem, gdy jeden agent prosi drugiego o wykonanie nowej akcji. Rozważmy praktyczny scenariusz, w którym Agent A działa na serwerze nasłuchującym na porcie 2024, a Agent B działa na innym serwerze na porcie 2025. Agent A orientuje się, że potrzebuje Agenta B do obsługi konkretnego subtaska, na przykład sprawdzenia zewnętrznych zasobów. Agent A przygotowuje wiadomość JSON-RPC. Wewnątrz tej wiadomości dołącza istniejący Context ID, dzięki czemu Agent B wie, do której trwającej konwersacji ona należy. Agent A generuje również zupełnie nowy Task ID dla tego konkretnego requestu o zasoby. Agent A wysyła ten payload na endpoint A2A na porcie 2025, wstawiając konkretny assistant ID Agenta B bezpośrednio do ścieżki URL. Agent B odbiera request. Odczytuje Context ID, aby przywołać niezbędny stan z tła, przetwarza zadanie z parametrów JSON-RPC i oblicza wynik. Następnie Agent B konstruuje odpowiedź JSON-RPC. Ta odpowiedź jawnie zawiera dokładnie ten sam Task ID, który pierwotnie podał Agent A. Agent B odsyła tę odpowiedź z powrotem do Agenta A na port 2024. Agent A odbiera wynik, dopasowuje Task ID do swojego oczekującego requestu i kontynuuje własne wewnętrzne działanie. Oto kluczowy wniosek. Ponieważ protokół wymusza standard JSON-RPC i izoluje śledzenie stanu do konkretnych identyfikatorów Context ID i Task ID, żaden z agentów nie musi wiedzieć, jak ten drugi działa wewnętrznie. Nie utrzymują stałego, otwartego połączenia po socketach. Po prostu na zmianę przesyłają ustrukturyzowane wiadomości w obie strony przez standardowe granice HTTP. Jeden serwer zadaje pytanie, drugi odpowiada, a nadrzędne zadanie idzie do przodu. Kiedy oddzielisz długoterminowy wątek konwersacji od wykonywania pojedynczych, krótkoterminowych tasków, możesz w nieskończoność skalować sieci wieloagentowe na różnych serwerach i frameworkach. Jeśli uważasz te odcinki za pomocne i chcesz wesprzeć program, możesz wyszukać DevStoriesEU na Patreonie. To wszystko w tym odcinku. Dzięki za wysłuchanie i koduj dalej!
20

Przyszłość to MCP

5m 11s

Patrzymy w przyszłość z Model Context Protocol, który standaryzuje sposób dostępu agentów do zewnętrznych narzędzi. Dowiesz się, jak łączyć zdalne serwery MCP ze swoim agentem przy użyciu standardowych transports.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, odcinek 20 z 20. Za każdym razem, gdy chcesz, żeby twój agent połączył się z nową bazą danych lub API, w końcu i tak piszesz customowy wrapper. Twój codebase wypełnia się kruchymi integracjami, które wysypują się przy każdej zmianie zewnętrznego API. To ogranicza tempo, w jakim możesz skalować swoje aplikacje. Rozwiązaniem tego integracyjnego wąskiego gardła jest Model Context Protocol, czyli MCP. Pomyśl o MCP jak o USB-C dla agentów AI. Standaryzuje on sposób, w jaki narzędzia i kontekst są wystawiane dla dużych modeli językowych. Przed tym protokołem, jeśli chciałeś, żeby twój agent odpytał bazę danych i sprawdził pogodę, musiałeś napisać dla obu dedykowane funkcje w Pythonie, ręcznie zdefiniować ich input schemas i podpiąć je pod swój model. Dzięki MCP, to sama zewnętrzna usługa dostarcza ustandaryzowany interfejs. Twój agent po prostu się do niego wpina i od razu rozumie, jakie narzędzia są dostępne, jakich argumentów wymagają i jak je wywołać. Częstym nieporozumieniem jest to, że używanie zdalnego serwera MCP oznacza, że logika twojego agenta przenosi się do sieci. Oto kluczowa sprawa. Twój agent pozostaje całkowicie lokalny. Zdalny serwer nie uruchamia twojego agenta ani nie kontroluje jego rozumowania. Wystawia on jedynie listę ustandaryzowanych JSON schemas, które reprezentują wspierane przez niego narzędzia. Twój lokalny agent czyta te schemas, decyduje, którego narzędzia użyć na podstawie user promptu, i wysyła request o wykonanie z powrotem do serwera. Wykonanie dzieje się tam, a surowy wynik wraca do twojego lokalnego agenta. W LangChain zarządzasz tymi połączeniami używając MultiServerMCPClient. Ten komponent działa jak centralny hub. Pozwala on pojedynczemu agentowi łączyć się z wieloma różnymi serwerami MCP jednocześnie, zbierając narzędzia z nich wszystkich. Klient obsługuje komunikację pod spodem używając różnych warstw transportowych. Dwa główne transporty, które będziesz konfigurować, to standard input i output, określane jako stdio, oraz HTTP. Przejdźmy przez konkretny scenariusz. Budujesz agenta, który musi wykonywać złożone obliczenia używając lokalnego skryptu w Pythonie, a jednocześnie pobierać na żywo dane pogodowe ze zdalnej usługi. Zamiast pisać customowe tool wrappery dla tych zadań, konfigurujesz MultiServerMCPClient, żeby obsłużył oba. Najpierw definiujesz swój lokalny serwer matematyczny używając transportu stdio. Konfigurujesz klienta podając komendę do uruchomienia, na przykład twój systemowy executable Pythona, oraz ścieżkę do twojego skryptu matematycznego. Kiedy klient się inicjalizuje, odpala ten skrypt jako lokalny proces w tle. Klient LangChain i skrypt przesyłają wiadomości w obie strony bezpośrednio przez strumienie standard input i standard output. Następnie definiujesz serwer pogodowy używając transportu HTTP. W tym celu podajesz po prostu URL endpointu zdalnej usługi pogodowej. Taki setup zazwyczaj opiera się na Server-Sent Events, żeby utrzymać stałe połączenie, pozwalając agentowi na requestowanie akcji i streamowanie odpowiedzi przez sieć. Kiedy oba transporty są zdefiniowane, inicjalizujesz MultiServerMCPClient. Klient natychmiast łączy się z lokalnym procesem matematycznym przez stdio i ze zdalnym URL-em pogodowym przez HTTP. Prosi oba serwery o przekazanie ich definicji narzędzi. Zbiera te schemas, merguje je w jedną ciągłą listę i przekazuje je do twojego agenta LangChain. Z perspektywy agenta, widzi on po prostu zunifikowaną listę dostępnych narzędzi. Jest on całkowicie nieświadomy, że jedno narzędzie wykonuje się w lokalnym procesie binarnym, a drugie triggeruje request HTTP do serwera na drugim końcu świata. Przejście na ustandaryzowane protokoły oznacza, że możesz poświęcić swój czas na budowanie lepszej logiki agenta, zamiast na utrzymywanie nieskończonej liczby API wrapperów. Ponieważ to już ostatni odcinek tej serii, gorąco zachęcam cię do przeczytania oficjalnej dokumentacji LangChain i spróbowania własnoręcznego postawienia lokalnego serwera MCP. Jeśli masz sugestie dotyczące tematów, które chcesz zobaczyć w naszej kolejnej serii, wejdź na devstories dot eu i zostaw nam wiadomość. Prawdziwa siła agenta nie leży w tym, co wie, ale w tym, z czym potrafi się płynnie połączyć. To wszystko w tym odcinku. Dzięki za słuchanie i twórz dalej!