커스텀 OpenAI 호환 base URL로 mem0 실행하기.

Updated 2026-07-29

mem0의 OpenAI 프로바이더는 openai_base_url 설정 키를 받습니다. 이를 https://api.apisrouter.com/v1로 설정하고 키 하나를 전달하면, 메모리를 추출하고 업데이트하는 모델을 카탈로그의 어떤 id로든(Claude와 DeepSeek 포함) 지정할 수 있으며, 메모리 파이프라인의 나머지 부분은 건드릴 필요가 없습니다.

빠른 답: llm 블록 안의 설정 키 하나.

mem0의 OpenAI LLM 프로바이더는 엔드포인트를 순서대로 해석합니다: 먼저 설정(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를 export하면) 모든 메모리 추출 호출이 게이트웨이를 통해 라우팅됩니다. 이것은 포크가 아니라 mem0/llms/openai.py에서 읽을 수 있는 업스트림 mem0의 동작입니다. TypeScript SDK는 같은 쌍을 camelCase로 노출합니다: openaiBaseUrl과 apiKey. 설정 딕셔너리의 값은 환경 변수를 이기고, 환경 변수는 기본값을 이기므로, OPENAI_BASE_URL이 다른 곳을 가리키는 머신에서도 설정 레벨의 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(GitHub의 mem0ai, 약 6.1만 스타)는 AI 에이전트를 위한 메모리 레이어입니다. 모든 add() 호출은 파이프라인을 실행합니다: LLM이 새 대화 턴을 읽고, 후보 메모리를 추출하고, 이미 저장된 것과 비교한 다음, 메모리별로 추가할지 업데이트할지 삭제할지 건너뛸지 결정합니다. 이것은 진짜 추론 작업이며 모든 쓰기마다 발생하므로, 프로덕션 에이전트에 메모리를 붙였을 때 사람들이 예상하는 것보다 LLM 슬롯이 훨씬 자주 발동합니다. 검색은 그 반대편이며 LLM을 전혀 쓰지 않습니다: search()는 쿼리를 임베드하고 스토어에 대해 벡터 유사도를 실행합니다. 서로 다른 클라이언트 둘, 서로 다른 모델 둘, 서로 다른 블록(llm과 embedder)에 설정된 둘. 이 분리는 무엇이든 재라우팅하기 전에 이해해야 할 가장 중요한 부분입니다. 임베더는 기존 프로바이더와 인덱스를 그대로 둔 채 추출 워크로드만 멀티벤더 게이트웨이로 옮길 수 있다는 뜻이기 때문입니다. 프로바이더는 설정에서 여전히 "openai"로 남으며, mem0는 model 필드를 /v1/chat/completions를 통해 순수 문자열로 전달합니다. openai_base_url 뒤의 엔드포인트가 여러 벤더를 서빙할 때 그 문자열은 Claude, GPT, DeepSeek, GLM id가 될 수 있으며, 추출 모델 교체는 프로바이더 마이그레이션이 아니라 한 줄짜리 설정 변경이 됩니다.

전체 설정: 설정 딕셔너리 또는 환경 변수.

설정 딕셔너리 경로가 정밀한 방법입니다: LLM만 이동시킵니다. 딕셔너리를 만들고 Memory.from_config에 넘긴 다음 평소처럼 메모리 API를 쓰세요. api_key 필드는 게이트웨이 키를 벡터 스토어와 임베더 설정에서 완전히 떨어뜨려 놓습니다. 환경 변수 경로도 존재합니다: 설정 키가 없을 때 mem0의 OpenAI 클래스는 OPENAI_BASE_URL을 읽습니다. 변수 하나를 export하면 코드 변경이 전혀 없지만, 범위를 유의하세요: 임베더의 OpenAI 클래스도 같은 변수를 읽습니다(LLM 클래스가 인식하지 않는 더 오래된 OPENAI_API_BASE 이름도 존중합니다). OPENAI_BASE_URL을 export하면 두 컴포넌트를 모두 이동시킨 것이며, 이는 엔드포인트가 여러분의 임베딩 모델도 서빙할 때만 올바릅니다. 확신이 서지 않으면 설정 딕셔너리를 선호하고 환경은 건드리지 마세요.

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이 무엇이 기억할 가치가 있는지, 새 정보가 예전 것과 모순되는지 결정합니다; 업데이트를 놓치는 모델은 이후 모든 세션의 검색을 오염시킵니다. claude-sonnet-4-6과 gpt-5.5가 이 트레이드오프에서 신뢰할 만한 중간 지점입니다.
  • 볼륨은 모든 쓰기마다 발생합니다. 매 대화 이후 add()를 호출하는 채팅 제품은 하루에 수천 번 추출을 실행하는데, 이곳에서 claude-haiku-4-5-20251001이나 deepseek-v4-flash 같은 빠른 id가 메모리 레이어가 토큰 청구서를 지배하지 못하게 막아줍니다.
  • 모순이 많은 도메인(바뀌는 선호, 만료되는 사실)은 호출당 비용이 더 들더라도 add()에 더 강한 모델을 쓸 가치가 있습니다. 잘못된 업데이트 결정은 나중에 감지하기 비싸기 때문입니다.
  • 온도는 낮게 두세요. 추출은 창의적 글쓰기가 아니라 구조화된 판단 작업입니다; 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가 라우팅을 가로챕니다. mem0의 OpenAI LLM 클래스는 그 변수를 특별 케이스로 처리합니다: 설정되어 있으면 클래스가 OpenRouter의 엔드포인트로 전환하고 여러분의 의도를 무시합니다. 요청이 설정한 base URL에 도달하지 않는다면 먼저 이 변수를 확인하고 unset하세요. 환경 변수는 의도한 것보다 더 많이 이동시킵니다. OPENAI_BASE_URL은 LLM과 임베더 둘 다 읽습니다. 게이트웨이가 여러분의 임베딩 모델을 서빙하지 않는다면 환경 레벨 오버라이드는 search()를 망가뜨리면서도 add()는 계속 작동하게 만들며, 이는 "메모리는 잘 쓰이는데 검색은 비어 있거나 오류가 난다"로 나타납니다. 오버라이드를 llm 설정 블록으로 범위를 좁히면 임베더는 전혀 눈치채지 못합니다. 설정 키는 SDK별로 다릅니다. Python은 snake_case(openai_base_url, api_key)이고 TypeScript는 camelCase(openaiBaseUrl, apiKey)입니다. Python 딕셔너리에 camelCase 키를 넣으면 조용히 무시되고 기본 엔드포인트로 폴백되는데, 이는 오버라이드가 "작동하지 않는" 것과 정확히 똑같아 보입니다. 모델 id는 정확한 문자열입니다. mem0는 model 필드를 검증하지 않고 전달할 뿐입니다. 오타는 첫 add()에서 게이트웨이의 model-not-found 오류로 드러나며, /v1/models 목록이 정답 표기입니다. 임베더를 바꾸는 것은 설정 결정이 아니라 인덱스 결정입니다. 서로 다른 모델의 임베딩은 서로 다른 벡터 공간에 살므로, 임베더를 재지정하면 기존 벡터에 대한 유사도가 무효화됩니다. LLM을 옮기는 것은 무료지만 임베더를 옮기는 것은 스토어 재임베딩을 뜻합니다. 이 둘을 별개의 마이그레이션으로 계획하세요.

어떤 사람들이 게이트웨이를 통해 mem0를 쓰는가.

  • 어시스턴트에 영구 메모리를 추가하는 에이전트 구축자. 추출은 모든 쓰기마다 실행되므로 키별 사용량이 있는 단일 청구 표면이 스택에 붙은 두 번째 벤더 대시보드보다 낫습니다.
  • OpenAI 형태의 설정 뒤에서 Claude급 추출을 원하는 팀. 프로바이더 문자열은 "openai"로 남고 base URL과 model 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 호환 엔드포인트로 지정하나요?

Python에서는 llm 프로바이더 설정 안의 openai_base_url입니다(TypeScript에서는 openaiBaseUrl). 설정 값은 OPENAI_BASE_URL 환경 변수를 이기고, 그 변수는 기본값 https://api.openai.com/v1을 이기므로, 설정 딕셔너리가 가장 결정적인 설정 위치입니다.

mem0가 이 설정으로 Claude나 DeepSeek 모델로 메모리를 추출할 수 있나요?

네. 프로바이더는 "openai"로 남고 mem0는 model 필드를 /v1/chat/completions를 통해 순수 문자열로 전달합니다. openai_base_url 뒤 엔드포인트가 서빙하는 어떤 id도 작동하며, Claude, DeepSeek, GLM id도 포함됩니다.

OPENAI_BASE_URL을 설정하면 임베더에도 영향을 주나요?

네. mem0의 OpenAI 임베더는 같은 환경 변수(그리고 더 오래된 OPENAI_API_BASE 이름)를 읽습니다. LLM만 옮기고 싶다면 llm 설정 블록 안에 openai_base_url을 설정하고 환경은 건드리지 마세요.

이를 쓰기 위해 임베더나 벡터 스토어를 바꿔야 하나요?

아니요. llm과 embedder 블록은 독립적인 클라이언트입니다. 추출 LLM은 게이트웨이를 통해 라우팅될 수 있는 반면 임베더는 현재 프로바이더를 유지하고 기존 벡터도 유효하게 남습니다. 임베더를 재지정하는 것은 스토어 재임베딩이 필요한 별도의 마이그레이션입니다.

왜 제 mem0 요청이 base URL이 아니라 OpenRouter로 가나요?

mem0의 OpenAI LLM 클래스는 OPENROUTER_API_KEY 환경 변수를 특별 케이스로 처리합니다: 설정되어 있으면 여러분의 base URL과 상관없이 OpenRouter로 재라우팅합니다. 그 변수를 unset하면 openai_base_url 설정이 적용됩니다.

이것이 호스팅된 Mem0 플랫폼에도 적용되나요, 아니면 오픈소스 SDK에만 적용되나요?

LLM 설정을 직접 제어하는 오픈소스 SDK(Memory / Memory.from_config)에 적용됩니다. 호스팅된 Mem0 플랫폼은 서버 사이드에서 자체 모델 호출을 관리하므로, 커스텀 base URL은 메모리 레이어를 직접 셀프 호스팅할 때 적용됩니다.