mem0 记忆层接入统一 API
最后更新: 2026-07-16
mem0 的 OpenAI 供应商接受 openai_base_url 这个配置项。填 https://api.kkaiapi.com/v1,传一个 Key,负责提取和更新记忆的模型就能换成目录里任意 ID,Claude、DeepSeek 都算在内,Embedding 层完全不受影响。
先说结论:llm 配置块里一个键
mem0 的 OpenAI LLM 供应商解析端点的顺序是配置优先、环境变量次之、默认值兜底:先看 self.config.openai_base_url,再看 OPENAI_BASE_URL 环境变量,最后落到 https://api.openai.com/v1。所以最干净的覆盖方式是在 llm 配置字典里加一个键:openai_base_url 填 https://api.kkaiapi.com/v1,api_key 跟着一起填(或者导出 OPENAI_API_KEY),每一次记忆提取调用就都经网关走。 这是 mem0 上游的行为,能在 mem0/llms/openai.py 里读到,不是分叉版本。TypeScript SDK 提供同样一对配置,写法是驼峰式:openaiBaseUrl 和 apiKey。配置字典里的值会覆盖环境变量,环境变量又覆盖默认值,所以就算机器上 OPENAI_BASE_URL 指向别处,配置层的 base URL 依然会生效。
config = {
"llm": {
"provider": "openai",
"config": {
"model": "claude-sonnet-5",
"openai_base_url": "https://api.kkaiapi.com/v1",
"api_key": os.environ["KKAIAPI_KEY"],
},
}
}mem0 拿它的 LLM 到底干什么
mem0(GitHub 上的 mem0ai,约 6.1 万星标)是给 AI Agent 用的记忆层。每一次 add() 调用都会跑一条流水线:LLM 读新的对话轮次,提取候选记忆,拿去和已存的东西比对,逐条决定是新增、更新、删除还是跳过。这是真正的推理工作,而且每次写入都会发生,所以给生产 Agent 接上记忆之后,LLM 槽位触发的频率比大多数人预期的要高得多。 检索是另一半,完全不用 LLM:search() 把查询向量化,在存储上跑向量相似度检索。两个不同的客户端,两个不同的模型,配置在两个不同的块里(llm 和 embedder)。这个划分是动手改路由之前最该理解的一件事,因为它意味着可以把提取工作挪到一个多厂商网关上,同时 Embedding 保持原来的供应商和索引不变。 配置里 provider 仍然写 "openai",mem0 把 model 字段按纯字符串经 /v1/chat/completions 转发。当 openai_base_url 背后的端点提供多个厂商的模型时,这个字符串可以是 Claude、GPT、DeepSeek 或 GLM 的 ID,换提取模型就变成一行配置改动,而不是一次供应商迁移。
完整配置:配置字典或环境变量
配置字典路径是精确的那条:它只挪动 LLM。搭好字典,交给 Memory.from_config,照常用记忆 API。api_key 字段能让网关密钥完全不出现在你的向量库和 Embedding 设置里。 环境变量路径也存在:配置键缺失时,mem0 的 OpenAI 类会读 OPENAI_BASE_URL。这只需要导出一个变量、零代码改动,但注意作用范围:Embedding 的 OpenAI 类读的是同一批环境变量(它还认老名字 OPENAI_API_BASE,LLM 类不认),导出 OPENAI_BASE_URL 就等于同时挪动了两个组件——只有当网关也提供你的 Embedding 模型时这么做才对。kkaiapi 目前不提供 Embedding 模型,所以拿不准的时候,优先用配置字典,别碰环境变量。
import os
from mem0 import Memory
config = {
"llm": {
"provider": "openai",
"config": {
"model": "claude-sonnet-5", # 任意目录 ID
"openai_base_url": "https://api.kkaiapi.com/v1",
"api_key": os.environ["KKAIAPI_KEY"],
"temperature": 0.1,
},
},
# embedder 块保持不变:继续用自己的供应商和 Key
}
m = Memory.from_config(config)
m.add("我喜欢靠窗座位和素食餐", user_id="alice")
print(m.search("座位偏好?", user_id="alice"))怎么选提取模型
实际的循环是固定住你的 Embedding,拿同一批对话样例跑两三个提取模型,对比存下来的记忆有什么不同。经一个端点,这个对比就是每个候选模型改一个配置字符串,按 Key 的用量日志会给每次对比标好价。
- 提取质量就是记忆质量。LLM 决定什么值得记住、新信息是否和旧记忆矛盾;一个漏掉更新的模型会污染之后每一次会话的检索,claude-sonnet-5 和 gpt-5.5 是这个权衡里可靠的中间档
- 每次写入都会用到它。一个聊天产品在每轮对话后调用 add(),一天要跑几千次提取,这正是 claude-haiku-4-5-20251001 或 deepseek-v4-flash 这类快速 ID 能防止记忆层主导 token 账单的地方
- 矛盾频发的领域(会变的偏好、会过期的事实)值得在 add() 上用更强的模型,哪怕单次调用更贵,因为一次错误的更新决策事后很难发现
- 温度要设低。提取是结构化决策任务,不是创意写作;mem0 在同一个配置块里暴露 temperature,大约 0.1 能让新增/更新/删除的决策保持一致
主力模型价格
价格按 kkaiapi 中文区实时价格计算,单位 ¥/1M tokens(输入/输出)。
| 模型 | 模型 ID | kkaiapi 价格(输入/输出) | 适合场景 |
|---|---|---|---|
| Claude Sonnet 5 | claude-sonnet-5 | ¥3 / ¥15 | 提取质量优先 |
| GPT-5.5 | gpt-5.5 | ¥4 / ¥25 | 提取质量优先 |
| Claude Haiku 4.5 | claude-haiku-4-5-20251001 | ¥1 / ¥5 | 高频写入 |
| DeepSeek V4 Flash | deepseek-v4-flash | ¥0.9 / ¥1.8 | 高频写入 |
| GLM-5 | glm-5 | ¥3.6 / ¥16.2 | 中文场景性价比 |
mem0 专属的翻车点
一个遗留的 OPENROUTER_API_KEY 会劫持路由。mem0 的 OpenAI LLM 类对这个变量做了特殊处理:一旦设置了,这个类会切到 OpenRouter 的端点,忽略你的意图。如果请求没有打到你配置的 base URL,先查这个变量并取消设置它。 环境变量挪动的范围比你想的大。OPENAI_BASE_URL 被 LLM 和 Embedding 同时读取。kkaiapi 不提供 Embedding 模型,如果网关不提供你的 Embedding 模型,一个环境层的覆盖会弄坏 search(),表现为"记忆写得进去,检索却是空的或报错"。把覆盖限定在 llm 配置块里,Embedding 完全不会察觉。 配置键按 SDK 各写各的。Python 是蛇形命名(openai_base_url、api_key);TypeScript 是驼峰命名(openaiBaseUrl、apiKey)。Python 字典里混入一个驼峰键会被悄悄忽略,你会掉回默认端点,表现得和覆盖"没生效"一模一样。 模型 ID 是精确字符串。mem0 不校验 model 字段,只是转发它。一个拼写错误会在第一次 add() 时表现为网关返回的模型不存在,/v1/models 列表是权威拼写来源。 换 Embedding 是索引层面的决定,不是配置层面的决定。不同模型的 Embedding 活在不同的向量空间里,重新指定 Embedding 供应商会让已有向量的相似度失效。挪动 LLM 是免费的,挪动 Embedding 意味着要重新向量化整个存储,把它们当成两次独立的迁移来规划。
验证接入与排查首次 add()
在跑流水线之前先确认网关列出了你配置的模型;model 字段必须和提供的某个 ID 精确匹配。 首次跑的失败很有规律。401 意味着 LLM 解析到的 Key 和它解析到的端点对不上,因为两者都来自一条配置覆盖环境的级联,打印两个实际生效的值,别去猜;一个来自配置的 api_key 配一个来自环境的 base URL(或者反过来)是经典的错配。模型不存在的报错是 ID 打错字。请求肉眼可见地打到了 openrouter.ai,说明 OPENROUTER_API_KEY 的特殊逻辑生效了。如果 add() 成功但 search() 失败,说明你不小心通过环境变量挪动了 Embedding,把 base URL 收回到 llm 配置块里。 记忆流动起来之后,kkaiapi 控制台会显示每次请求的模型、token 数和花费。提取调用又小又频繁,用量视图是弄清楚记忆层每千次写入实际花了多少钱的地方,不用靠估算。
curl -s https://api.kkaiapi.com/v1/models \
-H "Authorization: Bearer $KKAIAPI_KEY" | head -50常见问题
哪个配置键能让 mem0 指向一个自定义端点?
Python 里是 llm 供应商配置里的 openai_base_url(TypeScript 里是 openaiBaseUrl)。配置值会覆盖 OPENAI_BASE_URL 环境变量,环境变量又覆盖默认的 https://api.openai.com/v1,所以配置字典是最确定的设置方式。
mem0 能用这套配置让 Claude 或 DeepSeek 提取记忆吗?
能。provider 仍然写 "openai",mem0 把 model 字段按纯字符串经 /v1/chat/completions 转发。openai_base_url 背后端点提供的任何 ID 都能用,包括 Claude、DeepSeek、GLM 的 ID。
设置 OPENAI_BASE_URL 会影响 Embedding 吗?
会。mem0 的 OpenAI Embedding 类读的是同一批环境变量(还多认老名字 OPENAI_API_BASE)。kkaiapi 不提供 Embedding 模型,只想挪动 LLM 的话,把 openai_base_url 设在 llm 配置块里,环境变量不要动。
用这套配置需要换 Embedding 或向量库吗?
不需要。llm 和 embedder 是两个独立的客户端。提取用的 LLM 可以经网关路由,同时 Embedding 保留原来的供应商,已有向量继续有效。重新指定 Embedding 是单独的迁移,需要重新向量化整个存储。
为什么我的 mem0 请求跑去了 OpenRouter,而不是我配置的 base URL?
mem0 的 OpenAI LLM 类对 OPENROUTER_API_KEY 环境变量做了特殊处理:一旦设置,不管你的 base URL 是什么都会重新路由到 OpenRouter。取消设置这个变量,openai_base_url 的配置就会生效。
这套配置对托管版 Mem0 平台也适用吗?
适用于开源 SDK(Memory / Memory.from_config),你能控制自己的 LLM 配置。托管版 Mem0 平台在服务端自己管理模型调用,自建这层记忆层时才用得上自定义 base URL。