MemOS 获取记忆接口实战:/product/get_memory 分页查询与 /product/get_all 全量子图导出指南
MemOS 获取记忆接口实战:/product/get_memory 分页查询与 /product/get_all 全量子图导出指南
本篇指南聚焦 MemOS 开源仓库中"获取记忆(Get Memories)"这一核心 API 能力,讲解 POST /product/get_memory 分页查询与 POST /product/get_all 全量/子图导出两个接口的设计动机、请求参数、响应结构,并结合仓库源码剖析其底层实现原理。读完本文,你将能够独立完成记忆资产的前端分页展示、按类型全量导出以及基于查询语句提取相关记忆子图三类典型任务。
1. 接口总览:两种记忆集合访问模式
在 MemOS 中,用户的记忆资产以 MemCube 为组织单元存储,其中既包含系统自动生成的原始记忆片段,也包括用户偏好和工具使用记录。为了满足"轻量展示"与"批量处理"两类差异极大的使用场景,开源版通过 MemoryHandler 提供了两条独立的集合访问通道,路由均挂在 /product 前缀之下(定义见 server_router.py):
| 接口路径 | 方法 | 设计定位 | 核心能力 |
|---|---|---|---|
/product/get_memory |
POST | 前端 UI 列表分页展示 | 支持 page/page_size 分页,默认附带偏好记忆,支持细粒度类型开关与元数据过滤 |
/product/get_all |
POST | 数据迁移、复杂关系分析、全量导出 | 支持按 memory_type 导出全量数据,或传入 search_query 召回并返回相关记忆子图(Subgraph) |
配套的还有按 ID 精确获取的 POST /product/get_memory/{memory_id} 与 POST /product/get_memory_by_ids,它们与本文两个接口共同构成完整的记忆读取体系,相关说明可参考同目录文档 get_memory_by_id.md。
2. 核心机理:分页 vs 全量导出
两个接口虽然都是"读记忆",但底层处理链路完全不同,理解其设计差异有助于选对接口:
- 业务分页模式(
/get_memory):为前端列表设计,强调"轻量"。请求模型GetMemoryRequest(见 product_models.py)默认开启偏好记忆、工具记忆与技能记忆的附带返回,并允许通过filter对元数据做条件过滤。它返回的data是按记忆类别分组的四元结构,方便前端直接渲染。 - 全量导出模式(
/get_all):为数据迁移或关系分析设计,强调"完整"。当携带search_query时,服务端会执行一次语义检索,把命中的记忆节点及其关联关系整理成树形子图返回;当不携带查询词时,则按memory_type导出某一类记忆的全量数据。
从源码看,/get_all 的两个分支分别落到两个独立 handler:
- 有
search_query→ handle_get_subgraph:调用naive_mem_cube.text_mem.get_relevant_subgraph(...)获取相关子图; - 无
search_query→ handle_get_all_memories:调用naive_mem_cube.text_mem.get_all(...)获取指定类型全量数据。
两者随后走同一条"图 → 树"格式化链路(详见第 6 节)。
3. 关键接口参数详解
3.1 分页查询参数(/get_memory)
按文档定义,/get_memory 的核心参数如下:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
mem_cube_id |
str |
是 | 目标 MemCube ID。 |
user_id |
str |
否 | 用户唯一标识符。 |
page |
int |
否 | 页码(从 1 开始)。若设为 None 则尝试全量导出。 |
page_size |
int |
否 | 每页条目数。 |
include_preference |
bool |
否 | 是否包含偏好记忆。 |
对照源码中的 GetMemoryRequest,实际请求模型还提供了两个文档未展开但非常实用的扩展参数:
include_tool_memory(默认True):是否返回工具记忆(ToolSchemaMemory、ToolTrajectoryMemory);include_skill_memory(默认True):是否返回技能记忆(SkillMemory);filter:可选元数据过滤条件,支持嵌套的and/or结构以及gt等比较运算符,例如{"and": [{"id": "uuid-xxx"}, {"created_at": {"gt": "2024-01-01"}}]}。
设置 page=None(或 page_size=None)时接口会退化为不带分页的全量拉取,这与 /get_all 的定位在语义上互补:前者返回分组后的结构化结果,后者返回树形子图/类型化全量数据。
3.2 全量/子图导出参数(/get_all)
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
user_id |
str |
是 | 用户 ID。 |
memory_type |
str |
是 | 记忆类型:text_mem、act_mem、para_mem。 |
mem_cube_ids |
list |
否 | 待导出的 Cube ID 列表。 |
search_query |
str |
否 | 若提供,将基于此查询召回并返回相关的记忆子图。 |
对照源码 GetMemoryPlaygroundRequest(见 product_models.py),实际还包含两个值得注意的细节:
memory_type的完整字面量集合为["text_mem", "act_mem", "param_mem", "para_mem"],其中param_mem是文档表中未列出的第四个取值;- 额外提供了
search_type参数(默认fulltext),可选embedding或fulltext,用于指定子图召回的检索方式——即走向量语义检索还是全文检索。
同时需要说明一个实现现状:在 handle_get_all_memories 中,当前仅 text_mem 分支具备完整实现,act_mem 与 para_mem 分支会记录 "Activity memory retrieval not implemented yet" / "Parameter memory retrieval not implemented yet" 的 warning 日志。若你的需求是文本记忆(事实记忆),可放心使用;其余类型建议先确认服务端版本的实际支持情况。
4. 快速上手示例
4.1 前端分页展示(SDK 调用)
# 获取第一页,每页 10 条记忆
res = client.get_memory(
user_id="sde_dev_01",
mem_cube_id="cube_research_01",
page=1,
page_size=10
)
for mem in res.data:
print(f"[{mem['type']}] {mem['memory_value']}")
如果不经过 SDK、直接以 HTTP JSON 形式调用,对应的请求体应贴合 GetMemoryRequest 模型:
{
"user_id": "sde_dev_01",
"mem_cube_id": "cube_research_01",
"page": 1,
"page_size": 10,
"include_preference": true,
"include_tool_memory": true,
"include_skill_memory": true
}
include_preference 默认为 True,意味着默认返回结果中会附带用户的偏好记忆;若只想看正文记忆,可显式置为 false。另外,仓库中的 Python 客户端 src/memos/api/client.py 的 get_memory 方法对单次拉取条数做了 size <= 50 的校验(见 client.py),批量导大数据时建议配合分页循环或直接使用 /get_all。
4.2 导出特定的事实记忆子图
# 提取与“R 语言”相关的全部事实记忆
res = client.get_all(
user_id="sde_dev_01",
memory_type="text_mem",
search_query="R language visualization"
)
该请求在服务端的实际处理路径为:server_router.get_all_memories 检测到 search_query 非空后,会以 top_k=200 的召回规模调用 handle_get_subgraph。mem_cube_ids 为空时,mem_cube_id 会回退为 user_id 本身(见 server_router.py),因此即使只传 user_id 也能正常工作。
5. 响应结构说明
两个接口均返回标准的业务响应封装(BaseResponse),外层包含 message、code、data 三个字段,差异主要体现在 data 的组织方式上。
5.1 /get_memory 的响应 data
data 是一个按记忆类别分组的字典,最多包含四个键,每个键对应一个组,每组内含 cube_id、memories 与 total_nodes(节点总数,可用于前端分页控件):
{
"text_mem": [
{
"cube_id": "cube_research_01",
"memories": [ { "id": "...", "memory_value": "...", "tags": [] } ],
"total_nodes": 120
}
],
"pref_mem": [ { "cube_id": "...", "memories": [], "total_nodes": 8 } ],
"tool_mem": [ { "cube_id": "...", "memories": [], "total_nodes": 3 } ],
"skill_mem": [ { "cube_id": "...", "memories": [], "total_nodes": 2 } ]
}
该结构由 handle_get_memories 拼装:正文记忆固定返回(涵盖 WorkingMemory、LongTermMemory、UserMemory、OuterMemory 四种类型),其余三类受对应 include_* 开关控制。
5.2 /get_all 的响应 data
data 是列表结构,每项对应一个 Cube,包含 cube_id、memories 与 memory_statistics。与分页接口不同,这里的 memories 内嵌了 tree_structure 树形字段,用于描述记忆节点间的层次关系:
{
"data": [
{
"cube_id": "cube_research_01",
"memories": [
{
"tree_structure": { "children": [ ... ] },
"nodes": [ ... ]
}
],
"memory_statistics": { "WorkingMemory": 40, "LongTermMemory": 80 }
}
]
}
5.3 单条记忆的核心字段
data 中的记忆对象通常包含以下核心字段:
开发者提示:如果您已知记忆 ID 并希望查看其完整的元数据(如
confidence或usage记录),请使用获取记忆详情(Get_memory_by_id)接口,其实现为 handle_get_memory,统一从text_mem(含偏好记忆)中按 ID 精确读取,未命中时返回"Memory with ID xxx not found"消息。
6. 底层实现原理:从图数据库到树形结构
/get_all 之所以能返回"子图",是因为 MemOS 的记忆本体存储在图数据库中,节点之间天然存在关联边。为了把图结构变成前端易于渲染、LLM 易于消费的树,两个全量导出 handler 复用了一条完整的格式化链路(见 format_utils.py 相关函数):
remove_embedding_recursive:递归剔除向量字段,避免超大 embedding 数据随响应传输,实现"轻量导出";convert_graph_to_tree_forworkmem:将图结构转换为工作记忆树,采样目标节点数为 200(target_node_count=200),并按自定义类型比例分配节点配额:WorkingMemory:0.20LongTermMemory:0.40UserMemory:0.40
ensure_unique_tree_ids:保证树中所有节点 ID 唯一;filter_nodes_by_tree_ids:依据树节点 ID 集合回滤原始记忆,使返回的节点与树结构严格一致;sort_children_by_memory_type:按记忆类型对子节点排序,保证同类记忆在树中相邻呈现。
同时 convert_graph_to_tree_forworkmem 会产出各类型的节点计数(node_type_count),最终作为 memory_statistics 随响应返回,可用于前端图表统计或导出校验。这一整套逻辑在 text_mem 与子图两条路径中完全复用,保证了分页/导出两种模式下数据口径的一致性。
7. 与其他记忆接口的协作
获取记忆接口通常不是孤立使用的,实践中常见的组合方式如下:
- 列表 + 详情:先用
/get_memory分页拿到记忆 ID 列表,前端点击某条后调用/get_memory/{memory_id}获取完整元数据; - 检索定位 + 子图导出:先用 search_memory 接口做关键词/向量检索,再用
/get_all携带search_query拉取命中记忆的完整关系子图,用于复杂关系分析; - 导出备份 + 删除清理:用
/get_all全量导出后进行数据迁移,配合 delete_memory 接口(支持按memory_ids、file_ids或filter三种模式删除)完成清理或重建; - 新增回写:写入侧使用 add_memory 接口,读写闭环即构成一套完整的记忆资产管理链路。
8. 注意事项与最佳实践
- 分页参数置
None的含义:/get_memory的page/page_size均为可选,缺省为None,此时接口会一次性返回全部数据(不分页),与/get_all的导出定位接近,适合小规模 Cube 的场景; - 大 Cube 优先走
/get_all:/get_all内部有节点采样(200 节点上限)与树形化处理,结构更紧凑,适合迁移与关系分析;前端列表仍应优先使用/get_memory的total_nodes做分页; search_type的选择:默认fulltext适合精确关键词;涉及语义相近表述时可选embedding走向量召回,两者都经由get_relevant_subgraph统一返回子图;- 类型支持现状:当前
text_mem是完整实现的导出类型,act_mem/para_mem仅保留入口,调用前请确认部署版本; - 敏感数据与向量字段:导出结果默认已剔除 embedding 向量,若业务上需要原始向量,需另行定制或绕过
remove_embedding_recursive处理。
综上,/product/get_memory 与 /product/get_all 分别承担了"分页展示"与"全量子图导出"两种互补职责,配合 MemOS 的图存储与树形化格式化链路,为上层 Agent 应用提供了一套结构化、可迁移的记忆读取方案。