Bu yazıda vektör veritabanı, RAG mimarisi ve LangGraph’ın hafıza sistemi üzerine öğrendiklerimi ve yaptığım hataları paylaşıyorum.
ChromaDB metinleri direkt karşılaştırmıyor — önce sayı vektörlerine çeviriyor, sonra bu vektörler arasında mesafe hesaplıyor.
"kubernetes güvenlik"
↓
Embedding modeli
↓
[0.23, 0.87, 0.12, ...]
↓
ChromaDB'deki vektörlerle karşılaştır
↓
En yakın vektörleri bul → dökümanları döndür
“kubernetes” kelimesini yazmasan bile “container orkestrasyon” yazsan Kubernetes dökümanları geliyor — kelime eşleşmesi değil, anlam benzerliği.
Varsayılan olarak ChromaDB all-MiniLM-L6-v2 modelini kullanıyor,
ilk çalıştırmada internet üzerinden indiriyor, sonra local cache’de kalıyor.
Büyük dökümanları direkt ChromaDB’ye atmak yerine küçük parçalara (chunk) bölüyoruz. Nedeni basit — embedding modelleri uzun metinlerde anlam kaybı yaşıyor, küçük parçalar daha isabetli sonuç veriyor.
splitter = RecursiveCharacterTextSplitter(
chunk_size=200,
chunk_overlap=20
)
chunk_size=200 → her parça ~200 karakter
chunk_overlap=20 → her parça bir öncekiyle 20 karakter kesişiyor
Overlap neden var? Overlap olmadan bir cümle iki chunk’ın tam ortasında bölünebilir, anlam kaybolur. 20 karakterlik geri dönüş bu problemi önlüyor.
client = Client() # varsayılan
Uygulamayı her yeniden başlatınca ChromaDB sıfırlanıyordu.
Client() RAM’de çalışıyor — uygulama kapanınca her şey siliniyor.
client = chromadb.PersistentClient(path="./chroma_db")
./chroma_db klasörüne yazıyor, uygulama kapansa da veri kalıyor.
Agent’a iki tool verdim — sıralama önemli:
tools = [search_knowledge_base, TavilySearch(max_results=2)]
search_knowledge_base → önce local ChromaDB’ye bakTavilySearch → bilmiyorsa internette araAgent tool listesini yukarıdan aşağıya değerlendiriyor. Kubernetes sorusunda ChromaDB yetti, Tavily’e hiç gitmedi. Güncel haber sorusunda ChromaDB boş döndü, Tavily devreye girdi.
Başlangıçta MemorySaver kullandım:
from langgraph.checkpoint.memory import MemorySaver
memory = MemorySaver()
Çalışıyordu ama bir sorunu vardı — uygulama yeniden başlayınca tüm konuşma geçmişi siliniyor. RAM’de tuttuğu için kalıcı değil.
Çözüm olarak AsyncPostgresSaver‘a geçtim:
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
async with AsyncPostgresSaver.from_conn_string(DATABASE_URL) as checkpointer:
await checkpointer.setup()
agent_app = create_react_agent(llm, tools, checkpointer=checkpointer)
Artık konuşma geçmişi PostgreSQL’e yazılıyor. Uygulama kapanıp açılsa da model her şeyi hatırlıyor.
psycopg.OperationalError: the connection is closed
async with bloğu sadece setup() satırını kapsıyordu,
geri kalan tüm kod bloğun dışındaydı.
Connection kapanıyor, sonra kullanmaya çalışınca crash oluyordu.
# Yanlış
async with AsyncPostgresSaver.from_conn_string(DATABASE_URL) as checkpointer:
await checkpointer.setup() # sadece bu içeride
# Bloğun dışında — connection kapanmış
agent_app = create_react_agent(llm, tools, checkpointer=checkpointer)
result = await agent_app.ainvoke(...)
Tüm kodu async with bloğunun içine almak:
# Doğru
async with AsyncPostgresSaver.from_conn_string(DATABASE_URL) as checkpointer:
await checkpointer.setup()
agent_app = create_react_agent(llm, tools, checkpointer=checkpointer)
result = await agent_app.ainvoke(...)
return result["messages"][-1].content
async with bir context manager — bloğun dışına çıkınca
connection otomatik kapanıyor. Connection’a bağlı her şey içeride olmalı.
Başlangıçta hem kendi chat_histories tabloma yazıyordum
hem de LangGraph kendi tablolarına yazıyordu.
PostgreSQL tabloları:
├── chat_histories ← benim yazdığım servis
├── checkpoints ← LangGraph'ın kendi tablosu
├── checkpoint_blobs ← LangGraph'ın kendi tablosu
└── checkpoint_writes ← LangGraph'ın kendi tablosu
chat_histories tablosunu düşürünce model hâlâ geçmişi hatırlıyordu.
Çünkü LangGraph’ın tablolarına dokunmamıştım.
Sonuç: chat_histories tablosu ve save_chat_history servisi gereksizdi.
LangGraph zaten her şeyi kendi tablolarına yazıyor ve model her zaman
okuyabiliyor. Kendi servisimi kaldırdım, tek kaynak LangGraph checkpointer oldu.
PersistentClient ile kalıcı hale getirilmeliasync with context manager’larda connection tüm işlemler
boyunca açık kalmalı, scope dışına çıkınca kapanıyor