快速开始
环境配置
Mem0 依赖向量数据库存储长期记忆,官方推荐使用 Qdrant 作为向量存储提供商,以下是完整的环境配置流程,包含 Qdrant 部署、密钥配置及 Mem0 核心参数设置,确保环境稳定运行。
1. Qdrant 部署(必选)
Qdrant 是一款高性能向量数据库,支持多种部署方式,可根据自身环境(开发/测试/生产)选择,以下是最常用的两种部署方式,补充详细操作步骤及注意事项:
方式1:Docker 容器部署(推荐用于开发/测试环境)
- 优势:部署快捷、环境隔离,无需复杂配置,适合快速上手。
- 前提:已安装 Docker(建议版本 20.10+),确保 Docker 服务正常运行。
- 操作命令:
# 拉取最新版 Qdrant 镜像(当前最新稳定版 v1.17.1)
docker pull qdrant/qdrant
# 启动容器,映射端口并挂载持久化存储(避免容器删除后数据丢失)
docker run -d \
-p 6333:6333 \ # HTTP API 端口,Mem0 连接核心端口
-p 6334:6334 \ # gRPC API 端口,可选,用于高并发场景
-v $(pwd)/qdrant_data:/qdrant/storage \ # 挂载本地目录到容器,持久化存储向量数据
--name qdrant \ # 容器命名,便于后续管理
qdrant/qdrant
验证部署:访问 http://localhost:6333,若出现 Qdrant 欢迎页面,说明部署成功。
注意事项:
- Windows 系统使用 Docker/WSL 挂载本地目录时,可能出现文件系统问题导致数据丢失,建议使用 WSL2 环境,并确保挂载目录权限正确。
- 若需自定义 Qdrant 配置(如修改日志级别、量化策略),可挂载自定义配置文件,具体参考 Qdrant 官方文档。
方式2:二进制文件部署
优势:可根据硬件架构定制编译,性能更优,适合生产环境长期运行。
2. 密钥与 Base_URL 配置
Mem0 依赖 LLM 进行记忆提取、总结归纳,需配置对应的 LLM 密钥(此处以阿里云 DashScope 为例,适配通义千问系列模型),同时配置 Qdrant 连接参数,确保 Mem0 能正常调用 LLM 和向量数据库。
完整配置代码:
# 配置 LLM 密钥与 Base_URL(此处使用 DashScope,可替换为 OpenAI、Anthropic 等)
# 建议将密钥放在环境变量中,避免硬编码泄露
os.environ["OPENAI_API_KEY"] = os.getenv("DASHSCOPE_API_KEY") # 实际使用 DashScope 密钥
os.environ["OPENAI_BASE_URL"] = os.getenv("DASH_SCOPE_BASE_URL") # DashScope 接口地址(如 https://dashscope.aliyuncs.com/v1)
# Mem0 核心配置(涵盖向量存储、LLM、嵌入模型)
config = {
"vector_store": {
"provider": "qdrant",
"config": {
"host": "localhost",
"port": 6333,
"embedding_model_dims": 1024, # 嵌入模型维度,需与 embedder.dimensions 完全一致
"collection_name": "user_diet_memory", # 向量集合名称,用于区分不同类型的记忆
# 可选配置:用于分布式部署、安全认证等
# "api_key": "your_qdrant_api_key", # 若 Qdrant 配置了 API 密钥,需填写
# "https": True # 若 Qdrant 启用了 HTTPS,需设为 True
},
},
"llm": {
"provider": "openai", # LLM 提供商,此处兼容 DashScope(需确保 Base_URL 正确)
"config": {
"model": "qwen-flash", # 选用的 LLM 模型,建议使用轻量模型提升速度
"temperature": 0.1, # 温度参数,必须设为最低(0.1 左右),确保记忆提取准确、无冗余
"max_tokens": 1024
},
},
"embedder": {
"provider": "openai",
"config": {"model": "text-embedding-v3"},
"dimensions": 1024 # 嵌入模型维度,需与 vector_store.config.embedding_model_dims 一致
},
# 可选:重排模型,用于优化检索结果排序(对检索精度要求高时启用)
# "reranker": {
# "provider": "openai",
# "config": {"model": "qwen3-rerank"},
# }
}
关键配置注意事项
- 维度一致性:
vector_store.config.embedding_model_dims和embedder.dimensions最好显式配置,并且维度完全一致,否则会导致向量存储失败。 - 温度参数:
llm.config.temperature必须调整到最低(0.1~0.2),避免 LLM 生成冗余、不准确的记忆总结,确保记忆内容与用户输入一致。 - 集合名称:
vector_store.config.collection_name在测试环境下可省略,默认使用mem0集合;生产环境建议按业务场景命名(如user_diet_memory、user_travel_memory),避免不同类型记忆混淆。
添加与搜索记忆
Mem0 提供简洁的 API 接口,用于添加、搜索记忆,支持单条/批量操作,以下是完整示例(含异常处理),并补充操作场景说明。
1. 添加记忆
添加记忆是 Mem0 的核心功能,支持传入对话消息、用户标识、元数据等,可根据需求选择是否让 LLM 提炼记忆(默认开启)。
示例代码:
try:
# 初始化 Mem0 客户端
client = Memory.from_config(config)
# 定义需要添加的记忆(对话形式,支持多轮消息)
messages = [
{"role": "user", "content": "I'm a vegetarian and allergic to nuts."}, # 用户输入:饮食偏好
{"role": "assistant", "content": "Got it! I'll remember your dietary preferences."} # 助手回复:确认记忆
]
# 添加记忆,指定用户标识(用于后续过滤检索)
# user_id:必填,用于区分不同用户的记忆,支持自定义(如用户ID、账户名)
client.add(messages, user_id="user_0")
print("记忆添加成功!")
except Exception as e:
print(f"记忆添加失败:{str(e)}")
# 常见失败原因:Qdrant 服务未启动、密钥配置错误、维度不一致
2. 搜索记忆
搜索记忆时,可通过关键词查询,并结合过滤器(如用户ID、时间范围)缩小检索范围,支持重排功能优化结果顺序。
示例代码:
try:
# 搜索记忆:查询用户的饮食限制
# query:检索关键词,支持自然语言(如中文、英文)
# filters:过滤器,用于精准定位记忆(此处按 user_id 过滤,确保只检索 user_0 的记忆)
results = client.search("What are my dietary restrictions?", filters={"user_id": "user_0"})
print("检索结果:")
pprint(results)
except Exception as e:
print(f"记忆检索失败:{str(e)}")
检索结果说明:
检索结果返回一个列表,每个元素包含记忆ID、记忆内容、元数据、时间戳等信息,示例如下:
[
{
"id": "memory_123456", # 记忆唯一ID(用于更新、删除操作)
"text": "The user is a vegetarian and allergic to nuts.", # LLM 提炼后的记忆内容
"metadata": {}, # 元数据(添加记忆时可自定义)
"timestamp": "2025-01-15T12:00:00Z", # 记忆添加时间戳
"user_id": "user_0", # 关联的用户标识
"score": 0.98 # 检索相似度(0~1,分数越高越相关)
}
]
核心功能
记忆类型
Mem0 采用分层记忆架构,将记忆分为4类,分别对应不同的使用场景和生命周期,确保记忆的高效存储、检索和管理,以下是详细说明(补充应用场景和特点):
1. 感知记忆
- 定义:当前调用的原始输入信息,是记忆的“原始素材”,未经过 LLM 提炼和处理。
- 特点:瞬时性、原始性,仅在当前调用过程中临时存在,不持久化存储。
- 应用场景:用于 LLM 实时理解当前用户输入,为短期记忆、长期记忆的生成提供基础。
2. 短期记忆
-
定义:存储于 LLM 上下文窗口(context window)的 messages 列表,记录当前任务执行的全过程状态。
-
特点:
- 生命周期:任务存续期间持续存在,对话关闭、任务终止后自动清空。
- 访问特性:即时可访问,无需查询向量数据库,响应速度快。
- 限制:受 LLM 上下文窗口的 token 上限限制(如 qwen-flash 上下文窗口为 8192 token),超出上限后会自动丢弃最早的消息。
-
应用场景:记录当前对话的上下文(如用户连续提问、助手回复),确保对话的连贯性。
3. 长期记忆
定义:跨任务持久化存储于外部向量数据库(如 Qdrant)的记忆,可长期保存,支持跨对话、跨任务检索。
分类:
- 情节记忆(Episodic Memory) :
- 定义:存储用户的具体事件经历、对话细节,是原始对话的提炼总结。
- 特点:具备时间关联性、场景化,记录“何时、何地、发生了什么”。
- 应用场景:新任务时检索相似案例(如用户之前提到的饮食偏好、旅行计划),规避重复提问,提升回复准确性。
- 语义记忆(Semantic Memory) :
- 定义:从多次对话、事件中提炼的通用知识与规律,是抽象化的结论,而非具体细节。
- 特点:信息密度高、检索命中率高,不依赖具体场景,可迁移复用。
- 应用场景:回答用户的通用问题(如用户多次提到喜欢清淡饮食,可提炼为“用户偏好清淡、素食”,用于后续饮食推荐)。
- 程序记忆(Procedural Memory) :
- 定义:存储具体的操作流程(SOP)、步骤规范,是可重复执行的“操作指南”。
- 特点:结构化、可复用,适配重复性任务,减少操作冗余。
- 应用场景:智能体自动执行重复性任务(如用户定期查询饮食禁忌,程序记忆可记录查询流程,自动完成检索并返回结果)。
4. 实体记忆
- 定义:相较于长期记忆更精炼,从对话中主动提取的关键实体与事实,以结构化字段存储,是对话信息的结论提炼,而非原始内容。
- 特点:信息密度高、查询高效、不受原始表述影响(如用户说“我不吃坚果”和“坚果会让我过敏”,会被提炼为同一实体记忆)。
- 存储内容:用户偏好、客户预算、项目截止日、联系人信息等结构化数据。
- 应用场景:快速查询用户核心信息(如客服快速获取用户的饮食禁忌、会员等级),提升服务效率。
记忆层级关系图
flowchart LR
A[Conversation turn] --> B[Session memory]
B --> C[User memory]
C --> D[Org memory]
C --> E[Mem0 retrieval layer]
自定义实体记忆范围(Entity-Scoped Memory)
Mem0 支持通过标识符划定记忆范围,实现多维度的记忆隔离与管理,适用于多用户、多智能体、多应用场景,支持的标识符如下:
- user_id:最常用,用于区分不同用户,实现用户级别的记忆隔离(如 user_0、user_1),记忆持久化关联用户账户。
- agent_id:用于区分不同智能体或工具(如 travel-assistant、customer-support),确保智能体仅检索自身相关的记忆。
- app_id:用于区分不同应用(如 diet-app、travel-app),实现应用级别的记忆隔离,避免不同应用的记忆混淆。
- run_id:用于区分短生命周期的流程、工单或对话线程(如 session-123、task-456),任务结束后可批量删除该 run_id 对应的记忆。
添加记忆
Mem0 的记忆添加功能支持单条/批量添加、自定义元数据、记忆提炼开关等,以下是详细的参数说明、添加时机及流程解析。
1. 常用参数详解
Mem0 客户端的 add 方法支持多种参数,可灵活适配不同场景,参数说明如下:
client.add(
messages, # 必选,对话消息列表,格式为 [{"role": "user/assistant", "content": "..."}]
user_id="", # 可选,用户标识,用于记忆隔离与检索过滤
metadata={}, # 可选,额外元数据,键值对格式,用于提升检索效率(如 {"category": "diet", "priority": "high"})
infer=True, # 可选,默认 True,是否让 LLM 提炼记忆(True:提炼为简洁结论;False:直接存储原始消息)
timestamp=None # 可选,记忆的时间戳,默认使用当前时间(格式:YYYY-MM-DDTHH:MM:SSZ)
)
关键参数补充:
- messages:支持多轮对话消息,LLM 会综合所有消息提炼记忆,避免遗漏关键信息。
- metadata:可添加业务相关的标签(如分类、优先级),后续检索时可通过元数据过滤(如只检索“diet”分类的记忆)。
- infer:核心参数,建议默认开启(True),LLM会对消息进行提取压缩,并且处理和记忆库中的冲突。
2. 添加记忆的时机(最佳实践)
合理选择记忆添加时机,可避免冗余记忆、提升记忆质量,以下是推荐的添加时机:
- 用户有新的偏好或主动分享某件事(如“我不吃辣”“我喜欢爬山”)。
- 用户做出了一项决定或建议(如“我决定下周去北京旅行”“建议优先推荐素食餐厅”)。
- 目标或任务已完成(如“旅行计划已确认”“饮食禁忌已记录”),添加总结性记忆。
- 用户纠正之前的表述(如“我之前说的过敏是花生,不是所有坚果”),及时添加新记忆,覆盖旧记忆。
3. 记忆添加流程图
Mem0 添加记忆的完整流程分为3步,确保记忆的准确性、无冗余,流程如下:
- 提取信息:Mem0 向 LLM 发送请求,提取对话中的关键事实、决策和偏好(如用户的饮食禁忌、旅行计划)。默认开启
infer=True,LLM 会将原始对话提炼为简洁、准确的记忆内容;若设为infer=False,则直接存储原始消息,不进行提炼。 - 解决冲突:系统自动检查现有记忆中是否存在与新记忆重复或矛盾的内容,若存在冲突,以最新添加的记忆为准(如用户先说明“不吃坚果”,后纠正“只不吃花生”,系统会覆盖旧记忆)。 注意:若开启
infer=False,系统不会处理冲突,会直接存储新记忆,可能导致检索时出现重复或矛盾结果。 - 存储:提炼后的记忆(或原始消息)会存储到配置的向量数据库(Qdrant)中,同时生成唯一的记忆ID、时间戳等信息,便于后续检索、更新和删除;若开启了图存储配置,记忆也会同步存储到图数据库中,支持更复杂的关联检索。
检索记忆
Mem0 的检索功能支持关键词查询、多条件过滤、结果重排,确保快速、精准地获取所需记忆,以下是详细的检索流程、过滤器使用及代码示例。
1. 检索流程(核心逻辑)
Mem0 的记忆检索分为3个步骤,从粗筛到精排,确保检索结果的相关性和准确性:
- 查询重写:系统自动对用户的检索关键词进行重写和优化(如用户输入“我不能吃什么”,会重写为“用户的饮食禁忌”),提升检索的准确度,避免因关键词模糊导致检索失败。
- 向量搜索:通过嵌入模型将检索关键词转换为向量,在 Qdrant 中通过余弦相似度计算,定位与关键词最相关的记忆,返回初步候选结果。
- 过滤重排:使用用户指定的过滤器(如 user_id、时间范围)缩小候选范围,剔除无关记忆;若开启重排功能(reranker),会通过深度语义理解对候选结果进行重新排序,将最相关的记忆放在首位。
2. 检索代码示例(多场景)
以下是不同场景下的检索示例,涵盖基础查询、多条件过滤、重排等功能:
# 场景1:基础查询(无过滤器,检索所有相关记忆)
query = "What do you know about me?"
results = client.search(query)
pprint(results)
# 场景2:多条件过滤(结合 user_id、agent_id 过滤)
query = "What do you know about me?"
filters = {
"OR": [
{"user_id": "alice"}, # 检索 alice 的记忆
{"agent_id": {"in": ["travel-assistant", "customer-support"]}} # 检索指定智能体的记忆
]
}
results = client.search(query, filters=filters)
# 场景3:日期范围过滤(检索指定时间内的记忆)
query = "recent memories"
filters = {
"AND": [
{"user_id": "alice"}, # 限定用户
{"created_at": {"gte": "2024-07-01"}} # 检索 2024-07-01 及以后添加的记忆
]
}
results = client.search(query, filters=filters)
# 场景4:开启重排(优化检索结果顺序,适合对精度要求高的场景)
results = client.search(
query="What are my upcoming travel plans?",
rerank=True, # 开启重排
user_id="user123" # 同时限定用户
)
# 场景5:获取特定记忆(通过 memory_id 精准获取)
memory = client.history(memory_id="memory-id-here") # memory_id 从检索结果中获取
pprint(memory)
3. 过滤器详解
过滤器是 Mem0 检索的核心功能,支持多种逻辑组合(AND/OR)、比较操作(等于、包含、范围),可精准定位所需记忆,常用过滤器类型如下:
- 上下文过滤:通过 user_id、agent_id、app_id、run_id 等标识符过滤,实现多维度记忆隔离。
- 日期范围过滤:通过
created_at(记忆添加时间)过滤,支持gte(大于等于)、lte(小于等于)、eq(等于)等操作。 - 元数据过滤:通过添加记忆时设置的 metadata 过滤。
# 1. 上下文过滤(多维度记忆隔离)
filters={
"AND": [
{"user_id": "alice"}, # 必须满足 user_id 为 alice
{"agent_id": "chatbot"}, # 必须满足 agent_id 为 chatbot
{"run_id": "session-123"} # 必须满足 run_id 为 session-123
]
}
# 2. 日期范围过滤(基于创建时间)
filters={
"AND": [
{"user_id": "alice"},
{"created_at": {"gte": "2024-07-01", "lte": "2024-07-31"}} # 检索7月份的记忆
]
}
# 3. 元数据过滤(自定义metadata字段)
# 添加记忆时设置 metadata
client.add(messages, user_id="alice", metadata={"category": "travel", "priority": "high"})
# 检索时通过 metadata 过滤
filters={
"AND": [
{"user_id": "alice"},
{"metadata.category": "travel"}, # 检索分类为 travel 的记忆
{"metadata.priority": "high"} # 检索优先级为 high 的记忆
]
}
4. 重排功能说明
重排功能(rerank)通过深度语义理解对检索结果进行重新排序,解决向量搜索可能出现的“语义偏差”问题,将最相关的记忆放在首位,适用于对检索精度要求高的场景(如客服、医疗咨询)。
注意:开启重排功能需先配置 reranker 相关参数(参考环境配置部分的注释代码),且会增加少量检索延迟,非必要场景可关闭。
更新记忆
当记忆内容需要修改(如用户纠正偏好、信息更新)时,可通过 Mem0 提供的 update 方法更新记忆,支持单条更新和批量更新,以下是详细流程和代码示例。
1. 更新流程
- 通过
search方法检索需要修改的记忆,获取其唯一memory_id(记忆ID是更新的唯一标识)。 - 调用
update(单条更新)或batch_update(批量更新)方法,传入memory_id、新的记忆内容及可选的元数据、时间戳。 - 系统会覆盖原有的记忆内容,并更新向量数据库中的索引,确保后续检索能获取到更新后的记忆。
- 验证:重新调用
search方法,确认修改后的记忆已正确更新。
注意:对于 Immutable(不可变)的记忆(如系统自动生成的日志类记忆),无法直接更新,必须先删除该记忆,再重新添加新的记忆内容。
2. 更新代码示例
# 场景1:单条记忆更新
try:
# 1. 检索需要更新的记忆
results = client.search("What are my dietary restrictions?", filters={"user_id": "user_0"})
if not results:
print("未找到需要更新的记忆")
else:
memory_id = results[0].id # 获取第一条记忆的 ID
# 2. 调用 update 方法更新记忆
client.update(
memory_id=memory_id,
text="I'm a vegetarian and allergic to peanuts (not all nuts).", # 新的记忆内容
metadata={"category": "profile-update"}, # 可选,更新元数据
timestamp="2025-01-15T12:00:00Z" # 可选,更新时间戳
)
print("记忆更新成功!")
# 3. 验证更新结果
updated_memory = client.history(memory_id=memory_id)
pprint(updated_memory)
except Exception as e:
print(f"记忆更新失败:{str(e)}")
# 场景2:批量更新记忆
try:
# 定义需要更新的记忆列表(包含 memory_id 和新内容)
update_memories = [
{"memory_id": "id1", "text": "Watches football every weekend"},
{"memory_id": "id2", "text": "Likes to travel to coastal cities"}
]
# 调用批量更新方法
response = client.batch_update(update_memories)
print("批量更新成功!")
pprint(response)
except Exception as e:
print(f"批量更新失败:{str(e)}")
删除记忆
Mem0 支持单条删除、批量删除、全部删除三种方式,可根据需求灵活选择,删除后记忆无法恢复,建议操作前做好备份,以下是详细代码示例和注意事项。
1. 删除代码示例
try:
# 场景1:删除单个记忆(通过 memory_id)
memory_id = "your_memory_id" # 从检索结果中获取
client.delete(memory_id=memory_id)
print("单个记忆删除成功!")
# 场景2:批量删除记忆(通过 memory_id 列表)
delete_memories = [
{"memory_id": "id1"},
{"memory_id": "id2"}
]
response = client.batch_delete(delete_memories)
print("批量删除成功!")
pprint(response)
# 场景3:删除指定用户的所有记忆(通过 user_id 过滤)
client.delete_all(user_id="alice")
print("alice 的所有记忆已删除!")
except Exception as e:
print(f"记忆删除失败:{str(e)}")
2. 注意事项
- 删除操作不可逆,建议删除前通过
search或history方法确认记忆内容,避免误删。 delete_all方法若不指定user_id,会删除所有用户的记忆(慎用,适合测试环境清理数据)。- 批量删除时,若部分记忆ID不存在,系统会跳过该ID,继续删除其他存在的记忆,不会终止整个操作。
异步客户端
对于高并发场景(如多用户同时添加、检索记忆),Mem0 提供 AsyncMemoryClient 异步客户端,支持非阻塞操作,避免阻塞主线程,提升系统吞吐量,以下是详细使用示例。
import asyncio
from mem0 import AsyncMemoryClient
# 初始化异步客户端(配置与同步客户端一致)
async def main():
config = {
# 此处配置与同步客户端相同,省略重复代码
"vector_store": {"provider": "qdrant", "config": {"host": "localhost", "port": 6333, "embedding_model_dims": 1024}},
"llm": {"provider": "openai", "config": {"model": "qwen-flash", "temperature": 0.1}},
"embedder": {"provider": "openai", "config": {"model": "text-embedding-v3"}, "dimensions": 1024}
}
client = AsyncMemoryClient.from_config(config)
# 异步添加记忆
messages = [{"role": "user", "content": "I like drinking coffee."}]
await client.add(messages, user_id="user_0")
# 异步检索记忆
results = await client.search("What do I like to drink?", filters={"user_id": "user_0"})
print("异步检索结果:")
for res in results:
print(res.text)
# 运行异步函数
asyncio.run(main())
特点:
- API 方法与同步客户端一致,仅需在方法前添加
await关键字。 - 支持并发操作,可同时处理多个添加、检索请求,适合高并发场景(如 Web 应用、智能体集群)。
- 需运行在异步环境中(如使用 asyncio 框架),不可与同步客户端混合使用。
多模态
Mem0 支持图片、文档等多模态输入,可自动处理多模态内容,提取关键信息并添加到记忆中,提升系统对多模态输入的理解和调用能力,以下是详细使用示例(支持图片链接和 Base64 编码)。
1. 图片记忆添加(两种方式)
# 方式1:使用图片链接(需确保链接可访问)
messages = [
{
"role": "user",
"content": {
"type": "image_url",
"image_url": {
"url": "https://gitee.com/avengekiller/images/raw/master/Mem0%E8%AE%B0%E5%BF%86%E6%A3%80%E7%B4%A2"
# 注:该链接因文件乱码无法解析,实际使用时需替换为可访问的图片链接
}
}
},
]
client.add(messages, user_id="user_0")
# 方式2:使用 Base64 图像编码(适合本地图片)
image_path = "local_image.jpg" # 本地图片路径
with open(image_path, "rb") as image_file:
base64_image = base64.b64encode(image_file.read()).decode("utf-8") # 编码为 Base64 字符串
image_message = {
"role": "user",
"content": {
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}" # 拼接 Base64 编码字符串
}
}
}
client.add([image_message], user_id="user_0")
2. 多模态处理说明
- Mem0 会自动调用 LLM 的多模态能力(如 qwen-vl、gpt-4-vision),提取图片中的文本信息、物体、场景等关键内容,提炼为记忆。
- 支持的图片格式:JPG、PNG、GIF 等常见格式,Base64 编码建议控制文件大小(避免超过 LLM 输入限制)。
- 文档处理(如 PDF、TXT):类似图片处理,需将文档转换为可识别的文本格式(或 Base64 编码),Mem0 会提取文档中的关键信息添加到记忆中。
自定义分类
该功能仅在 Mem0 托管平台(Managed Service)上生效,本地部署版本暂不支持。
Mem0 会自动为每一条记忆添加标签(如旅行、运动、饮食),但默认标签可能与业务场景不匹配,自定义分类功能可替换标签列表,让标签与业务表述保持一致。
默认标签列表(可自定义替换)
- personal_details(个人详情)
- family(家庭)
- professional_details(职业详情)
- sports(运动)
- travel(旅行)
- food(饮食)
- music(音乐)
- health(健康)
- technology(技术)
- hobbies(爱好)
- fashion(时尚)
- entertainment(娱乐)
- milestones(里程碑)
- user_preferences(用户偏好)
- misc(其他)