Запустите mem0 против кастомного OpenAI-совместимого base URL.

Updated 2026-07-29

Провайдер OpenAI в mem0 принимает ключ конфига openai_base_url. Установите его в https://api.apisrouter.com/v1, передайте один ключ — и модель, извлекающая и обновляющая памяти, может быть любым id из каталога, включая Claude и DeepSeek, не трогая остальную часть вашего пайплайна памяти.

Короткий ответ: один ключ конфига внутри блока llm.

Провайдер LLM OpenAI в mem0 резолвит свой эндпоинт сначала из конфига, потом из окружения, потом из умолчания: self.config.openai_base_url, затем переменная окружения OPENAI_BASE_URL, затем https://api.openai.com/v1. Так что самое чистое переопределение — один ключ в словаре конфига llm: установите openai_base_url в https://api.apisrouter.com/v1, задайте api_key рядом с ним (или экспортируйте OPENAI_API_KEY) — и каждый вызов извлечения памяти пойдёт через шлюз. Это апстримное поведение mem0, читаемое в mem0/llms/openai.py, а не форк. TypeScript SDK выставляет ту же пару в camelCase: openaiBaseUrl и apiKey. Значения в словаре конфига переопределяют переменные окружения, которые переопределяют умолчания, так что base URL на уровне конфига побеждает даже на машинах, где OPENAI_BASE_URL указывает куда-то ещё.

config = {
    "llm": {
        "provider": "openai",
        "config": {
            "model": "claude-sonnet-4-6",
            "openai_base_url": "https://api.apisrouter.com/v1",
            "api_key": os.environ["APISROUTER_API_KEY"],
        },
    }
}

Что mem0 на самом деле делает со своей LLM.

mem0 (mem0ai на GitHub, около 61K звёзд) — слой памяти для AI-агентов. Каждый вызов add() прогоняет пайплайн: LLM читает новые ходы разговора, извлекает кандидатов в память, сравнивает их с тем, что уже сохранено, и решает по каждой памяти — добавить, обновить, удалить или пропустить. Это настоящая работа с рассуждением, и она происходит при каждой записи, так что слот LLM срабатывает намного чаще, чем большинство людей ожидает, когда прикручивают память к продакшн-агенту. Retrieval — это другая половина, и она вообще не использует LLM: search() эмбеддит запрос и прогоняет векторное сходство по хранилищу. Два разных клиента, две разные модели, настроенные в двух разных блоках (llm и embedder). Это разделение — самая важная вещь, которую нужно понять перед тем, как что-либо перенаправлять, потому что это означает, что вы можете перенести нагрузку извлечения на мультивендорный шлюз, пока эмбеддер сохраняет своего существующего провайдера и индекс нетронутыми. Провайдер в конфиге остаётся «openai»; mem0 пропускает поле model как простую строку через /v1/chat/completions. Когда эндпоинт за openai_base_url обслуживает нескольких вендоров, эта строка может быть id Claude, GPT, DeepSeek или GLM, и смена модели извлечения превращается в однострочную правку конфига вместо миграции провайдера.

Полная настройка: словарь конфига или переменная окружения.

Путь через словарь конфига — самый точный: он двигает только LLM. Постройте словарь, передайте его в Memory.from_config и используйте API памяти как обычно. Поле api_key держит ключ шлюза полностью вне настроек вашего векторного хранилища и эмбеддера. Путь через окружение тоже существует: классы OpenAI в mem0 читают OPENAI_BASE_URL, когда ключ конфига отсутствует. Это одна экспортированная переменная и ноль изменений кода, но обратите внимание на область действия: класс OpenAI эмбеддера читает те же переменные (он также уважает более старое имя OPENAI_API_BASE, которое класс LLM не уважает). Экспортируйте OPENAI_BASE_URL — и вы переместите оба компонента, что верно, только если эндпоинт обслуживает и вашу модель эмбеддинга тоже. В случае сомнений предпочитайте словарь конфига и оставьте окружение в покое.

import os
from mem0 import Memory

config = {
    "llm": {
        "provider": "openai",
        "config": {
            "model": "claude-sonnet-4-6",   # any catalog id
            "openai_base_url": "https://api.apisrouter.com/v1",
            "api_key": os.environ["APISROUTER_API_KEY"],
            "temperature": 0.1,
        },
    },
    # embedder block unchanged: keeps its own provider and key
}

m = Memory.from_config(config)
m.add("I prefer window seats and vegetarian meals.", user_id="alice")
print(m.search("seat preference?", user_id="alice"))

Выбор модели извлечения.

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

  • Качество извлечения — это качество памяти. LLM решает, что стоит запомнить и противоречит ли новая информация старой; модель, которая пропускает обновление, загрязняет retrieval для каждой будущей сессии. claude-sonnet-4-6 и gpt-5.5 — надёжная золотая середина этого компромисса.
  • Объём — на каждой записи. Чат-продукт, вызывающий add() после каждого обмена сообщениями, прогоняет извлечение тысячи раз в день, и именно здесь быстрый id вроде claude-haiku-4-5-20251001 или deepseek-v4-flash не даёт слою памяти доминировать в счёте за токены.
  • Домены, богатые противоречиями (предпочтения, которые меняются, факты, которые устаревают), выигрывают от более сильной модели на add(), даже если это стоит дороже за вызов, потому что неверное решение об обновлении дорого обнаружить позже.
  • Temperature должна быть низкой. Извлечение — это задача структурированного решения, а не творческое письмо; mem0 выставляет temperature в том же блоке конфига, и около 0.1 держит решения add/update/delete последовательными.

Оплата по факту · дешевле официальных цен

Selected models are priced below official list prices. Exact input, output, cache, and per-request prices are shown for each model.

МодельОфициальная ценаНаша цена
Claude Sonnet 4.6$3.00 / $15.00 per M$2.40 / $12.00 per M
GPT-5.5$5.00 / $30.00 per M$4.00 / $24.00 per M
Claude Haiku 4.5 20251001$1.00 / $5.00 per M$0.80 / $4.00 per M
DeepSeek V4 Flash$0.14 / $0.28 per M$0.10 / $0.30 per M
GLM-5.2$1.14 / $4.00 per M$1.10 / $4.00 per M

Сбои, специфичные именно для mem0.

Задержавшийся OPENROUTER_API_KEY перехватывает маршрутизацию. Класс LLM OpenAI в mem0 обрабатывает эту переменную особым образом: когда она задана, класс переключается на эндпоинт OpenRouter и игнорирует ваше намерение. Если запросы не доходят до настроенного вами base URL, сначала проверьте эту переменную и снимите её. Переменная окружения двигает больше, чем вы имели в виду. OPENAI_BASE_URL читается и LLM, и эмбеддером. Если шлюз не обслуживает вашу модель эмбеддинга, переопределение на уровне окружения ломает search(), пока add() продолжает работать, что выглядит как «записи памяти проходят нормально, а retrieval пуст или падает с ошибкой». Ограничьте переопределение блоком конфига llm — и эмбеддер этого никогда не заметит. Ключи конфига — свои для каждого SDK. Python — snake_case (openai_base_url, api_key); TypeScript — camelCase (openaiBaseUrl, apiKey). Ключ в camelCase в словаре Python тихо игнорируется, и вы проваливаетесь на эндпоинт по умолчанию, что выглядит ровно как переопределение, которое «не работает». Id моделей — точные строки. mem0 не валидирует поле model; она его пересылает. Опечатка проявляется как ошибка model-not-found от шлюза на первом add(), и листинг /v1/models — авторитетное написание. Смена эмбеддера — это решение об индексе, а не решение о конфиге. Эмбеддинги от разных моделей живут в разных векторных пространствах, так что перенаправление эмбеддера обесценивает сходство относительно существующих векторов. Перемещение LLM бесплатно; перемещение эмбеддера означает переэмбеддинг хранилища. Планируйте их как раздельные миграции.

Кто направляет mem0 через шлюз.

  • Разработчики агентов, добавляющие персистентную память ассистентам. Извлечение прогоняется на каждой записи, так что единая поверхность биллинга с использованием по ключу превосходит второй вендорский дашборд, прикрученный к стеку.
  • Команды, которым нужно извлечение качества Claude за конфигом в форме OpenAI. Строка провайдера остаётся «openai»; меняются только base URL и id модели.
  • Высокообъёмные чат-продукты, контролирующие юнит-стоимость слоя памяти, сочетая топовую чат-модель с быстрым id извлечения, каждый адресуемый через один и тот же эндпоинт.
  • Разработчики, оценивающие модели извлечения бок о бок. Каждый кандидат — это одна строка модели против фиксированных фикстур, а не новая интеграция провайдера на каждого вендора.
  • Разработчики без доступа к биллингу конкретного вендора. Доступ на основе пополнения без требования карты убирает зависимость от регистрации у каждого провайдера.

Проверьте эндпоинт и отладьте первый add().

Убедитесь, что шлюз листит модель, которую вы настроили, перед запуском пайплайна; поле model должно точно совпадать с обслуживаемым id. Сбои первого запуска следуют паттерну. 401 означает, что ключ, который резолвила LLM, неверен для эндпоинта, который она резолвила, и, поскольку оба приходят из каскада конфиг-поверх-окружения, распечатайте оба эффективных значения, а не полагайтесь на предположения; api_key из конфига с base URL из окружения (или наоборот) — классическое несовпадение. Ошибка model-not-found — это опечатка в id. Запросы, видимо уходящие на openrouter.ai, означают, что сработал особый случай OPENROUTER_API_KEY. А если add() проходит успешно, пока search() падает, вы случайно переместили эмбеддер через окружение; ограничьте base URL блоком llm. Как только памяти начинают работать, консоль APIsRouter показывает модель на запрос, счётчики токенов и расходы. Вызовы извлечения маленькие, но непрерывные, и вид использования — это то, как вы видите, во что реально обходится слой памяти на тысячу записей, а не оцениваете это на глаз.

curl -s https://api.apisrouter.com/v1/models \
  -H "Authorization: Bearer $APISROUTER_API_KEY" | head -50

Частые вопросы

Какой ключ конфига направляет mem0 на кастомный OpenAI-совместимый эндпоинт?

openai_base_url внутри конфига провайдера llm в Python (openaiBaseUrl в TypeScript). Значения конфига переопределяют переменную окружения OPENAI_BASE_URL, которая переопределяет умолчание https://api.openai.com/v1, так что словарь конфига — самое детерминированное место, чтобы его задать.

Может ли mem0 извлекать памяти моделями Claude или DeepSeek через эту настройку?

Да. Провайдер остаётся «openai», и mem0 пересылает поле model как простую строку через /v1/chat/completions. Работает любой id, обслуживаемый эндпоинтом за openai_base_url, включая id Claude, DeepSeek и GLM.

Влияет ли задание OPENAI_BASE_URL также на эмбеддер?

Да. Эмбеддер OpenAI в mem0 читает те же переменные окружения (плюс более старое имя OPENAI_API_BASE). Если вы хотите переместить только LLM, задайте openai_base_url внутри блока конфига llm и оставьте окружение нетронутым.

Нужно ли менять эмбеддер или векторное хранилище, чтобы это использовать?

Нет. Блоки llm и embedder — независимые клиенты. LLM извлечения может маршрутизироваться через шлюз, пока эмбеддер сохраняет своего текущего провайдера, а ваши существующие векторы остаются валидными. Перенаправление эмбеддера — это отдельная миграция, требующая переэмбеддинга хранилища.

Почему мои запросы mem0 уходят на OpenRouter вместо моего base URL?

Класс LLM OpenAI в mem0 обрабатывает переменную окружения OPENROUTER_API_KEY особым образом: когда она задана, он перенаправляет на OpenRouter независимо от вашего base URL. Снимите эту переменную, и конфигурация openai_base_url вступит в силу.

Применимо ли это к хостируемой платформе Mem0 или к open-source SDK?

К open-source SDK (Memory / Memory.from_config), где вы контролируете конфиг LLM. Хостируемая платформа Mem0 управляет своими вызовами моделей на стороне сервера, так что кастомный base URL применяется, когда вы self-host'ите слой памяти сами.