Strona główna / Artykuły

Pamięć klienta dla agentów AI przy ścisłym budżecie tokenów

Jak warstwa pamięci agenta wyodrębnia fakty, ocenia ich znaczenie, usuwa duplikaty przy współczynniku kosinusa 0,92, przechowuje wektory w pgvector oraz odzyskuje dane w ramach limitu 2048 tokenów z mechanizmem wyrzucania.

Wydawca: REACTAPP.TOP8 min czytania1942 słów

Źródła: Engineering a Multi-Agent AI Platform — Part 6: Memory Under Token Constraints

Pracownik obsługi klienta rozmawia z klientem, a wszystko, czego potrzebuje, musi zmieścić się w jednym oknie kontekstowym. GPT-4o oferuje 128K tokenów, natomiast mniejsze modele mogą dostarczać 32K lub mniej. To okno musi zawierać instrukcje systemu, definicje narzędzi, pozyskane informacje, bieżącą rozmowę oraz wszystko, co pracownik pamięta o danym klientie. Ten tekst opisuje projekt pamięci dla takiego układu: w jaki sposób fakty są wydobywane z zakończonych rozmów, oceniane, usuwane z duplikatami, przechowywane jako wektory i ponownie pobierane przy ścisłym limicie tokenów.

Okno to budżet, a nie pojemnik

Wszystko, co wiadomo o klientie, trafia do instrukcji systemu, przez co pozostałe dane muszą zostać pominięte. Pozyskiwanie informacji jest ograniczone, historia rozmów jest skracana, a instrukcje systemu mogą zostać umieszczone tak daleko w tekście, że model traci orientację co do własnych wytycznych.

Nie należy nic dodawać, dzięki czemu agent traktuje każdą rozmowę jak pierwsze spotkanie. Klient, który pyta o godzinę umówienia, otrzymuje odpowiedź „Nie mam tych informacji”, mimo że podał je w zeszły wtorek.

Rozwiązaniem jest ustalony limit pamięci klienta. W opisanym tutaj projekcie wynosi on 2 048 tokenów. W ramach tego limitu system przechowuje te fakty, które są najważniejsze dla danego klienta w danej rozmowie. Nie wszystkie fakty, nie te losowe, tylko te właściwe.

Wydobywanie faktów z zakończonych rozmów

Gdy rozmowa się kończy, uruchamiany jest proces konsolidacji, który przegląda ją w poszukiwaniu faktów wartych zachowania. Proces wydobywania informacji wykorzystuje model językowy LLM (GPT-4o-mini) z ustrukturyzowanym promptem, który pyta o te fakty dotyczące klienta, które można uzyskać, oraz ocenia każdy fakt w skali od 0 do 1 pod kątem specyficzności, możliwości zastosowania i częstotliwości występowania.

Słowem kluczowym jest „specyficzny”. Fakty muszą opisywać konkretnego klienta, a nie zawierać ogólnikowych spostrzeżeń. „Woli umowy rano” to fakt. „Zadał pytanie” – nie jest nim.

Model odpowiada tablicą JSON, w której każdy element zawiera ciąg tekstu oraz ocenę ważności. Proces przetwarzania przechowuje tylko te fakty, których ocena wynosi co najmniej 0,5. Ta granica eliminuje nieistotne spostrzeżenia, których ocena zwykle mieści się w przedziale 0,2–0,3, i zachowuje wszystko, co może być przydatne później.

Typowa wymiana dziesięciu wiadomości daje od dwóch do czterech faktów spełniających kryteria, a długa sesja rozwiązywania problemów może przynieść od sześciu do ośmiu. Większość rozmów dostarcza co najmniej jeden taki fakt.

Co obejmuje ocena ważności

Jedna liczba od 0,0 do 1,0 łączy w sobie trzy cechy.

  • Specyficzność. Jak konkretny jest ten fakt w odniesieniu do danego klienta? „Woli e-mail zamiast telefonu” jest takim przykładem, natomiast „Jest klientem” nie.
  • Zastosowalność. Czy agent może go wykorzystać, aby lepiej odpowiedzieć następnym razem? „Ma powtarzający się problem z fakturą nr 4821” spełnia ten warunek, podczas gdy „Powiedział cześć” – nie.
  • Powtarzalność. Czy będzie to istotne w kilku rozmowach? Czas zona UTC+3 pojawia się za każdym razem, gdy mowa o planowaniu, natomiast pytanie o dzisiejszą pogodę występuje tylko raz.

Zespół odpowiedzialny za projekt przetestował oddzielne oceny dla każdej dimensji i stwierdził, że połączona ocena daje lepsze wyniki przy jednoczesnym zachowaniu prostoty zapytania. Według ich pomiarów próg 0,5 odrzuca około 60% wyekstrahowanych faktów, pozostawiając tylko te o wysokim znaczeniu.

Embeddingi i kontrola duplikatów

Każdy zachowany fakt jest zapisywany jako wektor o 3072 wymiarach, co odpowiada po prostu rozdzielczości wyjściowej używanego modelu embedowania, OpenAI’s text-embedding-3-large. Więcej wymiarów umożliwia dokładniejsze rozróżnianie podobieństw, co jest przydatne, gdy trzeba odróżnić przeformułowaną informację od naprawdę nowego danych.

Zanim nowy fakt zostanie zapisany, porównuje się go ze wszystkimi istniejącymi faktami tego klienta. Podobieństwo kosinowe powyżej 0.92 oznacza „duplikat, pominąć”.

Dlaczego właśnie ta liczba? Ludzie wyrażają jedną rzecz na wiele sposobów. „Woli komunikację e-mailem”, „Chce być kontaktowany e-mailem” oraz „Powiedział, że rzadko sprawdza telefon, więc używa e-maila” – to wszystko opisuje ten sam podstawowy fakt. Przy wartości 0,92 system skutecznie wykrywa takie semantyczne powtórzenia. Niższe progi, takie jak 0,85 lub 0,88, zaczynały łączyć fakty, które w rzeczywistości były różne, natomiast wyższe, jak 0,95 lub 0,97, pozwalały na gromadzenie zbyt wielu różnych sformułowań.

Ta weryfikacja odbywa się przy każdym cyklu konsolidacji. Bez niej klient, który w każdej rozmowie podaje swój strefę czasową, mógłby zgromadzić dziesiątki niemal identycznych rekordów, co powodowałoby marnotrawstwo przestrzeni przechowywania oraz zasobów potrzebnych do wyszukiwania.

Dlaczego Postgres z pgvector

Fakty przechowywane są w PostgreSQL z użyciem rozszerzenia pgvector do przeprowadzania wyszukiwań podobieństwa. Rekord customer_memories zawiera:

  • content – fakt w postaci zwykłego tekstu
  • embedding – kolumna typu vector(3072) używana do wyszukiwania podobieństw
  • importance – ocena przypisana podczas wydobywania informacji
  • source_channel – miejsce, gdzie fakt został pozyskany (webchat, whatsapp, głos itp.)
  • created_at – data pierwszej insercji
  • last_accessed_at – najnowszy moment, w którym został użyty w czacie

Zwykłą alternatywą jest dedykowany magazyn takie jak Qdrant lub Pinecone, ale istnieją trzy powody przeciwko niemu.

  1. Kolekcje są bardzo małe. Maksymalnie 500 faktów na klienta. Dodatkowa usługa wprowadza dodatkowe etapy przesyłania danych, konieczność obsługi połączeń oraz problemy z spójnością, które przy takiej skali nie są uzasadnione.
  2. Transakcje są ważne. Dane należą do rekordu klienta. Gdy klient jest usuwany zgodnie z GDPR, jego dane muszą zniknąć wraz ze wszystkim innym. W pgvector jest to jedna transakcja, podczas gdy oddzielny magazyn wektorów wymagałby zgodności rozproszonej.
  3. Zapytanie jest proste. Filtruj według customer_id przy dokładnym dopasowaniu, a następnie sortuj według podobieństwa wektorów – pgvector radzi sobie z tym efektywnie dzięki indeksowi złożonemu.

Baza wiedzy to inna sprawa. Dokumentacja produktów, FAQ oraz podręczniki polityk znajdują się w Qdrant, ponieważ ta kolekcja jest duża, zawiera tysiące dokumentów na użytkownika, obsługuje duży ruch i nie wymaga powiązań transakcyjnych z danymi relacyjnymi. Inny problem, inny narzędzie.

Pobieranie z ograniczeniem liczby tokenów

Gdy przychodzi nowa wiadomość, a agent musi na nią odpowiedzieć, aktywuje się pobieranie z pamięci:

  1. Wbuduj przychodzącą wiadomość za pomocą tego samego modelu o wymiarze 3072 używanego do przechowywania.
  2. Wybierz dziesięć najbliższych wierszy z customer_memories dla danego customer_id, ułożonych według odległości <=> pomiędzy każdym przechowywanym embeddingiem a wektorem zapytania.
  3. Przejrzyj wyniki w kolejności podobieństwa, utrzymując aktualną liczbę tokenów.
  4. Oszacuj liczbę tokenów każdego faktu jako len(content) / 4 – to przybliżona, ale konserwatywna wartość.
  5. Zatrzymaj się, gdy dodanie kolejnego faktu spowoduje przekroczenie liczby 2048 tokenów.
  6. Uaktualnij last_accessed_at dla każdego pobranego faktu.

Operator <=> podaje odległość kosinową, więc im mniejsza wartość, tym bliższe jest dopasowanie do aktualnej wiadomości.

Limit to 2 048 tokenów sprawia, że sufit jest dość wysoki. Agent otrzymuje najbardziej istotne fakty, uporządkowane według ich znaczenia. Jeśli najważniejszy fakt zajmuje 800 tokenów, może zmieścić się tylko dwa lub trzy inne, natomiast jeśli każdy fakt jest krótki – od 50 do 80 tokenów – może ich być od piętnastu do dwudziestu. Budżet automatycznie dostosowuje się do rzeczywistej treści bez konieczności ręcznej regulacji. Dziesięć wierszy jako standard rzadko ma znaczenie w praktyce, ponieważ najczęściej pierwszym ograniczeniem jest limit tokenów, ale zapobiega to nieograniczonemu rozmiarowi zapytań do bazy danych.

Zapisanie wartości last_accessed_at pełni dwie funkcje: informuje politykę usuwania, które fakty nadal zachowują swoje miejsce, oraz pokazuje, na jakie informacje agent faktycznie się powołuje, a które pozostają nieużywane.

Limit 500 faktów i kto zostaje usunięty

Klient może mieć maksymalnie 500 przechowywanych faktów. Ten limit zapewnia przewidywalne koszty przechowywania na klienta oraz szybkie wyszukiwanie, ponieważ podobieństwo kosinowe dla 500 wektorów jest szybkie i istotne, natomiast przy 50 000 wektorach staje się niespójne.

Gdy proces konsolidacji ma na celu zachowanie jakiegoś faktu, a klient ma już 500 faktów, rozpoczyna się ich usuwanie. Kolejność usuwania:

  1. Fakty nienaruszone od 90 dni lub dłużej, które są przestarzałe i prawdopodobnie już nieistotne.
  2. Wśród pozostałych – te o najniższej ocenie ważności.
  3. W przypadku remisów – najstarszy rekord created_at.

Dziewięćdziesiąt dni pasuje do kontekstu biznesowego. Fakt poznany trzy miesiące temu i nigdy od tamtej pory nie wykorzystany raczej nie będzie miał znaczenia, natomiast informacja pozyskana sześć miesięcy temu i używana cotygodniowo, na przykład jako preferencja strefy czasowej, pozostaje niezmieniona, ponieważ jej last_accessed_at jest ciągle aktualizowany. Usunięcia następują po każdej konsolidacji, która osiągnęła limit, i dotyczą tylko tego, co jest konieczne – zazwyczaj od jednej do trzech informacji, a nie masowego czyszczenia.

Pamięć i wiedza to różne rzeczy

Te dwa systemy rozwiązują różne problemy i konkurują o ten sam zasób.

Pamięć jest przypisana do każdego klienta, mała, osobista i powstaje w wyniku interakcji: imię córki to Amara, raporty powinny być w formacie PDF, wcześniejsza skarga dotycząca dostawy została rozwiązana poprzez przyznanie 15% kredytu. Wiedza natomiast jest przypisana do każdego najemcy lub jest globalna, duża, udostępniana i tworzona przez ludzi: dokumentacja produktu, tabele cenowe, zasady zwrotów oraz przewodniki diagnostyczne.

Każdy z nich ma swój własny budżet tokenów: 2 048 na pamięć oraz większy, zazwyczaj od 4 096 do 8 192, na wiedzę. Dzielą się oknem kontekstowym modelu, nie wpływając na siebie nawzajem. Nawet jeśli pamięć zużyje cały swój budżet, wiedza nadal otrzymuje swój pełny limit.

Taki podział zapobiega niepożądanym sytuacjom. Bez oddzielnych budżetów klient posiadający 500 szczegółowych faktów mógłby zdominować proces wydobywania wiedzy, w wyniku czego agent pamiętałby wszystko o tej osobie, zapominając przy tym o dokumentacji produktu, której potrzebuje, by im pomóc.

Jak pamięć wpływa na głębokość rozumowania

Pamięć w dwóch sposobach dostarcza również danych do klasyfikatora złożoności, który decyduje, ile rozumowania wymaga dana prośba.

Pierwszym jest sygnał „zależności od kontekstu”. Gdy wyszukiwanie zwraca bardzo istotne fakty, co oznacza niską odległość kosinową od bieżącej wiadomości, wartość wskaźnika context_dependency wzrasta. Klasyfikator interpretuje to jako „odpowiedź zależy od danych specyficznych dla klienta” i może przesłać zapytanie do wyższego poziomu rozumowania. Pytanie „Czy może pan sprawdzić mój zamówienie?” otrzymuje wyższą ocenę, gdy przechowywane fakty odnoszą się do zamówienia w toku, niż to samo pytanie od klienta bez historii zamówień.

Drugim problemem jest konkurencja z budżetem przeznaczonym na rozmyślanie. W trybie pełnej ścieżki rozumowania model przydziela 4 096 lub 16 384 tokenów na rozmyślanie, w zależności od złożoności. Fakty pamięciowe wprowadzone do promptu wykorzystują tokeny z tego samego ograniczonego okna, więc klient posiadający 2 048 tokenów pamięci ma mniej miejsca niż ten, który ma 200 tokenów. Budżety te są zarządzane niezależnie i każdy z nich stanowi sztywny limit, więc system nigdy nie zamienia jednego na drugi.

Części, które wciąż są trudne

Dwie trudności nie są pokazane na diagramie architektury.

Drift faktów. Preferencje się zmieniają. „Woli umówienia rano” może po trzech miesiącach przekształcić się w „woli umówienia po południu”. System nie wykrywa automatycznie sprzeczności pomiędzy nowymi a starymi faktami. Progiem 0.92 udaje się czasami je zauważyć, gdy nowe stwierdzenie jest na tyle podobne do starego, by się pokrywać, ale nie zawsze. Na razie stare fakty przechodzą przez zasady dotyczące wieku i dostępu, a lepsze radzenie sobie ze sprzecznościami znajduje się na liście planów rozwoju.

Halucynacje wynikające z ekstrakcji. Model językowy używany do ekstrakcji czasami wnioskuje rzeczy, których nikt nie powiedział. Neutralne pytanie sformułowane w określony sposób może zostać zapisane jako „klient wydaje się sfrustrowany produktem”. Progiem 0,5 usuwane są najsłabsze wnioski, ale nie wszystkie. Redukcja duplikatów pomaga pośrednio, ponieważ wymyślone wnioski rzadko się powtarzają, więc pozostają jako rzadko używane wpisy, dopóki ich nie usunięto.

Nic tutaj nie stanowi ostatecznego rozwiązania. Obie te problemy są radzone poprzez ograniczenia, politykę usuwania oraz sygnał częstotliwości dostępu, które łącznie faworyzują najnowsze, często używane i najważniejsze fakty. Przestarzałe domysły i nieaktualne preferencje trafiają na dno i są usuwane, gdy potrzebna jest wolna przestrzeń.

Dwa główne kierunki w podsumowaniu

Po rozmowie pipeline konsolidacji wyodrębnia fakty za pomocą LLM, ocenia ich znaczenie, filtrowa je przy progu 0,5, generuje embeddingi, usuwa duplikaty przy progu kosinusowym 0,92, przechowuje to, co nowe, a usuwa dane po osiągnięciu limitu 500 faktów. Przed udzieleniem odpowiedzi nadchodząca wiadomość jest przekształcana w embedding, najważniejsze fakty są wybierane na podstawie podobieństwa kosinusowego, gromadzone w ramach budżetu 2048 tokenów i wprowadzane do kontekstu agenta.