Multimodal Embedding(多模态嵌入)

让AI不只读懂文字,还能"看懂"图片、"听懂"声音,并在同一个空间里比较它们

向量嵌入 CLIP Sentence Transformers Reranker OpenClaw语义搜索

📖 一句话定义

Multimodal Embedding是将不同模态(文本、图片、音频、视频)的数据映射到同一个高维向量空间的技术。在这个空间里,语义相关的内容——无论模态——彼此距离更近。

世界上有一种向量空间叫多模态嵌入,它就像一个万能翻译室。你把一张猫的照片扔进去,再把"一只毛茸茸的小东西正在睡觉"这句话扔进去,它们在这个空间里成了邻居。不是翻译成同一种语言,而是翻译成同一种"感觉"。Hugging Face的Sentence Transformers团队2026年4月刚发了多模态训练教程,教你如何自己训练这种"感觉翻译器"。

🧠 从文本嵌入到多模态嵌入

传统文本嵌入模型(如all-MiniLM-L6-v2)只能处理文字。输入一段话,输出一个768维向量。两个向量算余弦相似度,就知道两段话是否语义相关。

但现实世界的搜索不是这样的:

用户搜索:"红色的杯子"
传统文本搜索:只匹配含有"红色""杯子"的文本
多模态搜索:还能找到红色的杯子照片,即使照片没有任何文字描述

用户搜索:"像这种风格的界面"
传统文本搜索:懵了——"这种"是什么?
多模态搜索:用户上传一张参考图,找到视觉上相似的界面截图

🔬 核心原理

1. 对比学习 Contrastive Learning

多模态嵌入的基石是对比学习。核心思想:

2. CLIP架构

CLIP(Contrastive Language-Image Pre-training)是OpenAI 2021年提出的经典架构:

训练流程(4亿对图文数据):
┌──────────┐    对比损失    ┌──────────┐
│ 文本编码器 │ ←─────────→  │ 图像编码器 │
│ (Transformer) │             │ (ViT)     │
└─────┬────┘               └─────┬────┘
      │                           │
      ▼                           ▼
  文本向量[768维]           图像向量[768维]
      │                           │
      └──── 余弦相似度 ──────────┘
           正样本 → 接近 1.0
           负样本 → 接近 0.0

3. Sentence Transformers 多模态扩展

Hugging Face的Sentence Transformers库在2026年已经全面支持多模态:

from sentence_transformers import SentenceTransformer

# 加载多模态嵌入模型
model = SentenceTransformer("clip-ViT-B-32")

# 文本嵌入
text_emb = model.encode("一只橘猫在阳光下打盹")

# 图像嵌入
from PIL import Image
img = Image.open("cat_sleeping.jpg")
image_emb = model.encode(img)

# 跨模态比较
from sentence_transformers.util import cos_sim
similarity = cos_sim(text_emb, image_emb)
# similarity = 0.87 → 高度相关!

4. Reranker:粗筛+精排两阶段

多模态搜索的工业级做法是两阶段检索

阶段1 - 粗筛(Embedding模型)
  目标:从百万条数据中快速筛选top-100
  方法:向量相似度检索
  模型:CLIP / SigLIP(速度快、内存小)
  耗时:~10ms

阶段2 - 精排(Reranker模型)
  目标:从top-100中精排top-10
  方法:Cross-Encoder直接比较query和document
  模型:ColPali / 多模态Reranker(精度高)
  耗时:~100ms

为什么不用Reranker做全量?
  - Cross-Encoder需要把query和每个candidate拼起来算
  - 100万次Cross-Encoder计算 = 100分钟
  - Embedding全量只需5秒
  - 所以先Embedding粗筛,再Reranker精排

📊 主流多模态嵌入模型

| 模型 | 模态 | 向量维度 | 特点 |
|------|------|----------|------|
| CLIP ViT-L/14 | 图文 | 768 | OpenAI出品,经典标杆 |
| SigLIP | 图文 | 768 | Google出品,CLIP的改进版 |
| ColPali | 图文(文档) | 128 | 专为文档检索设计 |
| E5-V | 图文音 | 1024 | 微软出品,三模态统一 |
| ImageBind | 6模态 | 1024 | Meta出品,最广泛的多模态 |
| Nomic-Embed-Vision | 图文 | 768 | 开源,长上下文 |
| Jina-CLIP | 图文 | 768 | 高精度,支持多语言 |

训练自己的多模态嵌入:
  - Sentence Transformers >= 3.0 支持多模态微调
  - 支持 vision + text + audio 任意组合
  - Hugging Face 2026年4月发布完整训练教程

🛠️ OpenClaw 实战应用

场景:OpenClaw多模态语义搜索Agent

# openclaw agent config: multimodal-search-agent
name: multimodal-search-agent
model: auto

skills:
  - name: image-search
    description: "用文字描述搜索相似图片"
    tools:
      - image_encoder
      - vector_search

  - name: document-search
    description: "搜索文档中的图文内容"
    tools:
      - document_parser
      - multimodal_reranker

  - name: cross-modal-query
    description: "跨模态查询:用图搜图、用文搜图、用图搜文"
    tools:
      - embed_any
      - similarity_search

memory:
  type: vector
  embedder: sentence-transformers/clip-ViT-B-32
  storage: ~/.openclaw/multimodal-search/vectors/

Python完整示例

from sentence_transformers import SentenceTransformer, CrossEncoder
import numpy as np
from PIL import Image
import os

class MultimodalSearch:
    """基于OpenClaw的多模态语义搜索引擎"""

    def __init__(self):
        # 阶段1:嵌入模型(粗筛)
        self.embedder = SentenceTransformer("jina-clip-v2")

        # 阶段2:Reranker(精排)
        self.reranker = CrossEncoder("jina-reranker-v2-base-multilingual")

        self.corpus = []  # {(text, image_path, embedding)}
        self.corpus_matrix = None

    def index(self, items):
        """建立索引:items = [{"text": "...", "image": "path"}, ...]"""
        embeddings = []
        for item in items:
            if item.get("image") and os.path.exists(item["image"]):
                img = Image.open(item["image"])
                emb = self.embedder.encode({"text": item["text"], "image": img})
            else:
                emb = self.embedder.encode(item["text"])
            embeddings.append(emb)
            self.corpus.append(item)

        self.corpus_matrix = np.array(embeddings)
        print(f"✅ 索引完成:{len(self.corpus)}条记录")

    def search(self, query_text=None, query_image=None, top_k=100, rerank_top=10):
        """搜索:支持文本查询、图片查询、或两者混合"""
        # 编码query
        if query_image and os.path.exists(query_image):
            img = Image.open(query_image)
            query_emb = self.embedder.encode({"text": query_text or "", "image": img})
        else:
            query_emb = self.embedder.encode(query_text)

        # 阶段1:向量粗筛
        from sentence_transformers.util import cos_sim
        scores = cos_sim(query_emb, self.corpus_matrix)[0]
        top_indices = np.argsort(scores.numpy())[-top_k:][::-1]

        # 阶段2:Reranker精排
        query_str = query_text or "[image query]"
        pairs = [(query_str, self.corpus[i]["text"]) for i in top_indices]
        rerank_scores = self.reranker.predict(pairs)

        # 合并分数
        results = []
        for idx, (corpus_idx, score) in enumerate(zip(top_indices, rerank_scores)):
            results.append({
                "item": self.corpus[corpus_idx],
                "rerank_score": float(score),
                "embedding_score": float(scores[corpus_idx])
            })

        results.sort(key=lambda x: -x["rerank_score"])
        return results[:rerank_top]


# 使用示例
search = MultimodalSearch()

# 索引:混合图文内容
search.index([
    {"text": "OpenClaw Agent配置示例", "image": None},
    {"text": "MCP协议架构图", "image": "docs/mcp-architecture.png"},
    {"text": "多Agent协作流程", "image": "docs/multi-agent-flow.png"},
    {"text": "VLA机器人控制流程", "image": "docs/vla-robot.png"},
])

# 文本搜索图片
results = search.search(query_text="智能体架构图", top_k=50, rerank_top=5)
for r in results:
    print(f"🔍 {r['item']['text']} (score: {r['rerank_score']:.3f})")

# 图片搜索图片(以图搜图)
results = search.search(query_image="reference-architecture.png", top_k=50, rerank_top=5)
for r in results:
    print(f"🖼️ {r['item']['text']} (score: {r['rerank_score']:.3f})")

⚡ 性能优化要点