mem0 を、カスタムの OpenAI 互換 base URL で動かす。

Updated 2026-07-29

mem0 の OpenAI プロバイダーは openai_base_url という設定キーを取ります。これを https://api.apisrouter.com/v1 に設定し、キーを1つ渡せば、メモリを抽出・更新するモデルは、Claude や DeepSeek を含むカタログの任意の id にでき、メモリパイプラインの残りの部分には一切触れずに済みます。

早わかり: llm ブロックの中に設定キーを1つ。

mem0 の OpenAI LLM プロバイダーは、まず設定、次に環境変数、最後にデフォルトという順でエンドポイントを解決します。self.config.openai_base_url、次に OPENAI_BASE_URL 環境変数、それから https://api.openai.com/v1 です。したがって、最もクリーンな上書き方法は、llm 設定の辞書にキーを1つ入れることです。openai_base_url を https://api.apisrouter.com/v1 に設定し、その隣に api_key も設定する(あるいは OPENAI_API_KEY を export する)。これで、メモリ抽出のすべての呼び出しがゲートウェイ経由になります。 これは upstream の mem0 の挙動であり、mem0/llms/openai.py で読めるものであって、フォークではありません。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、スター数はおよそ61K)は、AI エージェント向けのメモリ層です。すべての add() 呼び出しはパイプラインを実行します。LLM が新しい会話のターンを読み、候補となるメモリを抽出し、すでに保存されているものと比較し、メモリごとに追加・更新・削除・スキップのいずれかを決定します。これは本物の推論作業であり、書き込みのたびに発生するため、本番エージェントにメモリを組み込んだとき、LLM スロットはほとんどの人が予想するよりもずっと頻繁に発火します。 検索はもう半分であり、LLM を一切使いません。search() はクエリを埋め込み、ストアに対してベクトル類似度検索を実行します。異なる2つのクライアント、異なる2つのモデル、それぞれ異なる2つのブロック(llm と embedder)で設定されます。この分離こそが、何かをルーティングし直す前に理解すべき最も重要な点です。なぜなら、それは、エンベダーが既存のプロバイダーとインデックスをそのまま保った状態で、抽出のワークロードだけをマルチベンダーのゲートウェイに移せることを意味するからです。 設定の中では、プロバイダーは "openai" のままです。mem0 は model フィールドを、/v1/chat/completions を通じてプレーンな文字列として渡します。openai_base_url の背後にあるエンドポイントが複数のベンダーを提供している場合、その文字列は Claude・GPT・DeepSeek・GLM の id になり得ます。抽出モデルの入れ替えは、プロバイダーの移行ではなく、設定の1行の変更で済むようになります。

フルセットアップ: 設定辞書か環境変数か。

設定辞書を使う経路は、正確な方です。LLM だけを動かします。辞書を組み立てて Memory.from_config に渡し、あとは通常どおりメモリ API を使ってください。api_key フィールドのおかげで、ゲートウェイキーがベクトルストアやエンベダーの設定に一切混ざりません。 環境変数を使う経路も存在します。mem0 の OpenAI クラスは、設定キーがない場合に OPENAI_BASE_URL を読みます。export する変数は1つでコードの変更はゼロですが、範囲に注意してください。エンベダーの OpenAI クラスも同じ変数を読みます(古い OPENAI_API_BASE という名前も尊重しますが、LLM クラスはそうしません)。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"))

抽出モデルの選び方。

実践的なループはこうです。エンベダーは固定したまま、同じ会話のフィクスチャを2つか3つの抽出モデルに通し、保存されたメモリを diff で比較します。1つのエンドポイントの裏側では、この比較は候補ごとの設定文字列の編集で済み、キーごとの利用ログが各候補の実行に価格をつけてくれます。

  • 抽出の品質がメモリの品質です。LLM は何が記憶に値するか、新しい情報が古い情報と矛盾していないかを決めます。更新を見逃すモデルは、以降のすべてのセッションで検索を汚染します。claude-sonnet-4-6 と gpt-5.5 は、このトレードオフの信頼できる中間点です。
  • ボリュームはすべての書き込みにかかってきます。やり取りのたびに add() を呼ぶチャットプロダクトは、1日に数千回抽出を実行し、そこでは claude-haiku-4-5-20251001 や deepseek-v4-flash のような速い id が、メモリ層がトークン請求を支配してしまうのを防ぎます。
  • 矛盾の多いドメイン(変わっていく好み、期限切れになる事実)では、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 がルーティングを乗っ取ります。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 とモデル id だけです。
  • フロンティア級のチャットモデルと速い抽出用 id を組み合わせて、メモリ層のユニットコストを制御する、高ボリュームのチャットプロダクト。どちらも同じエンドポイントからアドレスできます。
  • 抽出モデルを横並びで評価する開発者。各候補は、ベンダーごとの新しいプロバイダー統合ではなく、固定されたフィクスチャに対する1つのモデル文字列で済みます。
  • 特定ベンダーの請求手段にアクセスできない開発者。チャージ制でカード不要のアクセスなら、プロバイダーごとのサインアップという依存を取り除けます。

エンドポイントを検証し、最初の add() をデバッグする。

パイプラインを実行する前に、ゲートウェイが設定したモデルを一覧しているか確認してください。model フィールドは、提供されている id と正確に一致していなければなりません。 初回実行の失敗にはパターンがあります。401 は、LLM が解決したキーが、解決したエンドポイントに対して間違っているということです。両方とも設定優先・環境変数次点というカスケードから来るため、推測せず、両方の実効値を出力してください。設定の api_key と環境変数の base URL(あるいはその逆)の組み合わせは、典型的な不一致です。model-not-found エラーは id のタイプミスです。リクエストが目に見えて openrouter.ai に向かっている場合、OPENROUTER_API_KEY の特別扱いが発動しています。そして add() は成功するのに search() が失敗する場合、環境変数経由で誤ってエンベダーを動かしてしまっています。base URL を llm ブロックに限定してください。 メモリが流れ始めたら、APIsRouter コンソールがリクエストごとのモデル、トークン数、支出を表示します。抽出の呼び出しは小さいものの絶え間なく続くため、利用状況ビューこそが、推定するのではなく、メモリ層が1000回の書き込みあたり実際にいくらかかるかを知る方法です。

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 は、メモリ層をセルフホストする場合に適用されます。