SSD Nodes Learn Hosting plans →
Rehberler Matt ConnorYazan Matt Connor · Güncellendi 2026-10-26

Kendi VPS Sunucunuzda mem0 Kurulumu ve RAM Maliyeti

mem0 bellek sunucusunu VPS üzerinde barındırmak için gereken 2 GB RAM alt sınırını ve Ollama ile tam yerel kurulumda 8 GB RAM ihtiyacını teknik detaylarla inceleyin.

Bir VPS üzerinde mem0 barındırmanın gerçek RAM maliyeti

mem0'ı kendi sunucunuzda barındırmak, üç container çalıştırmak anlamına gelir: FastAPI bellek sunucusu, pgvector eklentili Postgres ve bir Next.js paneli. mem0, yapay zeka ajanları için bir bellek katmanıdır. Bir konuşmayı buraya gönderdiğinizde, bir dil modeli bu konuşmadan kalıcı gerçekleri çıkarır ve bu gerçekler, daha sonra ilgili olanların geri çağrılabilmesi için vektör olarak saklanır.

Üç container için yaklaşık 1 GB yerleşik bellek ve imajlar oluşturulduktan sonra 3 ila 4 GB disk alanı ayırın. Dil modeli başka bir yerde barındırıldığında, 2 GB RAM'e sahip bir VPS bu kurulumu rahatlıkla çalıştırır. Model, Ollama aracılığıyla aynı sunucuda çalıştırıldığında, model tüm kaynakları tüketir: 4 bit kuantize edilmiş 8B bir model tek başına yaklaşık 6 GB RAM gerektirir, bu nedenle tamamen yerel bir kurulum 8 GB RAM ile başlar.

Bu rakamları, bu yazı da dahil olmak üzere herhangi bir blog gönderisinden olduğu gibi almayın. Kendi oluşturduğunuz yığını ölçün.

docker compose ps
docker stats --no-stream
docker system df -v

docker stats, container başına yerleşik belleği yazdırır. docker system df -v, her imajın ve her birimin kapladığı disk alanını yazdırır.

Kararlı durum, tepe noktası değildir. docker compose up -d --build, Next.js panelini derler ve bu Node derleme süreci, tüm kurulumun en çok kaynak tüketen anıdır. 1 GB RAM'li bir VPS üzerinde çekirdeğin bellek yetersizliği sonlandırıcısı (OOM killer) bu işlemi durdurur ve derleme exit code 137 ile sona erer. Bir Docker hatası aramaya başlamadan önce nedeni doğrulayın:

dmesg -T | grep -i "killed process"

Bir sunucu, ihtiyaçlarınız için çok fazla donanım gerektiriyorsa, daha küçük seçenekler mevcuttur. hiç sunucu gerektirmeyen yerel bir ajan bellek deposu ve doğrudan Claude Code içinde yaşayan bellek, veritabanı ihtiyacını ortadan kaldırır. Birden fazla ajanın veya birden fazla makinenin aynı bellekleri okuması gerektiğinde buraya geri dönün.

mem0 grafik belleği için Neo4j gerekli mi?

Hayır. Eğer bir kılavuz size bir Neo4j container'ı eklemenizi söylüyorsa, o kılavuz koddan daha eskidir.

mem0 içindeki grafik belleği, eskiden graph_store anahtarı altında yapılandırılan ve enable_graph değeri true olarak ayarlanan harici bir grafik veritabanını ifade ediyordu. Nisan 2026'da yayınlanan yeni bellek algoritması, her iki anahtarı da açık kaynaklı SDK'dan kaldırdı. Varlık çıkarımı (entity extraction) artık normal add yolu içinde çalışır ve varlıklar, ana koleksiyonunuzun adının sonuna _entities eklenerek oluşturulan ikinci bir pgvector koleksiyonuna yazılır. Herhangi bir kurulum adımı yoktur: bu koleksiyon ilk kullanımda oluşturulur, böylece yerleşik varlık bağlama (entity linking) özelliği bir sonraki add çağrısında çalışmaya başlar.

Grafik deposunu kaldırmak, bir JVM container'ını, onun heap alanını ve birkaç yüz megabaytlık imaj boyutunu tasarruf etmenizi sağlar. 2 GB RAM'e sahip bir VPS üzerinde bu, sistemin çalışması ile swap yapması arasındaki farktır.

Açıkça belirtmek gerekirse, vazgeçtikleriniz şunlardır: Arama sonuçları eskiden varlıklar arasındaki kenarları listeleyen bir relations alanı taşıyordu. Bu alan artık yoktur. Varlık eşleşmeleri artık bir belleğin birleşik skor içindeki konumunu yükseltir ve üzerinde gezinebileceğiniz bir yapı kalmamıştır. Uygulamanız bu ilişkiler üzerinde geziniyorsa, mem0 artık bunları tutmaz; bu durumda kendi kodunuzla beslediğiniz, mem0 dışında kendi grafik veritabanınızı tutmanız gerekir.

Depodaki compose dosyası bir geliştirme compose dosyasıdır

server/docker-compose.yaml, name: mem0-dev değerini tanımlar ve bu durum tam olarak ifade edildiği anlama gelir. Çalıştırmadan önce içeriğini okuyun, çünkü dosya içerisinde sunucu ortamı için hatalı olan beş nokta bulunmaktadır.

  • server/dev.Dockerfile üzerinden derleme yapar ve .:/app ile yerel dizininizi imajın üzerine mount eder; bu nedenle container, derlediğiniz kodu değil, o dizinde o an ne varsa onu çalıştırır.
  • Komutu rm -rf /app/packages && pip install -q --force-reinstall --no-deps mem0ai && alembic upgrade head && uvicorn main:app --host 0.0.0.0 --port 8000 --reload şeklindedir. Bu komut, her başlatmada mem0ai paketini PyPI üzerinden yeniden kurar; dolayısıyla sunucunuzun çalıştırdığı sürüm, bir yükseltme yapmadığınızı düşündüğünüz bir yeniden başlatma sırasında değişebilir.
  • Aynı pip adımı, dış ağ bağlantısının olmadığı bir yeniden başlatma durumunda uvicorn çalışmadan önce işlemin başarısız olmasına neden olur. PyPI'a erişilemediği için bellek sunucunuz devre dışı kalır.
  • --reload, uvicorn'un dosya izleyicisini başlatır. Bu özellik, kod düzenlediğinizde süreci yeniden başlatmak için vardır; üretim ortamında hiçbir işe yaramaz ve ek bellek tüketimi ile fazladan bir süreç oluşturur. Üretim ortamındaki Dockerfile de kendi CMD içerisinde --reload taşır, bu yüzden komutu her iki durumda da geçersiz kılarsınız.
  • Yayınlanan portlar "8888:8000", "8432:5432" ve "3000:3000" şeklindedir. Önünde bir adres belirtilmeyen yayınlanmış bir port 0.0.0.0 adresine bağlanır; bu nedenle yığın başladığı anda Postgres, 8432 portu üzerinden genel internete yanıt verir.

Bu son nokta, kendi başına bir uyarıyı hak etmektedir. Docker, kendi kurallarını ufw tarafından yönetilen zincirin önüne yazarak bir portu yayınlar; bu yüzden ufw deny 8432 komutu, yayınlanmış bir container portunu kapatmaz. Docker'ın portları ufw'yi devre dışı bırakarak yayınlaması başlıklı bölüm, ilgili kuralları detaylıca açıklamaktadır.

Gerçek bir sunucu için compose dosyası

server/ içinde çalışın, init-db.sh öğesini olduğu yerde tutun ve docker-compose.yaml kısmını aşağıdakilerle değiştirin.

name: mem0

services:
  mem0:
    build:
      context: .
      dockerfile: Dockerfile
    restart: unless-stopped
    env_file: .env
    ports:
      - "127.0.0.1:8888:8000"
    networks: [mem0_network]
    volumes:
      - mem0_history:/app/history
    depends_on:
      postgres:
        condition: service_healthy
    command: >
      sh -c "alembic upgrade head &&
             uvicorn main:app --host 0.0.0.0 --port 8000"
    environment:
      - PYTHONUNBUFFERED=1
      - DASHBOARD_URL=https://mem0.example.com
      - APP_DB_NAME=mem0_app
      - AUTH_DISABLED=false
      - MEM0_TELEMETRY=false

  postgres:
    image: pgvector/pgvector:pg17
    restart: unless-stopped
    shm_size: "128mb"
    networks: [mem0_network]
    environment:
      - POSTGRES_USER=${POSTGRES_USER:-postgres}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -q -U ${POSTGRES_USER:-postgres}"]
      interval: 5s
      timeout: 5s
      retries: 5
    volumes:
      - postgres_db:/var/lib/postgresql/data
      - ./init-db.sh:/docker-entrypoint-initdb.d/init-db.sh

  mem0-dashboard:
    build: ./dashboard
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"
    networks: [mem0_network]
    environment:
      - NEXT_PUBLIC_API_URL=https://mem0.example.com
      - API_INTERNAL_URL=http://mem0:8000
    depends_on:
      mem0:
        condition: service_started

volumes:
  postgres_db:
  mem0_history:

networks:
  mem0_network:
    driver: bridge

Burada beş değişiklik önemlidir ve her birinin bir nedeni vardır.

Her ports girdisi 127.0.0.1 ile başlar, böylece çekirdek bu bağlantıları yalnızca sunucunun kendisinden kabul eder. Dışarıdan gelen her şey, sertifikayı elinde bulunduran tek bileşen olan reverse proxy üzerinden ulaşır.

Postgres tarafında hiçbir ports bloğu bulunmaz. mem0 container'ı, veritabanına mem0_network üzerinden servis adıyla erişir; bu nedenle 8432 portunu dışarı açmak size bir fayda sağlamaz, aksine açık bir port oluşturur. Kabuk erişimine ihtiyaç duyduğunuzda docker compose exec postgres psql -U postgres kullanın.

Geçmiş verisi, ./history bind mount konumundan adlandırılmış bir volume'a taşınır. Bind mount, veriyi bu ana makinedeki belirli bir yola ve kullanıcı kimliğine (uid) bağlarken, adlandırılmış volume Docker'ın snapshot alabileceği ve taşıyabileceği bir nesnedir. Adlandırılmış volume'lar ve bind mount'lar konusu, hangisinin ne zaman doğru tercih olduğunu açıklar.

Komut, --reload öğesini kaldırır ve alembic upgrade head öğesini tutar. Bu migrasyon adımını koruyun. Aksi takdirde uygulama, tabloları olmayan bir veritabanına karşı başlar ve her istek ilk sorguda başarısız olur.

NEXT_PUBLIC_API_URL, tarayıcınızın çağırdığı URL'dir; bu nedenle http://mem0:8000 değil, herkese açık HTTPS adresi olmalıdır. Next.js, NEXT_PUBLIC_ değerlerini derleme zamanında içine gömer (inline), ancak bu dashboard imajı bunun yerine bir yer tutucu (placeholder) kullanır ve container başladığında giriş noktası (entrypoint) bunu gerçek değerle değiştirir. Bu nedenle değeri değiştirmek, container'ı yeniden oluşturan docker compose up -d mem0-dashboard komutunu gerektirir, yeniden derleme (rebuild) gerekmez. docker compose restart mem0-dashboard ise dosyaları zaten eski değeri tutan eski container'ı yeniden kullanır ve dashboard yanlış ana bilgisayarı çağırmaya devam eder.

Gizli veriler .env dosyasında tutulur ve .env internete kapalı kalmalıdır

cd server
cp .env.example .env
openssl rand -hex 32    # paste into JWT_SECRET
openssl rand -hex 32    # paste into ADMIN_API_KEY
chmod 600 .env

POSTGRES_PASSWORD, JWT_SECRET ve ADMIN_API_KEY değerlerini ayarlayın. AUTH_DISABLED=false değerini olduğu gibi bırakın. Bayrağın ismi, yaptığı işi açıkça ifade eder: bu özellik açıkken sunucu, porta erişebilen herkese belleğindeki tüm verileri sunar. Onboarding etkinliğinin yukarı yönde (upstream) gönderilmesini istemiyorsanız MEM0_TELEMETRY=false değerini ayarlayın.

ADMIN_API_KEY, secrets.compare_digest kullanılarak X-API-Key başlığı ile karşılaştırılır ve bir eşleşme durumunda veritabanındaki anahtar bazlı arama tamamen atlanır: istek, sunucuda oluşturulan ilk kullanıcı yetkileriyle çalıştırılır. Bu, tüm API için bir root kimlik bilgisidir. Buna uygun şekilde muamele edin: shell geçmişine eklemeyin, git üzerinde kullanmayın ve herhangi bir yapay zeka istemine (prompt) yapıştırmayın. Compose ortam dosyaları ve içlerindeki gizli verilerin sızdığı noktalar ve API anahtarlarını bir ajanın bağlamından uzak tutmak başlıklarının her ikisi de doğrudan geçerlidir, çünkü bu sunucunun çağırıcıları ajanlardır.

env_file üzerinden yüklenen değerler container ortamında yer alır ve docker inspect bunları tam olarak yazdırır. docker grubundaki herkes bu değerleri okuyabilir ve docker grubundaki herkes ana makine (host) üzerinde fiilen root yetkisine sahiptir.

API'nin önüne 8888 portunu açmak yerine TLS yerleştirin

API, 127.0.0.1:8888 adresinde, dashboard ise 127.0.0.1:3000 adresinde yanıt verir. nginx, 443 portunda TLS (transport layer security) sonlandırmasını gerçekleştirir ve trafiği her iki servise de yönlendirir.

server {
    listen 443 ssl;
    server_name mem0.example.com;

    ssl_certificate     /etc/letsencrypt/live/mem0.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mem0.example.com/privkey.pem;

    location ~ ^/(memories|search|configure|reset|generate-instructions|auth|api-keys|entities|requests|docs|openapi.json) {
        proxy_pass http://127.0.0.1:8888;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_read_timeout 180s;
    }

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Dashboard'un tarayıcı kodu, NEXT_PUBLIC_API_URL içindeki tüm API yollarını çağırır; buna /entities ve /requests de dahildir. Birini atladığınız takdirde nginx bu çağrıyı Next.js'e iletir ve veriye ihtiyaç duyan dashboard sayfası veri yerine 404 hatası alır.

proxy_read_timeout göründüğünden daha önemlidir. Bir ekleme çağrısı, dil modeli konuşmayı okuyup gerçekleri çıkarana kadar bekler. CPU üzerinde çalışan yerel bir 8B model, genellikle nginx'in varsayılan 60 saniyelik süresinden daha uzun sürer; bu durumda model hala çalışırken ve bellek yazılmaya devam ederken çağrı yapan taraf 504 Gateway Time-out hatası görür. Sonuç olarak, başarısız olduğu bildirilen bir bellek ile karşılaşırsınız.

varsayılan bir deny ufw politikası ile diğer portları kapatın ve yalnızca 22, 80 ve 443 portlarını açık bırakın. Sertifikayı nginx arkasında Ubuntu 24.04 üzerinde certbot kullanarak oluşturun. 80 numaralı portun erişilebilir kalması gerekir; çünkü bu iş akışı, Let's Encrypt'in hem ilk oluşturma hem de her yenileme sırasında yalnızca 80 numaralı port üzerinden gerçekleştirdiği HTTP-01 sınamasını kullanır. 80 numaralı portu kapalı tutmak, DNS-01 sınamasına geçiş yapmayı gerektirir. Eğer sunucu halihazırda birden fazla Compose uygulamasını yönlendiren Traefik ile diğer uygulamalara hizmet veriyorsa, ikinci bir proxy kurmak yerine mem0'ı mevcut yönlendiriciye ekleyin.

Duman testi: bir bellek ekleyin ve geri okuyun

export MEM0_KEY='<the ADMIN_API_KEY from .env>'

curl -sS -X POST http://127.0.0.1:8888/memories \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $MEM0_KEY" \
  -d '{"messages":[{"role":"user","content":"I deploy with Docker Compose and I run Postgres 17."}],"user_id":"smoke"}'

Sağlıklı bir yanıt, bir results listesi içeren JSON nesnesidir; her girdi bir id, ayıklanan memory metni ve "event": "ADD" değerini tutar. Mevcut algoritma yalnızca ADD olaylarını döndürür. UPDATE ve DELETE olayları kaldırılmıştır, bu nedenle bunların yokluğu bir hata değildir.

curl -sS -X POST http://127.0.0.1:8888/search \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $MEM0_KEY" \
  -d '{"query":"which database do I run?","filters":{"user_id":"smoke"},"top_k":5}'

Postgres 17 hakkındaki bilgi, bir puan ile geri dönmelidir. Tanımlayıcıyı, gösterildiği gibi filters içine geçirin. Üst düzey bir user_id hala çalışır ve sunucu, her kullandığınızda Top-level user_id in /search is deprecated. Use filters={...} instead. kaydını tutar.

Test verilerinin gerçek aramaları kirletmemesi için temizlik yapın:

curl -sS -X DELETE "http://127.0.0.1:8888/memories?user_id=smoke" \
  -H "X-API-Key: $MEM0_KEY"

Arama beklediğinizden daha az satır döndürürse, geri getirme (retrieval) işlemini suçlamadan önce varsayılan değerleri kontrol edin. Mevcut sürümde top_k varsayılan olarak 100 yerine 20'dir ve threshold değeri yok yerine 0.1 olarak ayarlanmıştır; bu nedenle zayıf eşleşmeler artık sizin için filtrelenmektedir. Bu işlem curl üzerinden çalıştığında, aynı uç noktaları doğrudan veya aynı VPS üzerinde çalışan bir MCP sunucusu aracılığıyla bir aracıya (agent) bağlayabilirsiniz.

mem0'u OpenAI anahtarı olmadan çalıştırmak

İlk beş dakika içinde karşılaşacağınız engel ile başlayın. Sunucu imajı sabit bir sağlayıcı kütüphanesi setiyle gelir ve /configure bunların dışındaki her şeyi reddeder:

LLM provider 'ollama' is not bundled in this image. Bundled providers: openai, anthropic, gemini. To use another provider, install its Python package, rebuild the container, and extend BUNDLED_LLM_PROVIDERS in server/main.py.

Hiçbir şeyi yeniden derlemeniz gerekmez. Ollama, /v1 adresinde OpenAI uyumlu bir API sunar; bu API /v1/chat/completions ve /v1/embeddings kapsamındadır. mem0'ın openai sağlayıcısı bir openai_base_url kabul eder. Bu anahtarı Ollama'ya yönlendirdiğinizde paketlenmiş kontrol başarılı olur, çünkü sağlayıcı aslında openai'dir. Yalnızca adres değişir.

Ollama'yı aynı Compose projesine ekleyin:

  ollama:
    image: ollama/ollama
    restart: unless-stopped
    networks: [mem0_network]
    ports:
      - "127.0.0.1:11434:11434"
    volumes:
      - ollama_models:/root/.ollama

En üst düzey volumes: anahtarının altına ollama_models: ekleyin, ardından bir sohbet modeli ve bir gömme (embedding) modeli çekin:

docker compose up -d ollama
docker compose exec ollama ollama pull llama3.1:8b
docker compose exec ollama ollama pull nomic-embed-text

Eğer Ollama ana makinede bir systemd birimi olarak çalışıyorsa (bkz: Ollama'yı doğrudan bir VPS üzerinde çalıştırmak), konteyneri 127.0.0.1:11434 adresine yönlendirmeyin. mem0 konteynerinin içinde 127.0.0.1, mem0 konteynerinin kendisidir. mem0 servisine extra_hosts: ["host.docker.internal:host-gateway"] verin, Ollama'nın köprü ağının erişebileceği bir adreste dinleme yapması için bir systemd drop-in dosyasında Environment="OLLAMA_HOST=0.0.0.0:11434" ayarını yapın ve 11434 numaralı portu güvenlik duvarında kapalı tutun.

Herhangi bir yapılandırma yapmadan önce modele gömme boyutunu sorun

Bu tek adım, geri getirmenin (retrieval) çalışıp çalışmayacağını belirler.

mem0'ın pgvector deposu, tablosunu sabit bir vektör genişliği olan vector vector(1536) ile oluşturur; çünkü embedding_model_dims varsayılan olarak OpenAI'ın text-embedding-3-small genişliği olan 1536 değerini kullanır. nomic-embed-text ise 768 değerini döndürür. mem0 içinde bu iki sayıyı karşılaştıran bir mekanizma yoktur, bu nedenle uyumsuzluk ilk ekleme (insert) sırasında Postgres'ten gelen bir hata ile ortaya çıkar:

expected 1536 dimensions, not 768

Bu paragraftaki sayıya da güvenmeyin. Modele sorun:

curl -sS http://127.0.0.1:11434/v1/embeddings \
  -H "Content-Type: application/json" \
  -d '{"model":"nomic-embed-text","input":"dimension check"}' \
  | python3 -c "import json,sys; print(len(json.load(sys.stdin)['data'][0]['embedding']))"

Bu komut, koleksiyonunuzun kullanması gereken genişliği yazdırır. Yapılandırmayı bir dosyaya yazın; çünkü Postgres şifresini kabuk tırnakları üzerinden yapıştırmak, üretim ortamında yazım hatalarına yol açar.

{
  "vector_store": {
    "provider": "pgvector",
    "config": {
      "host": "postgres",
      "port": 5432,
      "dbname": "postgres",
      "user": "postgres",
      "password": "<POSTGRES_PASSWORD from .env>",
      "collection_name": "memories_local_768",
      "embedding_model_dims": 768
    }
  },
  "llm": {
    "provider": "openai",
    "config": {
      "model": "llama3.1:8b",
      "api_key": "ollama",
      "openai_base_url": "http://ollama:11434/v1",
      "temperature": 0.2
    }
  },
  "embedder": {
    "provider": "openai",
    "config": {
      "model": "nomic-embed-text",
      "api_key": "ollama",
      "openai_base_url": "http://ollama:11434/v1"
    }
  }
}
curl -sS -X POST http://127.0.0.1:8888/configure \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $MEM0_KEY" \
  -d @config.json

curl -sS http://127.0.0.1:8888/configure -H "X-API-Key: $MEM0_KEY"

İkinci çağrı yapılandırmayı geri okur; bu, yazma işleminin başarılı olduğunu doğrulayan kontroldür. Ardından yukarıdaki duman testini tekrarlayın.

Bu JSON içindeki dört detay belirgin değildir ve yanlış yapıldığında her biri bir şeyleri bozar.

api_key, ollama dizgisidir ve Ollama bu değeri görmezden gelir. Boş olamaz, çünkü OpenAI istemci kütüphanesi hiçbir anahtar ayarlanmadığında süreçten herhangi bir istek çıkmadan önce hata verir. Boş olmayan herhangi bir dizgi çalışır.

embedding_model_dims, vektör deposuna uygulanır ve gömme aracında (embedder) kasıtlı olarak embedding_dims yoktur. mem0, OpenAI dimensions parametresini yalnızca embedding_dims ayarlandığında gönderir ve Matryoshka kırpma işlemini uygulamayan arka uçlar bu parametreyi doğrudan reddeder. Genişliği tablonun oluşturulduğu yerde ayarlayın ve gömme aracını olduğu gibi bırakın.

collection_name yenidir. mem0 tablosunu CREATE TABLE IF NOT EXISTS ile oluşturur, bu nedenle mevcut bir koleksiyona farklı bir genişlik işaret etmek hiçbir işe yaramaz: eski vector(1536) sütunu kalır ve her ekleme işlemi başarısız olur. Genişlik değişikliği için yeni bir koleksiyon adı gerekir ya da eski tabloyu elle silmeniz gerekir.

openai_base_url içindeki ana makine, localhost değil, Compose servis adı olan ollama'dir. Konteynerler paylaşılan ağ üzerinde birbirlerini servis adlarıyla çözerler.

Tamamen yerel yolun maliyeti

Kalite konusunda kendinize karşı dürüst olun. mem0'ın manşetlerdeki kıyaslama puanları, README dosyasında belirtildiği üzere açık kaynaklı SDK'da bulunmayan ve ismi açıklanmayan bir model yığını üzerinde çalışan özel optimizasyonlar içeren yönetilen platformundan gelmektedir. Orijinal LOCOMO sonuçlarının arkasındaki araştırma makalesi, her model çağrısını barındırılan bir model olan GPT-4o-mini üzerinde çalıştırmıştır. Her iki durumda da bu puanları, VPS üzerindeki 8B bir model için bir tahmin değil, bir tavan değeri olarak kabul edin. Küçük bir model daha belirsiz gerçekler yazar ve bazen JSON istendiğinde düz metin döndürür; bu durum, ekleme çağrısının hata vermeden boş bir results listesi döndürmesiyle sonuçlanır.

Hız diğer maliyettir. Sadece CPU ile çıkarma işlemi, her ekleme çağrısı için saniyeler sürer ve depoladığınız her mesaj bu maliyeti öder. İstenen JSON'ın dışına çıkan bir model bu durumu daha da kötüleştirir; bu nedenle yanıtı num_predict ile sınırlamak, herhangi bir ekleme çağrısının ne kadar süreceğine bir tavan getirir. Eğer bu gecikme önemliyse, GPU takılı bir VPS dürüst çözümdür. 8B bir modele daha fazla CPU çekirdeği vermek, insanların beklediğinden çok daha az yardımcı olur. Modeli değiştirmek, makineyi değiştirmekten daha ucuz bir kaldıraçtır ve VPS üzerinde Nemotron 3.5 Lightning, çekmeniz gereken etiketi, ihtiyaç duyduğu RAM miktarını ve sadece CPU ile çalışmanın yaşanabilir olup olmadığını size gösterir.

Ne seçerseniz seçin, tek bir kural geçerlidir: aynı koleksiyon içinde asla farklı gömme modellerini karıştırmayın. Tesadüfen aynı genişliğe sahip iki farklı model, karşılaştırılamaz vektörler üretir. Ekleme başarılı olur, arama satırları döndürür ve satırlar yanlıştır; hiçbir yerde bir hata rapor edilmez.

Yedeklemeler: tek değil, iki veritabanı var

En yaygın mem0 yedekleme hatası, yalnızca tek bir veritabanının dışa aktarılmasıdır. init-db.sh, varsayılan postgres veritabanının yanında mem0_app veritabanını oluşturur ve bu veritabanları farklı veriler içerir. postgres veritabanında anıların tutulduğu pgvector koleksiyonları bulunur. mem0_app ise kullanıcıları, oturumları, API anahtarlarını ve istek günlüklerini içerir. Her self-hosted uygulama durum verilerini kendine özgü biçimde ayırır. Bu nedenle aynı işi yapan iki fotoğraf sunucusu için bile farklı yedekleme komutları gerekir. Bir dump dosyasına güvenmeden önce uygulamanızın hangi verileri depoladığını inceleyin. Bu yelpazenin diğer ucunda, 90'lar video mağazası olarak yeniden oluşturulan bir Jellyfin kitaplığı gibi bir yapı bulunur. Bu yapı tüm kataloğunu başka bir servisten okur. Bu nedenle kendi yapılandırmasının kopyalanması genellikle yeterlidir. mem0 için ise her iki veritabanının da yedeklenmesi gerekir; aksi halde geri yükleme kullanılamaz.

Yalnızca postgres yedeğini geri yüklerseniz bellekler geri gelir ancak tüm hesaplar ve API anahtarları kaybolur; bu durumda hiçbir şey kimlik doğrulaması yapamaz ve bellekleri okuyamaz. Her ikisini ve rolleri tek komutla yedekleyin:

docker compose exec -T postgres pg_dumpall -U postgres --clean \
  | gzip > "mem0-$(date +%F).sql.gz"

Geçmiş (history) birimi Postgres'ten ayrıdır ve kendi kopyasına ihtiyaç duyar:

docker run --rm -v mem0_mem0_history:/data -v "$PWD:/backup" \
  alpine tar czf /backup/mem0-history.tgz -C /data .

Docker, birim adlarının başına proje adını ekler; bu nedenle mem0_mem0_history varsayımında bulunmadan önce docker volume ls ile kendi adlarınızı doğrulayın.

Yedeği boş bir container içine geri yükleyin ve herhangi bir veriye güvenmeden önce satır sayılarını kontrol edin:

gunzip -c mem0-2026-08-03.sql.gz \
  | docker compose exec -T postgres psql -U postgres -d postgres

Daha önce geri yüklemediğiniz bir yedek, sadece bir tahmindir. Yedekler doğru alındıktan sonra, bunları restic ile uzak depolama alanına snapshot göndererek sunucudan dışarı aktarın; çünkü koruduğu sunucuda barınan bir yedek, hiçbir şeyi korumaz.

Hata modları ve göreceğiniz kesin dizeler

{"detail":"Authentication required. Provide a Bearer token or X-API-Key header."} ifadesi, başlığın eksik veya yanlış yazılmış olduğu anlamına gelir. İsim X-API-Key şeklindedir ve curl başlık isimlerini olduğu gibi gönderir.

Bir ekleme işleminde {"detail":"At least one identifier (user_id, agent_id, run_id) is required."} hatası, isteğin bunlardan hiçbirini içermediğini belirtir. Arama filtreleri tam olarak bu alanlar üzerinde çalıştığı için bir belleğin belirli bir kapsamda olması gerekir.

HTTP 400 ile birlikte LLM provider 'ollama' is not bundled in this image hatası, "provider": "ollama" gönderdiğiniz anlamına gelir. openai_base_url Ollama'ya yönlendirilmiş şekilde "provider": "openai" kullanın.

Postgres'ten gelen expected 1536 dimensions, not 768 hatası, koleksiyonun bir genişlikte oluşturulduğunu ancak gömme (embedder) işleminin başka bir genişlik döndürdüğünü gösterir. Vektör deposunda embedding_model_dims ayarını yapın ve yeni bir collection_name kullanın.

Arama, model değişikliğinden sonra anlamsız satırlar döndürür ve hiçbir yerde hata oluşmaz. Genişlik hala eşleştiği için veritabanı çalışmaya devam eder, ancak iki farklı model aynı cümleyi farklı konumlara yerleştirir. Yeni bir koleksiyon başlatın ve verileri yeniden ekleyin.

Ollama'ya ulaşırken mem0 günlüklerinde görülen Connection refused, genellikle openai_base_url içindeki 127.0.0.1 hatasıdır. Container içinde bu adres, container'ın kendisidir. Servis ismini kullanın veya Ollama ana makinede (host) çalışıyorsa host gateway adresini kullanın.

Bir ekleme işleminde nginx'ten gelen 504 Gateway Time-out, modelin proxy_read_timeout süresinden daha uzun sürdüğü anlamına gelir. Bu süreyi artırın ve isteği yeniden denemeden önce belleğin yazılıp yazılmadığını kontrol edin.

docker compose up --build sırasında exit code 137 hatası, bir sürecin SIGKILL ile sonlandırıldığını gösterir; çünkü ölümcül bir sinyal N, 128 + N olarak raporlanır ve SIGKILL 9 numaralı sinyaldir. Dashboard küçük bir VPS üzerinde oluşturulurken bu hatanın en olası sorumlusu out-of-memory (bellek yetersizliği) katilidir; bu nedenle işlem yapmadan önce ilk bölümdeki dmesg kontrolünü çalıştırın. Eğer bu kontrol bir sürecin sonlandırıldığını gösteriyorsa swap alanı ekleyin veya imajı daha büyük bir makinede oluşturup bir kayıt defterine (registry) gönderin.

error: port 3000 is already in use, 3000 veya 8888 portları kullanımdayken başlatılmayı reddeden deponun make up hedefinden gelir. lsof -iTCP:3000 -sTCP:LISTEN ile portu kullanan süreci bulun.

FAQ

Grafik belleği ile mem0 çalıştırmak için hala Neo4j'ye ihtiyacım var mı?

Hayır. Nisan 2026'da yayınlanan yeni bellek algoritması, açık kaynaklı SDK'dan graph_store ve enable_graph yapılandırma anahtarlarını kaldırdı. Varlık çıkarma işlemi artık normal bir ekleme sırasında çalışır ve <collection_name>_entities adlı ikinci bir pgvector koleksiyonuna yazılır; bu nedenle harici bir grafik veritabanı, fazladan bir container veya kurulum adımı gerekmez. Bunun karşılığında, arama sonuçlarındaki relations alanı artık mevcut değildir. Varlıklar artık ilişkileri takip etmenizi sağlamak yerine bir belleğin sıralamasını yükseltir; bu nedenle bu ilişkileri kullanan bir uygulamanın mem0 dışında kendi grafik deposuna ihtiyacı vardır.

Kendi kendine barındırılan bir mem0 sunucusunu çalıştırabilecek en küçük VPS nedir?

Dil modeli başka bir yerde barındırılıyorsa, API container'ı, Postgres ve dashboard için 2 GB RAM ve yaklaşık 4 GB boş disk alanı yeterlidir. Kritik an ilk derleme aşamasıdır; çünkü Next.js dashboard'unu derlemek, çalıştırmaktan daha fazla bellek tüketir ve 1 GB'lık bir sunucuda derleme işlemi exit code 137 hatasıyla sonlandırılır. Eğer Ollama aynı sunucuda çalışıyorsa, modeli de hesaba katın: 4-bit kuantizasyonlu 8B bir model tek başına yaklaşık 6 GB bellek gerektirir, bu yüzden 8 GB RAM planlayın.

mem0'ı OpenAI API anahtarı olmadan çalıştırabilir miyim?

Evet, Ollama'nın OpenAI uyumlu uç noktası aracılığıyla çalıştırabilirsiniz. "provider": "ollama" ayarını yapmak başarısız olur, çünkü sunucu imajı yalnızca openai, anthropic ve gemini kütüphanelerini içerir ve HTTP 400 hatası döndürür. Bunun yerine "provider": "openai" değerini koruyun ve hem llm hem de embedder için "openai_base_url": "http://ollama:11434/v1" ayarını boş olmayan herhangi bir api_key değeriyle yapılandırın. Ollama anahtarı görmezden gelir ve paketlenmiş sağlayıcı kontrolü, sağlayıcı gerçekten openai olduğu için başarılı olur.

Yerel bir embedding modeline geçtikten sonra mem0 neden sonuç döndürmüyor?

Çünkü pgvector tablosu sabit bir genişlikte oluşturulmuştur. embedding_model_dims varsayılan olarak 1536 değerindedir, nomic-embed-text ise 768 döndürür ve Postgres, expected 1536 dimensions, not 768 hatasıyla ekleme işlemini reddeder. mem0 tabloyu CREATE TABLE IF NOT EXISTS ile oluşturur, bu nedenle sadece sayıyı değiştirmek mevcut koleksiyon üzerinde bir etki yaratmaz. embedding_model_dims değerini modelinizin gerçek genişliğine ayarlayın, /v1/embeddings çağrısı yapıp döndürdüğü değerleri sayarak bu genişliği doğrulayın ve aynı anda vektör deposuna yeni bir collection_name atayın.

Bu yazı işinize yaradı mı?