今天我们要聊的 Mem0,就是专门给 AI 智能体打造的"海马体"。我会带你从零开始,把它接入到 Spring AI Alibaba 项目中,让 AI 真正记住用户是谁、喜欢什么、之前聊过什么。


一、Mem0

1.1 概念

Mem0(Memory for AI Agents)是 AI 智能体的长期记忆层。 它不是一个简单的数据库,而是一个懂语义的记忆管家——它知道该记什么、怎么记、以及什么时候把合适的记忆调取出来。

1.2 为什么不用普通的数据库或 RAG?

很多人第一反应是:“我直接把聊天记录存进向量数据库不就行了?” 差得远呢。

普通向量存储 Mem0
存的是原始文本片段 存的是提取后的语义事实(如"用户喜欢三角洲行动")
检索靠关键词匹配 检索靠语义理解(你说"我喜欢玩什么游戏",它能找到"三角洲行动")
没有用户维度 支持 user_id / agent_id / run_id 三维隔离
纯向量,无关系 向量(pgvector)+ 图(Neo4j)双引擎,能理解"用户-偏好-行为"之间的关系

打个比方: 普通向量库像把书页撕碎扔进抽屉,找的时候只能看碎片上的字;Mem0 则像一位图书管理员,读完书后做了摘要卡片,还知道哪些卡片之间有关联。

1.3 三种记忆类型

Mem0 把记忆分成了三个层次,对应真实世界中的三种"记得":

  1. 用户记忆(User Memory) —— 跨所有对话永久保存。比如"用户叫万能的喵,爱玩三角洲行动"。
  2. 智能体记忆(Agent Memory) —— 某个 AI 角色的专属知识。比如"这个客服代理负责处理退款"。
  3. 会话记忆(Session/Run Memory) —— 一次具体对话的上下文。比如"这次用户在咨询去日本的旅行"。

想象一下,你去理发店。Tony 老师记得你上次剪了什么发型(会话记忆),知道你喜欢短一点(用户记忆),而且他自己擅长剪寸头(智能体记忆)。Mem0 就是让 AI 也能拥有这种分层记忆能力。

1.4 本项目要做什么?

我们会搭建一个 Spring Boot 应用,暴露三个 REST 接口:

端点 方法 功能
/advisor/memory/mem0/call GET 和 AI 对话,自动存取记忆
/advisor/memory/mem0/messages GET 主动搜索某个用户的记忆
/advisor/memory/mem0/test GET 演示长期记忆的存储与检索效果

二、技术架构:这些组件是怎么配合的?

2.1 整体架构一览

先上一张全景图,看看数据是怎么流的:

大模型服务

存储层

Mem0 记忆管理层
端口: 8888

Spring AI Alibaba 应用
端口: 10009

客户端

1. 检索记忆
m.search(query, user_id)

2. 带记忆的 Prompt

3. 生成回答

4. 存储记忆
m.add(message, user_id)

HTTP 请求
/advisor/memory/mem0/call

Mem0MemoryController

Mem0ChatMemoryAdvisor
• 拦截消息
• 调用 Mem0 API
• 注入记忆上下文

ChatClient
带记忆增强的 LLM 调用

Mem0 Server
• 语义提取
• 记忆路由

事实提取引擎
LLM 驱动

PostgreSQL + pgvector
端口: 8432
• 向量存储
• 语义相似度检索

Neo4j 图数据库
端口: 8687/7474
• 关系图谱
• 关联检索

DashScope
• deepseek-chat
• qwen 系列

返回给用户

数据流向解读:

  1. 用户发送消息 → Spring 应用接收
  2. Mem0ChatMemoryAdvisor 拦截消息,先去 Mem0 Server 问:“关于这个用户,有什么相关的记忆?”
  3. Mem0 Server 同时在 pgvector(向量相似度)和 Neo4j(关系图谱)里查找
  4. 找到的记忆被注入到 Prompt 上下文里,一起送给大模型
  5. 大模型生成回答后,Advisor 再把这次对话中的新事实送回 Mem0 Server 存储
  6. 用户收到回答

2.2 为什么需要 pgvector + Neo4j 双存储?

这是 Mem0 设计最精妙的地方,很多人一开始看不懂为什么要两个数据库。

pgvector(向量数据库)负责"像什么":

  • 把记忆转成高维向量
  • 当你问"我喜欢玩什么"时,通过语义相似度找到"用户爱玩三角洲行动"
  • 解决的是模糊匹配问题

Neo4j(图数据库)负责"有什么关系":

  • 存储"用户 → 喜欢 → 三角洲行动"这样的关系
  • 能回答"这个用户还有什么其他爱好?"这类关联问题
  • 解决的是关系推理问题

举个生活中的例子:向量库像是你通过"味道相似"来找菜(语义相似),图数据库像是你看菜单上的"搭配推荐"(关系关联)。两者结合,AI 既能理解你说的意思,又能联想出相关的信息。

2.3 核心组件速查表

组件 作用 端口 类比
Mem0 Server 记忆管理的"大脑",决定记什么、怎么记、怎么取 8888 图书管理员
PostgreSQL + pgvector 记忆的"内容仓库",支持语义搜索 8432 索引卡片盒
Neo4j 记忆的"关系地图",存储人-事-物关联 8687/7474 思维导图
DashScope 提供大模型能力,负责理解和生成 云端 聪明的大脑

三、核心代码:记忆是怎么自动工作的?

3.1 引入依赖

pom.xml 中加入 Spring AI Alibaba 的 Mem0 起步依赖:

<dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-starter-memory-mem0</artifactId>
    <version>1.0.0-M6.3</version>
</dependency>

这个 starter 已经帮你封装好了和 Mem0 Server 的通信、记忆注入逻辑,你只需要配置就行。

3.2 控制器代码

@RestController
@RequestMapping("/advisor/memory/mem0")
public class Mem0MemoryController {

    private final ChatClient chatClient;
    private final VectorStore store;
    private final Mem0ServiceClient mem0ServiceClient;

    public Mem0MemoryController(
            ChatClient.Builder builder,
            VectorStore store,
            Mem0ServiceClient mem0ServiceClient) {
        
        // 创建 ChatClient,并挂上 Mem0 记忆增强器
        this.chatClient = builder
            .defaultAdvisors(
                // 核心:Mem0ChatMemoryAdvisor 自动管理记忆生命周期
                Mem0ChatMemoryAdvisor.builder(store).build()
            )
            .build();
    }

    /**
     * 对话接口 - 自动存储和检索记忆
     * 
     * 你不需要手动调用"存储记忆"或"查询记忆",
     * Mem0ChatMemoryAdvisor 会在幕后自动完成一切。
     */
    @GetMapping("/call")
    public String call(
            @RequestParam String message,
            @RequestParam(defaultValue = "miao") String userId) {
        
        return chatClient.prompt(message)
            .advisors(a -> a.params(Map.of(USER_ID, userId)))
            .call()
            .content();
    }
}

代码解读:

  • ChatClient 是 Spring AI 的统一 LLM 调用入口
  • Mem0ChatMemoryAdvisor 是一个拦截器(Advisor),它会在每次对话前后自动干活
  • 你只需要传一个 userId,Mem0 就知道"这是谁在说话",从而找到对应的记忆

3.3 Mem0 的完整工作流程(重点)

这是整个系统最核心的机制,我用流程图帮你拆解每一步:

DashScope LLM Neo4j pgvector Mem0 Server Mem0Chat MemoryAdvisor Spring AI 应用 DashScope LLM Neo4j pgvector Mem0 Server Mem0Chat MemoryAdvisor Spring AI 应用 【记忆检索阶段】 先回忆,再回答 【对话生成阶段】 带着记忆去对话 【记忆存储阶段】 把新信息记下来 用户 发送消息:"你好,我是万能的喵, 我爱玩三角洲行动" 1 拦截请求 2 m.search(query, user_id="miao") 3 语义向量相似度搜索 4 关系图谱查询 5 返回相关记忆向量 6 返回关联实体 7 返回记忆文档列表 8 组装 Prompt: [系统指令] + [相关记忆] + [用户消息] 9 发送增强后的 Prompt 10 返回生成结果 11 m.add(message, user_id="miao") 12 提取结构化事实 (偏好、习惯、关系等) 13 返回 JSON 格式事实 14 存储向量 15 存储关系图谱 16 返回最终回答 17 "你好万能的喵! 三角洲行动确实很好玩..." 18 用户

这个流程的精妙之处在于:

  • 检索在生成之前:AI 回答前已经"想起"了用户是谁
  • 存储在生成之后:新信息被实时提取并保存,下次就能用上
  • 事实提取是自动的:不是存原始聊天记录,而是存"用户爱好:三角洲行动"这样的结构化事实

3.4 事实提取:Mem0 到底存了什么?

这是很多人困惑的地方。Mem0 存的不是聊天记录原文,而是 LLM 从对话中提炼出的事实。比如:

用户原话 Mem0 存储的事实
“你好,我是万能的喵,我爱玩三角洲行动” {"type": "preference", "content": "用户爱玩三角洲行动", "entity": "万能的喵"}
“我每周三晚上都有空” {"type": "habit", "content": "用户周三晚上有空", "entity": "万能的喵"}
“帮我推荐个游戏,不要射击类的” {"type": "preference", "content": "用户不喜欢射击类游戏", "entity": "万能的喵"}

这就是为什么 Mem0 比直接存聊天记录高效得多——它存的是"知识点",而不是"课本原文"。


四、配置详解:让系统跑起来

4.1 application.yml 完整配置

spring:
  ai:
    dashscope:
      api-key: ${DASHSCOPE_API_KEY}
      chat:
        options:
          # 强烈推荐使用 DeepSeek,原因见下文
          model: deepseek-chat
          temperature: 0.7

    memory:
      mem0:
        # Mem0 服务器地址,本地开发用 localhost
        base-url: http://localhost:8888
        
        # 可选:自定义事实提取 Prompt
        # 如果你希望提取特定领域的信息,可以写自己的模板
        fact-extraction-prompt: classpath:prompts/custom_fact_extraction_prompt.st

# 禁用 Spring 的默认数据源自动配置
# 因为 Mem0 自己管理 pgvector 和 Neo4j 的连接,不需要 Spring Data JPA
spring.datasource.autoconfigure.enabled: false

# 调试日志:看看记忆是怎么被提取和检索的
logging:
  level:
    com.alibaba.cloud.ai.memory.mem0: DEBUG

4.2 环境变量清单

变量 必填 说明
DASHSCOPE_API_KEY 阿里云 DashScope 的 API Key,用于调用大模型
MEM0_BASE_URL Mem0 Server 的访问地址,默认 http://localhost:8888

4.3 为什么模型推荐 DeepSeek 而不是 Qwen?

这里有一个坑,原文件提了一嘴但没有细说。Mem0 内部需要 LLM 做结构化 JSON 输出(提取事实时必须按固定格式返回 JSON)。

# 推荐配置
model: deepseek-chat

# 不推荐(默认可能配置的是这个)
# model: qwen-turbo

原因很实际:

维度 DeepSeek Qwen(部分版本)
JSON 输出稳定性 ✅ 非常稳定,格式严格遵守 ⚠️ 偶尔会出现格式偏差
事实提取准确率 ✅ 高 ⚠️ 中等
价格 ✅ 相对便宜 视版本而定

这不是说 Qwen 不好,而是在"结构化输出"这个特定任务上,DeepSeek 当前表现更稳。如果你的场景已经验证了 Qwen 可以稳定输出 JSON,当然也可以用。


五、Docker 部署:一步一步来

5.1 启动所有依赖服务

Mem0 需要三个服务协同工作,我们用 Docker Compose 一键拉起:

# 进入项目自带的 docker-compose 目录
cd /home/tht/examples-main/docker-compose/mem0

# 复制环境变量模板
cp .env.example .env

# 编辑 .env 填入必要配置(见下文)
vim .env

# 后台启动所有服务
docker-compose up -d

5.2 .env 文件模板

# Mem0 服务自身的 API Key(用于服务间认证)
MEM0_API_KEY=your-mem0-api-key

# PostgreSQL 配置
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres

# Neo4j 配置(格式:用户名/密码)
# 注意:Neo4j 的默认用户名必须是 neo4j,只能改密码
NEO4J_AUTH=neo4j/mem0graph

注意: Neo4j 有一个特殊约定——默认用户名固定为 neo4jNEO4J_AUTH 里设置的是密码。如果你写成 NEO4J_AUTH=admin/123456,它会报错。

5.3 验证服务是否健康

启动后别急着跑应用,先检查每个服务是否正常:

# 查看所有容器状态
docker-compose ps

# 检查 Mem0 Server 是否就绪
curl http://localhost:8888/health

# 检查 PostgreSQL 是否接受连接
docker exec -it mem0-postgres-1 pg_isready -U postgres
# 期望输出:/var/run/postgresql:5432 - accepting connections

# 检查 Neo4j 是否可访问
curl -I http://localhost:7474
# 期望返回 HTTP 200

如果某个服务起不来,看日志:

# 实时跟踪 Mem0 日志
docker-compose logs -f mem0

# 查看 PostgreSQL 日志
docker-compose logs postgres

# 查看 Neo4j 日志
docker-compose logs neo4j

5.4 启动 Spring Boot 应用

依赖服务全部健康后,启动你的 Java 应用:

cd /home/tht/examples-main/spring-ai-alibaba-mem0-example

# 方式一:开发调试模式
mvn spring-boot:run

# 方式二:打包生产运行
mvn clean package -DskipTests
java -jar target/spring-ai-alibaba-mem0-example-1.0.0.jar

应用默认运行在 10009 端口。


六、API 使用指南:动手试一试

6.1 对话接口(记忆自动存取)

第一步:首次对话,让 AI 记住你

curl "http://localhost:10009/advisor/memory/mem0/call?message=你好,我是万能的喵,我爱玩三角洲行动&user_id=miao"

AI 可能会回答:“你好万能的喵!三角洲行动确实是一款很棒的战术射击游戏…”

第二步:换个话题,测试 AI 是否记得你

curl "http://localhost:10009/advisor/memory/mem0/call?message=推荐一款游戏给我&user_id=miao"

如果记忆生效,AI 会基于"你爱玩三角洲行动"推荐类似游戏,而不是随机推荐。

第三步:主动搜索记忆

curl "http://localhost:10009/advisor/memory/mem0/messages?query=我的爱好是什么?&user_id=miao"

返回示例:

[
  {
    "id": "doc-xxx",
    "content": "用户爱好:玩三角洲行动",
    "metadata": {
      "user_id": "miao",
      "memory_type": "user_preference",
      "confidence": 0.95
    }
  }
]

6.2 测试接口(快速验证长期记忆)

curl "http://localhost:10009/advisor/memory/mem0/test"

如果看到日志输出:

用户和 agent 的长期记忆保存成功
agent 的长期记忆: [Document{...}]

说明记忆写入和读取链路都是通的。

6.3 记忆的三维层级(重要)

Mem0 支持按三个维度隔离和检索记忆,这是设计多租户、多智能体系统的关键:

Mem0 记忆空间

会话维度 run_id

智能体维度 agent_id

用户维度 user_id

会话: trip-planning-2025

用户: alice

客服助手

健身教练

旅行规划师

会话: diet-week-1

用户: bob

检索示例:

# 获取某个用户的所有长期记忆(跨所有智能体和会话)
m.get_all(user_id="alice")

# 获取用户在特定智能体下的记忆
# 比如 alice 在"饮食助手"里的记忆
m.get_all(user_id="alice", agent_id="diet-assistant")

# 获取某次具体会话的记忆(短期记忆)
# 比如这次旅行咨询的对话
m.get_all(user_id="alice", run_id="trip-planning-2025")

# 语义搜索:用自然语言查找相关记忆
m.search("What do you know about me?", user_id="alice")

什么时候用什么维度?

场景 使用的维度 记忆类型
AI 记住用户名字、爱好 user_id 长期记忆
不同 AI 角色有各自的专业知识 user_id + agent_id 长期记忆
一次具体的客服对话上下文 user_id + run_id 短期记忆

七、自定义 Prompt:让记忆提取更精准

7.1 默认提取的问题

Mem0 自带的事实提取 Prompt 是通用的,但你的业务可能有特殊需求。比如:

  • 你是医疗助手,需要提取"过敏史"、“用药记录”
  • 你是电商助手,需要提取"品牌偏好"、“价格敏感度”
  • 你是教育助手,需要提取"薄弱知识点"、“学习目标”

7.2 自定义提取模板

src/main/resources/prompts/custom_fact_extraction_prompt.st 创建文件:

你是一个专业的记忆提取专家。请从以下对话中提取关键信息,
并严格按照 JSON 格式输出。

对话内容:
{{messages}}

提取规则:
1. 只提取明确陈述的事实,不要推测
2. 忽略寒暄、问候等无信息量的内容
3. 如果用户纠正了之前的信息,以最新说法为准

请提取以下类别的信息:
- preferences: 用户偏好(喜欢的、不喜欢的)
- habits: 用户习惯(时间规律、行为模式)
- facts: 重要事实(身份、职业、目标等)
- relationships: 关系信息(家人、同事、宠物等)

输出格式(必须是合法 JSON):
{
  "preferences": [
    {"subject": "游戏", "content": "爱玩三角洲行动", "sentiment": "positive"}
  ],
  "habits": [],
  "facts": [
    {"subject": "名字", "content": "万能的喵"}
  ],
  "relationships": []
}

7.3 启用自定义 Prompt

spring:
  ai:
    memory:
      mem0:
        fact-extraction-prompt: classpath:prompts/custom_fact_extraction_prompt.st

落地建议: 先跑一段时间默认 Prompt,观察提取效果,再针对漏提取或错提取的场景定制模板。不要一开始就写很复杂的模板。


八、常见问题与排查

8.1 Mem0 Server 连接失败

现象: 应用启动或调用时报 Connection refused: localhost:8888

排查步骤:

# 1. 先看 Mem0 容器是否在跑
docker-compose ps | grep mem0

# 2. 看 Mem0 日志找错误
docker-compose logs mem0 | tail -50

# 3. 常见原因:pgvector 或 Neo4j 还没就绪,Mem0 在重连
# 等 30 秒再试

# 4. 检查端口是否映射正确
curl http://localhost:8888/health

8.2 记忆检索不准确或为空

可能原因排查:

# 1. 检查 pgvector 是否健康
docker exec -it mem0-postgres-1 pg_isready -U postgres

# 2. 检查向量维度是否匹配(如果手动改过配置)
# 默认使用 1536 维或模型对应维度

# 3. 检查 LLM 模型
# 如果用的是 Qwen 且 JSON 输出不稳定,事实提取可能失败
# 建议切换到 deepseek-chat

调试技巧: 开启 DEBUG 日志,看记忆提取和检索的详细过程:

logging:
  level:
    com.alibaba.cloud.ai.memory.mem0: DEBUG

8.3 Neo4j 认证失败

现象: Unable to connect to Neo4jAuthentication failed

解决:

# 确认 .env 中的 NEO4J_AUTH 格式
# 必须是:neo4j/<你的密码>
# 用户名不能改,只能是 neo4j

# 如果之前启动过且改了密码,可能需要清理数据卷
docker-compose down -v
docker-compose up -d

8.4 内存占用过高

PostgreSQL + pgvector + Neo4j 一起跑比较吃资源,低配机器可能会卡。

# 在 docker-compose.yaml 中限制资源
services:
  postgres:
    shm_size: "64mb"  # 减小共享内存
    deploy:
      resources:
        limits:
          memory: 512M
  
  neo4j:
    deploy:
      resources:
        limits:
          memory: 1G

8.5 首次启动特别慢

正常现象。 首次启动需要:

  1. 拉取 Docker 镜像(几百 MB)
  2. Neo4j 初始化系统数据库(1-2 分钟)
  3. pgvector 创建扩展和表结构
# 耐心等待,看实时日志
docker-compose logs -f

# 当看到类似 "Mem0 server started" 或健康检查通过时即可

九、进阶用法:玩转三层记忆

9.1 短期记忆(按会话隔离)

适合需要记住"这次对话的上下文",但不需要永久保存的场景:

// 存储带 runId 的记忆(短期)
mem0ServiceClient.addMemory(
    Mem0ServerRequest.MemoryCreate.builder()
        .userId("test1")
        .runId("trip-planning-2025")  // 会话 ID,比如"日本旅行规划"
        .messages(List.of(
            new Message("user", "I'm planning a trip to Japan next month.")
        ))
        .build()
);

// 检索时指定 runId,只查这次会话的记忆
mem0ServiceClient.search("What was my travel plan?", "test1", null, "trip-planning-2025");

9.2 长期记忆(跨会话共享)

适合用户画像、偏好等永久信息:

// 不指定 runId,就是长期记忆
mem0ServiceClient.addMemory(
    Mem0ServerRequest.MemoryCreate.builder()
        .userId("test2")
        .agentId("agent2")  // 可选:指定属于哪个智能体
        .messages(List.of(
            new Message("user", "I'm travelling to San Francisco"),
            new Message("assistant", "That's great! I'm going to Dubai next month.")
        ))
        .build()
);

9.3 记忆的更新与删除

记忆不是只增不减的,用户可能会说"我之前说错了":

// 更新某条具体记忆(需要知道 memoryId)
mem0ServiceClient.updateMemory(
    memoryId,
    Map.of("memory", "用户实际喜欢的是使命召唤,不是三角洲行动")
);

// 删除单条记忆
mem0ServiceClient.deleteMemory(memoryId);

// 清空某个用户的所有记忆(慎用!)
mem0ServiceClient.deleteAllMemories("user_id", null, null);

写在最后

给 AI 加记忆,不是简单地"把聊天记录存起来"。Mem0 的价值在于它让 AI 拥有了"提炼-存储-联想"的完整记忆能力——就像人类不是记住每一秒的画面,而是记住经过大脑加工后的知识和经验。

特性 价值
自动事实提取 不用写规则,LLM 自动从对话中提炼知识点
语义理解检索 用户换种说法问,也能找到相关记忆
向量 + 图双引擎 既懂"像什么",又懂"有什么关系"
三维记忆隔离 用户级、智能体级、会话级灵活控制
Spring AI 原生集成 一个 Advisor 搞定,对业务代码零侵入

按照本文,你应该能顺利地把 Mem0 集成到自己的 Spring AI 项目中。如果在部署过程中遇到问题,建议按照第八章的排查清单一步一步来,大部分问题都是服务依赖没就绪或配置项填错了。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐