SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-10-26

Self-hosting mem0: установка на VPS и требования к RAM

Узнайте, как развернуть mem0 на собственном VPS. Инструкция включает настройку Docker Compose, привязку к localhost, использование TLS и интеграцию с Ollama. Реальные затраты памяти.

Реальные затраты оперативной памяти при self-hosting mem0 на VPS

Self-hosting mem0 подразумевает запуск трех контейнеров: сервера FastAPI для работы с памятью, базы данных Postgres с расширением pgvector и панели управления на Next.js. mem0 — это уровень памяти для агентов. Вы отправляете в него диалог, языковая модель извлекает из него устойчивые факты, которые сохраняются в виде векторов, чтобы при последующем запросе можно было получить релевантные данные.

Закладывайте примерно 1 GB оперативной памяти для трех контейнеров и от 3 до 4 GB дискового пространства после сборки образов. VPS с 2 GB RAM комфортно справляется с этой задачей, если языковая модель работает на другом узле. Если модель запущена на том же сервере через Ollama, она потребляет основные ресурсы: модель с 8B параметров, квантованная до 4 бит, требует около 6 GB RAM, поэтому для полностью локальной сборки потребуется от 8 GB.

Не полагайтесь на цифры из блогов, включая этот. Измеряйте стек, который вы развернули на самом деле.

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

docker stats выводит объем резидентной памяти для каждого контейнера. docker system df -v показывает объем дискового пространства, занимаемый каждым образом и томом.

Стабильное состояние — это не пиковая нагрузка. docker compose up -d --build компилирует панель управления Next.js, и этот процесс сборки на Node является самым ресурсоемким этапом всей установки. На VPS с 1 GB RAM механизм OOM-killer (out-of-memory killer) ядра принудительно завершает процесс, и сборка заканчивается ошибкой exit code 137. Подтвердите причину, прежде чем искать ошибку в Docker:

dmesg -T | grep -i "killed process"

Если сервер кажется избыточным решением для ваших задач, существуют более компактные варианты. локальное хранилище памяти агента без использования сервера и память, работающая внутри самого Claude Code позволяют обойтись без базы данных. Возвращайтесь к этому руководству, когда нескольким агентам или нескольким машинам потребуется доступ к одним и тем же данным памяти.

Нужен ли Neo4j для графовой памяти mem0?

Нет. Если в руководстве предлагается добавить контейнер Neo4j, значит, это руководство устарело.

Ранее графовая память в mem0 подразумевала использование внешней графовой базы данных, настраиваемой через ключ graph_store с параметром enable_graph, установленным в true. Новый алгоритм работы с памятью, выпущенный в апреле 2026 года, исключил оба этих ключа из SDK с открытым исходным кодом. Извлечение сущностей теперь выполняется в рамках стандартного процесса добавления данных, а сами сущности записываются во вторую коллекцию pgvector, название которой совпадает с основной с добавлением суффикса _entities. Этап настройки отсутствует: коллекция создается при первом обращении, поэтому встроенная привязка сущностей начинает работать сразу после следующего вызова добавления.

Отказ от графового хранилища позволяет не запускать контейнер JVM, не выделять память под его кучу и экономить несколько сотен мегабайт дискового пространства. На VPS с 2 GB оперативной памяти это определяет разницу между нормальной работой и уходом системы в swap.

Ниже перечислены возможности, от которых вы отказываетесь. Ранее результаты поиска содержали поле relations, в котором перечислялись связи между сущностями. Это поле удалено. Теперь совпадения сущностей просто повышают позицию записи в памяти в общем рейтинге, а структуры, по которой можно было бы перемещаться, больше нет. Если ваше приложение использовало эти связи, mem0 их больше не хранит. В таком случае вам потребуется собственная графовая база данных вне mem0, которую вы будете наполнять своим кодом.

Файл compose в репозитории предназначен для разработки

server/docker-compose.yaml объявляет name: mem0-dev, и это именно то, что он делает. Прочитайте его перед запуском, так как пять моментов в нем не подходят для сервера.

  • Он выполняет сборку из server/dev.Dockerfile и монтирует вашу рабочую копию поверх образа с помощью .:/app, поэтому контейнер запускает то, что находится в этой директории, а не то, что вы собрали.
  • Его команда — 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. Она переустанавливает mem0ai из PyPI при каждом запуске, поэтому версия, которую использует ваш сервер, может измениться во время перезагрузки, которую вы не планировали как обновление.
  • Тот же шаг pip означает, что перезагрузка при отсутствии исходящего сетевого соединения завершится ошибкой до запуска uvicorn. Ваш сервер памяти окажется недоступен, так как PyPI был недостижим.
  • --reload запускает файловый наблюдатель uvicorn. Он нужен для перезапуска процесса при редактировании кода, но в продакшене он лишь потребляет память и создает лишний процесс, не принося пользы. Продакшн-образ Dockerfile содержит --reload в своем CMD, поэтому вы в любом случае переопределяете команду.
  • Опубликованные порты — "8888:8000", "8432:5432" и "3000:3000". Опубликованный порт без указания адреса привязывается к 0.0.0.0, поэтому Postgres будет отвечать всему интернету на порту 8432 сразу после запуска стека.

Последний пункт заслуживает отдельного предупреждения. Docker публикует порт, записывая свои правила до цепочки, которой управляет ufw, поэтому ufw deny 8432 не закрывает опубликованный порт контейнера. В публикации портов Docker в обход ufw подробно описаны соответствующие правила.

Файл 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, поэтому ядро принимает эти соединения только с самой машины. Всё, что поступает извне, проходит через reverse proxy, который является единственным компонентом, хранящим сертификат.

У Postgres вообще нет блока ports. Контейнер mem0 обращается к нему по mem0_network, используя имя сервиса, поэтому публикация 8432 ничего не дает, кроме открытого порта. Используйте docker compose exec postgres psql -U postgres, когда вам нужен shell.

История перемещается из bind mount ./history в именованный том (named volume). Bind mount привязывает данные к одному пути и одному uid на хосте, в то время как именованный том — это объект, который Docker может копировать и перемещать. Именованные тома против bind mounts описывает, когда и что лучше использовать.

Команда убирает --reload и оставляет alembic upgrade head. Обязательно сохраните этот шаг миграции. Без него приложение запустится с пустой базой данных без таблиц, и каждый запрос будет завершаться ошибкой при первом же обращении.

NEXT_PUBLIC_API_URL — это URL, который вызывает ваш браузер, поэтому он должен быть публичным HTTPS-адресом, а не http://mem0:8000. Next.js встраивает значения NEXT_PUBLIC_ во время сборки, но образ этой панели управления содержит плейсхолдер, а точка входа (entrypoint) подставляет реальное значение при запуске контейнера. Поэтому для изменения значения требуется docker compose up -d mem0-dashboard, что пересоздает контейнер, а не просто перезапускает его. docker compose restart mem0-dashboard повторно использует старый контейнер, файлы которого уже содержат старое значение, и панель управления продолжает обращаться к неверному хосту.

Секреты хранятся в .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. Название флага точно описывает его действие: при включении сервер передает всю память, которой располагает, любому, кто имеет доступ к порту. Установите MEM0_TELEMETRY=false, если не хотите, чтобы событие онбординга отправлялось вышестоящему узлу.

ADMIN_API_KEY сравнивается с заголовком X-API-Key с помощью secrets.compare_digest, и совпадение полностью исключает поиск по ключу в базе данных: запрос выполняется от имени первого пользователя, созданного на сервере. Это корневые учетные данные для всего API. Обращайтесь с ними соответствующим образом: никакой истории командной оболочки, никакого git, не вставляйте их в запрос к ИИ. Статьи Составление файлов env и места утечки секретов из них и защита API-ключей от попадания в контекст агента применимы напрямую, так как вызывающие стороны этого сервера являются агентами.

Значения, загруженные из env_file, находятся в окружении контейнера, а docker inspect выводит их полностью. Любой пользователь в группе docker может прочитать их, а любой пользователь в группе docker фактически является root на хосте.

Размещение TLS перед API вместо открытия порта 8888

API отвечает по адресу 127.0.0.1:8888, а панель управления — по 127.0.0.1:3000. nginx выполняет TLS termination (завершение шифрования) на 443 порту и перенаправляет запросы к обоим сервисам.

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

Код панели управления в браузере обращается к каждому пути API по шаблону NEXT_PUBLIC_API_URL, включая /entities и /requests. Если пропустить хотя бы один, nginx передаст этот запрос в Next.js, и страница панели управления, которой требуются данные, получит ошибку 404 вместо ответа.

Параметр proxy_read_timeout важнее, чем кажется. Вызов добавления данных блокируется, пока языковая модель анализирует диалог и извлекает факты. Локальная модель 8B на CPU обычно работает дольше, чем стандартный таймаут nginx в 60 секунд. В результате вызывающая сторона видит 504 Gateway Time-out, хотя модель всё ещё работает, а запись в память продолжается. В итоге вы получаете сообщение об ошибке записи, хотя фактически процесс завершился успешно.

Закройте остальные порты с помощью политики ufw по умолчанию «запретить всё», оставив открытыми только 22, 80 и 443. Выпустите сертификат, используя certbot в Ubuntu 24.04 с nginx. Порт 80 должен оставаться доступным, так как этот процесс использует проверку HTTP-01, которую Let's Encrypt выполняет только на 80 порту при выпуске и при каждом продлении сертификата. Если закрыть 80 порт, потребуется переключиться на проверку DNS-01. Если сервер уже использует Traefik для маршрутизации нескольких Compose-приложений, добавьте mem0 в этот маршрутизатор вместо установки второго прокси-сервера.

Smoke-тест: добавление одной записи в память и её чтение

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

Корректный ответ представляет собой JSON-объект со списком results, где каждая запись содержит id, извлечённый текст memory и "event": "ADD". Текущий алгоритм возвращает только события ADD. События UPDATE и DELETE были удалены, поэтому их отсутствие не является ошибкой.

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 должен вернуться с оценкой (score). Передайте идентификатор внутри filters, как показано в примере. Использование user_id верхнего уровня по-прежнему работает, и сервер записывает Top-level user_id in /search is deprecated. Use filters={...} instead. в логи при каждом таком обращении.

Удалите тестовые данные после завершения, чтобы они не влияли на реальные результаты поиска:

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

Если поиск возвращает меньше строк, чем ожидалось, проверьте значения по умолчанию, прежде чем искать проблему в механизме извлечения. В текущем релизе top_k по умолчанию равно 20 (ранее было 100), а threshold по умолчанию равно 0.1 вместо отсутствия фильтрации, поэтому слабые совпадения теперь отсеиваются автоматически. Как только это заработает через curl, эти же эндпоинты можно подключать к агенту — напрямую или через MCP-сервер, запущенный на том же VPS.

Запуск mem0 без ключа OpenAI

Начните с блокирующего фактора, так как вы столкнетесь с ним в первые пять минут. Образ сервера содержит фиксированный набор библиотек провайдеров, и /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.

Вам не нужно ничего пересобирать. Ollama предоставляет API, совместимый с OpenAI, по адресу /v1, поддерживая /v1/chat/completions и /v1/embeddings, а провайдер openai в mem0 принимает openai_base_url. Укажите этот ключ для Ollama, и встроенная проверка будет пройдена, так как провайдер действительно является openai. Меняется только адрес.

Добавьте Ollama в тот же проект Compose:

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

Добавьте ollama_models: в раздел volumes: верхнего уровня, затем загрузите одну модель для чата и одну модель для эмбеддингов:

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

Если Ollama уже запущена на хосте как systemd-юнит, как описано в запуске Ollama напрямую на VPS, не указывайте контейнеру адрес 127.0.0.1:11434. Внутри контейнера mem0 адрес 127.0.0.1 — это сам контейнер mem0. Предоставьте сервису mem0 extra_hosts: ["host.docker.internal:host-gateway"], установите Environment="OLLAMA_HOST=0.0.0.0:11434" в drop-in файле systemd, чтобы Ollama слушала адрес, доступный через bridge-сеть, и закройте порт 11434 на межсетевом экране.

Узнайте размерность эмбеддингов модели перед настройкой

Этот шаг определяет, будет ли вообще работать поиск.

Хранилище pgvector в mem0 создает таблицу с фиксированной шириной вектора vector vector(1536), так как embedding_model_dims по умолчанию использует 1536 — ширину модели text-embedding-3-small от OpenAI. nomic-embed-text возвращает 768 значений. Внутри mem0 нет проверки соответствия этих двух чисел, поэтому несоответствие проявится со стороны Postgres при первой же попытке вставки:

expected 1536 dimensions, not 768

Не доверяйте числу из этого абзаца. Спросите модель:

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

Это выведет ширину, которую должна использовать ваша коллекция. Запишите конфигурацию в файл, так как вставка пароля Postgres через экранирование в командной строке — верный способ допустить опечатку в продакшене.

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

Второй вызов считывает конфигурацию обратно — это проверка того, что запись прошла успешно. Затем повторите дымовой тест, описанный выше.

Четыре детали в этом JSON не очевидны, и каждая из них приводит к сбоям при ошибке.

api_key — это строка ollama, и Ollama игнорирует её значение. Она не может быть пустой, так как клиентская библиотека OpenAI вызывает ошибку до отправки запроса, если ключ не задан. Подойдет любая непустая строка.

embedding_model_dims применяется к векторному хранилищу, и для эмбеддера намеренно не задан embedding_dims. mem0 отправляет параметр OpenAI dimensions только если вы установили embedding_dims, а бэкенды, не реализующие усечение Matryoshka, отклоняют этот параметр. Установите ширину там, где создается таблица, и не трогайте эмбеддер.

collection_name — новый параметр. mem0 создает таблицу с CREATE TABLE IF NOT EXISTS, поэтому указание другой ширины для существующей коллекции ничего не даст: старый столбец vector(1536) останется, и каждая вставка будет завершаться ошибкой. Изменение ширины требует создания новой коллекции или удаления старой таблицы вручную.

Хост в openai_base_url — это имя сервиса в Compose ollama, а не localhost. Контейнеры находят друг друга по имени сервиса в общей сети.

Цена полностью локального решения

Будьте честны с собой относительно качества. Заявленные показатели производительности mem0 получены на управляемой платформе, которая, согласно README, включает проприетарные оптимизации, недоступные в open source SDK, и работает на стеке моделей, который не разглашается. В исследовании, лежащем в основе оригинальных результатов LOCOMO, каждый вызов модели выполнялся на GPT-4o-mini — облачной модели. В любом случае, воспринимайте эти показатели как потолок, а не как прогноз для модели 8B на вашем VPS. Маленькая модель пишет более расплывчатые факты и иногда возвращает текст там, где требовался JSON, что выглядит как вызов add, возвращающий пустой список results без ошибок.

Скорость — это вторая цена. Извлечение данных только на CPU занимает секунды на каждый вызов add, и каждое сохраняемое сообщение увеличивает это время. Модель, которая выдает лишний текст помимо запрошенного JSON, усугубляет проблему, поэтому ограничение ответа через num_predict устанавливает предел времени выполнения одного вызова add. Если задержка критична, VPS с GPU — единственное честное решение. Увеличение количества ядер CPU для модели 8B помогает гораздо меньше, чем ожидается. Смена модели — более эффективный рычаг, чем смена оборудования, а Nemotron 3.5 Lightning на VPS дает вам тег для загрузки, требования к RAM и понимание того, достаточно ли быстр режим только на CPU.

Одно правило действует независимо от вашего выбора: никогда не смешивайте модели эмбеддингов в одной коллекции. Две разные модели, случайно имеющие одинаковую ширину, создают векторы, которые невозможно сравнивать. Вставка проходит успешно, поиск возвращает строки, но эти строки неверны, и нигде не возникает ошибки.

Резервное копирование: две базы данных, а не одна

Самая распространённая ошибка при резервном копировании mem0 — выгрузка только одной базы данных. init-db.sh создаёт базу данных mem0_app в дополнение к базе данных postgres по умолчанию, и они хранят разные данные. В базе данных postgres находятся коллекции pgvector, то есть воспоминания. В mem0_app хранятся пользователи, сеансы, API keys и журналы запросов. Каждое самостоятельно размещённое приложение по-своему разделяет состояние, поэтому два фотосервера с одинаковыми функциями всё равно требуют разных команд резервного копирования. Поэтому перед использованием дампа проверьте, какие данные сохраняет приложение. На другом конце этого диапазона находится, например, библиотека Jellyfin, перестроенная под видеопрокат 90-х, которая получает весь каталог из другого сервиса и поэтому обычно требует только копирования собственной конфигурации. Для mem0 нужны обе базы данных, иначе восстановление будет бесполезным.

Если восстановить только postgres, воспоминания вернутся, но все учетные записи и API-ключи будут утеряны, поэтому ничто не сможет пройти аутентификацию для их чтения. Создавайте дамп обеих баз данных, включая роли, одной командой:

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

Том с историей (history volume) отделен от Postgres и требует собственного копирования:

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

Docker добавляет префикс имени проекта к именам томов, поэтому уточните свои имена с помощью docker volume ls, прежде чем полагаться на mem0_mem0_history.

Выполняйте восстановление в пустой контейнер и проверяйте количество строк, прежде чем считать данные достоверными:

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

Резервная копия, которую вы никогда не восстанавливали, — это лишь предположение. Как только дампы станут корректными, выгружайте их с сервера с помощью снимков restic во внешнее хранилище, так как резервная копия, хранящаяся на том же сервере, который она защищает, не обеспечивает никакой защиты.

Режимы сбоев и точные сообщения, которые вы увидите

{"detail":"Authentication required. Provide a Bearer token or X-API-Key header."} означает, что заголовок отсутствует или написан с ошибкой. Имя должно быть X-API-Key, при этом curl передает имена заголовков буквально.

{"detail":"At least one identifier (user_id, agent_id, run_id) is required."} при добавлении означает, что в запросе не было ни одного из них. Память должна быть привязана к чему-либо, так как фильтры поиска работают именно по этим полям.

LLM provider 'ollama' is not bundled in this image с кодом HTTP 400 означает, что вы отправили "provider": "ollama". Используйте "provider": "openai" с openai_base_url, указывающим на Ollama.

expected 1536 dimensions, not 768 от Postgres означает, что коллекция была создана с одной размерностью, а модель эмбеддинга возвращает другую. Установите embedding_model_dims в хранилище векторов и используйте новую collection_name.

Поиск возвращает бессмысленные строки после смены модели, при этом ошибок нет. Размерность совпадает, поэтому база данных работает корректно, но разные модели размещают одно и то же предложение в разных позициях. Создайте новую коллекцию и добавьте данные заново.

Connection refused в логах mem0 при попытке обращения к Ollama обычно означает 127.0.0.1 в openai_base_url. Внутри контейнера этот адрес указывает на сам контейнер. Используйте имя сервиса или host gateway, если Ollama запущена на хосте.

504 Gateway Time-out от nginx при добавлении означает, что модель выполнялась дольше, чем proxy_read_timeout. Увеличьте это значение и проверьте, была ли память записана до того, как вы повторите запрос.

exit code 137 во время docker compose up --build означает, что процесс был завершен сигналом SIGKILL, так как фатальный сигнал N отображается как 128 + N, а SIGKILL — это сигнал 9. Если сборка панели управления происходит на небольшом VPS, вероятным инициатором является OOM-killer (out-of-memory killer), поэтому выполните проверку dmesg из первого раздела, прежде чем предпринимать действия. Если она показывает завершенный процесс, добавьте swap или соберите образ на более мощной машине и отправьте его в реестр.

error: port 3000 is already in use возникает из цели make up в репозитории, которая отказывается запускаться, если порты 3000 или 8888 заняты. Найдите владельца процесса с помощью lsof -iTCP:3000 -sTCP:LISTEN.

FAQ

Нужно ли по-прежнему использовать Neo4j для работы mem0 с графовой памятью?

Нет. Новый алгоритм работы с памятью, выпущенный в апреле 2026 года, исключил ключи конфигурации graph_store и enable_graph из SDK с открытым исходным кодом. Извлечение сущностей теперь выполняется во время стандартной операции добавления и записывается во вторую коллекцию pgvector с именем <collection_name>_entities. Таким образом, внешняя графовая база данных, дополнительный контейнер и этап настройки больше не требуются. Обратной стороной является то, что поле relations в результатах поиска больше не существует. Сущности теперь повышают рейтинг памяти, а не предоставляют ребра для обхода, поэтому приложению, которому требовалось перемещаться по этим связям, необходимо собственное графовое хранилище вне mem0.

Какой минимальный размер VPS требуется для запуска self-hosted сервера mem0?

Если языковая модель размещена на другом сервере, для контейнера API, Postgres и панели управления достаточно 2 GB оперативной памяти и около 4 GB свободного места на диске. Критическим моментом является первая сборка, так как компиляция панели управления Next.js потребляет больше памяти, чем её работа, и процесс на сервере с 1 GB памяти будет завершен с ошибкой exit code 137. Если Ollama работает на том же сервере, учитывайте размер модели: модель 8B с 4-битной квантованием сама по себе требует около 6 GB, поэтому планируйте использование 8 GB.

Можно ли запустить mem0 без API-ключа OpenAI?

Да, через совместимый с OpenAI эндпоинт Ollama. Установка "provider": "ollama" приведет к ошибке, так как образ сервера содержит только библиотеки openai, anthropic и gemini и возвращает HTTP 400. Вместо этого оставьте "provider": "openai" и установите "openai_base_url": "http://ollama:11434/v1" с любым непустым значением api_key как для llm, так и для embedder. Ollama игнорирует ключ, а проверка встроенного провайдера проходит успешно, так как провайдером действительно является openai.

Почему mem0 не возвращает результаты после переключения на локальную модель эмбеддингов?

Потому что таблица pgvector была создана с фиксированной шириной. embedding_model_dims по умолчанию имеет значение 1536, nomic-embed-text возвращает 768, и Postgres отклоняет вставку с ошибкой expected 1536 dimensions, not 768. mem0 создает таблицу с CREATE TABLE IF NOT EXISTS, поэтому изменение только числа не влияет на существующую коллекцию. Установите embedding_model_dims в соответствии с реальной шириной вашей модели, подтвердите эту ширину, вызвав /v1/embeddings и подсчитав количество возвращаемых значений, и одновременно задайте векторному хранилищу новое имя collection_name.

Была ли эта статья полезной?