Wprowadzenie: Pamięć jako podstawa inteligencji
Model wielkojęzykowy bez pamięci jest jak ekspert cierpiący na amnezję: genialny w odpowiadaniu na pojedyncze pytania, ale nie jest w stanie zbudować trwałej relacji, uczyć się na podstawie przeszłych interakcji ani gromadzić wiedzy w czasie. Tam pamięć to właśnie zamienia bezpaństwowego LLM w agent trwałe, zdolne do zapamiętania, kim jesteś, o czym rozmawialiście i jakie decyzje wspólnie podjęliście.
Bez systemu pamięci każda interakcja zaczyna się od zera. Agent nie wie, że wczoraj naprawiłeś błąd w module uwierzytelniania nie pamięta, że wolisz Python od JavaScript, nie ma pojęcia, w którym projekcie pracujesz i masz termin za dwa tygodnie. Jednak dzięki pamięci agent staje się prawdziwym współpracownikiem: gromadzi kontekst, rozpoznaje powtarzające się wzorce i z czasem poprawia swoje reakcje.
W tym artykule przyjrzymy się systemom pamięci dla agentów AI, począwszy od najprostszych strategii takich jak historia rozmów aż do podejść zaawansowanych z osadzeniem wektorowym, wykresami wiedzy i wzorcem hybrydowym Mem0, który stanie się najlepszą praktyką w 2026 r. Przeanalizujemy kompromisy między kompletnością a kosztem, między dokładnością a opóźnieniem, zapewniając pseudokod i konkretną architekturę do wdrożenia każdego podejścia.
Czego dowiesz się w tym artykule
- Cztery rodzaje pamięci agentów AI: sensoryczna, krótkotrwała, długoterminowa i epizodyczna
- Strategie zarządzania historią rozmów: przesuwane okno, podsumowanie, próbkowanie ważności
- Jak działa osadzanie wektorów i wzorzec RAG (generowanie rozszerzone pobieranie).
- Wykresy wiedzy z Neo4j do wnioskowania relacyjnego
- Wzorzec hybrydowy Mem0: połączony magazyn wektorowy + wykres wiedzy
- Optymalizacja okna kontekstowego i budżet tokenów
- Benchmarking i kompromisy między różnymi podejściami do pamięci
Rodzaje pamięci w agentach AI
Badania nad systemami pamięci agentów AI inspirowane są ludzką psychologią poznawczą, dostosowującą koncepcje jako pamięć krótko- i długoterminowa w kontekście modeli językowych. Możemy wyróżnić cztery podstawowe typy pamięci, każdy o odmiennych cechach i przypadkach użycia.
Cztery typy pamięci
| Typ | Opis | Czas trwania | Przykład |
|---|---|---|---|
| Pamięć sensoryczna | Natychmiastowe wprowadzenie: bieżący monit i wyniki właśnie uruchomionych narzędzi | Pojedyncza iteracja | Wiadomość użytkownika, wynik zapytania SQL |
| Pamięć krótkotrwała | Kontekst bieżącej sesji: skumulowana historia rozmów | Pojedyncza sesja | Poprzednie wiadomości na czacie, podjęte decyzje |
| Pamięć długoterminowa | Trwała wiedza pomiędzy różnymi sesjami, zapisana w pamięci zewnętrznej | Stały | Preferencje użytkownika, dokumenty biznesowe, kod źródłowy |
| Pamięć epizodyczna | Specyficzne wspomnienia przeszłych interakcji w kontekście relacyjnym | Stały | „Moment, w którym naprawiliśmy błąd w parserze JSON” |
Pamięć sensoryczna: natychmiastowe wejście
Pamięć sensoryczna reprezentuje wszystko, co agent „postrzega” w danej chwili: wiadomość użytkownika, wyniki właśnie uruchomionych narzędzi, odpowiedzi wywoływanych API. To najwyższy poziom mała i przejściowa pamięć, która istnieje tylko przez czas trwania pojedynczej iteracji pętli agent. Nie wymaga żadnego mechanizmu trwałości, ponieważ działa całkowicie w bieżącym znaku zachęty.
W praktyce pamięć sensoryczna odpowiada parametrom przekazywanym modelowi w trybie pojedynczym wywołanie: monit systemowy, komunikaty użytkownika i asystenta oraz wyniki wywołań narzędzi. Ogranicza go okno kontekstowe modelu, które określa maksymalną liczbę tokenów, które można przetworzyć w jednym wniosku.
Pamięć krótkotrwała: kontekst sesji
Pamięć krótkotrwała utrzymuje kontekst w ramach pojedynczej sesji konwersacyjnej. Jest zaimplementowany jako lista komunikatów wymienianych pomiędzy użytkownikiem a agentem, zawierająca wyniki pośrednich wywołań narzędzi. Ta pamięć pozwala agentowi odwoływać się do czego jak już powiedziano wcześniej, aby rozwiązać niejasności kontekstowe i zachować spójność w dialogu.
Głównym problemem pamięci krótkotrwałej jest wzrost liniowy: tym więcej rozmowa trwa, zużywa się więcej tokenów. W przypadku modeli, które mają okno kontekstowe z 128K-200K tokenów, intensywna rozmowa techniczna może osiągnąć limit w ciągu kilku godzin pracy. Dlatego konieczne jest wdrożenie strategii kompresji i ustalania priorytetów.
Pamięć długoterminowa: wiedza trwała
Pamięć długoterminowa pozwala agentowi zapamiętać informacje pomiędzy różnymi sesjami. W przeciwieństwie do pamięci krótkotrwałej, która żyje w rozmowie, pamięć długoterminowa tego wymaga pamięć zewnętrzna: wektorowa baza danych, relacyjna baza danych, ustrukturyzowany system plików. Agent zapisuje istotne informacje podczas interakcji i odzyskuje je w razie potrzeby przyszłe sesje.
Przykładami pamięci długotrwałej są: preferencje użytkownika (język programowania preferowany, styl kodu, konwencje nazewnictwa), indeksowane dokumenty firmowe, wiedza podstawie projektu, specyfikacji technicznych i wymagań. Ten typ pamięci podlega przemianom agenta z ogólnego asystenta w spersonalizowanego i kontekstowego współpracownika.
Pamięć epizodyczna: wspomnienia specyficzne
Pamięć epizodyczna jest najbardziej wyrafinowanym typem: nie chodzi tylko o zapamiętywanie faktów, ale o pamiętaj konkretne doświadczenia z ich kontekstem relacyjnym. Agent pamięta nie tylko, że „jest błąd w parserze”, ale że „15 stycznia zdiagnozowaliśmy błąd w parserze Parser JSON spowodowany nieprawidłowym kodowaniem, które użytkownik rozwiązał, dodając walidację UTF-8 w przetwarzaniu wstępnym”.
Pamięć epizodyczna jest zwykle implementowana za pomocą grafów wiedzy, w których jednostki (ludzie, projekty, błędy, decyzje) to węzły i relacje między nimi (has_solved, has_caused, zależy_on) są łukami. Umożliwia to agentowi nawigację po połączeniach między zdarzeniami oraz zapewnienie bogatego i odpowiedniego kontekstu.
Zarządzanie historią rozmów
Historia rozmów to najszybsza forma pamięci: pełna lista wiadomości notowane na bieżącej sesji. Efektywne zarządzanie nim jest kluczowe ze względu na kontekst okno ma ustalony limit, a przekroczenie go oznacza utratę informacji lub, co gorsza, ich otrzymanie błędy z modelu. Istnieją trzy główne strategie, każda z własnymi kompromisami.
Strategia 1: Przesuwane okno
Najprostsze podejście: zachowaj tylko te ostatnie N wiadomości i odrzuć starsze. Jest łatwy do wdrożenia, przewidywalny w zużyciu tokenów i nie wymaga dodatkowych wywołań modeli. Minusem jest to, że całkowicie traci początkowy kontekst rozmowy, która może prowadzić do niespójności, gdy agent odwołuje się do decyzji podjętych na początku dialogu.
class SlidingWindowMemory:
def __init__(self, max_messages: int = 20):
self.max_messages = max_messages
self.messages: list[dict] = []
def add_message(self, role: str, content: str):
self.messages.append({"role": role, "content": content})
# Mantieni sempre il system prompt (indice 0)
if len(self.messages) > self.max_messages:
system = self.messages[0]
self.messages = [system] + self.messages[-(self.max_messages - 1):]
def get_context(self) -> list[dict]:
return self.messages.copy()
def token_count(self) -> int:
return sum(len(m["content"]) // 4 for m in self.messages)
Strategia 2: Stopniowe podsumowanie
Zamiast odrzucać stare wiadomości, stopniowo je podsumowuj. Kiedy rozmowa przekracza próg tokena, starsze wiadomości są kompresowane w zachowujące podsumowanie kluczowe informacje: podjęte decyzje, ważne fakty, wyrażone preferencje. Podsumowanie jest odpowiedzialny za aktywną rozmowę, utrzymując kontekst bez zużywania zbyt wielu tokenów.
Strategia ta wymaga dodatkowych wywołań modeli w celu wygenerowania podsumowań, które zwiększa koszty i opóźnienia. Jednak znacznie skuteczniej zachowuje kontekst w porównaniu do okna przesuwnego, ponieważ ważne informacje nigdy nie zostaną całkowicie utracone.
class SummarizationMemory:
def __init__(self, max_tokens: int = 4000, summary_threshold: int = 3000):
self.max_tokens = max_tokens
self.summary_threshold = summary_threshold
self.summary: str = ""
self.active_messages: list[dict] = []
def add_message(self, role: str, content: str):
self.active_messages.append({"role": role, "content": content})
if self._count_tokens(self.active_messages) > self.summary_threshold:
self._compress()
def _compress(self):
# Prendi i messaggi più vecchi (prima meta)
half = len(self.active_messages) // 2
old_messages = self.active_messages[:half]
self.active_messages = self.active_messages[half:]
# Genera un riassunto dei messaggi vecchi
prompt = f"Riassumi i punti chiave di questa conversazione:\n"
for msg in old_messages:
prompt += f"{msg['role']}: {msg['content']}\n"
new_summary = llm_call(prompt) # Chiamata al modello
self.summary = f"{self.summary}\n{new_summary}".strip()
def get_context(self) -> list[dict]:
context = []
if self.summary:
context.append({
"role": "system",
"content": f"Riassunto conversazione precedente:\n{self.summary}"
})
context.extend(self.active_messages)
return context
Strategia 3: Próbkowanie według ważności
Najbardziej wyrafinowane podejście: każda wiadomość jest oceniana indywidualnie znaczenie i tylko te istotne są trzymane w kontekście. Znaczenie można określić na podstawie kilka czynników: obecność jednoznacznych decyzji, odniesienie do kluczowych podmiotów projektu, wyrażanie preferencji, definicja ograniczeń lub wymagań.
Strategia ta daje najlepsze rezultaty pod względem jakości kontekstu, ale tak też jest najbardziej skomplikowany do wdrożenia. Do oceny ważności potrzebny jest model (lub heurystyka). każdego komunikatu oraz ryzyko wyeliminowania pozornie nieistotnych, ale kluczowych informacji i zawsze obecny.
class ImportanceSamplingMemory:
def __init__(self, max_tokens: int = 4000):
self.max_tokens = max_tokens
self.messages: list[dict] = []
self.importance_scores: list[float] = []
def add_message(self, role: str, content: str):
score = self._evaluate_importance(content)
self.messages.append({"role": role, "content": content})
self.importance_scores.append(score)
self._prune()
def _evaluate_importance(self, content: str) -> float:
score = 0.5 # Base score
# Decisioni esplicite
if any(kw in content.lower() for kw in ["deciso", "scelta", "usero", "implemento"]):
score += 0.3
# Vincoli e requisiti
if any(kw in content.lower() for kw in ["deve", "requisito", "vincolo", "deadline"]):
score += 0.2
# Errori e bug
if any(kw in content.lower() for kw in ["errore", "bug", "fix", "problema"]):
score += 0.2
# Messaggi recenti hanno un bonus
score = min(score, 1.0)
return score
def _prune(self):
while self._count_tokens() > self.max_tokens:
# Rimuovi il messaggio con l'importanza più bassa
# (escludi system prompt e ultimo messaggio)
min_idx = min(
range(1, len(self.importance_scores) - 1),
key=lambda i: self.importance_scores[i]
)
self.messages.pop(min_idx)
self.importance_scores.pop(min_idx)
Kompromis pomiędzy strategiami
| Strategia | Złożoność | Dodatkowy koszt | Kontekst jakości | Przypadek użycia |
|---|---|---|---|---|
| Przesuwane okno | Niski | Zero | Przeciętny | Krótkie rozmowy, prototypy |
| Streszczenie | Przeciętny | 1-2 połączenia LLM | Wysoki | Długie sesje, złożone zadania |
| Próbkowanie znaczenia | Wysoki | Heurystyka lub LLM | Bardzo wysoki | Agenci wyspecjalizowani, produkcja |
Osadzanie wektorów i generowanie wspomagane wyszukiwaniem
I osadzania wektorów są to gęste numeryczne reprezentacje tekstu w przestrzeni wielowymiarowy. Każde zdanie, akapit lub dokument zostaje przekształcony w wektor liczb (zwykle wymiary 768 lub 1536), gdzie odległość geometryczna między wektorami odzwierciedla podobieństwo semantyczne pomiędzy odpowiednimi tekstami. Dwa zdania o podobnym znaczeniu będą miały wektory blisko w przestrzeni, nawet jeśli używają zupełnie innych słów.
Jak działają osadzania
Proces osadzania wykorzystuje wyspecjalizowany model neuronowy (taki jak text-embedding-3-small
OpenAI lub all-MiniLM-L6-v2 of Sentence Transformers), który przyjmuje ciąg znaków jako dane wejściowe
tekstu i tworzy wektor numeryczny. Modele te są szkolone na ogromnych ilościach tekstu
w celu umieszczenia semantycznie podobnych zdań blisko siebie w przestrzeni wektorowej.
Wyszukiwanie podobieństwa odbywa się poprzez obliczenie małe podobieństwo lub Odległość euklidesowa pomiędzy wektorem zapytania a wektorami indeksowanego dokumentu. Najbardziej istotne dla zapytania są dokumenty charakteryzujące się najmniejszą odległością (lub największym podobieństwem).
import numpy as np
def cosine_similarity(vec_a: np.ndarray, vec_b: np.ndarray) -> float:
"""Calcola la similarità coseno tra due vettori."""
dot_product = np.dot(vec_a, vec_b)
norm_a = np.linalg.norm(vec_a)
norm_b = np.linalg.norm(vec_b)
return dot_product / (norm_a * norm_b)
# Esempio: embedding di due frasi
embedding_1 = embed("Come risolvere un bug nel parser JSON")
embedding_2 = embed("Fix di un errore nel parsing di file JSON")
embedding_3 = embed("Ricetta per la torta al cioccolato")
# Le prime due frasi avranno alta similarità (~0.85-0.95)
# La terza sarà molto distante (~0.05-0.15)
print(cosine_similarity(embedding_1, embedding_2)) # ~0.91
print(cosine_similarity(embedding_1, embedding_3)) # ~0.08
Bazy danych wektorowych: główne opcje
Baza danych wektorów to system przechowywania zoptymalizowany do przechowywania i wyszukiwania wektorów wysokowymiarowe. W przeciwieństwie do relacyjnych baz danych korzystających z indeksów drzewa B, wektor bazy danych korzystają z algorytmów takich jak HNSW (Hierarchiczny żeglowny mały świat) o Zapłodnienie in vitro (Odwrócony indeks plików), aby przeprowadzić przybliżone wyszukiwanie w czasie subliniowym.
Porównanie baz wektorowych
| Bazy danych | Typ | Punkt siły | Przypadek użycia |
|---|---|---|---|
| Szyszka | Zarządzane (w chmurze) | Skalowalność, zero operacji, indeksy bezserwerowe | Produkcja na dużą skalę, zespół bez infrastruktury |
| Tkać | Samodzielnie / w chmurze | Wyszukiwanie hybrydowe (wektor + BM25), GraphQL API | Wyszukiwanie zaawansowane z filtrami, e-commerce |
| Chroma | Wbudowane / hostowane samodzielnie | Lekki, natywny interfejs API języka Python, rozwój lokalny | Prototypy, zastosowania lokalne, rozwój |
| Qdrant | Samodzielnie / w chmurze | Wydajność, zaawansowane filtry, bogata ładowność | Aplikacje o wysokiej wydajności |
| pgwektor | Rozszerzenie PostgreSQL | Integracja z istniejącym stosem, SQL | Zespoły już korzystające z PostgreSQL |
Rurociąg RAG: generacja wzmocniona odzyskiwaniem
Wzór SZMATA (Retrieval-Augmented Generation) jest podstawową techniką zintegrować pamięć długoterminową z agentami AI. Pomysł jest prosty: zanim odpowiesz na a na pytanie agent przeszukuje bazę wiedzy pod kątem najbardziej odpowiednich dokumentów i uwzględnia je w zgłoszeniu jako dodatkowy kontekst. Dzięki temu model może opierać swoje odpowiedzi na informacjach konkretne i aktualne, redukujące halucynacje.
class RAGPipeline:
def __init__(self, vector_db, embedding_model, llm):
self.vector_db = vector_db
self.embedding_model = embedding_model
self.llm = llm
def ingest(self, documents: list[str], metadata: list[dict] = None):
"""Indicizza documenti nella knowledge base."""
for i, doc in enumerate(documents):
# 1. Chunking: dividi il documento in frammenti
chunks = self._chunk_document(doc, chunk_size=512, overlap=50)
for chunk in chunks:
# 2. Embedding: genera il vettore
vector = self.embedding_model.embed(chunk)
# 3. Store: salva nel vector database
self.vector_db.upsert(
id=f"doc_{i}_{hash(chunk)}",
vector=vector,
text=chunk,
metadata=metadata[i] if metadata else {}
)
def query(self, question: str, top_k: int = 5) -> str:
"""Rispondi a una domanda usando RAG."""
# 1. Embedding della query
query_vector = self.embedding_model.embed(question)
# 2. Retrieval: cerca i documenti più simili
results = self.vector_db.search(
vector=query_vector,
top_k=top_k,
threshold=0.7 # Soglia minima di similarità
)
# 3. Context assembly: costruisci il contesto
context = "\n\n---\n\n".join([r.text for r in results])
# 4. Generation: genera la risposta
prompt = f"""Rispondi alla domanda basandoti SOLO sul contesto fornito.
Se il contesto non contiene la risposta, dillo esplicitamente.
Contesto:
{context}
Domanda: {question}
Risposta:"""
return self.llm.generate(prompt)
def _chunk_document(self, doc: str, chunk_size: int, overlap: int) -> list[str]:
"""Dividi un documento in chunk con overlap."""
words = doc.split()
chunks = []
for i in range(0, len(words), chunk_size - overlap):
chunk = " ".join(words[i:i + chunk_size])
chunks.append(chunk)
return chunks
Najlepsze praktyki dotyczące fragmentowania
- Rozmiar kawałka: 256-1024 tokenów. Zbyt małe tracą kontekst, zbyt duże wprowadzają szum
- Zachodzić na siebie: 10-20% wielkości porcji, aby uniknąć zerwania koncepcji w połowie
- Kawałek semantyczny: wolą dzielić według akapitów lub sekcji logicznych, a nie według liczby znaków
- Metadane: powiąż źródło, datę i typ dokumentu z każdą porcją, aby filtrować wyniki
- Ponowne rankingowanie: Po pobraniu użyj modelu obejmującego wiele koderów, aby zmienić kolejność wyników według trafności
Grafy wiedzy dla pamięci relacyjnej
I wykresy wiedzy reprezentować wiedzę jako sieć jednostek (węzłów) połączone relacjami (łukami), z których każdy ma powiązane właściwości. W przeciwieństwie do wektorowych baz danych które wyróżniają się w wyszukiwaniu podobieństw semantycznych, wykresy wiedzy błyszczą w rozumowanie relacyjne: zrozum, w jaki sposób jednostki łączą się ze sobą, postępuj zgodnie z nimi łańcuchów relacji i wnioskować nową wiedzę z istniejących powiązań.
Struktura Grafu Wiedzy
Wykres wiedzy składa się z trzech podstawowych elementów:
- Węzły (elementy): reprezentują obiekty domeny. Każdy węzeł ma typ (etykietę), czyli zestaw właściwości. Przykład:
(:User {name: "Federico", role: "developer"}) - Ciągi (relacje): Łączą dwa węzły i mają typ i kierunek. Każdy łuk może mieć właściwości. Przykład:
[:RESOLVED {date: "2026-01-15", time_spent: "2h"}] - Nieruchomość: pary klucz-wartość powiązane z węzłami lub krawędziami, które dodają szczegółów i kontekstu
Neo4j to język szyfrowania
Neo4j jest to najpopularniejsza baza grafowa z deklaratywnym językiem zapytań
zadzwonił Szyfrować co sprawia, że nawigacja po wykresie jest intuicyjna. Cypher używa
składnia wizualna odzwierciedlająca strukturę wykresu: węzły są przedstawione w nawiasach
okrągły () i relacje w nawiasach kwadratowych [] ze strzałkami wskazującymi kierunek.
// Creare nodi e relazioni per la memoria episodica
CREATE (u:User {name: "Federico", role: "developer"})
CREATE (p:Project {name: "E-commerce API", language: "Python"})
CREATE (b:Bug {id: "BUG-142", description: "Parser JSON crash on UTF-8"})
CREATE (s:Session {date: "2026-01-15", duration: "45min"})
// Relazioni con proprietà
CREATE (u)-[:WORKS_ON {since: "2025-11-01"}]->(p)
CREATE (b)-[:FOUND_IN]->(p)
CREATE (u)-[:RESOLVED {method: "UTF-8 validation", time: "2h"}]->(b)
CREATE (s)-[:DISCUSSED]->(b)
CREATE (s)-[:INVOLVED]->(u)
// Query: Trova tutti i bug risolti da Federico con il contesto
MATCH (u:User {name: "Federico"})-[r:RESOLVED]->(b:Bug)-[:FOUND_IN]->(p:Project)
RETURN b.description, r.method, r.time, p.name
// Query: Ricostruisci la timeline di una sessione
MATCH (s:Session {date: "2026-01-15"})-[:DISCUSSED]->(topic)
MATCH (s)-[:INVOLVED]->(participant)
RETURN s.date, collect(topic.description), collect(participant.name)
// Query: Trova bug correlati per progetto e tipo
MATCH (b1:Bug)-[:FOUND_IN]->(p:Project)<-[:FOUND_IN]-(b2:Bug)
WHERE b1 <> b2 AND b1.description CONTAINS "parser"
RETURN b1.description, b2.description, p.name
Zalety Grafu Wiedzy dla pamięci
Wykresy wiedzy oferują wyjątkowe korzyści dla pamięci agentów AI niż wektorowe bazy danych nie mogą odpowiedzieć:
- Rozumowanie relacyjne: Agent może nawigować po relacjach między jednostkami, aby odkryć nieoczywiste powiązania. „Federico naprawił błąd BUG-142 występujący w projekcie E-commerce, a w tym samym projekcie występuje inny podobny błąd BUG-198”
- Wydajny kontekst: zamiast włączać całą historię do monitu, agent wyodrębnia tylko podgraf odnoszący się do bieżącego zapytania, oszczędzając tokeny
- Wnioskowanie: Można zdefiniować reguły wnioskowania, które wyprowadzają nową wiedzę z istniejących relacji. Jeśli A zależy od B i B zależy od C, to A zależy przechodnio od C
- Aktualizacja przyrostowa: Nowe informacje są dodawane jako nowe węzły i krawędzie, bez konieczności przebudowy całego indeksu
- Wyjaśnialność: Agent może prześledzić ścieżkę rozumowania na wykresie, dostarczając przejrzystych wyjaśnień
Podejście hybrydowe: wzorzec Mem0
Wzorzec Mem0: najlepsze praktyki 2026
Wzorzec wyłaniający się w 2026 r. dla systemów pamięci agentów AI łączy sklep wektorowy e wykres wiedzy w jeden spójny system. Nazwa „Mem0” (wymawiane „mem-zero”) odnosi się do projektu open source o tej samej nazwie i do wprowadzonego przez nią wzorca architektonicznego: pamięci, która zaczyna się od zera i rośnie organicznie przy każdej interakcji.
Architektura wzorca Mem0
Podstawowa idea jest prosta: kiedy agent otrzymuje nowe informacje, zapisuje je naraz w obu systemach przechowywania. Kiedy musi wyzdrowieć kontekście, przeprowadza wyszukiwanie hybrydowy który łączy wyniki obu systemy maksymalizujące jakość wyszukiwania.
class HybridMemory:
"""Pattern Mem0: Vector Store + Knowledge Graph combinati."""
def __init__(self, vector_db, graph_db, embedding_model, llm):
self.vector_db = vector_db
self.graph_db = graph_db
self.embedding_model = embedding_model
self.llm = llm
def store(self, interaction: str, metadata: dict):
"""Salva una nuova memoria in entrambi i sistemi."""
# 1. Estrai entità e relazioni dal testo
entities, relations = self._extract_knowledge(interaction)
# 2. Vector Store: salva l'embedding del testo completo
vector = self.embedding_model.embed(interaction)
self.vector_db.upsert(
id=metadata.get("id", str(hash(interaction))),
vector=vector,
text=interaction,
metadata=metadata
)
# 3. Knowledge Graph: salva entità e relazioni
for entity in entities:
self.graph_db.merge_node(entity.label, entity.properties)
for relation in relations:
self.graph_db.merge_relation(
relation.source, relation.type, relation.target,
properties=relation.properties
)
def retrieve(self, query: str, top_k: int = 5) -> dict:
"""Recupera contesto da entrambi i sistemi."""
# 1. Vector similarity search
query_vector = self.embedding_model.embed(query)
vector_results = self.vector_db.search(query_vector, top_k=top_k)
# 2. Estrai entità dalla query per il graph traversal
query_entities = self._extract_entities(query)
# 3. Graph traversal: espandi il contesto relazionale
graph_context = []
for entity in query_entities:
neighbors = self.graph_db.get_neighbors(
entity, depth=2, limit=10
)
graph_context.extend(neighbors)
# 4. Combina e deduplica i risultati
return {
"vector_results": vector_results,
"graph_context": graph_context,
"combined_context": self._merge_results(
vector_results, graph_context
)
}
def _extract_knowledge(self, text: str):
"""Usa un LLM per estrarre entità e relazioni."""
prompt = f"""Estrai le entità e le relazioni dal seguente testo.
Formato output:
ENTITIES: [tipo:nome:proprietà, ...]
RELATIONS: [source-TIPO_RELAZIONE->target, ...]
Testo: {text}"""
response = self.llm.generate(prompt)
return self._parse_extraction(response)
Przepływ odzyskiwania hybrydowego
Wyszukiwanie hybrydowe przebiega w dwuetapowym procesie, który wykorzystuje mocne strony obu systemów:
- Podobieństwo wektora do zawężania: Wyszukiwanie wektorowe szybko filtruje istotne semantycznie dokumenty, redukując przestrzeń wyszukiwania z tysięcy do kilkudziesięciu wyników
- Przechodzenie wykresu w celu wzbogacenia: zaczynając od jednostek znalezionych w wynikach wektorowych, przemierzanie wykresu poszerza kontekst, podążając za relacjami na wykresie wiedzy, dodając powiązane informacje, których samo podobieństwo semantyczne nie dałoby znaleźć
- Zmiana rankingu i fuzja: Połączone wyniki są uporządkowane według ogólnej trafności, biorąc pod uwagę zarówno podobieństwo semantyczne, jak i odległość na wykresie
- Zgromadzenie kontekstu: Ostateczny kontekst jest tworzony w ramach budżetu symbolicznego, przy czym priorytet mają najbardziej odpowiednie wyniki
Optymalizacja okna kontekstowego
Okno kontekstowe to najcenniejszy atut agenta AI. Każdy token zmarnowany w kontekście nieistotne i o jeden token mniej za użyteczną odpowiedź. Optymalizacja okna kontekstowego wymaga systematycznego podejścia, które równoważy ilość dostępnych informacji jakość i trafność wybranego kontekstu.
Liczenie tokenów i alokacja budżetu
Pierwszym krokiem jest zdefiniowanie a budżet symboliczny dla każdego elementu podpowiedzi. Typowa alokacja dla agenta z tokenami okna kontekstowego o wielkości 128 tys. może wyglądać następująco:
Budżet tokenów na komponent
| Część | Przydzielone tokeny | Procent | Notatki |
|---|---|---|---|
| Monit systemowy | 2000 - 4000 | 2-3% | Instrukcje, osobowość, ograniczenia |
| Definicje narzędzi | 3000 - 8000 | 3-6% | Opis i schemat dostępnych narzędzi |
| Pamięć długoterminowa | 5 000 - 15 000 | 5-12% | Wyniki RAG, kontekst z wykresu wiedzy |
| Historia rozmów | 20 000 - 50 000 | 15-40% | Najnowsze wiadomości, podsumowania |
| Zarezerwowane do odpowiedzi | 8 000 - 16 000 | 6-12% | Miejsce na reakcję modelu |
| Bufor bezpieczeństwa | 5 000 - 10 000 | 4-8% | Margines na nieoczekiwane wyniki narzędzia |
Buforowanie semantyczne
Il buforowanie semantyczne jest to technika optymalizacji, która pozwala uniknąć ponownych obliczeń osadzanie i zapytania dotyczące pytań podobnych do już przetworzonych. Gdy agent otrzyma zapytanie, najpierw sprawdza, czy zapytanie podobne semantycznie nie było już ostatnio przetwarzane. Jeśli podobieństwo przekracza próg (zwykle 0,95), wynik jest zwracany z pamięci podręcznej bez konieczności ponownego wyszukiwania w bazie wektorów.
Takie podejście znacznie zmniejsza opóźnienia i koszty operacji pobierania, szczególnie w scenariuszach, w których użytkownik przeformułowuje to samo pytanie na różne sposoby i gdzie kolejne zapytania są odmianami tego samego motywu.
Odzyskiwanie hierarchiczne
Podejście pobieranie hierarchiczne organizuje bazę wiedzy na wielu poziomach ziarnistości. Na najwyższym poziomie znajdują się ogólne streszczenia całych dokumentów. Na poziomie pośrednie znajdują się streszczenia sekcji. Na najniższym poziomie znajdują się oryginalne kawałki z wszystkie szczegóły.
Wyszukiwanie rozpoczyna się na najwyższym poziomie: jeśli z ogólnych podsumowań wynika, że dokument i istotne, schodzisz do poziomu sekcji, a następnie do poziomu fragmentów tylko dla sekcji bardziej istotne. Takie podejście drastycznie zmniejsza liczbę porównań osadzania konieczne i poprawia jakość wyników poprzez eliminację szumów.
Benchmarking i kompromisy
Wybór odpowiedniego systemu pamięci zależy od konkretnego kontekstu aplikacji. Nie ma uniwersalnego, najlepszego rozwiązania: każde podejście ma swoje mocne strony i słabości, a optymalny wybór zależy od wymagań dotyczących opóźnień, kosztów i dokładności i złożoność wdrożenia.
Kompleksowe porównanie podejść do pamięci
| Zbliżać się | Utajenie | Dokładność | Koszt | Złożoność | Idealny dla |
|---|---|---|---|---|---|
| Przesuwane okno | ~0 ms | Niski | Zero | Minimalny | Proste czaty, prototypy |
| Streszczenie | 200-500 ms | Średnio-wysoki | Średni | Niski | Długie sesje, kodowanie |
| Wektor DB (RAG) | 50-200ms | Wysoki | Średni | Przeciętny | Baza wiedzy, dokumentacja |
| Graf wiedzy | 100-500ms | Bardzo wysoki | Wysoki | Wysoki | Rozumowanie relacyjne |
| Hybrydowy (Mem0) | 200-800 ms | Doskonały | Wysoki | Bardzo wysoki | Agenci korporacyjni, produkcja |
Kiedy używać czego
- Tylko okno przesuwne: proste chatboty, krótkie interakcje, szybkie prototypy, gdzie wytrwałość nie jest konieczna
- Przesuwane okno + podsumowanie: długie sesje kodowania, osobiści asystenci, gdzie kontekst rozmowy jest wystarczający
- Wektor DB (RAG): Gdy agent potrzebuje dostępu do zewnętrznej bazy wiedzy (dokumentacja, kod źródłowy, często zadawane pytania dotyczące firmy), a zapytania są niezależne
- Graf wiedzy: gdy istotne są relacje między podmiotami (zarządzanie projektami, CRM, systemy diagnostyczne) i potrzebne jest rozumowanie wieloprzeskokowe
- Hybrydowy (Mem0): agenci przedsiębiorstwa produkcyjnego, gdzie potrzebne są zarówno poszukiwania semantyczne, jak i rozumowanie relacyjne, a budżet na to pozwala
Praktyczne wdrożenie: zagadnienia produkcyjne
Wdrożenie systemu pamięci w produkcji wymaga zwrócenia uwagi na kilka aspektów wykraczają poza prosty wybór algorytmu. Zarządzanie współbieżnością, spójność danych, monitorowanie i prywatność to krytyczne aspekty.
- Prywatność i RODO: Wspomnienia mogą zawierać dane osobowe. Zawsze wdrażaj mechanizmy selektywnego usuwania i wyraźnej zgody
- Zanik czasu: Stare wspomnienia tracą na znaczeniu. Implementuje system zaniku, który stopniowo zmniejsza wagę niedostępnych wspomnień
- Konflikty i aktualizacje: Kiedy nowe informacje zaprzeczają istniejącym wspomnieniom, agent musi zdecydować, którą wersję zachować. Zawsze traktuj priorytetowo najnowsze informacje, korzystając z dziennika aktualizacji
- Monitorowanie: Śledź wskaźniki, takie jak współczynnik trafień pobierania, średnie opóźnienie, dystrybucja tokenów na komponent i postrzegana jakość odpowiedzi
- Powrót pełen wdzięku: jeśli system pamięci ulegnie awarii (wektorowa baza danych nie działa, uszkodzony wykres), agent musi nadal działać, ograniczając się tylko do bieżącej konwersacji
Wnioski
Pamięć to komponent, który zamienia bezstanowy LLM w naprawdę inteligentnego agenta i trwałe. Od prostej historii rozmów po wyrafinowane systemy hybrydowe z wektorem baza danych i graf wiedzy, każde podejście oferuje inną równowagę pomiędzy złożonością, koszt i jakość kontekstu.
Wzorzec Mem0, który łączy składnicę wektorową i graf wiedzy, staje się najlepszą praktyką dla agentów produkcyjnych w 2026 r. Kluczem nie jest wybór jednego podejścia, ale zrozum kompromisy i wybierz odpowiednią kombinację dla swojego przypadku użycia, zaczynanie od prostych i dodawanie złożoności tylko wtedy, gdy jest to konieczne.
W następnym artykule omówimy zaawansowane narzędzie do rozmów: jak agenci integrują interfejsy API REST, usługi sieciowe i niestandardowe narzędzia do działania w świecie rzeczywistym. Zobaczymy Schemat JSON do definicji narzędzi, walidacji danych wejściowych i strategii sanityzacji, oraz jak zbudować strukturę narzędzi wielokrotnego użytku.







