Як розгорнути mem0 на VPS для пам’яті агентів
Дізнайтеся, скільки RAM потребує mem0: близько 1 GB для трьох контейнерів, від 2 GB на VPS і щонайменше 8 GB з локальним Ollama.
Скільки RAM насправді потребує self-hosting mem0 на VPS
Self-hosting mem0 означає запуск трьох контейнерів: memory server на FastAPI, Postgres із розширенням pgvector і dashboard на Next.js. mem0 — це memory layer для агентів. Ви надсилаєте йому розмову, мовна модель виділяє з неї довготривалі факти, а ці факти зберігаються як вектори, щоб пізніший запит міг отримати релевантні з них.
Для трьох контейнерів закладіть приблизно 1 GB resident memory, а після збирання образів — 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 -vdocker stats виводить resident memory для кожного контейнера. docker system df -v виводить дисковий простір, який займають кожен образ і кожен volume.
Стабільне споживання ресурсів не дорівнює піковому. docker compose up -d --build компілює dashboard на Next.js, і під час цього збирання Node споживає найбільше ресурсів за весь процес встановлення. На VPS із 1 GB RAM kernel 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 року, вилучив обидва ключі з open source SDK. Тепер виділення сутностей виконується під час звичайного шляху add, а сутності записуються в окрему колекцію pgvector з назвою основної колекції та суфіксом _entities. Міграцію виконувати не потрібно. Вбудоване зв’язування сутностей починає працювати під час наступного виклику add.
Відмова від графового сховища дає змогу позбутися JVM-контейнера, його heap і кількох сотень мегабайт образу. На VPS із 2 GB RAM це може визначати, чи працюватиме система, чи почнеться swapping.
Ось від чого ви відмовляєтеся. Раніше результати пошуку містили поле 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 --reload. Під час кожного запуску вона повторно встановлюєmem0aiіз PyPI. Через це версія, яку запускає сервер, може змінитися під час перезапуску, який ви не вважали оновленням. - Той самий крок pip означає, що перезапуск без вихідного мережевого з’єднання завершується помилкою ще до запуску uvicorn. Тоді ваш memory server недоступний, оскільки PyPI був недоступний.
--reloadзапускає спостерігач за файлами uvicorn. Він потрібен для перезапуску процесу після редагування коду, але у production споживає пам’ять і запускає додатковий процес без практичної користі. ProductionDockerfileтакож містить--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.
Історія переноситься з bind mount ./history до іменованого тому. Bind mount прив’язує дані до одного шляху та одного uid на цьому сервері, а іменований том є об’єктом Docker, який можна створювати зі snapshot і переносити. У матеріалі Іменовані томи та bind mount описано, коли використовувати кожен із них.
Команда видаляє --reload і залишає alembic upgrade head. Не пропускайте цей крок міграції. Без нього застосунок запускається з базою даних без таблиць, і кожен запит завершується помилкою під час першого звернення до бази даних.
NEXT_PUBLIC_API_URL — це URL, до якого звертається браузер, тому тут має бути публічна HTTPS-адреса, а не http://mem0:8000. Next.js вбудовує кожне значення NEXT_PUBLIC_ під час складання, тому для його зміни потрібен docker compose up -d --build mem0-dashboard. Простий перезапуск залишає старе значення, вбудоване в JavaScript, і 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, і за збігу всі звернення до бази даних пропускаються. Це root-облікові дані для всього API. Поводьтеся з ними відповідно: не зберігайте їх в історії shell, не додавайте до git і не вставляйте в запрошення командного рядка. Файли env для Compose і місця витоку секретів із них та як не допускати потрапляння API-ключів у контекст агента безпосередньо стосуються цього випадку, оскільки клієнтами цього сервера є агенти.
Значення, завантажені з env_file, зберігаються в середовищі контейнера, а docker inspect виводить їх повністю. Будь-хто з групи docker може їх прочитати, а будь-хто з групи docker фактично має права root на хості.
Розмістіть TLS перед API замість відкриття порту 8888
API відповідає на 127.0.0.1:8888, а dashboard — на 127.0.0.1:3000. nginx завершує TLS (transport layer security) на 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|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 блокується, поки мовна модель читає діалог і виділяє факти. Локальна модель 8B на CPU регулярно працює довше за стандартний 60-секундний тайм-аут nginx, після чого викликаюча сторона отримує 504 Gateway Time-out, хоча модель ще працює, а пам’ять усе одно записується. У результаті ви отримуєте пам’ять, про помилку запису якої вам повідомили.
Закрийте решту з’єднань за допомогою політики ufw із забороною за замовчуванням, залишивши відкритими 22 і 443. Отримайте сертифікат за допомогою certbot на Ubuntu 24.04 за nginx. Якщо сервер уже використовує Traefik для маршрутизації кількох Compose-застосунків, додайте mem0 до цього маршрутизатора замість встановлення другого reverse proxy.
Димовий тест: додайте один спогад і прочитайте його назад
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 має повернутися з оцінкою. Передайте ідентифікатор у 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, а не none, тому слабкі збіги тепер автоматично відфільтровуються. Після того як це запрацює через 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 надає OpenAI-сумісний API за адресою /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:, потім завантажте одну chat model і одну embedding model:
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 unit, як у випадку безпосереднього запуску Ollama на VPS, не вказуйте для контейнера 127.0.0.1:11434. Усередині контейнера mem0 127.0.0.1 — це контейнер mem0. Додайте сервісу mem0 extra_hosts: ["host.docker.internal:host-gateway"], у systemd drop-in задайте Environment="OLLAMA_HOST=0.0.0.0:11434", щоб Ollama слухала адресу, доступну з bridge-мережі, і залиште порт 11434 закритим у firewall.
Запитайте в моделі розмірність embedding перед будь-яким налаштуванням
Цей крок визначає, чи працюватиме retrieval взагалі.
Сховище 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']))"Команда виведе ширину, яку має використовувати ваша collection. Запишіть конфігурацію у файл, оскільки передавання пароля Postgres через shell quoting — надійний спосіб занести помилки в production.
{
"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"Другий виклик зчитує конфігурацію назад. Це перевіряє, що запис виконано. Потім повторіть наведений вище smoke test.
У цьому JSON є чотири неочевидні деталі. Кожна з них спричиняє помилку, якщо налаштувати її неправильно.
api_key — це рядок ollama, і Ollama ігнорує його значення. Він не може бути порожнім, оскільки клієнтська бібліотека OpenAI завершує роботу ще до надсилання будь-якого запиту, якщо ключ не задано. Підійде будь-який непорожній рядок.
embedding_model_dims задається для vector store, а embedding_dims для embedder навмисно відсутній. mem0 надсилає параметр OpenAI dimensions лише тоді, коли ви задаєте embedding_dims, а бекенди, які не реалізують Matryoshka truncation, одразу відхиляють цей параметр. Задайте ширину під час створення таблиці, а embedder залиште без змін.
collection_name — новий параметр. mem0 створює таблицю з CREATE TABLE IF NOT EXISTS, тому вказування іншої ширини для наявної collection нічого не змінює: старий стовпець vector(1536) залишається, і кожна вставка завершується помилкою. Для зміни ширини потрібне нове ім’я collection або ручне видалення старої таблиці.
Хост у openai_base_url — це ім’я Compose-сервісу ollama, а не localhost. Контейнери знаходять один одного за іменами сервісів у спільній мережі.
Яку ціну має повністю локальний варіант
Реалістично оцініть якість. Опубліковані benchmark-результати mem0 вимірювалися з frontier models, які виконували extraction, тому сприймайте їх як верхню межу, а не як прогноз для моделі 8B на вашому VPS. Невелика модель формулює менш конкретні факти, а іноді повертає прозу замість запитаного JSON. Це проявляється як виклик add, що повертає порожній список results без помилки.
Інша ціна — швидкість. Extraction лише на CPU займає секунди для кожного виклику add, і це додається до кожного збереженого повідомлення. Якщо така затримка має значення, чесне рішення — VPS із підключеним GPU. Додавання ядер CPU до моделі 8B допомагає набагато менше, ніж зазвичай очікують.
Одне правило діє за будь-якого варіанта: ніколи не змішуйте embedding models в одній collection. Дві різні моделі, які випадково мають однакову ширину, створюють непорівнювані вектори. Вставка проходить успішно, пошук повертає рядки, але ці рядки неправильні, і ніде не повідомляється про помилку.
Резервні копії: є дві бази даних, а не одна
Найпоширеніша помилка під час резервного копіювання mem0 — дамп лише однієї бази даних. init-db.sh створює mem0_app разом із базою даних за замовчуванням postgres, і вони містять різні дані. База даних postgres містить колекції pgvector, тобто спогади. mem0_app містить користувачів, сеанси, API keys і журнали запитів.
Якщо відновити лише postgres, спогади повернуться, але всі облікові записи й API keys буде втрачено, тому жоден клієнт не зможе автентифікуватися для їх читання. Створюйте дамп обох баз даних разом із ролями однією командою:
docker compose exec -T postgres pg_dumpall -U postgres --clean \
| gzip > "mem0-$(date +%F).sql.gz"Том журналу історії не належить до Postgres і потребує окремої копії:
docker run --rm -v mem0_mem0_history:/data -v "$PWD:/backup" \
alpine tar czf /backup/mem0-history.tgz -C /data .Docker додає до назв томів назву проєкту, тому перед використанням mem0_mem0_history перевірте свою назву командою docker volume ls.
Відновіть дані в тимчасовому контейнері та перевірте кількість рядків, перш ніж вважати резервну копію коректною:
gunzip -c mem0-2026-08-03.sql.gz \
| docker compose exec -T postgres psql -U postgres -d postgresРезервна копія, яку жодного разу не відновлювали, є лише припущенням. Після перевірки дампів перемістіть їх за межі сервера за допомогою restic для створення snapshot у віддаленому сховищі, оскільки резервна копія, що зберігається на сервері, який вона має захищати, нічого не захищає.
Режими відмов і точні рядки, які ви побачите
{"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 означає, що колекцію створено з однією розмірністю, а embedder повертає іншу. Установіть embedding_model_dims у векторному сховищі та використайте новий collection_name.
Пошук повертає рядки, які не мають сенсу після зміни моделі, і помилок ніде немає. Розмірність усе ще збігається, тому база даних не виявляє проблеми, але дві моделі розміщують те саме речення в різних позиціях. Створіть нову колекцію та додайте записи повторно.
Connection refused у журналах mem0 під час підключення до Ollama зазвичай означає 127.0.0.1 у openai_base_url. Усередині контейнера ця адреса вказує на сам контейнер. Використайте ім’я сервісу або шлюз хоста, якщо Ollama працює на хості.
504 Gateway Time-out від nginx під час додавання означає, що модель виконувалася довше за proxy_read_timeout. Збільште це значення та перевірте, чи було пам’ять записано, перш ніж повторювати запит.
exit code 137 під час docker compose up --build означає, що засіб завершення роботи через нестачу пам’яті зупинив збирання dashboard. Додайте swap або зберіть image на потужнішій машині та завантажте його до registry.
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 і dashboard достатньо 2 GB RAM та приблизно 4 GB вільного дискового простору. Найбільше навантаження припадає на першу збірку, оскільки компіляція dashboard на Next.js потребує більше пам’яті, ніж його запуск, а на сервері з 1 GB збірка завершується примусово через exit code 137. Якщо Ollama працює на тому самому сервері, орієнтуйтеся на вимоги моделі: моделі 8B із 4-бітним квантуванням потрібно приблизно 6 GB, тому плануйте 8 GB.
Чи можна запускати mem0 без ключа OpenAI API?
Так, через сумісний з OpenAI endpoint Ollama. Встановлення "provider": "ollama" завершується помилкою, оскільки образ сервера містить лише бібліотеки openai, anthropic і gemini та повертає HTTP 400. Натомість залиште "provider": "openai" і встановіть "openai_base_url": "http://ollama:11434/v1" із будь-яким непорожнім api_key для llm та embedder. Ollama ігнорує цей ключ, а вбудована перевірка провайдера проходить, оскільки фактично використовується openai.
Чому mem0 не повертає результатів після переходу на локальну модель embedding?
Тому що таблицю 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 і підрахувавши повернуті ним значення, та одночасно вкажіть для vector store новий collection_name.