feat(clip): 多模态向量器(CLIP ONNX)——文本/图像 512 维共享空间 + 媒体向量写入与重算

- internal/memory/clip:CLIP ONNX 向量器(onnxruntime 构建标签控制,默认构建不链接 ONNX)
  - clip.New(modelDir) 加载 text.onnx/vision.onnx(输出 text_embed/image_embed [batch,512])
  - 实现 vector.Vectorizer + vector.MultimodalEmbedder(Vectorize/EmbedImage + Dense 变体)
  - 词级 BPE tokenizer:merges 合并后词末片段带 </w> 查 vocab,与官方 encode 逐 id 对齐
  - EmbedImage:解码→resize 224→NCHW→normalize→vision session
  - Fingerprint(text+vision 文件 sha256)供模型切换检测
  - stub 版(无 onnxruntime 标签)保持默认构建行为不变
- vector/store.go:新增 MultimodalEmbedder 接口
- media.Store:新增 StaleVecDigests(currentModel)——查 vec_model 不匹配/缺失的图片
- agent core:AgentConfig.ClipEmbedder + Agent.clipEmb 接线;
  describePendingMedia 描述成功后 EmbedImageDense→SetVec;
  新增 reembedStaleMedia 启动补算历史无向量图片
- config:core.memory.media.clip_model_dir(未配置退化为现有 fastText/TF-IDF 行为)
- cmd/homed:读 clip_model_dir 加载 CLIP,失败仅记日志不阻塞启动

测试:TestSmokeLoadAndEncode(文本语义 cat>dog 0.914>physics 0.740)、
TestCrossModalAlignment(red-image vs red-text 0.063>blue -0.009,与 Python 一致)、
TestTokEnd(与官方 encode 逐 id 对齐)、TestStaleVecDigests,含 -race 全绿
This commit is contained in:
JianFeeeee
2026-09-09 10:23:31 +08:00
parent 8c9d96e065
commit 98365f3a55
10 changed files with 863 additions and 2 deletions

View File

@ -17,6 +17,18 @@ type Vectorizer interface {
EmbedImage(img []byte, mime string) (Vector, error)
}
// MultimodalEmbedder 扩展 Vectorizer提供直接返回 dense 向量的方法
// 与模型生命周期管理。CLIP 等视觉向量化器实现此接口;未启用时用空 stub。
type MultimodalEmbedder interface {
Vectorizer
VectorizeDense(text string) ([]float64, error)
EmbedImageDense(img []byte, mime string) ([]float64, error)
Fingerprint() string
Dim() int
Loaded() bool
Close()
}
// ErrNotSupported 表示 Vectorizer 不支持图像嵌入,调用方按文本描述降级。
var ErrNotSupported = fmt.Errorf("vectorizer does not support image embedding")
@ -256,7 +268,7 @@ func CosineSimilarity(a, b Vector) float64 {
// InvertedIndex 倒排索引,加速向量搜索
type InvertedIndex struct {
mu sync.RWMutex
mu sync.RWMutex
postings map[string]map[string]float64 // feature → {docID: weight}
}