docs: design memory attachment path mapping
This commit is contained in:
@ -0,0 +1,101 @@
|
|||||||
|
# Memory 附件真实路径映射设计
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
让 `/resources` 和 `/memories/add` 两种摄入方式都保存附件与 session 的映射。
|
||||||
|
`/memories/search` 返回结果时,根据结果 `session_id` 查询当前用户附件,并且只有
|
||||||
|
当附件完整文件名出现在结果 `raw` 的字符串字段中时,才返回该附件真实 URI。
|
||||||
|
|
||||||
|
## 数据模型
|
||||||
|
|
||||||
|
新增 SQLite 表 `memory_attachments`:
|
||||||
|
|
||||||
|
- `id TEXT PRIMARY KEY`
|
||||||
|
- `user_id TEXT NOT NULL`
|
||||||
|
- `app_id TEXT NOT NULL DEFAULT 'default'`
|
||||||
|
- `project_id TEXT NOT NULL DEFAULT 'default'`
|
||||||
|
- `session_id TEXT NOT NULL`
|
||||||
|
- `resource_id TEXT`
|
||||||
|
- `content_type TEXT NOT NULL`
|
||||||
|
- `name TEXT NOT NULL`
|
||||||
|
- `internal_uri TEXT NOT NULL`
|
||||||
|
- `source TEXT NOT NULL`
|
||||||
|
- `sha256 TEXT`
|
||||||
|
- `created_at TIMESTAMP NOT NULL`
|
||||||
|
- `deleted_at TIMESTAMP`
|
||||||
|
|
||||||
|
以 `(user_id, session_id, internal_uri)` 建立唯一索引,避免幂等上传产生重复映射;
|
||||||
|
以 `(user_id, session_id, deleted_at)` 建立查询索引。
|
||||||
|
|
||||||
|
数据库初始化时,将现有未删除 `user_resources` 回填为附件映射。历史
|
||||||
|
`/memories/add` 请求没有保存在 Gateway 数据库中,因此无法自动回填。
|
||||||
|
|
||||||
|
## 摄入规则
|
||||||
|
|
||||||
|
### `/resources`
|
||||||
|
|
||||||
|
资源记录创建后,为保存的真实 `file://` URI 创建附件映射:
|
||||||
|
|
||||||
|
- `session_id` 使用 `resource:{user_id}:{resource_id}`;
|
||||||
|
- `resource_id` 指向资源;
|
||||||
|
- `source` 为 `resource_upload`;
|
||||||
|
- `content_type`、文件名、SHA256 复用资源元数据。
|
||||||
|
|
||||||
|
重复资源上传时确保已有资源对应的附件映射存在。
|
||||||
|
|
||||||
|
### `/memories/add`
|
||||||
|
|
||||||
|
API 将已鉴权的 `user_id` 一并传给 service。逐条检查 message 的 content item:
|
||||||
|
|
||||||
|
- 只有字符串 content 或纯文本 item 时不创建附件;
|
||||||
|
- 有 `uri` 时记录该 URI,`source=memory_add_uri`;
|
||||||
|
- 没有 `uri` 但有 `base64` 时,解码并保存到
|
||||||
|
`storage/{user_id}/memory_attachments/{attachment_id}/{safe_name}`,记录生成的
|
||||||
|
`file://` URI,`source=memory_add_base64`;
|
||||||
|
- 同时存在 `uri` 和 `base64` 时优先使用 `uri`,不重复落盘;
|
||||||
|
- 文件名优先使用 `name`,否则从 URI 路径或 `ext` 生成安全名称。
|
||||||
|
|
||||||
|
上游 add 调用失败时,删除本次 base64 生成的文件,不写入映射。调用成功后写入
|
||||||
|
附件映射。上游请求体保持原样,不修改现有 add 行为。
|
||||||
|
|
||||||
|
## 搜索匹配规则
|
||||||
|
|
||||||
|
对每条标准化搜索结果:
|
||||||
|
|
||||||
|
1. 根据已鉴权 `user_id` 和结果 `session_id` 查询未删除附件;
|
||||||
|
2. 递归遍历 `raw` 中 dict、list 的字符串值;
|
||||||
|
3. 跳过键名为 `base64` 的值,避免扫描大块编码数据;
|
||||||
|
4. 使用附件完整文件名做不区分大小写的子串匹配;
|
||||||
|
5. 仅命中的附件进入 `attachments`,按 `internal_uri` 去重;
|
||||||
|
6. 没有 session 或没有命中时返回 `attachments: []`。
|
||||||
|
|
||||||
|
响应附件格式:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "image",
|
||||||
|
"name": "simple-multimodal-image.png",
|
||||||
|
"internal_uri": "file:///home/tom/memory-gateway/tests/simple-multimodal-image.png"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
episode 是 session 级记忆,因此只能在同一 session 的附件中按文件名匹配,不能
|
||||||
|
证明具体附件是向量召回的直接来源。
|
||||||
|
|
||||||
|
## 删除与隔离
|
||||||
|
|
||||||
|
- 所有附件查询必须同时匹配 `user_id` 和 `session_id`;
|
||||||
|
- 删除 `/resources` 时,对应附件映射设置 `deleted_at`;
|
||||||
|
- 真实路径按用户明确要求直接出现在搜索结果中;
|
||||||
|
- 不改变资源列表和详情现有的 `resource://` 对外 URI。
|
||||||
|
|
||||||
|
## 测试
|
||||||
|
|
||||||
|
- 资源上传创建附件映射;
|
||||||
|
- 资源搜索仅在 raw 出现文件名时返回真实 URI;
|
||||||
|
- raw 不含文件名时返回空附件数组;
|
||||||
|
- `/memories/add` 的 URI content 创建映射;
|
||||||
|
- `/memories/add` 的 base64 content 落盘并创建映射;
|
||||||
|
- 不扫描 raw 中的 base64 字段;
|
||||||
|
- 不返回其他用户同 session 的附件;
|
||||||
|
- 现有测试继续通过。
|
||||||
Reference in New Issue
Block a user