SSD Nodes Learn 🎉 VPS $5.50/ماہ سے
تعلیمی Matt Connorتحریر: Matt Connor · اپ ڈیٹ شدہ 2026-08-13

VPS پر mem0 کو self-host کرنے کے لیے کتنی RAM چاہیے؟

VPS پر mem0 چلانے کے لیے حقیقی RAM اور disk ضرورت جانیں، localhost سے بند Compose setup، API کے آگے TLS، اور مکمل local Ollama طریقہ دیکھیں۔

VPS پر mem0 کو self-host کرنے کے حقیقی RAM اخراجات

mem0 کو self-host کرنے کا مطلب تین containers چلانا ہے: FastAPI memory server، pgvector extension کے ساتھ Postgres، اور Next.js dashboard۔ mem0، agents کے لیے memory layer ہے۔ آپ اس میں گفتگو بھیجتے ہیں، language model اس گفتگو سے مستقل نوعیت کی معلومات اخذ کرتا ہے، اور یہ معلومات vectors کے طور پر محفوظ ہوتی ہیں تاکہ بعد میں کی جانے والی query متعلقہ معلومات واپس حاصل کر سکے۔

تینوں containers کے لیے تقریباً 1 GB resident memory مختص کریں، اور images build ہونے کے بعد disk کے لیے 3 سے 4 GB درکار ہوں گے۔ جب language model کسی دوسرے مقام پر چل رہا ہو تو 2 GB VPS یہ stack آسانی سے چلا لیتا ہے۔ جب model اسی machine پر Ollama کے ذریعے چلتا ہے تو باقی تمام اجزا کے مقابلے میں model سب سے زیادہ memory استعمال کرتا ہے: 4 bits پر quantised 8B model کو اکیلے تقریباً 6 GB درکار ہوتے ہیں، اس لیے مکمل local build کم از کم 8 GB سے شروع ہوتا ہے۔

ان اعداد و شمار کو کسی blog post، حتیٰ کہ اس تحریر، سے اخذ نہ کریں۔ اپنے بنائے ہوئے stack کی خود پیمائش کریں۔

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

docker stats ہر container کی resident memory دکھاتا ہے۔ docker system df -v ہر image اور ہر volume کے زیرِ استعمال disk space دکھاتا ہے۔

Steady state، peak استعمال نہیں ہوتا۔ docker compose up -d --build Next.js dashboard کو compile کرتا ہے، اور یہ Node build پوری installation کے دوران سب سے زیادہ memory استعمال کرتا ہے۔ 1 GB VPS پر kernel کا out-of-memory killer اسے روک دیتا ہے، اور build exit code 137 کے ساتھ ختم ہوتی ہے۔ Docker bug تلاش کرنے سے پہلے وجہ کی تصدیق کریں:

dmesg -T | grep -i "killed process"

اگر آپ کی ضرورت کے مقابلے میں server بہت زیادہ پیچیدہ محسوس ہو تو چھوٹے اختیارات واقعی موجود ہیں۔ بغیر کسی server کے local agent memory store اور Claude Code کے اندر موجود memory دونوں database کو خارج کر دیتے ہیں۔ جب متعدد agents یا متعدد machines کو ایک ہی memories پڑھنے کی ضرورت ہو تو یہاں واپس آئیں۔

کیا mem0 کی graph memory کے لیے Neo4j درکار ہے؟

نہیں۔ اگر کوئی guide آپ کو Neo4j container شامل کرنے کا کہتی ہے تو وہ guide موجودہ code سے پرانی ہے۔

mem0 میں graph memory سے پہلے مراد ایک external graph database ہوتی تھی، جسے graph_store key کے تحت configure کیا جاتا تھا اور enable_graph کو true پر set کیا جاتا تھا۔ April 2026 میں جاری کیے گئے نئے memory algorithm نے open source SDK سے دونوں keys ہٹا دی ہیں۔ اب entity extraction عام add path کے اندر چلتی ہے، اور entities دوسری pgvector collection میں لکھی جاتی ہیں۔ اس collection کا نام آپ کی main collection کے نام کے ساتھ _entities جوڑ کر بنایا جاتا ہے۔ کسی migration کی ضرورت نہیں۔ Built-in entity linking اگلی add call پر کام شروع کر دیتی ہے۔

Graph store ہٹانے سے JVM container، اس کی heap اور image کے کئی سو megabytes درکار نہیں رہتے۔ 2 GB VPS پر یہی فرق system کے معمول کے مطابق چلنے اور swapping شروع ہونے کے درمیان ہو سکتا ہے۔

آپ کیا کھوتے ہیں، اسے واضح طور پر سمجھ لیں۔ پہلے search results میں relations field شامل ہوتی تھی، جس میں entities کے درمیان edges درج ہوتے تھے۔ اب یہ field موجود نہیں۔ Entity matches اب combined score میں memory کی position بڑھاتے ہیں، لیکن کوئی ایسا structure موجود نہیں جسے traverse کیا جا سکے۔ اگر آپ کی application ان relationships کو traverse کرتی تھی تو mem0 اب انہیں محفوظ نہیں رکھتا۔ ایسی صورت میں mem0 کے باہر اپنا graph database برقرار رکھیں اور اپنے code کے ذریعے اسے data فراہم کریں۔

ریپو میں موجود compose فائل development کے لیے ہے

server/docker-compose.yaml میں name: mem0-dev درج ہے، اور یہ واقعی اسی طرح کام کرتا ہے۔ اسے چلانے سے پہلے پڑھیں، کیونکہ سرور کے لیے اس میں پانچ چیزیں غلط ہیں۔

  • یہ server/dev.Dockerfile سے build ہوتی ہے اور .:/app کے ذریعے آپ کے checkout کو image کے اوپر mount کرتی ہے۔ اس لیے container اس directory میں موجود چیز چلاتا ہے، نہ کہ وہ چیز جو آپ نے build کی تھی۔
  • اس کا command rm -rf /app/packages && pip install -q --force-reinstall --no-deps mem0ai && alembic upgrade head && uvicorn main:app --reload ہے۔ یہ ہر start پر PyPI سے mem0ai دوبارہ install کرتا ہے۔ اس لیے restart کے دوران، جسے آپ upgrade نہیں سمجھ رہے تھے، server پر چلنے والا version تبدیل ہو سکتا ہے۔
  • اسی pip مرحلے کی وجہ سے outbound network کے بغیر restart ناکام ہو جاتا ہے، اس سے پہلے کہ uvicorn چل سکے۔ اس صورت میں آپ کا memory server down ہوتا ہے کیونکہ PyPI قابل رسائی نہیں تھا۔
  • --reload، uvicorn کا file watcher شروع کرتا ہے۔ یہ code میں ترمیم کرنے پر process restart کرنے کے لیے ہے۔ production میں اس کا کوئی مفید کام نہیں، لیکن یہ memory اور ایک اضافی process استعمال کرتا ہے۔ production Dockerfile اپنے CMD میں بھی --reload رکھتا ہے، اس لیے دونوں صورتوں میں command کو override کرنا ہوگا۔
  • شائع شدہ ports "8888:8000"، "8432:5432" اور "3000:3000" ہیں۔ جس published port کے آگے کوئی address نہ ہو، وہ 0.0.0.0 پر bind ہوتا ہے۔ اس لیے stack شروع ہوتے ہی Postgres، port 8432 پر public internet سے درخواستیں قبول کرنے لگتا ہے۔

اس آخری نکتے کے لیے الگ warning ضروری ہے۔ Docker اپنے rules، ufw کے زیر انتظام chain سے پہلے شامل کر کے port publish کرتا ہے۔ اس لیے ufw deny 8432، published container port کو بند نہیں کرتا۔ Docker کے ذریعے ports کو ufw سے براہ راست گزارنا متعلقہ rules کی وضاحت کرتا ہے۔

حقیقی سرور کے لیے compose فائل

server/ کے اندر کام کریں، init-db.sh کو اسی جگہ رہنے دیں، اور docker-compose.yaml کو اس سے تبدیل کریں۔

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

یہاں پانچ تبدیلیاں اہم ہیں، اور ہر تبدیلی کی ایک وجہ ہے۔

ہر ports اندراج 127.0.0.1 سے شروع ہوتا ہے، اس لیے kernel ان connections کو صرف اسی host سے قبول کرتا ہے۔ باہر سے آنے والی تمام درخواستیں reverse proxy کے ذریعے پہنچتی ہیں، اور certificate صرف اسی کے پاس ہوتا ہے۔

Postgres میں ports block بالکل نہیں ہے۔ mem0 container، service name کے ذریعے mem0_network پر اس تک پہنچتا ہے، اس لیے 8432 کو publish کرنے سے کوئی فائدہ نہیں ہوتا اور ایک open port ضرور بڑھ جاتا ہے۔ Shell درکار ہو تو docker compose exec postgres psql -U postgres استعمال کریں۔

History، ./history bind mount سے named volume میں منتقل ہو جاتی ہے۔ Bind mount اس data کو اس host کے ایک path اور ایک uid کے ساتھ باندھ دیتا ہے، جبکہ named volume ایک ایسا object ہے جس کا Docker snapshot لے کر اسے منتقل کر سکتا ہے۔ Named volumes اور bind mounts کا موازنہ میں بتایا گیا ہے کہ ہر ایک کب مناسب ہے۔

Command میں --reload نکال کر alembic upgrade head برقرار رکھا گیا ہے۔ Migration کا یہ مرحلہ برقرار رکھیں۔ اس کے بغیر app ایسی database کے خلاف boot ہوتی ہے جس میں tables موجود نہیں ہوتیں، اور ہر request پہلی query پر fail ہو جاتی ہے۔

NEXT_PUBLIC_API_URL وہ URL ہے جسے آپ کا browser call کرتا ہے، اس لیے یہ public HTTPS address ہونا چاہیے، http://mem0:8000 نہیں۔ Next.js ہر NEXT_PUBLIC_ value کو build time پر inline کرتا ہے، اس لیے اسے تبدیل کرنے کے لیے docker compose up -d --build mem0-dashboard درکار ہے۔ سادہ restart کرنے سے JavaScript میں پرانی value برقرار رہتی ہے، اور dashboard غلط host کو call کرتا ہے۔

راز .env میں رہتے ہیں، اور .env انٹرنیٹ سے دور رہتی ہے

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 اور ADMIN_API_KEY مقرر کریں۔ AUTH_DISABLED=false کو نہ چھیڑیں۔ اس flag کا نام واضح طور پر بتاتا ہے کہ یہ کیا کرتا ہے: فعال ہونے پر server اپنی تمام memory ہر اس شخص کو دے دیتا ہے جو port تک پہنچ سکتا ہو۔ اگر آپ onboarding event کو upstream بھیجنا نہیں چاہتے تو MEM0_TELEMETRY=false مقرر کریں۔

ADMIN_API_KEY کا موازنہ X-API-Key header سے secrets.compare_digest کے ذریعے کیا جاتا ہے، اور match ہونے پر database کی تمام lookup کارروائیاں چھوڑ دی جاتی ہیں۔ یہ پوری API کے لیے root credential ہے۔ اسے اسی طرح محفوظ رکھیں: shell history میں نہ آنے دیں، git میں commit نہ کریں، اور اسے prompt میں paste نہ کریں۔ Compose env files اور ان سے secrets کے افشا ہونے کی جگہیں اور API keys کو agent کے context سے باہر رکھنا دونوں یہاں براہ راست لاگو ہوتے ہیں، کیونکہ اس server کو استعمال کرنے والے callers agents ہیں۔

env_file سے load کی جانے والی values container environment میں موجود رہتی ہیں، اور docker inspect انہیں مکمل طور پر دکھاتا ہے۔ docker group کا ہر رکن انہیں پڑھ سکتا ہے، اور docker group کا ہر رکن host پر عملاً root ہوتا ہے۔

API کو 8888 کھولنے کے بجائے اس کے سامنے TLS رکھیں

API، 127.0.0.1:8888 پر اور dashboard، 127.0.0.1:3000 پر جواب دیتا ہے۔ nginx، 443 پر TLS (transport layer security) ختم کرتا ہے اور دونوں درخواستیں متعلقہ سروسز کو بھیج دیتا ہے۔

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 کی اہمیت بظاہر زیادہ محسوس نہیں ہوتی، لیکن یہ اہم ہے۔ add call اس وقت تک block رہتی ہے جب تک language model گفتگو پڑھ کر حقائق اخذ نہیں کر لیتا۔ CPU پر چلنے والا مقامی 8B model، عموماً nginx کے 60 second default سے زیادہ وقت لیتا ہے۔ اس صورت میں caller کو 504 Gateway Time-out نظر آتا ہے، جبکہ model ابھی کام کر رہا ہوتا ہے اور memory پھر بھی لکھ دی جاتی ہے۔ نتیجتاً ایسی memory بن جاتی ہے جس کے بارے میں آپ کو بتایا گیا تھا کہ یہ fail ہو گئی ہے۔

باقی رسائی کو default deny ufw policy کے ذریعے بند کریں اور صرف 22 اور 443 کھلے رکھیں۔ certificate، nginx کے پیچھے Ubuntu 24.04 پر certbot کے ذریعے جاری کریں۔ اگر یہ server پہلے ہی متعدد Compose apps کی Traefik routing کے ذریعے دوسری apps کے سامنے proxy فراہم کر رہا ہے تو دوسرا proxy نصب کرنے کے بجائے mem0 کو اسی router میں شامل کریں۔

Smoke test: ایک memory شامل کریں اور اسے دوبارہ پڑھیں

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

درست response ایک JSON object ہوتا ہے جس میں results list شامل ہوتی ہے۔ ہر entry میں id، اخذ کیا گیا memory متن، اور "event": "ADD" شامل ہوتے ہیں۔ موجودہ algorithm صرف ADD events واپس کرتا ہے۔ UPDATE اور DELETE events ہٹا دیے گئے ہیں، اس لیے ان کا نہ ہونا 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}'

Postgres 17 سے متعلق fact score کے ساتھ واپس آنا چاہیے۔ identifier کو filters کے اندر، دکھائے گئے طریقے کے مطابق، بھیجیں۔ top level user_id اب بھی کام کرتا ہے، اور server اسے ہر بار استعمال کرنے پر Top-level user_id in /search is deprecated. Use filters={...} instead. log کرتا ہے۔

اپنے بعد cleanup کریں تاکہ test data حقیقی searches کو متاثر نہ کرے:

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

اگر search آپ کی توقع سے کم rows واپس کرے تو retrieval کو ذمہ دار ٹھہرانے سے پہلے defaults چیک کریں۔ موجودہ release میں top_k کی default value 20 ہے، جو پہلے 100 تھی، اور threshold کی default value none کے بجائے 0.1 ہے۔ اس لیے کمزور matches اب خودکار طور پر filter ہو جاتے ہیں۔ جب یہ curl کے ذریعے کام کرنے لگے تو یہی endpoints آپ agent کے ساتھ wire کریں گے، خواہ براہِ راست یا اسی VPS پر چلنے والے MCP server کے ذریعے۔

mem0 کو کسی OpenAI key کے بغیر چلائیں

رکاوٹ سے شروع کریں، کیونکہ پہلے پانچ منٹ میں آپ اس سے ٹکرائیں گے۔ سرور image میں provider libraries کا ایک مقررہ مجموعہ شامل ہوتا ہے، اور /configure اس مجموعے سے باہر کی کسی چیز کو قبول نہیں کرتا:

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.

آپ کو کچھ بھی دوبارہ build کرنے کی ضرورت نہیں۔ Ollama، /v1 پر OpenAI-compatible API فراہم کرتا ہے، جو /v1/chat/completions اور /v1/embeddings کو support کرتی ہے، اور mem0 کا openai provider ایک openai_base_url قبول کرتا ہے۔ اس key کو Ollama کی طرف point کریں۔ bundled check کامیاب ہو جائے گا، کیونکہ provider واقعی openai ہے۔ صرف address تبدیل ہوتا ہے۔

اسی Compose project میں Ollama شامل کریں:

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

top-level volumes: key کے تحت ollama_models: شامل کریں، پھر ایک chat model اور ایک embedding model pull کریں:

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

اگر Ollama پہلے ہی host پر systemd unit کے طور پر چل رہا ہے، جیسا کہ VPS پر Ollama براہ راست چلانا میں ہے، تو container کو 127.0.0.1:11434 کی طرف point نہ کریں۔ mem0 container کے اندر 127.0.0.1، mem0 container ہے۔ mem0 service کو extra_hosts: ["host.docker.internal:host-gateway"] دیں، systemd drop-in میں Environment="OLLAMA_HOST=0.0.0.0:11434" set کریں تاکہ Ollama ایسے address پر listen کرے جس تک bridge پہنچ سکے، اور firewall پر 11434 بند رکھیں۔

کچھ بھی configure کرنے سے پہلے model سے اس کا embedding dimension پوچھیں

یہ ایک قدم طے کرتا ہے کہ retrieval بالکل کام کرے گا یا نہیں۔

mem0 کا pgvector store اپنی table ایک مقررہ vector width، vector vector(1536)، کے ساتھ بناتا ہے، کیونکہ embedding_model_dims کی default value 1536 ہے، جو OpenAI کے text-embedding-3-small کی width ہے۔ nomic-embed-text 768 values واپس کرتا ہے۔ mem0 کے اندر ان دونوں نمبروں کا موازنہ نہیں ہوتا، اس لیے یہ mismatch پہلے insert پر Postgres کی طرف سے ظاہر ہوتا ہے:

expected 1536 dimensions, not 768

اس paragraph میں موجود number پر بھی بھروسا نہ کریں۔ 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']))"

یہ وہ width دکھاتا ہے جو آپ کی collection کو استعمال کرنی ہوگی۔ configuration کو ایک file میں لکھیں، کیونکہ shell quoting کے ذریعے Postgres password paste کرنے سے production میں typos شامل ہو جاتے ہیں۔

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

دوسری call configuration واپس پڑھتی ہے۔ یہ اس بات کی تصدیق ہے کہ write کامیاب ہوئی۔ اس کے بعد اوپر دیا گیا smoke test دوبارہ چلائیں۔

اس JSON میں چار details واضح نہیں ہیں، اور ہر detail غلط ہونے کی صورت میں کچھ نہ کچھ توڑ دیتی ہے۔

api_key، ollama string ہے، اور Ollama اس کی value کو ignore کرتا ہے۔ یہ empty نہیں ہو سکتی، کیونکہ key set نہ ہونے پر OpenAI client library کوئی request process سے باہر جانے سے پہلے ہی exception raise کر دیتی ہے۔ کوئی بھی non-empty string کام کرتی ہے۔

embedding_model_dims vector store میں شامل ہوتا ہے، اور embedder پر جان بوجھ کر embedding_dims نہیں ہے۔ mem0 صرف اس وقت OpenAI کا dimensions parameter بھیجتا ہے جب آپ embedding_dims set کریں۔ جو backends Matryoshka truncation implement نہیں کرتے، وہ اس parameter کو براہ راست reject کر دیتے ہیں۔ width وہاں set کریں جہاں table بنائی جاتی ہے، اور embedder کو تبدیل نہ کریں۔

collection_name نیا ہے۔ mem0 اپنی table CREATE TABLE IF NOT EXISTS کے ساتھ بناتا ہے، اس لیے کسی موجودہ collection کو مختلف width کی طرف point کرنے سے کچھ بھی نہیں ہوتا: پرانا vector(1536) column برقرار رہتا ہے، اور ہر insert fail ہو جاتا ہے۔ width تبدیل کرنے کے لیے نئی collection name درکار ہے، یا پرانی table کو دستی طور پر drop کریں۔

openai_base_url میں host، Compose service name ollama ہے، localhost نہیں۔ Containers اپنے shared network پر ایک دوسرے کو service name کے ذریعے resolve کرتے ہیں۔

مکمل local path کی لاگت

quality کے بارے میں خود سے دیانت دار رہیں۔ mem0 کے شائع شدہ benchmark scores frontier models کے ذریعے extraction کے ساتھ ناپے گئے تھے، اس لیے انہیں VPS پر 8B model کے لیے forecast کے بجائے ceiling سمجھیں۔ چھوٹا model زیادہ مبہم facts لکھتا ہے، اور کبھی کبھی JSON کی درخواست کے باوجود prose واپس کرتا ہے۔ اس کا نتیجہ یہ ہوتا ہے کہ add call بغیر کسی error کے empty results list واپس کرتی ہے۔

رفتار دوسری لاگت ہے۔ صرف CPU پر extraction ہر add call کے لیے کئی seconds لیتی ہے، اور آپ جو ہر message store کرتے ہیں اس کی یہ لاگت ادا کرتے ہیں۔ اگر یہ latency اہم ہے تو GPU کے ساتھ منسلک VPS ہی درست حل ہے۔ 8B model کو زیادہ CPU cores دینے سے فائدہ لوگوں کی توقع سے کہیں کم ہوتا ہے۔

آپ جو بھی انتخاب کریں، ایک اصول برقرار رہتا ہے: ایک collection میں embedding models کو کبھی mix نہ کریں۔ دو مختلف models جن کی width اتفاقاً یکساں ہو، ایسے vectors بناتے ہیں جو ایک دوسرے سے comparable نہیں ہوتے۔ insert کامیاب ہو جاتا ہے، search rows واپس کرتی ہے، اور rows غلط ہوتی ہیں، جبکہ کہیں بھی کوئی error report نہیں ہوتا۔

بیک اپس: ایک نہیں، دو databases ہیں

mem0 کا سب سے عام backup مسئلہ صرف ایک database کا dump بنانا ہے۔ init-db.sh، default postgres database کے ساتھ mem0_app بناتا ہے، اور دونوں میں مختلف ڈیٹا ہوتا ہے۔ postgres database میں pgvector collections ہوتی ہیں، جو memories ہیں۔ mem0_app میں users، sessions، API keys اور request logs ہوتے ہیں۔

صرف postgres restore کرنے سے memories واپس آ جائیں گی، لیکن ہر account اور API key ختم ہو جائے گی، اس لیے کوئی بھی ان memories کو پڑھنے کے لیے authenticate نہیں کر سکے گا۔ ایک ہی command میں دونوں databases اور roles کا dump بنائیں:

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

history volume، Postgres سے الگ ہے اور اس کی اپنی copy درکار ہے:

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

Docker، volume names کے شروع میں project name شامل کرتا ہے۔ اس لیے docker volume ls سے اپنا نام confirm کریں، mem0_mem0_history فرض نہ کریں۔

Restore کو ایک scratch container میں کریں اور کسی بھی نتیجے پر اعتماد کرنے سے پہلے row counts چیک کریں:

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

جس backup کو کبھی restore نہ کیا گیا ہو، وہ صرف ایک اندازہ ہے۔ Dumps درست ہونے کے بعد انہیں restic snapshots کو off-site storage میں منتقل کریں، کیونکہ جس server کی حفاظت کے لیے backup بنایا گیا ہو، اگر وہ اسی server پر موجود رہے تو کسی چیز کی حفاظت نہیں کرتا۔

ناکامی کی صورتیں اور نظر آنے والے عین strings

{"detail":"Authentication required. Provide a Bearer token or X-API-Key header."} کا مطلب ہے کہ header موجود نہیں یا اس کا املا غلط ہے۔ نام X-API-Key ہے، اور curl header names کو بعینہٖ بھیجتا ہے۔

کسی memory کو شامل کرتے وقت {"detail":"At least one identifier (user_id, agent_id, run_id) is required."} کا مطلب ہے کہ request میں ان میں سے کوئی بھی شامل نہیں تھا۔ memory کو کسی مخصوص scope سے وابستہ ہونا ضروری ہے، کیونکہ search عین انہی fields پر filter کرتی ہے۔

HTTP 400 کے ساتھ LLM provider 'ollama' is not bundled in this image کا مطلب ہے کہ آپ نے "provider": "ollama" بھیجا ہے۔ openai_base_url کو Ollama کی طرف متوجہ کر کے "provider": "openai" استعمال کریں۔

Postgres سے آنے والا expected 1536 dimensions, not 768 بتاتا ہے کہ collection ایک width پر بنایا گیا تھا، جبکہ embedder دوسری width واپس کر رہا ہے۔ vector store پر embedding_model_dims مقرر کریں اور نیا collection_name استعمال کریں۔

model تبدیل کرنے کے بعد، اور کہیں بھی کوئی error نہ ہونے کے باوجود، Search returns rows that make no sense۔ width اب بھی مطابقت رکھتی ہے، اس لیے database اسے درست سمجھتا ہے، لیکن دونوں models ایک ہی sentence کو مختلف positions پر رکھتے ہیں۔ نئی collection شروع کریں اور entries دوبارہ شامل کریں۔

Ollama تک پہنچتے وقت mem0 logs میں Connection refused عموماً openai_base_url میں 127.0.0.1 کی نشاندہی کرتا ہے۔ container کے اندر وہ address خود container ہوتا ہے۔ service name استعمال کریں، یا جب Ollama host پر چل رہا ہو تو host gateway استعمال کریں۔

کسی memory کو شامل کرتے وقت nginx سے آنے والا 504 Gateway Time-out بتاتا ہے کہ model نے proxy_read_timeout سے زیادہ وقت لیا۔ اس timeout کو بڑھائیں، اور request دوبارہ بھیجنے سے پہلے جانچیں کہ memory پہلے ہی لکھی گئی ہے یا نہیں۔

docker compose up --build کے دوران آنے والا exit code 137 out-of-memory killer کی طرف سے dashboard build روکنے کی نشاندہی کرتا ہے۔ swap شامل کریں، یا image کسی بڑی machine پر build کر کے اسے registry میں push کریں۔

error: port 3000 is already in use repo کے make up target سے آتا ہے۔ یہ target اس وقت start نہیں ہوتا جب 3000 یا 8888 استعمال میں ہوں۔ مالک کا process lsof -iTCP:3000 -sTCP:LISTEN سے معلوم کریں۔

FAQ

کیا graph memory کے ساتھ mem0 چلانے کے لیے اب بھی Neo4j درکار ہے؟

نہیں۔ اپریل 2026 میں جاری کیے گئے نئے memory algorithm نے open source SDK سے graph_store اور enable_graph configuration keys ہٹا دی ہیں۔ Entity extraction اب معمول کے add operation کے دوران چلتی ہے اور <collection_name>_entities نام کے دوسرے pgvector collection میں data لکھتی ہے۔ اس لیے external graph database، اضافی container یا migration step کی ضرورت نہیں رہتی۔ اس کے عوض search results میں relations field اب موجود نہیں ہے۔ Entities اب memory کی ranking بڑھاتی ہیں، لیکن traverse کرنے کے لیے edges فراہم نہیں کرتیں۔ اس لیے جو application ان relationships کو traverse کرتی تھی، اسے mem0 سے باہر اپنا graph store استعمال کرنا ہوگا۔

self-hosted mem0 server چلانے والا سب سے چھوٹا VPS کون سا ہے؟

اگر language model کسی دوسرے server پر hosted ہو تو API container، Postgres اور dashboard کے لیے 2 GB RAM اور تقریباً 4 GB free disk کافی ہے۔ اصل دباؤ پہلے build کے دوران آتا ہے، کیونکہ Next.js dashboard کو compile کرنے میں اسے چلانے کے مقابلے میں زیادہ memory درکار ہوتی ہے۔ 1 GB machine پر build process exit code 137 کے ساتھ terminate ہو جاتا ہے۔ اگر Ollama اسی server پر چلانا ہو تو model کے مطابق sizing کریں۔ 4-bit quantisation والا 8B model اکیلا تقریباً 6 GB memory لیتا ہے، اس لیے 8 GB RAM کا منصوبہ بنائیں۔

کیا OpenAI API key کے بغیر mem0 چلایا جا سکتا ہے؟

ہاں، Ollama کے OpenAI compatible endpoint کے ذریعے۔ "provider": "ollama" set کرنے سے failure ہوتا ہے، کیونکہ server image میں صرف openai، anthropic اور gemini libraries bundled ہیں اور وہ HTTP 400 واپس کرتی ہے۔ اس کے بجائے "provider": "openai" برقرار رکھیں اور llm اور embedder دونوں کے لیے "openai_base_url": "http://ollama:11434/v1" کو کسی بھی non empty api_key کے ساتھ set کریں۔ Ollama اس key کو نظرانداز کرتا ہے، اور bundled provider check کامیاب ہو جاتا ہے کیونکہ provider حقیقت میں openai ہے۔

مقامی embedding model پر switch کرنے کے بعد mem0 کوئی result کیوں واپس نہیں کرتا؟

کیونکہ pgvector table ایک مقررہ width کے ساتھ بنائی گئی تھی۔ embedding_model_dims کی default value 1536 ہے، جبکہ nomic-embed-text سے 768 واپس آتا ہے، اور Postgres expected 1536 dimensions, not 768 کے ساتھ insert مسترد کر دیتا ہے۔ mem0 table کو CREATE TABLE IF NOT EXISTS کے ساتھ بناتا ہے، اس لیے صرف number تبدیل کرنے سے موجودہ collection پر کوئی اثر نہیں پڑتا۔ embedding_model_dims کو اپنے model کی حقیقی width پر set کریں۔ /v1/embeddings call کرکے اور اس سے واپس آنے والی values گن کر width کی تصدیق کریں۔ اسی وقت vector store کے لیے نیا collection_name فراہم کریں۔