|
|
e9856c8f65
|
feat(media): media.Item 加视觉嵌入字段,Store 加 QueryMedia 跨模态检索
路线 3(完整跨模态检索)的媒体层基础:
- Item 新增 Vec []float64(视觉嵌入向量,JSON 序列化存库)和 VecModel
(模型标识,用于模型切换后触发重算)
- initSchema 加 ALTER TABLE 迁移 vec/vec_model 两列(幂等,列已存在可忽略)
- scanItem 扩展读回 vec/vec_model
- SetVec(digest, vec, model) 写入向量
- QueryMedia(queryVec, model, topK):对所有已嵌入媒体做余弦相似度检索,
维度不一致的项自动跳过(防不同模型空间的向量被混算)
混合检索的设计意图:查询可以是图片也可以是文本(经向量化后调用 QueryMedia),
被查的媒体库里每个 item 也有视觉向量。两者在同一空间比对,谁相似度更高召回谁。
不再区分「图片查询」还是「文本查询」——向量空间的相似度自动决定。
|
2026-09-07 17:11:10 +08:00 |
|
|
|
a82267484a
|
feat(memory): 内容寻址媒体存储(CAS)——图记忆支持二进制多媒体节点的底座
此前四层记忆全是纯文本载体,没有任何一层能存二进制:
L0 ContextEvent — Input/Response/ToolResults[].Output 全 string
L1 text.Event — 同上
L2 document.Doc — Summary/Content/Tags 全 string
L3 图库 — sentences.text TEXT UNIQUE,节点身份就是那串文本
于是 multimodal 插件注入的图只在本轮对话内可见(走 message 数组,不经
记忆),下一轮起只剩 ToolResultItem.Output 里那句
"[已将图片注入后续对话] /tmp/x.png"——一条路径字符串。那个文件被删或
被覆盖之后连线索都断了。
## 为何内容寻址而不是存路径
- 路径会失效。/tmp 下的探针图、下载缓存、别的进程的临时产物,记忆里
留个路径等于留个悬空指针。
- 同一内容常被反复注入(连问几轮同一张截图、see_video 相邻帧高度相似),
按 sha256 寻址天然去重。
- 内容即身份,与 L3 图库 sentences.text UNIQUE 思路一致:文本节点用文本
本身做身份,媒体节点用内容摘要做身份。
## 结构
元数据(SQLite media.db)与内容(磁盘 blobs/ 两级前缀分桶)分离,不把
blob 塞进库:单张图动辄几 MB,塞进去让每次 VACUUM/备份都拖着几百 MB 走,
WAL 也会迅速膨胀。
media(digest PK, kind, mime, size, width, height, origin_path, tool,
description, described_by, ref_count, first_seen, last_seen)
media_refs(digest, owner_kind, owner_id, created_at, PK 三列)
digest 既是主键也是文件名,所以没有 Path 字段——路径由 digest 推导,
不落库(落了就又是个会失效的引用)。origin_path 仅供人类溯源,注释里
明确标注不可用于读取。owner_kind 预留 context/document/graph_sentence。
## 几处刻意的决定
- Get 强制校验 digest:CAS 的全部保证建立在「文件名 == 内容摘要」上,
位翻转或外部误改必须被发现——把损坏的图喂给模型只会得到无从追溯的幻觉。
- 先写 .tmp 再 rename:中途崩溃不留半个 blob 被当成完整内容读走。
- AddRef 幂等:只有真插进 media_refs 才递增,否则计数虚高会让 GC 永远
不敢清。DropRef 用 MAX(0,...) 兜底防负数。
- Put 的空描述不冲掉已有描述(先到的可能来自更强的模型),但尺寸/工具名
这类前一次缺失的信息会被补写。Describe 是显式操作,允许覆盖。
- GC 两段 + minAge 保护:刚 Put 还没 AddRef 的项 refcount 也是 0,minAge
防「落地后还没挂上就被清掉」。有引用的项永不删除,即使超容量——宁可
超限也不断引用。
## 测试
21 例,覆盖去重 / MIME 归类 / 损坏检测 / 无残留临时文件 / AddRef 幂等 /
计数不为负 / DropOwner / GC 保留有引用项 / minAge 保护 / 容量淘汰 /
描述覆盖与补写策略 / Search 按描述与 kind 过滤 / Pending / data URL
往返 / Stats / 跨重启持久化。
本 commit 只加存储层,尚未接入 L0/L2/L3 与描述生成。
|
2026-09-04 11:03:36 +08:00 |
|