Files
MemoryBear/docs/rag/pipeline/02-embedding.md
Multica PM Agent 343a5eebe3
Some checks failed
Sync to Gitee / sync (push) Has been cancelled
docs(rag): add MemoryBear RAG implementation docs v1.0
Submit the formed RAG documentation set produced across Sprint-1/2/3
(WS-12 through WS-26) under docs/rag/. Includes:

- README.md / INDEX.md: landing + total index (responsibility matrix,
  review verdicts, dual-link to source issues)
- overview/: full-pipeline architecture (4 .mmd diagrams),
  11-stage boundary contracts, doc map, source-code inventory
- pipeline/: 5 deep-dives (Loader/Parser/Chunking, Embedding,
  VDB & retrieval, GraphRAG, Rerank/Prompt/LLM)
- graphrag/, end-to-end/: v1.0 formal versions with full source
  retained as reference
- evolution/: 11 architecture-refactor proposals,
  6-direction roadmap, capability map
- review/: S3-T1 / S3-T2 final reviews, S2-T7 final summary
- _indexes/: glossary (81 terms), source->doc reverse index, chart index
- _release/: v1.0-RC1 release manifest, versioning convention,
  ops & freshness plan
- _meta/README.md: placeholder noting WS-12 governance assets gap

Aggregate review score 92.6/100 (8/8 PASS, 31/31 source-code spot
checks hit). The legacy docs/ ignore in .gitignore is narrowed to
docs/* with an explicit allowlist for docs/rag/.

Refs: WS-26
Co-authored-by: multica-agent <github@multica.ai>
2026-05-09 10:51:48 +08:00

26 KiB
Raw Blame History

[S2-T2] Embedding 模型选择与向量生成实现详解


一句话定位

MemoryBear 的 Embedding 层负责将文本 Chunk 转化为稠密向量,是连接"非结构化文本"与"向量数据库"的核心桥梁。当前系统同时存在两条 Embedding 调用路径:基于 LangChain 的统一封装层RedBearEmbeddings面向 ES 向量库)遗留的原始实现层embedding_model.py面向 GraphRAG 与 Dealer 检索)


设计目标与适用场景

  • 多提供商兼容:覆盖 OpenAI、Azure、DashScope通义千问、Volcano火山引擎、Xinference、GPUStack、Ollama、Bedrock 等主流 Embedding 服务
  • 多模态扩展:火山引擎支持文本/图片/视频多模态 Embedding
  • 知识库隔离:每个知识库独立配置 Embedding 模型,通过 knowledge.embedding_id 关联
  • GraphRAG 支撑:为实体/关系节点生成向量,用于图检索中的语义匹配

关键概念与术语表

术语 含义
RedBearEmbeddings LangChain 统一封装类,面向 ES 向量库的主入口
OpenAIEmbed 遗留原始实现,面向 GraphRAG 与 Dealer 检索
ModelApiKey 数据库表,存储模型的 API Key、base_url、provider
ModelConfig 数据库表存储模型的配置参数capability、timeout、max_retries 等)
EMBEDDING_BATCH_SIZE 环境变量,控制向量化批处理大小
chat_limiter Trio 并发限流器,控制 GraphRAG 中 Embedding 并发数
get_embed_cache Redis 缓存函数,缓存 GraphRAG 中的实体/关系向量

实现概览

架构分层

┌─────────────────────────────────────────────────────────────┐
│                    调用方(检索 / 入库)                       │
│  ElasticSearchVector   Dealer.search   GraphRAG             │
├─────────────────────────────────────────────────────────────┤
│                    Embedding 封装层                          │
│  RedBearEmbeddings  │  embedding_model.py遗留      │
├─────────────────────────────────────────────────────────────┤
│                    底层 SDK / API                            │
│  langchain_openai  dashscope  volcenginesdkarkruntime  ...  │
└─────────────────────────────────────────────────────────────┘

数据流Chunk → Vector

DocumentChunk(page_content="...", metadata={...})
        │
        ▼
ElasticSearchVector.add_chunks(chunks)           [elasticsearch_vector.py:55]
        │
        ├─► 火山引擎多模态: self.embeddings.embed_batch(texts)
        └─► 其他 provider: self.embeddings.embed_documents(list(texts))
                    │
                    ▼
        RedBearEmbeddings.embed_documents(texts) [models/embedding.py:65]
                    │
                    ▼
        OpenAIEmbeddings.embed_documents(texts)  [LangChain 内部]
                    │
                    ▼
        HTTP API Call (OpenAI-compatible / provider-specific)
                    │
                    ▼
        List[List[float]] → ES dense_vector field

1. 模型选择策略

1.1 遗留层支持的模型embedding_model.py

类名 _FACTORY_NAME 默认模型 上下文长度 截断策略 batch_size 备注
OpenAIEmbed OpenAI text-embedding-ada-002 8000 tokens truncate(t, 8000) 16 OpenAI 官方 API
AzureEmbed Azure-OpenAI 继承 OpenAI 8000 tokens 同上 16 Azure OpenAI Service
BaiChuanEmbed BaiChuan Baichuan-Text-Embedding 8000 tokens 同上 16 百川智能
QWenEmbed Tongyi-Qianwen text_embedding_v2 2048 tokens truncate(t, 2048) 4 阿里 DashScope自带 5 次重试
XinferenceEmbed Xinference 用户指定 8000 tokens 同上 16 Xinference 本地部署
NvidiaEmbed NVIDIA 用户指定 不截断API 端截断) 16 NVIDIA API含特殊模型路由
HuggingFaceEmbed HuggingFace 用户指定 不截断 无(全量发送) 本地 TEI 服务
VolcEngineEmbed VolcEngine 用户指定 8000 tokens 同上 16 火山引擎 Ark
GPUStackEmbed GPUStack 用户指定 8000 tokens 同上 16 GPUStack 本地部署
LocalAIEmbed LocalAI 用户指定 8000 tokens 同上 16 LocalAI / LMStudio

1.2 统一封装层支持的模型RedBearEmbeddings

Provider 对应的 LangChain 类 默认超时 默认重试 多模态支持
openai langchain_openai.OpenAIEmbeddings 120s 2 次
xinference langchain_openai.OpenAIEmbeddings 120s 2 次
gpustack langchain_openai.OpenAIEmbeddings 120s 2 次
dashscope langchain_community.DashScopeEmbeddings 120s 2 次
ollama langchain_ollama.OllamaEmbeddings 120s 2 次
bedrock langchain_aws.BedrockEmbeddings 120s 2 次
volcano volcenginesdkarkruntime.Ark (原生 SDK) 120s 2 次 (文本/图片/视频)

1.3 默认模型

  • 知识库默认 Embedding:通过 workspace.embedding 继承,或管理员在创建知识库时手动指定 embedding_id
  • 数据库关联knowledge.embedding_idmodel_configs.idModelConfig 表)→ model_api_keysAPI Key 表)
  • 无默认模型硬编码:系统不内置默认模型名称,完全依赖数据库配置

1.4 切换方式

  1. 管理后台配置:在模型管理页面添加新的 Embedding 模型配置provider + model_name + api_key + base_url
  2. 知识库绑定:创建/编辑知识库时选择新的 embedding_id
  3. 即时生效:新写入的 Chunk 使用新模型;历史 Chunk 向量保持不变(见"维度变更兼容"章节)

2. 调用链路详解

2.1 入库链路Chunk → ES Vector

memory_konwledges_server.py:430
    vector_service.add_chunks([chunk])
        │
        ▼
elasticsearch_vector.py:55-63
    def add_chunks(self, chunks: list[DocumentChunk], **kwargs):
        texts = [chunk.page_content for chunk in chunks]
        if self.is_multimodal_embedding:
            embeddings = self.embeddings.embed_batch(texts)      # 火山引擎
        else:
            embeddings = self.embeddings.embed_documents(list(texts))  # 其他
        self.create(chunks, embeddings, **kwargs)
        │
        ▼
models/embedding.py:65-78
    def embed_documents(self, texts: list[str]) -> list[list[float]]:
        if self._is_volcano:
            # 多模态 Embedding
            contents = [{"type": "text", "text": text} for text in texts]
            response = self._client.multimodal_embeddings.create(...)
            return [response.data.embedding]
        else:
            return self._model.embed_documents(texts)  # LangChain 标准接口
elasticsearch_vector.py:374-380
    def search_by_vector(self, query: str, **kwargs: Any) -> list[DocumentChunk]:
        if self.is_multimodal_embedding:
            query_vector = self.embeddings.embed_text(query)     # 火山引擎
        else:
            query_vector = self.embeddings.embed_query(query)    # 其他
        # ES script_score: cosineSimilarity(params.query_vector, 'vector') + 1.0

2.3 GraphRAG 链路Entity/Relation → Vector

graphrag/utils.py:301-327
    async def graph_node_to_chunk(kb_id, embd_mdl, ent_name, meta, chunks):
        ebd = get_embed_cache(embd_mdl.model_name, ent_name)
        if ebd is None:
            async with chat_limiter:                              # 并发限流
                with trio.fail_after(...):
                    ebd, _ = await trio.to_thread.run_sync(
                        lambda: embd_mdl.encode([ent_name]))      # 遗留 OpenAIEmbed
            ebd = ebd[0]
            set_embed_cache(embd_mdl.model_name, ent_name, ebd)  # Redis 缓存
        chunk["q_%d_vec" % len(ebd)] = ebd

2.4 Dealer 检索链路(加权融合检索)

nlp/search.py:365-373
    def get_vector(self, txt, emb_mdl, topk=10, similarity=0.1):
        qv, _ = emb_mdl.encode_queries(txt)                      # 遗留 OpenAIEmbed
        embedding_data = [get_float(v) for v in qv]
        vector_column_name = f"q_{len(embedding_data)}_vec"
        return MatchDenseExpr(vector_column_name, embedding_data, ...)

2.5 同步/异步说明

场景 模式 说明
ES 向量入库 同步 embed_documents() 为同步调用,在请求线程中执行
ES 向量检索 同步 embed_query() 为同步调用
GraphRAG 实体嵌入 异步 trio.to_thread.run_sync() 将同步 Embedding 调用放入线程池
模型验证 异步 asyncio.to_thread() 包装同步调用

2.6 批量大小与并发控制

控制点 数值 位置
OpenAI 兼容类 batch_size 16 embedding_model.py:52, :83, :178
QWen batch_size 4 embedding_model.py:133
HuggingFace 无批量(全量发送) embedding_model.py:258
GraphRAG 并发限流 MAX_CONCURRENT_CHATS(默认 10 graphrag/utils.py:41
RedBearModelConfig 并发 5配置项当前未在 Embedding 中使用) models/base.py:37

3. 生产级关注点

3.1 限流与配额管理

现状分析:

  • 无显式 API 速率限制:代码中未发现针对 Embedding API 的 RPM/TPM 限流逻辑
  • LangChain 内部限流OpenAIEmbeddings 内部有基础请求间隔控制,但不可配置
  • 并发控制仅存在于 GraphRAGchat_limiter = trio.CapacityLimiter(10) 限制 GraphRAG 中实体/关系嵌入的并发数

源码引用:

# graphrag/utils.py:41
chat_limiter = trio.CapacityLimiter(int(os.environ.get("MAX_CONCURRENT_CHATS", 10)))

# graphrag/utils.py:320-322
async with chat_limiter:
    with trio.fail_after(3 if enable_timeout_assertion else 30000000):
        ebd, _ = await trio.to_thread.run_sync(lambda: embd_mdl.encode([ent_name]))

3.2 失败重试与降级

现状分析:

路径 重试机制 降级策略
QWenEmbed遗留 显式 5 次重试,间隔 10s 抛出异常,无降级
RedBearEmbeddings统一层 max_retries(默认 2由 LangChain SDK 内部实现) 抛出异常,无降级
ES 连接 retry_on_timeout=True, max_retries=3 抛出 ConnectionError
知识检索 单库失败不影响其他库 continue 跳过

源码引用:

# embedding_model.py:138-143QWen 显式重试)
retry_max = 5
resp = dashscope.TextEmbedding.call(...)
while (resp["output"] is None ...) and retry_max > 0:
    time.sleep(10)
    resp = dashscope.TextEmbedding.call(...)
    retry_max -= 1

# models/base.py:34-36统一层重试配置
timeout: float = Field(default_factory=lambda: float(os.getenv("LLM_TIMEOUT", "120.0")))
max_retries: int = Field(default_factory=lambda: int(os.getenv("LLM_MAX_RETRIES", "2")))

⚠️ 关键缺口:无备用模型降级机制。 当主 Embedding 模型服务不可用时,系统会直接失败,不会自动切换备用模型。

3.3 缓存策略

现状分析:

  • GraphRAG 实体/关系缓存Redis 缓存TTL 24 小时key 为 xxhash(model_name + text)
  • ES 向量入库/检索无缓存,每次调用都实时请求 Embedding API
  • 无全局 Embedding 缓存层

源码引用:

# graphrag/utils.py:115-134
redis_client = redis.StrictRedis(**redis_conn_params)

def get_embed_cache(llmnm, txt):
    hasher = xxhash.xxh64()
    hasher.update(str(llmnm).encode("utf-8"))
    hasher.update(str(txt).encode("utf-8"))
    k = hasher.hexdigest()
    bin = redis_client.get(k)
    if not bin:
        return
    return np.array(json.loads(bin))

def set_embed_cache(llmnm, txt, arr):
    # ... 设置 RedisTTL = 24 * 3600

影响评估:

  • 重复文本(如相同实体名)在 GraphRAG 中可命中缓存,节省 API 调用
  • 常规知识库检索/入库中,相同 Chunk 或 Query 重复向量化,造成冗余 API 开销

3.4 维度变更对历史向量的兼容

现状分析:

  • 无自动兼容机制:更换 Embedding 模型后,历史 Chunk 的向量维度不变,新 Chunk 使用新维度
  • ES Mapping 冲突create_collection() 在创建索引时根据第一条向量的长度设置 dense_vector.dims,若后续向量维度不同会写入失败
  • 混合维度风险:同一索引中既有 1536 维又有 768 维的向量ES dense_vector 字段要求固定维度

源码引用:

# elasticsearch_vector.py:653-658
Field.VECTOR.value: {
    "type": "dense_vector",
    "dims": len(embeddings[0]),  # 根据第一条向量动态决定
    "index": True,
    "similarity": "cosine"
}

推荐操作(如何安全替换 Embedding 模型):

  1. 创建新知识库:为新知识库配置新的 Embedding 模型,避免影响已有数据
  2. 重建索引(谨慎):如需迁移历史数据,需:
    • 删除旧 ES 索引(Vector_index_{knowledge_id}_Node
    • 重新解析所有文档(触发新的 Embedding 调用)
    • 确认所有 Chunk 使用同一模型生成向量
  3. 版本标记:建议在知识库 metadata 中记录当前使用的 Embedding 模型版本,便于追踪

影响面分析:

操作 影响范围 风险等级
修改知识库 embedding_id 仅新入库 Chunk
修改已有知识库 embedding_id + 不重建索引 检索时 Query 向量与 Chunk 向量维度不匹配
重建索引 全量重新 EmbeddingAPI 费用 + 时间成本

4. 配置项汇总

4.1 环境变量

变量名 默认值 说明 影响范围
LLM_TIMEOUT 120.0 Embedding HTTP 请求超时(秒) RedBearEmbeddings 统一层
LLM_MAX_RETRIES 2 Embedding 请求最大重试次数 RedBearEmbeddings 统一层
MAX_CONCURRENT_CHATS 10 GraphRAG Embedding 并发限流 graphrag/utils.py
ELASTICSEARCH_HOST 127.0.0.1 ES 主机地址 ES 向量存储
ELASTICSEARCH_PORT 9200 ES 端口 ES 向量存储
ELASTICSEARCH_REQUEST_TIMEOUT 100000 ES 请求超时 ES 连接
ELASTICSEARCH_MAX_RETRIES 10 ES 连接重试 ES 连接
EMBEDDING_BATCH_SIZE (注释掉,未使用) 预留环境变量

4.2 数据库配置model_configs / model_api_keys 表)

字段 类型 说明 推荐值
provider String 提供商标识 openai / dashscope / volcano / xinference
model_name String 模型实际名称 text-embedding-3-small / text-embedding-v3
api_key String API 密钥
api_base String 基础 URL https://api.openai.com/v1
timeout Float 请求超时 120.0(复杂文档可适当延长)
max_retries Int 最大重试 2生产环境建议 3-5
capability Array 模型能力列表 []Embedding 模型通常无需特殊能力)

4.3 调用入参(运行时)

参数 位置 默认值 说明
top_k search_by_vector() 1024 向量检索返回数量
score_threshold search_by_vector() 0.3 相似度阈值(归一化后 [0,1]
similarity_threshold knowledge_retrieval() 0.2 全文检索阈值
vector_similarity_weight knowledge_retrieval() 0.3 混合检索中向量权重

5. 关键源码片段

5.1 Embedding 模型基类与统一接口

# api/app/core/rag/llm/embedding_model.py:14-38
class Base(ABC):
    def __init__(self, key, model_name, **kwargs):
        pass

    def encode(self, texts: list):
        raise NotImplementedError("Please implement encode method!")

    def encode_queries(self, text: str):
        raise NotImplementedError("Please implement encode method!")

5.2 OpenAI 兼容 Embedding 实现(批量处理)

# api/app/core/rag/llm/embedding_model.py:50-65
class OpenAIEmbed(Base):
    def encode(self, texts: list):
        batch_size = 16
        texts = [truncate(t, 8000) for t in texts]  # 安全截断
        ress = []
        total_tokens = 0
        for i in range(0, len(texts), batch_size):
            res = self.client.embeddings.create(
                input=texts[i : i + batch_size],
                model=self.model_name,
                encoding_format="float",
                extra_body={"drop_params": True}
            )
            ress.extend([d.embedding for d in res.data])
            total_tokens += self.total_token_count(res)
        return np.array(ress), total_tokens

5.3 统一封装层RedBearEmbeddings

# api/app/core/models/embedding.py:9-23
class RedBearEmbeddings(Embeddings):
    def __init__(self, config: RedBearModelConfig):
        self._config = config
        self._is_volcano = config.provider.lower() == ModelProvider.VOLCANO
        if self._is_volcano:
            self._client = self._create_volcano_client(config)
            self._model = None
        else:
            self._model = self._create_model(config)
            self._client = None

# api/app/core/models/embedding.py:65-78
    def embed_documents(self, texts: list[str]) -> list[list[float]]:
        if self._is_volcano:
            contents = [{"type": "text", "text": text} for text in texts]
            response = self._client.multimodal_embeddings.create(
                model=self._config.model_name,
                input=contents,
                encoding_format="float"
            )
            return [response.data.embedding]
        else:
            return self._model.embed_documents(texts)

5.4 ES 向量写入与 Mapping 创建

# api/app/core/rag/vdb/elasticsearch/elasticsearch_vector.py:55-63
    def add_chunks(self, chunks: list[DocumentChunk], **kwargs):
        texts = [chunk.page_content for chunk in chunks]
        if self.is_multimodal_embedding:
            embeddings = self.embeddings.embed_batch(texts)
        else:
            embeddings = self.embeddings.embed_documents(list(texts))
        self.create(chunks, embeddings, **kwargs)

# api/app/core/rag/vdb/elasticsearch/elasticsearch_vector.py:653-658
                        Field.VECTOR.value: {
                            "type": "dense_vector",
                            "dims": len(embeddings[0]),
                            "index": True,
                            "similarity": "cosine"
                        }

5.5 检索端向量生成

# api/app/core/rag/vdb/elasticsearch/elasticsearch_vector.py:374-380
    def search_by_vector(self, query: str, **kwargs: Any) -> list[DocumentChunk]:
        if self.is_multimodal_embedding:
            query_vector = self.embeddings.embed_text(query)
        else:
            query_vector = self.embeddings.embed_query(query)
        # cosineSimilarity(params.query_vector, 'vector') + 1.0

5.6 GraphRAG 中的 Embedding 缓存

# api/app/core/rag/graphrag/utils.py:115-134
redis_client = redis.StrictRedis(**redis_conn_params)

def get_embed_cache(llmnm, txt):
    hasher = xxhash.xxh64()
    hasher.update(str(llmnm).encode("utf-8"))
    hasher.update(str(txt).encode("utf-8"))
    k = hasher.hexdigest()
    bin = redis_client.get(k)
    if not bin:
        return
    return np.array(json.loads(bin))

def set_embed_cache(llmnm, txt, arr):
    # ... TTL = 24 * 3600

5.7 模型配置基类

# api/app/core/models/base.py:22-38
class RedBearModelConfig(BaseModel):
    model_name: str
    provider: str
    api_key: str
    base_url: Optional[str] = None
    timeout: float = Field(default_factory=lambda: float(os.getenv("LLM_TIMEOUT", "120.0")))
    max_retries: int = Field(default_factory=lambda: int(os.getenv("LLM_MAX_RETRIES", "2")))
    concurrency: int = 5
    extra_params: Dict[str, Any] = {}

6. 如何替换 Embedding 模型(操作步骤 + 影响面分析)

6.1 操作步骤

场景 A为新知识库配置新模型推荐零风险

  1. 进入管理后台 → 模型管理 → 添加新 Embedding 模型配置
  2. 填写 provider、model_name、api_key、base_url
  3. 验证模型可用性model_service.py 会调用 embed_documents 测试)
  4. 创建新知识库时选择该模型作为 embedding_id
  5. 新入库文档自动使用新模型生成向量

场景 B替换已有知识库的 Embedding 模型(高风险,需重建索引)

  1. 备份数据:导出知识库下所有文档元数据
  2. 删除旧 ES 索引
    # 索引名格式: Vector_index_{knowledge_id}_Node
    vector_service.delete()  # elasticsearch_vector.py:176
    
  3. 更新知识库配置:修改 knowledge.embedding_id 为新模型 ID
  4. 重新解析所有文档:触发完整的 Chunk → Embedding → ES 写入流程
  5. 验证维度一致性:确认所有 Chunk 向量维度相同
  6. 检索验证:执行测试查询,确认向量检索正常返回

6.2 影响面分析

组件 影响 说明
ES 索引 必须重建 dense_vector.dims 在创建时固定,不支持动态变更
历史 Chunk 需重新嵌入 旧向量与新向量维度/语义空间不同,不能混用
检索质量 可能变化 不同模型的语义表示能力不同,需重新调参阈值
API 成本 短期增加 重建索引期间产生全量 Embedding API 调用费用
GraphRAG 需同步更新 实体/关系向量也需使用同一模型,否则语义空间不一致
混合检索 需重新校准 向量相似度权重 vector_similarity_weight 可能需要调整

7. 边界条件与已知限制

  1. 维度上限ES dense_vector 字段 index: True 时维度上限 1024index: False 时上限 2048。当前代码 index: True,若使用 1536 维模型(如 OpenAI text-embedding-ada-002会触发此限制
  2. batch_size 硬编码:各模型的 batch_size16 或 4在源码中写死不可配置
  3. 无 Embedding 调用计费统计:系统未记录 Embedding API 的调用次数和 Token 消耗(仅 LLM 有统计)
  4. 无 Embedding 降级:主模型失败时无自动切换到备用模型的机制
  5. QWen 截断差异QWen 截断到 2048 tokens而其他 OpenAI 兼容类截断到 8000混合使用时需特别注意
  6. 文本截断使用 cl100k_basetoken_utils.py 使用 cl100k_base 编码器,可能与实际模型使用的 tokenizer 不一致(如 QWen 使用自己的 tokenizer导致截断长度不准

8. 监控指标与排错指引

8.1 建议监控指标

指标 采集方式 告警阈值建议
Embedding API 响应时间 LangChain callback 或中间件拦截 P99 > 5s
Embedding API 错误率 异常捕获统计 > 1%
Embedding Token 消耗 API 响应中的 usage.total_tokens 按预算设置
ES 向量写入延迟 ES bulk API 响应时间 > 2s
Redis 缓存命中率 get_embed_cache 命中统计 < 50% 时排查

8.2 常见故障排查

现象 根因 排查路径
向量检索返回空 维度不匹配 / 相似度阈值过高 检查 dense_vector.dims 与 Embedding 输出维度是否一致;降低 score_threshold
Embedding 调用超时 API 服务商响应慢 / 文本过长 检查 LLM_TIMEOUT;检查文本是否被正确截断
批量 Embedding 失败 batch_size 过大 减小 batch_size需改源码
GraphRAG 实体向量不一致 缓存命中但模型已更换 清除 Redis 中 get_embed_cache 相关 key
ES 写入报错 "illegal_argument_exception" dense_vector 维度超限 确认 index: True 时 dims <= 1024

9. 优化建议与未来扩展点

9.1 短期优化(代码级)

  1. 全局 Embedding 缓存层:将 get_embed_cache / set_embed_cache 机制扩展到 ES 向量入库/检索链路,减少重复 API 调用
  2. 可配置 batch_size:将硬编码的 16/4 提取为环境变量或数据库配置项
  3. 备用模型降级:实现 Embedding 模型的主备切换逻辑(类似 LLM 的 fallback 机制)
  4. 维度一致性校验:在 add_chunks()search_by_vector() 中增加维度校验,提前发现不匹配问题

9.2 中期优化(架构级)

  1. Embedding 服务化:将 Embedding 调用抽离为独立微服务,支持:
    • 统一缓存Redis + 本地 LRU
    • 请求队列 + 速率限制
    • 多模型负载均衡
  2. 异步 Embedding 流水线:文档入库时先写入队列,后台异步完成 Embedding 和 ES 写入
  3. Embedding 质量监控:定期抽样检测向量空间的分布质量(如余弦相似度分布、异常值检测)

9.3 长期扩展(功能级)

  1. 多模态 Embedding 全链路支持:当前仅火山引擎支持多模态,未来可扩展到更多 provider
  2. 自适应维度选择:根据知识库数据量和精度需求,自动推荐最优 Embedding 维度
  3. Embedding 微调:支持基于领域数据的 Embedding 模型微调(如 fine-tune BGE
  4. 跨模型向量映射:研究不同 Embedding 模型之间的向量映射技术,实现平滑迁移而不重建索引

文档基于 MemoryBear 仓库 commit 最新状态梳理。关键源码路径均已标注行号,可在 ±3 行范围内验证。