Memory Service
Cel
Memory Service ogranicza koszt tokenów i poprawia ciągłość rozmowy przez zastąpienie pełnej historii krótkim kontekstem pamięciowym:
- rolling summary aktualnej rozmowy,
- wybrane trwałe fakty i preferencje użytkownika,
- kolejka background jobs w Redis,
- lokalny extractor LLM z fallbackiem heurystycznym,
- docelowo vector search w Postgres + pgvector.
Status MVP
- [x] Dodać
ConversationSummarydla krótkiego streszczenia rozmowy per użytkownik. - [x] Dodać
MemoryItemdla zapamiętanych faktów i preferencji. - [x] Dodać Redis queue dla jobów po każdej zapisanej odpowiedzi chatu.
- [x] Dodać
memory-workerjako osobny proces/kontener z tego samego obrazu aplikacji. - [x] Worker aktualizuje summary rozmowy i zapisuje kandydatów pamięci.
- [x] Dodać lokalny LLM extractor z modelem
qwen2.5:3b-instruct. - [x] Prompt builder dodaje krótkie memory context przed ostatnimi wiadomościami.
- [x] Docker Compose uruchamia Postgres z obsługą pgvector jako docelowy storage embeddings.
Przepływ
POST /chat/askgeneruje odpowiedź przez OpenAI.openai_service.pyzapisujeConversationHistory.- Po zapisie historii aplikacja wrzuca payload do
jarvis:memory:jobsw Redis. backend.workers.memory_workerpobiera job przezBRPOP.- Worker ładuje historię i aktualny
ConversationSummary. memory_extractors.pypróbuje użyć lokalnego LLM albo fallbacku heurystycznego.- Wynik jest walidowany, filtrowany i zapisywany do
conversation_summaryorazmemory_items. - Kolejny prompt może dostać
Context memoryz summary i najtrafniejszych memory items.
Chat nie czeka na worker. Jeżeli Redis albo lokalny LLM są chwilowo niedostępne, odpowiedź użytkownika nadal może zostać zwrócona, a worker loguje problem w tle.
Lokalny LLM Extractor
memory-worker może używać lokalnego modelu przez OpenAI-compatible endpoint Ollamy:
MEMORY_EXTRACTOR_PROVIDER=local_llm
MEMORY_LLM_BASE_URL=http://local-llm:11434/v1
MEMORY_LLM_API_KEY=local
MEMORY_LLM_MODEL=qwen2.5:3b-instruct
MEMORY_LLM_TIMEOUT_SECONDS=30
MEMORY_MIN_CONFIDENCE=0.7
Kontrakt odpowiedzi extractora jest walidowany po stronie aplikacji. Worker zapisuje tylko elementy pamięci z dozwolonym kind, confidence >= MEMORY_MIN_CONFIDENCE, krótkim content i bez sekretów.
Ostatnie filtry jakości:
- odrzucanie
restricted=true, - odrzucanie wpisów poniżej
MEMORY_MIN_CONFIDENCE, - odrzucanie pustych albo zbyt długich treści,
- odrzucanie placeholderów typu
favorite color,favorite hobby,preferred music genre, - odrzucanie ustawień samego asystenta jako pamięci użytkownika,
- deduplikacja z ignorowaniem wielkości liter, nadmiarowych spacji i końcowej kropki.
Debugowanie
Sprawdzenie kolejki:
docker compose exec redis redis-cli llen jarvis:memory:jobs
Ostatnie memory items:
docker compose exec db psql -U jarvis -d jarvis_db -c "select kind, content, salience, updated_at from memory_items order by updated_at desc limit 10;"
Ostatnie summary:
docker compose exec db psql -U jarvis -d jarvis_db -c "select user_id, conversation_id, summary, message_count, updated_at from conversation_summary order by updated_at desc limit 5;"
Logi workera:
docker compose logs -f memory-worker
Jeżeli w logach pojawia się Timeout reading from socket przy pustej kolejce Redis, aktualna implementacja traktuje to jako brak joba, a nie błąd procesu. BRPOP ma krótki timeout i jest wykonywany w pętli.
Następne Kroki
- [ ] Dodać prawdziwe embeddings dla
MemoryItem. - [ ] Przenieść
embedding_jsonna natywną kolumnęvectorpo ustaleniu migracji. - [ ] Dodać vector similarity search per
user_id. - [ ] Dodać panel do przeglądania i usuwania pamięci użytkownika.
- [ ] Dodać politykę retencji i sanityzację pamięci.