SSD Nodes Learn Hosting plans →
Gidsen Matt ConnorDoor Matt Connor · Bijgewerkt 2026-08-28

Mem0 zelf hosten op een VPS: handleiding en RAM-eisen

Leer hoe u mem0 op een eigen VPS draait met Docker Compose. Ontdek de exacte RAM-eisen van 1 GB voor de stack en hoe u Ollama lokaal configureert voor uw AI-geheugenlaag.

Wat het zelf hosten van mem0 op een VPS daadwerkelijk kost aan RAM

Het zelf hosten van mem0 betekent dat u drie containers draait: de FastAPI-geheugenserver, Postgres met de pgvector-extensie en een Next.js-dashboard. mem0 is een geheugenlaag voor agents. U stuurt een gesprek naar de server, een taalmodel haalt de duurzame feiten uit dat gesprek en deze feiten worden opgeslagen als vectoren, zodat een latere query de relevante informatie kan ophalen.

Reken op ongeveer 1 GB aan resident geheugen voor de drie containers en 3 tot 4 GB aan schijfruimte zodra de images zijn gebouwd. Een 2 GB VPS draait dit comfortabel wanneer het taalmodel ergens anders staat. Wanneer het model op dezelfde machine draait via Ollama, domineert het model alles: een 8B-model gekwantiseerd naar 4 bits vereist op zichzelf al ongeveer 6 GB, dus de volledig lokale installatie begint bij 8 GB.

Vertrouw niet blindelings op deze cijfers uit een blogpost, inclusief deze. Meet de stack die u daadwerkelijk heeft gebouwd.

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

docker stats toont het resident geheugen per container. docker system df -v toont de schijfruimte die elke image en elk volume in beslag neemt.

De stabiele toestand is niet de piekbelasting. docker compose up -d --build compileert het Next.js-dashboard en die Node-build is het meest veeleisende moment van de gehele installatie. Op een 1 GB VPS stopt de out-of-memory killer van de kernel het proces en eindigt de build met exit code 137. Bevestig de oorzaak voordat u op zoek gaat naar een Docker-bug:

dmesg -T | grep -i "killed process"

Als een server te veel overhead met zich meebrengt voor wat u nodig heeft, zijn er kleinere opties beschikbaar. een lokale agent-geheugenopslag zonder server en geheugen dat zich binnen Claude Code zelf bevindt slaan beide de database over. Kom hier terug wanneer meerdere agents, of meerdere machines, hetzelfde geheugen moeten kunnen lezen.

Heb ik Neo4j nodig voor mem0 graph memory?

Nee. Als een handleiding u adviseert om een Neo4j-container toe te voegen, dan is die handleiding verouderd.

Graph memory in mem0 betekende voorheen een externe grafiekdatabase, geconfigureerd onder een graph_store-sleutel met enable_graph ingesteld op true. Het nieuwe geheugenalgoritme, uitgebracht in april 2026, heeft beide sleutels uit de open source SDK verwijderd. Entiteit-extractie verloopt nu via het standaard add-pad en de entiteiten worden weggeschreven naar een tweede pgvector-collectie die vernoemd is naar uw hoofdcollectie met _entities als toevoeging. Er is geen migratie vereist. Ingebouwde entiteitskoppeling werkt vanaf de volgende add-aanroep.

Het verwijderen van de graph store bespaart een JVM-container, het bijbehorende geheugen (heap) en enkele honderden megabytes aan image-grootte. Op een 2 GB VPS is dat het verschil tussen soepel draaien en swappen.

Dit is wat u verliest, kort en bondig: zoekresultaten bevatten voorheen een relations-veld met een lijst van verbindingen (edges) tussen entiteiten. Dat veld is verdwenen. Entiteitsmatches verhogen nu de positie van een geheugenitem in de gecombineerde score, en er is geen structuur meer die u kunt doorlopen. Als uw applicatie die relaties gebruikte, dan bevat mem0 deze niet langer en dient u zelf een grafiekdatabase buiten mem0 te beheren, gevoed door uw eigen code.

Het compose-bestand in de repository is een development-versie

server/docker-compose.yaml declareert name: mem0-dev, en dat is precies wat het doet. Lees het bestand voordat u het uitvoert, want er staan vijf zaken in die onjuist zijn voor een server.

  • Het bouwt vanuit server/dev.Dockerfile en mount uw checkout over de image met .:/app, waardoor de container uitvoert wat er in die map staat in plaats van wat u heeft gebouwd.
  • Het commando is rm -rf /app/packages && pip install -q --force-reinstall --no-deps mem0ai && alembic upgrade head && uvicorn main:app --reload. Dit installeert mem0ai bij elke start opnieuw vanaf PyPI, waardoor de versie die uw server draait kan veranderen tijdens een herstart waarvan u niet dacht dat het een upgrade was.
  • Door diezelfde pip-stap mislukt een herstart zonder uitgaand netwerkverkeer nog voordat uvicorn draait. Uw memory-server is dan offline omdat PyPI onbereikbaar was.
  • --reload start de file watcher van uvicorn. Deze is bedoeld om het proces te herstarten wanneer u code bewerkt, en het kost geheugen en een extra proces zonder dat het in productie nuttig is. De productie-Dockerfile bevat ook --reload in zijn CMD, dus u overschrijft het commando hoe dan ook.
  • De gepubliceerde poorten zijn "8888:8000", "8432:5432" en "3000:3000". Een gepubliceerde poort zonder adres ervoor bindt aan 0.0.0.0, waardoor Postgres direct reageert op het publieke internet via 8432 zodra de stack start.

Dat laatste punt verdient een eigen waarschuwing. Docker publiceert een poort door eigen regels te schrijven vóór de keten die ufw beheert, waardoor ufw deny 8432 een gepubliceerde containerpoort niet afsluit. Docker publiceert poorten direct langs ufw behandelt de betrokken regels.

Een compose-bestand voor een productieserver

Werk binnen server/, behoud init-db.sh op de huidige locatie en vervang docker-compose.yaml door het onderstaande.

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

Er zijn vijf belangrijke wijzigingen, elk met een specifieke reden.

Elke ports-vermelding begint met 127.0.0.1, zodat de kernel deze verbindingen alleen accepteert vanaf de server zelf. Al het externe verkeer komt binnen via de reverse proxy, die als enige een certificaat beheert.

Postgres bevat in het geheel geen ports-blok. De mem0-container bereikt de database via mem0_network op basis van de servicenaam; het publiceren van 8432 levert geen voordeel op en resulteert enkel in een openstaande poort. Gebruik docker compose exec postgres psql -U postgres wanneer u een shell nodig heeft.

De geschiedenis wordt verplaatst van de ./history bind mount naar een named volume. Een bind mount koppelt de data aan één specifiek pad en één uid op de host, terwijl een named volume een object is dat Docker kan back-uppen en verplaatsen. Named volumes versus bind mounts beschrijft wanneer u welke optie kiest.

Het commando verwijdert --reload en behoudt alembic upgrade head. Voer deze migratiestap uit. Zonder deze stap start de applicatie met een database zonder tabellen, waardoor elk verzoek bij de eerste query faalt.

NEXT_PUBLIC_API_URL is de URL die uw browser aanroept; dit moet het publieke HTTPS-adres zijn en niet http://mem0:8000. Next.js verwerkt elke NEXT_PUBLIC_-waarde tijdens het build-proces, dus voor wijzigingen is docker compose up -d --build mem0-dashboard vereist. Een eenvoudige herstart behoudt de oude waarde in de JavaScript-bestanden, waardoor het dashboard de verkeerde host aanroept.

Geheimen horen in .env thuis en .env blijft buiten het internet

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

Stel POSTGRES_PASSWORD, JWT_SECRET en ADMIN_API_KEY in. Laat AUTH_DISABLED=false ongewijzigd. De naam geeft duidelijk aan wat deze vlag doet: als deze is ingeschakeld, geeft de server alle opgeslagen geheugen vrij aan iedereen die de poort kan bereiken. Stel MEM0_TELEMETRY=false in als u niet wilt dat het onboarding-event naar upstream wordt verzonden.

ADMIN_API_KEY wordt vergeleken met de X-API-Key-header via secrets.compare_digest; bij een overeenkomst wordt elke database-lookup overgeslagen. Dit is een root-credential voor de gehele API. Behandel het als zodanig: sla het niet op in de shell-history, zet het niet in git en plak het niet in een prompt. Compose env-bestanden en waar geheimen daaruit kunnen lekken en API-sleutels buiten de context van een agent houden zijn beide direct van toepassing, aangezien de aanroepers van deze server agents zijn.

Waarden die vanuit env_file worden geladen, bevinden zich in de container-omgeving en docker inspect print deze volledig uit. Iedereen in de docker-groep kan ze lezen, en iedereen in de docker-groep heeft effectief root-rechten op de host.

Plaats TLS voor de API in plaats van poort 8888 te openen

De API reageert op 127.0.0.1:8888 en het dashboard op 127.0.0.1:3000. nginx handelt de TLS-terminatie (transport layer security) af op poort 443 en stuurt het verkeer door naar beide services.

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|auth|api-keys|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;
    }
}

proxy_read_timeout is belangrijker dan het lijkt. Een add-aanroep blokkeert terwijl het taalmodel de conversatie leest en feiten extraheert. Een lokaal 8B-model op de CPU duurt regelmatig langer dan de standaard time-out van 60 seconden van nginx, waarna de aanroeper 504 Gateway Time-out ziet terwijl het model nog werkt en het geheugen nog wordt weggeschreven. U eindigt dan met een geheugen waarvan werd gemeld dat het mislukt is.

Sluit de overige poorten af met een standaard deny ufw-beleid, waarbij u alleen 22 en 443 openlaat. Vraag het certificaat aan met certbot op Ubuntu 24.04 achter nginx. Als de server al andere applicaties ontsluit met Traefik voor het routeren van meerdere Compose-applicaties, voeg mem0 dan toe aan die router in plaats van een tweede proxy te installeren.

Smoke test: voeg één geheugenitem toe en lees dit terug

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"}'

Een correcte respons is een JSON-object met een results-lijst, waarbij elk item een id, de geëxtraheerde memory-tekst en "event": "ADD" bevat. Het huidige algoritme retourneert alleen ADD-gebeurtenissen. UPDATE- en DELETE-gebeurtenissen zijn verwijderd, dus hun afwezigheid is geen bug.

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}'

Het feit over Postgres 17 zou met een score moeten terugkeren. Geef de identifier door in filters, zoals getoond. Een user_id op het hoogste niveau werkt nog steeds en de server logt Top-level user_id in /search is deprecated. Use filters={...} instead. telkens wanneer u dit gebruikt.

Ruim uw gegevens op zodat de testdata de echte zoekopdrachten niet vervuilt:

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

Als de zoekopdracht minder rijen retourneert dan verwacht, controleer dan de standaardinstellingen voordat u de retrieval de schuld geeft. In de huidige release is de standaardwaarde van top_k 20, in plaats van 100, en de standaardwaarde van threshold is 0.1 in plaats van geen, waardoor zwakke matches nu voor u worden gefilterd. Zodra dit werkt via curl, zijn dezelfde endpoints degene die u koppelt aan een agent, hetzij direct of via een MCP-server die op dezelfde VPS draait.

mem0 uitvoeren zonder OpenAI-sleutel

Begin bij het blokkerende probleem, want dit zult u binnen vijf minuten tegenkomen. De server-image bevat een vaste set provider-libraries en /configure wijst alles af wat daarbuiten valt:

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.

U hoeft niets opnieuw te compileren. Ollama biedt een OpenAI-compatibele API op /v1, die /v1/chat/completions en /v1/embeddings dekt, en de openai-provider van mem0 accepteert een openai_base_url. Wijs die sleutel naar Ollama en de ingebouwde controle slaagt, omdat de provider daadwerkelijk openai is. Alleen het adres verandert.

Voeg Ollama toe aan hetzelfde Compose-project:

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

Voeg ollama_models: toe onder de hoofd-key volumes: en haal vervolgens één chatmodel en één embedding-model op:

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

Als Ollama al op de host draait als systemd-unit, zoals beschreven in Ollama rechtstreeks op een VPS draaien, wijs de container dan niet naar 127.0.0.1:11434. Binnen de mem0-container is 127.0.0.1 de mem0-container zelf. Geef de mem0-service extra_hosts: ["host.docker.internal:host-gateway"], stel Environment="OLLAMA_HOST=0.0.0.0:11434" in via een systemd drop-in zodat Ollama luistert op een adres dat de bridge kan bereiken, en houd poort 11434 gesloten in de firewall.

Vraag het model naar de embedding-dimensie voordat u iets configureert

Deze ene stap bepaalt of retrieval überhaupt werkt.

De pgvector-store van mem0 maakt de tabel aan met een vaste vectorbreedte, vector vector(1536), omdat embedding_model_dims standaard op 1536 staat, de breedte van OpenAI's text-embedding-3-small. nomic-embed-text retourneert 768 waarden. Niets in mem0 vergelijkt deze twee getallen, dus de mismatch komt bij de eerste insert vanuit Postgres naar boven:

expected 1536 dimensions, not 768

Vertrouw ook niet op het getal in deze paragraaf. Vraag het aan het model:

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']))"

Dit print de breedte die uw collectie moet gebruiken. Schrijf de configuratie naar een bestand, want het plakken van een Postgres-wachtwoord via shell-quoting is hoe typefouten in productie terechtkomen.

{
  "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"

De tweede aanroep leest de configuratie terug; dit is de controle of het schrijven is gelukt. Herhaal daarna de bovenstaande smoke test.

Vier details in die JSON liggen niet voor de hand, en elk detail veroorzaakt problemen als u het verkeerd doet.

api_key is de string ollama en Ollama negeert de waarde ervan. Deze mag niet leeg zijn, omdat de OpenAI-clientlibrary een fout genereert voordat een verzoek het proces verlaat als er geen sleutel is ingesteld. Elke niet-lege string werkt.

embedding_model_dims hoort bij de vector store en er is bewust geen embedding_dims op de embedder. mem0 verstuurt de OpenAI dimensions-parameter alleen wanneer u embedding_dims instelt, en backends die geen Matryoshka-truncatie implementeren, wijzen die parameter direct af. Stel de breedte in waar de tabel wordt aangemaakt en laat de embedder ongemoeid.

collection_name is nieuw. mem0 maakt de tabel aan met CREATE TABLE IF NOT EXISTS, dus een andere breedte naar een bestaande collectie wijzen doet helemaal niets: de oude vector(1536)-kolom blijft bestaan en elke insert mislukt. Een breedtewijziging vereist een nieuwe collectienaam, of u moet de oude tabel handmatig verwijderen.

De host in openai_base_url is de Compose-servicenaam ollama, niet localhost. Containers resolven elkaar op hun gedeelde netwerk via de servicenaam.

Wat het volledig lokale pad u kost

Wees eerlijk tegen uzelf over de kwaliteit. De gepubliceerde benchmarkscores van mem0 zijn gemeten met frontier-modellen die de extractie uitvoerden; beschouw deze dus als een plafond en niet als een voorspelling voor een 8B-model op uw VPS. Een klein model schrijft vagere feiten en retourneert soms proza waar JSON werd gevraagd, wat zichtbaar is als een add-aanroep die een lege results-lijst retourneert zonder foutmelding.

Snelheid is de andere kostenpost. Extractie op enkel de CPU kost seconden per add-aanroep, en elk bericht dat u opslaat betaalt die prijs. Een model dat uitweidt voorbij de gevraagde JSON maakt dit erger, dus het antwoord beperken met num_predict stelt een plafond aan hoe lang een enkele add-aanroep kan duren. Als die latentie belangrijk is, is een VPS met een GPU de eerlijke oplossing. Meer CPU-cores toevoegen aan een 8B-model helpt veel minder dan mensen verwachten. Het model wijzigen is een goedkopere hefboom dan de machine wijzigen, en Nemotron 3.5 Lightning op een VPS geeft u de tag om op te halen, het benodigde RAM-geheugen en of CPU-only snel genoeg is om mee te werken.

Eén regel geldt ongeacht uw keuze: meng nooit embedding-modellen binnen één collectie. Twee verschillende modellen die toevallig dezelfde breedte delen, produceren vectoren die niet vergelijkbaar zijn. De insert slaagt, de zoekopdracht retourneert rijen, en de rijen zijn onjuist, zonder dat er ergens een foutmelding verschijnt.

Backups: er zijn twee databases, niet één

De meest voorkomende fout bij het maken van een back-up van mem0 is dat u slechts één database dumpt. init-db.sh maakt naast de standaarddatabase postgres ook mem0_app aan. Deze databases bevatten verschillende gegevens. De database postgres bevat de pgvector-collecties, dus de herinneringen. mem0_app bevat gebruikers, sessies, API-sleutels en aanvraaglogboeken. Elke zelfgehoste app splitst zijn status op een eigen manier op. Daarom hebben twee fot servers die hetzelfde werk doen toch verschillende back-upopdrachten nodig. Controleer dus welke gegevens uw app opslaat voordat u op een dump vertrouwt. Aan het andere uiteinde van dit spectrum staat bijvoorbeeld een Jellyfin-bibliotheek die opnieuw is opgebouwd als een videotheek uit de jaren 90. Die leest de volledige catalogus uit een andere service en heeft daarom meestal niet meer nodig dan een kopie van de eigen configuratie. Voor mem0 zijn beide databases nodig, anders is de restore onbruikbaar.

Herstelt u alleen postgres, dan komen de herinneringen terug, maar zijn alle accounts en API-keys verdwenen, waardoor authenticatie om ze te lezen onmogelijk is. Dump beide, inclusief rollen, in één commando:

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

Het history-volume staat los van Postgres en vereist een eigen kopie:

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

Docker voegt de projectnaam toe als prefix aan volumenamen. Controleer daarom de uwe met docker volume ls voordat u uitgaat van mem0_mem0_history.

Herstel naar een scratch-container en controleer het aantal rijen voordat u de backup als betrouwbaar beschouwt:

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

Een backup die u nooit heeft hersteld, is slechts een aanname. Zodra de dumps correct zijn, verplaatst u ze van de server met restic-snapshots naar externe opslag, want een backup die op dezelfde server staat als de data die hij moet beschermen, biedt geen enkele bescherming.

Foutmodi en de exacte meldingen die u zult zien

{"detail":"Authentication required. Provide a Bearer token or X-API-Key header."} betekent dat de header ontbreekt of verkeerd gespeld is. De naam is X-API-Key en curl verstuurt headernamen letterlijk.

{"detail":"At least one identifier (user_id, agent_id, run_id) is required."} bij een add betekent dat het verzoek er geen bevatte. Een memory moet aan iets gekoppeld zijn, omdat zoekfilters precies op die velden filteren.

LLM provider 'ollama' is not bundled in this image met HTTP 400 betekent dat u "provider": "ollama" heeft verstuurd. Gebruik "provider": "openai" met openai_base_url gericht op Ollama.

expected 1536 dimensions, not 768 vanuit Postgres betekent dat de collectie met een bepaalde breedte is aangemaakt, terwijl de embedder een andere breedte teruggeeft. Stel embedding_model_dims in op de vector store en gebruik een nieuwe collection_name.

Zoekopdrachten retourneren onlogische resultaten na een modelwijziging, zonder dat er ergens een fout optreedt. De breedte komt nog steeds overeen, dus de database functioneert naar behoren, maar twee modellen plaatsen dezelfde zin op verschillende posities. Start een nieuwe collectie en voeg de data opnieuw toe.

Connection refused in de mem0 logs tijdens het bereiken van Ollama betekent meestal 127.0.0.1 in openai_base_url. Binnen de container is dat adres de container zelf. Gebruik de servicenaam of de host gateway wanneer Ollama op de host draait.

504 Gateway Time-out vanuit nginx bij een add betekent dat het model er langer over deed dan proxy_read_timeout. Verhoog deze waarde en controleer of het geheugen al was weggeschreven voordat u het verzoek opnieuw probeert.

exit code 137 tijdens docker compose up --build is de out-of-memory killer die de build van het dashboard stopt. Voeg swap toe of bouw de image op een krachtigere machine en push deze naar een registry.

error: port 3000 is already in use is afkomstig van het make up target van de repo, dat weigert te starten wanneer 3000 of 8888 in gebruik zijn. Zoek de eigenaar met lsof -iTCP:3000 -sTCP:LISTEN.

FAQ

Heb ik nog steeds Neo4j nodig om mem0 met graph memory te draaien?

Nee. Het nieuwe geheugenalgoritme, dat in april 2026 werd uitgebracht, heeft de configuratiesleutels graph_store en enable_graph uit de open source SDK verwijderd. Entiteit-extractie vindt nu plaats tijdens een normale toevoeging en schrijft naar een tweede pgvector-collectie genaamd <collection_name>_entities. Er is dus geen externe graph database, geen extra container en geen migratiestap meer nodig. Het nadeel is dat het veld relations in zoekresultaten niet langer bestaat. Entiteiten verhogen nu de ranking van een geheugen in plaats van dat ze u randen (edges) bieden om te doorlopen; een applicatie die die relaties doorliep, heeft dus een eigen graph store buiten mem0 nodig.

Wat is de kleinste VPS die een zelfgehoste mem0-server kan draaien?

Wanneer het taalmodel elders wordt gehost, zijn 2 GB RAM en ongeveer 4 GB vrije schijfruimte voldoende voor de API-container, Postgres en het dashboard. Het kritieke moment is de eerste build, omdat het compileren van het Next.js-dashboard meer geheugen verbruikt dan het draaien ervan; een server met 1 GB RAM krijgt tijdens de build een exit code 137-foutmelding. Als Ollama op dezelfde server draait, moet u rekening houden met de grootte van het model: een 8B-model met 4-bit kwantisatie heeft op zichzelf al ongeveer 6 GB nodig, dus plan voor 8 GB.

Kan ik mem0 draaien zonder OpenAI API-sleutel?

Ja, via het OpenAI-compatibele eindpunt van Ollama. Het instellen van "provider": "ollama" mislukt, omdat de server-image alleen de openai-, anthropic- en gemini-bibliotheken bevat en een HTTP 400-foutmelding teruggeeft. Behoud in plaats daarvan "provider": "openai" en stel "openai_base_url": "http://ollama:11434/v1" in met een willekeurige niet-lege api_key, zowel voor de llm als de embedder. Ollama negeert de sleutel en de ingebouwde providercontrole slaagt omdat de provider daadwerkelijk openai is.

Waarom geeft mem0 geen resultaten terug nadat ik ben overgestapt op een lokaal embedding-model?

Omdat de pgvector-tabel is aangemaakt met een vaste breedte. embedding_model_dims staat standaard op 1536, nomic-embed-text geeft 768 terug en Postgres weigert de insert met expected 1536 dimensions, not 768. mem0 maakt de tabel aan met CREATE TABLE IF NOT EXISTS, dus het wijzigen van alleen het getal heeft geen effect op een bestaande collectie. Stel embedding_model_dims in op de werkelijke breedte van uw model, bevestig die breedte door /v1/embeddings aan te roepen en de waarden te tellen die het teruggeeft, en geef de vector store tegelijkertijd een nieuwe collection_name.