记忆 API
管理当前用户的长期记忆实体与关系图谱
记忆 API 维护当前用户私有的长期记忆图谱:从 Agent 对话中提取的实体(节点),以及实体之间的有向关系(边)。所有端点都以调用者本人为边界——路径与查询参数里都不存在 team_id,一个用户永远无法读取或修改另一个用户的实体与关系。基础路径为 /api/v1/memories。
前置条件与认证
所有端点都需要已认证的 JWT 用户会话(Authorization: Bearer <token>)。这些端点不接受 API Key 认证,也不做任何权限码校验——数据隔离完全由 user_id 过滤实现。
对不属于自己的 ID,服务端统一按“不存在”处理,不会区分“不存在”与“无权访问”。注意本组端点的“资源不存在”返回的是 HTTP 400 + 业务码 4000(memory_entity_not_found / memory_relation_not_found),HTTP 状态不是 404——判断成败请以响应体 code 为准。
记忆通常在 Agent 对话过程中被自动提取;下面的手动增删改接口用于纠错和整理。自动提取的触发条件与开关见 Agent 记忆。
端点总览
| 方法 | 路径 | 用途 |
|---|---|---|
| GET | /api/v1/memories/entities | 列出当前用户的记忆实体 |
| POST | /api/v1/memories/entities | 手动创建记忆实体 |
| GET | /api/v1/memories/entities/{entity_id} | 获取实体详情及其出边与入边 |
| PUT | /api/v1/memories/entities/{entity_id} | 更新实体 |
| DELETE | /api/v1/memories/entities/{entity_id} | 删除实体及其全部关系 |
| GET | /api/v1/memories/relations | 列出当前用户的记忆关系 |
| POST | /api/v1/memories/relations | 手动创建记忆关系 |
| DELETE | /api/v1/memories/relations/{relation_id} | 删除关系 |
| GET | /api/v1/memories/graph | 获取用于可视化的记忆图谱 |
所有响应都使用统一信封 {"code": 0, "data": ..., "msg": "success"}。
认证与权限
| 项 | 说明 |
|---|---|
| 认证方式 | JWT Bearer 令牌(get_current_user) |
| API Key | 不支持 |
| 权限码 | 无(不经过 PermissionChecker) |
| 作用域 | 用户级:仅能操作 user_id 等于调用者的数据 |
数据结构
实体对象(Entity)
| 字段 | 类型 | 说明 |
|---|---|---|
id | string (UUID) | 实体 ID |
user_id | string (UUID) | 归属用户 |
name | string | 实体名称,最长 255 字符 |
entity_type | string | 实体类型,见下方枚举 |
description | string | null | 详细描述 |
properties | object | 自由结构属性,默认 {} |
source_conversation_id | string | null | 自动提取时的来源会话 ID |
source_message_id | string | null | 自动提取时的来源消息 ID |
access_count | integer | 被召回次数,默认 0 |
last_accessed_at | string | null | 最近一次被召回的时间 |
created_at | string | 创建时间 |
updated_at | string | 最后更新时间 |
同一用户下 name + entity_type 组合唯一;重复创建不会新增记录(见创建记忆实体)。
关系对象(Relation)
| 字段 | 类型 | 说明 |
|---|---|---|
id | string (UUID) | 关系 ID |
user_id | string (UUID) | 归属用户 |
source_entity_id | string (UUID) | 起点实体 ID |
target_entity_id | string (UUID) | 终点实体 ID |
relation_type | string | 关系类型,见下方枚举 |
description | string | null | 关系描述 |
properties | object | 自由结构属性,默认 {} |
source_conversation_id | string | null | 自动提取时的来源会话 ID |
source_message_id | string | null | 自动提取时的来源消息 ID |
created_at | string | 创建时间 |
updated_at | string | 最后更新时间 |
同一用户下 source_entity_id + target_entity_id + relation_type 组合唯一。
entity_type 枚举
| 取值 | 含义 |
|---|---|
person | 用户本人或其提到的人 |
preference | 用户偏好 |
skill | 技能、技术栈 |
project | 项目、工作 |
goal | 目标、目的 |
fact | 一般事实 |
concept | 抽象概念 |
organization | 公司、团队 |
location | 地点 |
custom | 其它 |
relation_type 枚举
| 取值 | 含义 |
|---|---|
prefers | 用户偏好 X |
works_on | 用户正在做 X |
knows | 用户认识 X |
uses | 用户使用 X |
works_at | 用户就职于 X |
located_in | 用户/实体位于 X |
has_goal | 用户的目标是 X |
related_to | 通用关联 |
part_of | X 属于 Y |
列出记忆实体
GET /api/v1/memories/entities返回当前用户的实体,支持按类型筛选与分页。未显式排序,按数据库返回顺序;需要稳定顺序时请自行按 created_at / name 排序。
查询参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
entity_type | string | 否 | - | 按实体类型过滤 |
page | integer | 否 | 1 | 页码,最小 1 |
page_size | integer | 否 | 20 | 每页条数,范围 1–100 |
curl -X GET "https://your-domain.com/api/v1/memories/entities?entity_type=preference&page=1&page_size=20" \
-H "Authorization: Bearer YOUR_TOKEN"成功响应(200 OK):
{
"code": 0,
"data": {
"items": [
{
"id": "8f14e45f-ceea-467a-9c1c-1b0c1a2d3e4f",
"user_id": "3d1f7a92-5b6c-4f8e-9a01-2c3d4e5f6a7b",
"name": "Python",
"entity_type": "preference",
"description": "Prefers concise Python snippets using async/await syntax.",
"properties": {"level": "expert"},
"source_conversation_id": "0b2c3d4e-5f60-4a71-8b92-c3d4e5f60718",
"source_message_id": null,
"access_count": 4,
"last_accessed_at": "2026-09-20T10:15:00Z",
"created_at": "2026-03-02T08:30:00Z",
"updated_at": "2026-09-20T10:15:00Z"
}
],
"total": 1,
"page": 1,
"page_size": 20
},
"msg": "success"
}分页信封固定为 data.items / data.total / data.page / data.page_size。
创建记忆实体
POST /api/v1/memories/entities请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 是 | 实体名称,最长 255 字符 |
entity_type | string | 是 | 实体类型枚举值 |
description | string | null | 否 | 实体描述 |
properties | object | 否 | 附加属性,默认 {} |
curl -X POST "https://your-domain.com/api/v1/memories/entities" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Python",
"entity_type": "preference",
"description": "Prefers concise Python snippets using async/await syntax.",
"properties": {"level": "expert"}
}'成功响应(200 OK): data 为创建(或更新,见下)后的实体对象。
同名同类型写入是幂等的
name + entity_type 已存在时不会新建记录,而是合并到已有实体:description 追加到原描述之后,properties 逐键合并(同名键覆盖),并刷新向量嵌入。响应 code 仍为 0,但 data.id 是既有实体 ID。
无法创建(如服务端内部错误)时返回 400 + 1003。
获取实体详情
GET /api/v1/memories/entities/{entity_id}返回实体本身,以及它以起点身份出现在其中的全部关系(outgoing_relations)和以终点身份出现的全部关系(incoming_relations)。两组关系都不分页。
路径参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
entity_id | string (UUID) | 是 | 实体 ID |
成功响应(200 OK):
{
"code": 0,
"data": {
"entity": {
"id": "8f14e45f-ceea-467a-9c1c-1b0c1a2d3e4f",
"user_id": "3d1f7a92-5b6c-4f8e-9a01-2c3d4e5f6a7b",
"name": "Python",
"entity_type": "preference",
"description": "Prefers concise Python snippets using async/await syntax.",
"properties": {"level": "expert"},
"source_conversation_id": null,
"source_message_id": null,
"access_count": 4,
"last_accessed_at": "2026-09-20T10:15:00Z",
"created_at": "2026-03-02T08:30:00Z",
"updated_at": "2026-09-20T10:15:00Z"
},
"outgoing_relations": [
{
"id": "c6d5e4f3-a2b1-4c0d-9e8f-7a6b5c4d3e2f",
"user_id": "3d1f7a92-5b6c-4f8e-9a01-2c3d4e5f6a7b",
"source_entity_id": "8f14e45f-ceea-467a-9c1c-1b0c1a2d3e4f",
"target_entity_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"relation_type": "uses",
"description": null,
"properties": {},
"source_conversation_id": null,
"source_message_id": null,
"created_at": "2026-03-02T08:31:00Z",
"updated_at": "2026-03-02T08:31:00Z"
}
],
"incoming_relations": []
},
"msg": "success"
}错误:
| HTTP | 错误码 | 说明 |
|---|---|---|
400 | 4000 | memory_entity_not_found:ID 不存在或不属于当前用户 |
更新实体
PUT /api/v1/memories/entities/{entity_id}请求体
所有字段可选。省略或传 null 的字段保持不变;因此无法通过本端点把 description 清空。
| 字段 | 类型 | 说明 |
|---|---|---|
name | string | null | 新名称,最长 255 字符 |
description | string | null | 新描述(直接覆盖,不追加) |
properties | object | null | 与既有 properties 逐键合并,同名键覆盖 |
curl -X PUT "https://your-domain.com/api/v1/memories/entities/8f14e45f-ceea-467a-9c1c-1b0c1a2d3e4f" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Python 3.13",
"description": "Prefers concise Python snippets using async/await syntax.",
"properties": {"level": "expert", "years": 5}
}'成功响应(200 OK): data 为更新后的实体对象。修改 name 或 description 会同步刷新实体的向量嵌入。
错误:
| HTTP | 错误码 | 说明 |
|---|---|---|
400 | 4000 | memory_entity_not_found |
400 | 1003 | memory_entity_update_failed |
删除实体
DELETE /api/v1/memories/entities/{entity_id}删除实体,并级联删除所有以它为起点或终点的关系,同时清理 Qdrant 中的向量。
成功响应(200 OK):
{
"code": 0,
"data": {"message": "Memory entity deleted successfully"},
"msg": "Memory entity deleted successfully"
}错误:
| HTTP | 错误码 | 说明 |
|---|---|---|
400 | 4000 | memory_entity_not_found |
400 | 1003 | memory_entity_delete_failed |
列出记忆关系
GET /api/v1/memories/relations查询参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
entity_id | string (UUID) | 否 | - | 按实体过滤;匹配该实体作为起点或终点的关系 |
relation_type | string | 否 | - | 按关系类型过滤 |
page | integer | 否 | 1 | 页码,最小 1 |
page_size | integer | 否 | 20 | 每页条数,范围 1–100 |
成功响应(200 OK):
{
"code": 0,
"data": {
"items": [
{
"id": "c6d5e4f3-a2b1-4c0d-9e8f-7a6b5c4d3e2f",
"user_id": "3d1f7a92-5b6c-4f8e-9a01-2c3d4e5f6a7b",
"source_entity_id": "8f14e45f-ceea-467a-9c1c-1b0c1a2d3e4f",
"target_entity_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"relation_type": "uses",
"description": null,
"properties": {},
"source_conversation_id": null,
"source_message_id": null,
"created_at": "2026-03-02T08:31:00Z",
"updated_at": "2026-03-02T08:31:00Z"
}
],
"total": 1,
"page": 1,
"page_size": 20
},
"msg": "success"
}创建记忆关系
POST /api/v1/memories/relations请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
source_entity_id | string (UUID) | 是 | 起点实体,必须属于当前用户 |
target_entity_id | string (UUID) | 是 | 终点实体,必须属于当前用户 |
relation_type | string | 是 | 关系类型枚举值 |
description | string | null | 否 | 关系描述 |
properties | object | 否 | 附加属性,默认 {} |
成功响应(200 OK): data 为关系对象。
重复关系是幂等的
相同 source_entity_id + target_entity_id + relation_type 已存在时,直接返回既有关系(code: 0),不会重复写入,也不会用新请求的 description / properties 覆盖它。
错误:
| HTTP | 错误码 | 说明 |
|---|---|---|
400 | 1002 | memory_source_entity_not_found / memory_target_entity_not_found(实体不存在或不属于当前用户) |
400 | 1002 | memory_relation_create_failed(其它创建失败) |
400 | 1003 | 服务端内部错误 |
删除关系
DELETE /api/v1/memories/relations/{relation_id}路径参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
relation_id | string (UUID) | 是 | 关系 ID |
成功响应(200 OK):
{
"code": 0,
"data": {"message": "Memory relation deleted successfully"},
"msg": "Memory relation deleted successfully"
}错误:
| HTTP | 错误码 | 说明 |
|---|---|---|
400 | 4000 | memory_relation_not_found |
400 | 1003 | memory_relation_delete_failed |
获取记忆图谱
GET /api/v1/memories/graph返回用于可视化的实体与关系集合。响应只包含 entities 与 relations 两个数组,不含分页字段。
查询参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
entity_ids | array of UUID | 否 | - | 重复该参数可指定种子实体,只返回其周围子图 |
max_depth | integer | 否 | 1 | 子图遍历深度,范围 1–3(超范围返回 422) |
省略 entity_ids 时返回当前用户的全量图谱(全部实体 + 全部关系,不分页)。传入 entity_ids 时返回的是一张有界子图:服务端会限制节点数与关系数上限,超出部分静默截断——需要完整数据请改用 GET /entities 与 GET /relations 分页拉取。
curl -X GET "https://your-domain.com/api/v1/memories/graph?entity_ids=8f14e45f-ceea-467a-9c1c-1b0c1a2d3e4f&max_depth=2" \
-H "Authorization: Bearer YOUR_TOKEN"成功响应(200 OK):
{
"code": 0,
"data": {
"entities": [
{
"id": "8f14e45f-ceea-467a-9c1c-1b0c1a2d3e4f",
"user_id": "3d1f7a92-5b6c-4f8e-9a01-2c3d4e5f6a7b",
"name": "Python",
"entity_type": "preference",
"description": "Prefers concise Python snippets using async/await syntax.",
"properties": {"level": "expert"},
"source_conversation_id": null,
"source_message_id": null,
"access_count": 4,
"last_accessed_at": "2026-09-20T10:15:00Z",
"created_at": "2026-03-02T08:30:00Z",
"updated_at": "2026-09-20T10:15:00Z"
}
],
"relations": [
{
"id": "c6d5e4f3-a2b1-4c0d-9e8f-7a6b5c4d3e2f",
"user_id": "3d1f7a92-5b6c-4f8e-9a01-2c3d4e5f6a7b",
"source_entity_id": "8f14e45f-ceea-467a-9c1c-1b0c1a2d3e4f",
"target_entity_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"relation_type": "uses",
"description": null,
"properties": {},
"source_conversation_id": null,
"source_message_id": null,
"created_at": "2026-03-02T08:31:00Z",
"updated_at": "2026-03-02T08:31:00Z"
}
]
},
"msg": "success"
}错误处理
| HTTP | 错误码 | 触发场景 |
|---|---|---|
401 | 2000 / 2001 / 2002 | 缺少令牌、令牌无效或已过期 |
400 | 4000 | 实体/关系不存在或不属于当前用户 |
400 | 1002 | 关系端点引用了不存在的实体,或关系创建失败 |
400 | 1003 | 实体创建/更新/删除的内部错误 |
422 | 1001 | 请求校验失败:UUID 格式错误、未知枚举值、page < 1、page_size 超出 1–100、max_depth 超出 1–3 |
本组端点未实现单独限流,无专属速率限制中间件;通用错误处理约定见 错误处理。
相关文档
这篇文章对你有帮助吗?