mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-03 15:53:56 +00:00
feat(vector): pluggable multimodal vector space
核心暴露 MultimodalEmbedder 接口,两条路径共享同一套 L0/L2/L3 向量缓存、media.Store 坐标、QueryMemoryMediaScored 检索: - onnx:内嵌 ONNX 模型(CLIP 等),通过 build tag 编译 - http:外部向量 API 服务(Jina v5 / OpenAI / 自建) 跨模态融合权重改为 CrossModalFusionConfig 可配置结构体, 移除所有模型特定硬编码(CLIP/Jina),版本切换只需改配置。 模型切换自动迁移: - StaleVecDigestsAll 支持全模态(image+audio+video) - 启动时并发重算(ONNX 4 workers / API 8 workers) - 修复 SQL 运算符优先级导致 kind 过滤失效的 bug 实测对比(492 篇生产文档 + 3 张真实图片): - TF-IDF:MRR 0.457(精确匹配快,语义差) - fastText:MRR 0.530(语义中等,延迟 8ms) - Jina v5-omni:MRR 0.900(全面领先,延迟 40ms) - 中文文本→图片:Jina MRR 0.833 vs CLIP 0.611 See docs/embedding-comparison.md for full benchmark.
This commit is contained in:
@ -63,11 +63,35 @@ func (a *Agent) captureBlockMedia(blocks []agentAPI.ContentBlock, tool string) [
|
||||
log.Printf("[media] 落盘失败 (tool=%s mime=%s): %v", tool, mime, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 入库即算一次多模态坐标并缓存(多模态空间可用时)。
|
||||
// 之后 doc_query / memory_recall / 内部召回直接复用 SetVec 的缓存坐标,
|
||||
// 不重复跑 ONNX;模型切换由启动时的 reembedStaleMedia 补算。
|
||||
a.embedMediaOnIngest(d, mime, data)
|
||||
digests = append(digests, d)
|
||||
}
|
||||
return digests
|
||||
}
|
||||
|
||||
// embedMediaOnIngest 给刚入库的图片立即计算多模态坐标并缓存。
|
||||
// 只在 多模态空间可用且为图像时执行;音频/未配置时静默跳过(保持既有行为)。
|
||||
func (a *Agent) embedMediaOnIngest(digest, mime string, data []byte) {
|
||||
if a.multimodalSpace == nil || !a.multimodalSpace.Loaded() {
|
||||
return
|
||||
}
|
||||
if !strings.HasPrefix(mime, "image/") {
|
||||
return
|
||||
}
|
||||
vec, err := a.multimodalSpace.EmbedImageDense(data, mime)
|
||||
if err != nil {
|
||||
log.Printf("[media] 入库嵌入失败 %s: %v", shortDigest(digest), err)
|
||||
return
|
||||
}
|
||||
if err := a.mediaStore.SetVec(digest, vec, a.multimodalSpace.Fingerprint()); err != nil {
|
||||
log.Printf("[media] 入库写向量失败 %s: %v", shortDigest(digest), err)
|
||||
}
|
||||
}
|
||||
|
||||
// stageMediaDigests 累积本轮捕获的 digest,等 ContextEvent 建好后一起挂上。
|
||||
//
|
||||
// 为何要缓存而不是当场 AddRef:媒体在 process() 执行期间被捕获,而承载它的
|
||||
|
||||
Reference in New Issue
Block a user