# LangChain 其他 Embedding 模型实践:Hugging Face、本地模型、云厂商与生产选型

在 RAG 系统里,Embedding 模型决定的是“知识能不能被召回来”的上限。

很多人一开始会直接使用 OpenAI Embedding,因为接入简单、效果稳定。但生产里经常会遇到这些约束:

  • 数据不能出内网。
  • 中文、代码、医疗、法律、金融等领域语义需要专项优化。
  • 单量太大,外部 API 成本不可控。
  • 企业已经有云厂商资源池。
  • 需要离线批处理,吞吐比单次延迟更重要。
  • 向量库已经固定维度,不能随意切模型。

这时就需要评估其他 Embedding 模型。LangChain 的价值不在于替你决定用哪个模型,而在于提供统一的 Embeddings 接口,让不同 provider 的模型都能接到同一条 RAG 链路里。

# 先抓住统一接口

无论底层是 OpenAI、Hugging Face、Ollama、Cohere、百度千帆,还是自研 Embedding 服务,接入 LangChain 后核心接口都类似:

query_vector = embeddings.embed_query("用户问题")
document_vectors = embeddings.embed_documents(
    [
        "文档片段 1",
        "文档片段 2",
    ]
)
1
2
3
4
5
6
7

这两个方法的语义不同:

  • embed_query():把用户查询转成向量,通常用于检索时的 query vector。
  • embed_documents():把文档 chunk 批量转成向量,通常用于入库。

有些模型会对 query 和 document 使用不同的 prompt、instruction 或 encode 参数。即使大多数 provider 在实现上差异不明显,生产设计时也要把这两个入口分开看。

# 当前 LangChain 的包结构

现在 LangChain 更推荐按 provider 安装独立包,而不是把所有模型都从一个大包里导入。

常见路径如下:

类型 安装包 常见导入
OpenAI langchain-openai from langchain_openai import OpenAIEmbeddings
Azure OpenAI langchain-openai from langchain_openai import AzureOpenAIEmbeddings
Hugging Face 本地 langchain-huggingface from langchain_huggingface import HuggingFaceEmbeddings
Hugging Face Endpoint langchain-huggingface from langchain_huggingface import HuggingFaceEndpointEmbeddings
Ollama langchain-ollama from langchain_ollama import OllamaEmbeddings
Cohere langchain-cohere from langchain_cohere import CohereEmbeddings
Mistral AI langchain-mistralai from langchain_mistralai import MistralAIEmbeddings
Google Gemini langchain-google-genai from langchain_google_genai import GoogleGenerativeAIEmbeddings
AWS Bedrock langchain-aws from langchain_aws import BedrockEmbeddings
百度千帆 langchain-community from langchain_community.embeddings.baidu_qianfan_endpoint import QianfanEmbeddingsEndpoint

这张表的重点不是背包名,而是理解当前生态的方向:核心接口统一,provider 实现拆包。这样可以减少依赖体积,也能让各家模型集成独立迭代。

# Hugging Face 本地 Embedding

如果数据不能出内网,或者希望把 Embedding 成本控制在自有机器上,本地 Hugging Face 模型是常见选择。

安装:

pip install -U langchain-huggingface sentence-transformers
1

基础使用:

from langchain_huggingface import HuggingFaceEmbeddings


embeddings = HuggingFaceEmbeddings(
    model_name="sentence-transformers/all-mpnet-base-v2",
    encode_kwargs={"normalize_embeddings": True},
)

query_vector = embeddings.embed_query("Embedding 模型应该怎么选?")
document_vectors = embeddings.embed_documents(
    [
        "本地模型适合数据敏感场景。",
        "云端模型适合快速接入和弹性扩容。",
    ]
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

本地模型第一次加载会下载模型权重,后续会从本地缓存读取。生产环境不要让服务启动时临时下载模型,应该在镜像构建、模型仓库同步或部署发布阶段提前准备好。

可以指定缓存目录:

embeddings = HuggingFaceEmbeddings(
    model_name="BAAI/bge-large-zh-v1.5",
    cache_folder="/data/models/huggingface",
    encode_kwargs={"normalize_embeddings": True},
)
1
2
3
4
5

中文知识库可以优先评估 BGE、GTE、E5、Jina 等系列模型。代码检索、医学检索、法律检索则要额外找领域模型或做领域评估,不能只看通用榜单。

# Hugging Face Endpoint

如果不想在本地维护模型和推理环境,可以使用 Hugging Face 的远程推理服务。

安装:

pip install -U langchain-huggingface huggingface_hub
1

配置环境变量:

export HUGGINGFACEHUB_API_TOKEN="your-token"
1

使用:

from langchain_huggingface import HuggingFaceEndpointEmbeddings


embeddings = HuggingFaceEndpointEmbeddings(
    model="sentence-transformers/all-MiniLM-L12-v2",
)

query_vector = embeddings.embed_query("远程 Embedding 服务适合什么场景?")
1
2
3
4
5
6
7
8

远程 endpoint 的优势是接入快、无需维护 GPU;代价是网络延迟、服务稳定性、费用和数据出境问题。它适合原型验证、低频任务、临时评估,不一定适合所有生产知识库。

# Ollama 本地 Embedding

如果你已经用 Ollama 管理本地模型,也可以用 LangChain 接入:

pip install -U langchain-ollama
1
from langchain_ollama import OllamaEmbeddings


embeddings = OllamaEmbeddings(model="nomic-embed-text")

query_vector = embeddings.embed_query("Ollama 本地 Embedding 怎么接入?")
1
2
3
4
5
6

Ollama 的好处是本地开发体验顺滑,适合桌面开发、PoC、内部小工具。生产里要关注模型服务的并发、冷启动、资源隔离、监控和版本固定。

# 云厂商 Embedding

如果企业已经使用某个云平台,云厂商 Embedding 往往是更容易落地的选择。

例如 Azure OpenAI:

import os

from langchain_openai import AzureOpenAIEmbeddings


embeddings = AzureOpenAIEmbeddings(
    azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
    azure_deployment=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"],
    openai_api_version=os.environ["AZURE_OPENAI_API_VERSION"],
)
1
2
3
4
5
6
7
8
9
10

例如 AWS Bedrock:

from langchain_aws import BedrockEmbeddings


embeddings = BedrockEmbeddings(
    model_id="amazon.titan-embed-text-v2:0",
)
1
2
3
4
5
6

例如 Google Gemini:

from langchain_google_genai import GoogleGenerativeAIEmbeddings


embeddings = GoogleGenerativeAIEmbeddings(
    model="models/gemini-embedding-001",
)
1
2
3
4
5
6

云厂商方案的优势是稳定、合规能力较好、权限和审计体系成熟。缺点是供应商绑定更强,不同区域、模型版本、限流策略会影响上线方案。

# 百度千帆 Embedding

国内业务如果已经在百度智能云体系内,可以评估千帆 Embedding。

当前在 LangChain API 参考里,QianfanEmbeddingsEndpoint 仍位于 langchain_community:

pip install -U langchain-community qianfan
1
from langchain_community.embeddings.baidu_qianfan_endpoint import (
    QianfanEmbeddingsEndpoint,
)


embeddings = QianfanEmbeddingsEndpoint(
    model="bge-large-zh",
)

query_vector = embeddings.embed_query("中文知识库应该如何选择 Embedding?")
1
2
3
4
5
6
7
8
9
10

千帆这类国内 provider 的价值通常不只是模型本身,还包括网络访问、数据合规、账单体系、企业合同和国内云资源协同。选型时要把这些因素纳入评估,而不是只比较一个 Recall@K。

# OpenAI 兼容接口

有些自研网关或第三方模型服务会提供 OpenAI 兼容接口。理论上可以直接使用供应商 SDK,也可以自己实现 LangChain 的 Embeddings 接口。

当 provider 没有官方 LangChain 包,最稳的方式是自定义一个适配器:

from langchain_core.embeddings import Embeddings


class CompanyEmbeddings(Embeddings):
    def __init__(self, client, model: str):
        self.client = client
        self.model = model

    def embed_documents(self, texts: list[str]) -> list[list[float]]:
        response = self.client.embed(
            model=self.model,
            input=texts,
        )
        return [item.embedding for item in response.data]

    def embed_query(self, text: str) -> list[float]:
        return self.embed_documents([text])[0]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

这样上层 RAG 链路不需要知道底层 provider 细节,只依赖 Embeddings 接口。

# 生产选型维度

Embedding 选型不要只看“哪个模型分数高”。生产里至少看八个维度:

维度 要问的问题
语言 中文、英文、多语言、混合中英是否稳定
领域 是否适合业务术语、代码、表格、法律、医疗等内容
维度 向量维度是否影响存储成本和向量库索引
上下文长度 单个 chunk 最大输入长度是多少
吞吐 批量入库时每秒能处理多少文本
延迟 在线 query embedding 延迟是否可接受
成本 API 调用费、GPU 成本、存储成本是否可控
合规 数据是否允许出域,是否有审计和脱敏要求

如果只根据 demo 效果选模型,很容易在上线后被成本、限流、维度迁移、权限合规卡住。

# 和向量库的耦合

Embedding 模型一旦选定,就会和向量库形成强耦合。

原因很简单:向量库索引是按向量维度和向量分布建立的。换模型通常意味着:

  • 向量维度可能变化。
  • 相似度分布变化。
  • 召回阈值要重新调。
  • 已有索引需要重建。
  • 评估集需要重新跑。
  • 缓存 namespace 需要更新。

所以生产里不要把 Embedding 模型切换做成一个随手改配置的动作。它更像一次索引版本升级。

# 建议的工程封装

可以把不同 provider 封装成统一工厂:

from dataclasses import dataclass

from langchain_community.embeddings.baidu_qianfan_endpoint import (
    QianfanEmbeddingsEndpoint,
)
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_ollama import OllamaEmbeddings
from langchain_openai import OpenAIEmbeddings


@dataclass(frozen=True)
class EmbeddingSettings:
    provider: str
    model: str
    normalize: bool = True


def build_embeddings(settings: EmbeddingSettings):
    if settings.provider == "openai":
        return OpenAIEmbeddings(model=settings.model)

    if settings.provider == "huggingface":
        return HuggingFaceEmbeddings(
            model_name=settings.model,
            encode_kwargs={"normalize_embeddings": settings.normalize},
        )

    if settings.provider == "ollama":
        return OllamaEmbeddings(model=settings.model)

    if settings.provider == "qianfan":
        return QianfanEmbeddingsEndpoint(model=settings.model)

    raise ValueError(f"Unsupported embedding provider: {settings.provider}")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

再把它和缓存、向量库、索引版本组合:

settings = EmbeddingSettings(
    provider="huggingface",
    model="BAAI/bge-large-zh-v1.5",
)

embeddings = build_embeddings(settings)
1
2
3
4
5
6

这样后续从 OpenAI 切到 Hugging Face,或者从本地模型切到云厂商,业务链路不需要大改。

# 评估方式

Embedding 模型必须用自己的数据评估。

建议准备一批 golden queries,每条 query 至少包含:

  • 用户问题。
  • 期望命中的文档 ID。
  • 期望命中的 chunk。
  • 必须命中的关键事实。
  • 不应该命中的干扰文档。
  • 权限和租户边界。

评估指标可以从这些开始:

  • Recall@K:正确 chunk 是否出现在前 K 个结果中。
  • MRR:第一个正确结果排得有多靠前。
  • nDCG:多个相关结果的排序质量。
  • 在线延迟:query embedding + vector search 的总耗时。
  • 成本:每万条文档入库和每万次查询的成本。
  • 稳定性:限流、超时、重试、批处理失败率。

不要只看模型排行榜。排行榜不能替你覆盖业务文档质量、chunk 策略、metadata filter 和用户真实问法。

# 问题

其他 Embedding 模型接入时,最容易踩这些坑。

第一,导入路径过时。很多旧示例还在使用 langchain_community.embeddings,新项目应优先查看 provider 独立包。

第二,只比较 demo 查询,不做固定评估集。Embedding 的好坏必须放到自己的知识库里测。

第三,忽略向量维度。模型一换,向量库 schema、索引、缓存和历史数据都可能要重建。

第四,忽略 normalize。部分模型需要归一化向量才能更稳定地使用 cosine similarity。

第五,混用 query 和 document 策略。有些模型对查询和文档有不同 instruction,统一当成普通文本可能损失效果。

第六,生产服务启动时才下载本地模型。模型下载失败会直接影响发布。

# 拓展

Embedding 选型可以继续往三个方向扩展。

第一,混合召回。Dense Embedding 适合语义相似,BM25 适合关键词精确匹配,生产里经常用 dense + sparse + rerank。

第二,领域微调。如果通用模型对业务术语理解不好,可以考虑对比掌握、hard negative mining 或使用领域模型。

第三,模型路由。不同知识库、不同语言、不同业务线可以使用不同 Embedding 模型,但必须用统一索引版本和评估体系治理。

# 实际生产是否使用

会,而且经常会使用多种 Embedding。

比如内部知识库可能用本地 Hugging Face 模型,公开文档问答用 OpenAI 或云厂商模型,中文业务知识库用国内 provider,代码检索单独使用代码向量模型。

不过生产里很少让业务代码直接散落各种 provider 初始化。更常见的做法是统一封装 Embedding 工厂、配置中心、缓存层和评估任务。

# 现在是否抛弃

没有抛弃,但旧写法需要更新。

HuggingFaceEmbeddings 仍然可用,不过新项目应优先使用 langchain_huggingface 包。HuggingFaceEndpointEmbeddings 也在 langchain_huggingface 中。百度千帆这类集成仍可通过 langchain_community 使用。

真正被淘汰的不是“其他 Embedding 模型”,而是把模型接入当作几行示例代码的思路。当前生产关注的是 provider 独立包、统一接口、版本治理、缓存、评估和可观测性。

# 最新生产如何实现

当前更推荐这样做:

第一,使用 provider 独立包接入模型,例如 langchain-huggingface、langchain-ollama、langchain-openai、langchain-cohere。

第二,通过统一工厂返回 Embeddings 实例,业务链路只依赖 embed_query() 和 embed_documents()。

第三,把 provider、model、dimension、normalize、preprocess_version、chunk_version 写入索引版本。

第四,用固定评估集比较候选模型,不直接在生产索引上盲切。

第五,模型切换时新建索引版本,重新入库,灰度切流,再下线旧索引。

第六,配合 CacheBackedEmbeddings 或自研缓存层,降低重复入库成本。

一个生产级最小结构可以是:

class RAGEmbeddingRuntime:
    def __init__(self, settings, cache, metrics):
        self.settings = settings
        self.embeddings = build_embeddings(settings)
        self.cache = cache
        self.metrics = metrics

    def embed_query(self, query: str) -> list[float]:
        self.metrics.count("embedding.query", provider=self.settings.provider)
        return self.embeddings.embed_query(query)

    def embed_documents(self, texts: list[str]) -> list[list[float]]:
        self.metrics.count(
            "embedding.documents",
            provider=self.settings.provider,
            count=len(texts),
        )
        return self.embeddings.embed_documents(texts)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

这层封装看起来简单,但它让后续的缓存、限流、重试、指标、trace、模型切换和索引版本治理都有地方落。

# 总结

选择其他 Embedding 模型,本质是在效果、成本、合规、延迟、吞吐和运维复杂度之间做工程取舍。

LangChain 提供的是统一接口和 provider 集成,不是自动选型答案。真正的生产能力来自三件事:把模型接入封装成稳定接口,把模型版本纳入索引治理,把模型效果放进固定评估集里持续验证。

参考: