Przejdź do treści
DedicatedPHP Kontakt

Pamięć konwersacyjna w PHP: jak odizolować kontekst między użytkownikami i organizacjami

Zaprojektuj pamięć asystenta w PHP tak, aby każda rozmowa respektowała tożsamość, organizację i aktualne uprawnienia — bez mieszania kontekstów.

Schemat koncepcyjny rozmów odizolowanych według użytkownika i organizacji w aplikacji PHP

Gdy asystent odpowiada informacjami dotyczącymi innej osoby lub firmy, problem nie ogranicza się do jakości: może dojść do naruszenia prywatności i kontroli dostępu. W wieloużytkownikowej aplikacji PHP pamięć konwersacyjną należy traktować jak dane o określonym właścicielu, zakresie i cyklu życia. Samo zapisywanie wiadomości i pobieranie ich na podstawie identyfikatora sesji nie wystarczy.

Izolacja kontekstu konwersacyjnego w aplikacjach PHP polega na zagwarantowaniu, że materiał używany do wygenerowania odpowiedzi należy do bieżącej rozmowy i nadal jest autoryzowany. Obejmuje to wcześniejsze wiadomości, podsumowania i wszelkie pobrane dane. Wyszukiwanie w dokumentach może uzupełniać kontekst, ale podlega innym zasadom dostępu i służy innym celom.

Oddziel pamięć konwersacyjną, historię i dokumenty

Oddziel pamięć konwersacyjną, historię i dokumenty — guía visual de DedicatedPHP

Pełna historia to zapis wiadomości z rozmowy. Pamięć jest natomiast podzbiorem, który aplikacja decyduje się pobrać na potrzeby konkretnego zadania — na przykład ostatnie tury rozmowy lub zaktualizowane podsumowanie. Dokumenty pobrane za pomocą wyszukiwania stanowią odrębne źródło, wybierane na podstawie zapytania i uprawnień do dokumentów. Nie należy ich mylić ani zapisywać tak, jakby były wiadomościami wypowiedzianymi przez użytkownika.

To rozróżnienie ułatwia podejmowanie decyzji, które można zweryfikować. Historię można zachować ze względów audytowych lub produktowych, a jednocześnie ograniczyć pamięć przekazywaną modelowi. Każdy fragment dokumentu może też zachować własne pochodzenie i kontrolę dostępu. Jeśli źródła zostaną zmieszane bez ich oznaczenia, trudniej wyjaśnić, jakie dane wpłynęły na odpowiedź, i zastosować wobec nich zasady retencji.

Określ właściciela każdej rozmowy

Zanim zaprojektujesz pobieranie danych, ustal stabilną tożsamość rozmowy. Uwzględnij co najmniej:

  • Rozmowa: losowy lub nieprzewidywalny identyfikator, przy czym sama jego znajomość nie powinna oznaczać dostępu.
  • Użytkownik: uwierzytelniona tożsamość, która rozpoczęła interakcję lub ma uprawnienia do jej przeglądania.
  • Organizacja: zakres danych, do którego należy rozmowa, jeśli aplikacja obsługuje wiele firm lub obszarów roboczych.
  • Aktualne uprawnienia: autoryzacja sprawdzana przy każdym odczycie, a nie bezterminowa kopia uprawnień początkowych.

Sesja internetowa może służyć do uwierzytelnienia żądania, ale nie powinna być jedynym trwałym kluczem określającym właściciela. Użytkownik może się wylogować, zmienić organizację lub utracić uprawnienie, gdy rozmowa nadal jest przechowywana. Przy każdym żądaniu aplikacja musi sprawdzić, czy bieżący użytkownik może uzyskać dostęp do tej rozmowy w ramach aktywnej organizacji.

Warto jawnie określić, co dzieje się przy zmianie kontekstu. Jeśli ktoś zmieni organizację, czy może kontynuować poprzednią rozmowę, powinien rozpocząć nową, czy może zachować tylko zatwierdzone podsumowanie? Nie ma jednej uniwersalnej odpowiedzi: zależy to od produktu i jego wymagań dotyczących prywatności. Decyzja powinna być odzwierciedlona w weryfikowalnych regułach, a nie w niejawnym założeniu interfejsu.

Stosuj zakres dostępu przed pobraniem kontekstu

Autoryzacja musi być częścią zapytania pobierającego dane i zostać zastosowana, zanim dane trafią do promptu. Najpierw pobranie szerokiego zbioru, a potem filtrowanie go w PHP zwiększa ryzyko, że błąd, alternatywna ścieżka lub wpis debugowania ujawni cudzą treść.

W relacyjnej bazie danych zapytanie może jednocześnie uwzględniać identyfikator rozmowy oraz uprawnionego użytkownika i organizację. Przykładowo, koncepcyjnie:

SELECT message_id, role, content, created_at
FROM conversation_messages
WHERE conversation_id = :conversation_id
  AND organization_id = :organization_id
  AND conversation_id IN (
      SELECT conversation_id
      FROM conversations
      WHERE owner_user_id = :user_id
         OR EXISTS (/* sprawdź aktualne uprawnienie */)
  )
ORDER BY created_at DESC
LIMIT :message_limit

Rzeczywisty schemat może być inny, ale najważniejsze jest to, by zakres dostępu ograniczał pobierane rekordy. Używaj parametrów wiązanych i spójnej warstwy autoryzacji dla operacji odczytu, zapisu, eksportu i usuwania. Jeśli korzystasz z bazy wektorowej lub usługi wyszukiwania, ograniczenia dotyczące organizacji i uprawnień muszą być stosowane w zapytaniu pobierającym dane; samo polecenie modelowi, by ignorował nieautoryzowane wyniki, nie wystarczy.

Gdy wyszukiwanie dokumentów i pamięć konwersacyjna są łączone, najpierw zastosuj autoryzację właściwą dla każdego źródła. Zachowuj metadane pochodzenia i nie przekształcaj wyników wyszukiwania dokumentów w trwałą pamięć bez jawnej polityki.

Zapobiegaj mieszaniu danych w pamięciach podręcznych, kolejkach i współdzielonych komponentach

Poprawny dostęp do bazy danych nie gwarantuje izolacji, jeśli inne warstwy współdzielą stan. Klucz pamięci podręcznej, taki jak conversation:123, może nie wystarczyć, jeśli ten sam identyfikator jest używany w więcej niż jednym zakresie, może zostać ponownie użyty albo konfiguracja cache dopuszcza kolizje. Uwzględnij w kluczu identyfikatory organizacji i rozmowy, a w razie potrzeby także wersję uprawnień lub danych. Nie umieszczaj poufnych treści w kluczu.

W zadaniach działających w tle przekazuj minimalny, jawnie określony kontekst: organizację, rozmowę, aktora i cel zadania. Podczas wykonywania ponownie sprawdź, czy zadanie nadal jest autoryzowane i nie korzysta z tożsamości pobranej ze współdzielonego stanu globalnego. Unikaj zmiennych statycznych, usług singleton zawierających zmienne dane użytkownika i obiektów sesji ponownie używanych między żądaniami, zwłaszcza w długotrwale działających procesach PHP.

Określ też, co ma się dziać w przypadku błędów i ponownych prób. Ponowiona próba zadania nie powinna zmienić organizacji wskutek stanu innego procesu, a odpowiedź zapisana w pamięci podręcznej nie powinna pozostać dostępna po cofnięciu uprawnień, jeśli polityka wymaga jej unieważnienia. Zachowanie systemu powinno być zamierzone i możliwe do zaobserwowania.

Ogranicz pamięć do informacji potrzebnych do zadania

Izolacja nie oznacza przekazywania modelowi całej historii. Pobieraj ostatnie tury rozmowy lub podsumowanie przydatne dla bieżącego żądania, z ograniczeniami liczby elementów i rozmiaru. Uwzględnij aktualność danych: starych preferencji, skorygowanych informacji i cofniętych decyzji nie należy automatycznie traktować jako aktualnych faktów.

Jeśli używasz podsumowań, zapisuj ich zakres i pochodzenie oraz aktualizuj je według jasnych reguł. Podsumowanie nie jest źródłem prawdy ani nie zastępuje kontroli uprawnień. W przypadku danych krytycznych odwołuj się do autoryzowanego systemu ewidencji zamiast polegać na stwierdzeniu zapisanym we wcześniejszej rozmowie. Małe okno kontekstowe ogranicza ujawnienie danych i koszty, ale nie rekompensuje błędnej autoryzacji.

Sprawdź, czy jedna rozmowa nie wpływa na drugą

Testy powinny obejmować zarówno dozwolony, jak i zabroniony dostęp. Przygotuj przypadki z różnymi użytkownikami i organizacjami, a następnie sprawdź, czy żądanie nie pobiera wiadomości, podsumowań ani dokumentów dotyczących innej tożsamości. Uwzględnij sytuacje brzegowe:

  • Użytkownik zmienia organizację, a następnie ponownie otwiera stary identyfikator rozmowy.
  • Uprawnienie zostaje cofnięte po utworzeniu rozmowy, ale przed pobraniem jej pamięci.
  • Dwóch użytkowników wysyła żądania jednocześnie, korzystając ze współdzielonych procesów, pamięci podręcznej lub infrastruktury kolejkowej.
  • Nieistniejący lub cudzy identyfikator powoduje kontrolowaną odpowiedź, która nie ujawnia, czy należy on do innej osoby.
  • Zadanie jest ponawiane po zmianie uprawnień lub organizacji.

Oprócz testów jednostkowych sprawdź cały przebieg — od uwierzytelnionego żądania po zbudowanie kontekstu. Możesz dodać wiadomości-znaczniki do oddzielnych rozmów i zweryfikować, że wynik pobrany dla każdej z nich nigdy nie zawiera znacznika z innej rozmowy. Celem jest przetestowanie granicy danych, a nie ocena, czy model tworzy przekonującą odpowiedź.

Badaj incydenty bez rejestrowania poufnych treści

Badaj incydenty bez rejestrowania poufnych treści — guía visual de DedicatedPHP

Obserwowalność powinna umożliwiać śledzenie przepływu bez kopiowania prywatnych wiadomości do logów. Rejestruj odpowiednie identyfikatory techniczne, decyzję autoryzacyjną, liczbę pobranych elementów, źródło danych, czas trwania i wynik każdego etapu. W miarę możliwości używaj identyfikatorów pseudonimizowanych oraz ograniczaj dostęp do logów i okres ich przechowywania.

Sygnały takie jak nieoczekiwany brak pobranych danych, niezgodność organizacji, nietypowy odsetek odmów lub ponowne użycie klucza pamięci podręcznej poza jego zakresem pomagają wykrywać błędy. Domyślnie unikaj rejestrowania pełnych promptów, dokumentów i odpowiedzi. Jeśli szczegółowa diagnostyka jest konieczna, ustanów tymczasową i autoryzowaną procedurę o ograniczonym zakresie, obejmującą redagowanie danych poufnych.

Bezpieczny projekt jawnie określa właściciela, zakres i aktualność każdego fragmentu kontekstu. Stosowanie tych reguł w zapytaniach, pamięciach podręcznych i zadaniach asynchronicznych oraz weryfikowanie przypadków negatywnych sprawia, że izolacja staje się sprawdzalną właściwością aplikacji PHP, a nie oczekiwaniem pokładanym w asystencie.

Chcesz zastosować te pomysły w swoim projekcie?Omówmy Twoją platformę PHP.
Zobacz powiązaną usługę