# Weaviate 向量数据库实践:开源检索引擎与 LangChain 生产封装

Weaviate 是一个开源向量数据库,适合做语义搜索、RAG 知识库、多模态检索、推荐召回和带 metadata 过滤的检索服务。

它和 FAISS、Pinecone、TCVectorDB 的定位不太一样。FAISS 更像本地检索内核,Pinecone 和 TCVectorDB 更偏托管服务,Weaviate 则在“可自建、可上云、功能完整、生态开放”之间取得了平衡。团队既可以用 Weaviate Cloud 快速上线,也可以用 Docker、Kubernetes 在自己的环境里部署。

但 Weaviate 不是只跑一个容器就能生产可用。真正要设计的是:collection schema、向量化策略、gRPC 端口、metadata 过滤、多租户、批量写入、索引版本、备份恢复、LangChain 和原生 client 的边界。

# Weaviate 的核心层级

Weaviate v4 Python client 以 collection 为核心入口。可以把它理解成传统数据库里的表,但它同时绑定了属性字段、向量配置、倒排索引、向量索引和多租户配置。

概念 作用 生产理解
Cluster Weaviate 服务集群 部署、网络、认证、资源和高可用边界
Collection 数据集合 同一 schema、同一向量配置和索引策略的数据容器
Object 数据对象 一条业务记录,包含 properties、uuid、vector
Property 属性字段 正文、来源、租户、状态、页码等 metadata
Vector index 向量索引 决定相似度检索速度、召回和资源消耗
Inverted index 倒排索引 支撑关键词、过滤和混合检索

生产设计里,collection 是最关键的边界。不同 Embedding 维度、不同业务 schema、不同强隔离要求的数据,不应该随便混到一个 collection 里。

# 部署方式怎么选

Weaviate 常见部署方式有四种。

部署方式 适用场景 注意点
Weaviate Cloud 快速上线、少运维、海外云环境 关注地域、账单、数据合规和 API key 管理
Docker 本地开发、功能验证、小型内网服务 必须挂载 volume,否则数据随容器删除丢失
Kubernetes 生产自建、私有化、多副本 需要补监控、备份、滚动升级和容量规划
Embedded 本地实验和测试 平台支持有限,不适合作为通用生产方案

本地开发最小启动:

docker run -d --name weaviate-dev \
  -p 8080:8080 \
  -p 50051:50051 \
  cr.weaviate.io/semitechnologies/weaviate:latest
1
2
3
4

注意两个端口:

  • 8080 是 HTTP/REST 访问端口。
  • 50051 是 gRPC 端口,Weaviate Python v4 client 和 LangChain 当前集成会用到它。

如果线上用 Docker 或 Kubernetes,一定要配置持久化卷、认证、网络访问控制和备份。没有持久化卷的容器只适合本地试验。

# 安装与当前包路径

新项目建议使用 Weaviate Python v4 client 和独立 LangChain 集成包:

pip install -U weaviate-client langchain-weaviate langchain-openai
1

当前 LangChain 官方文档使用:

from langchain_weaviate import WeaviateVectorStore
1

不要把旧路径作为新项目主路径:

from langchain.vectorstores import Weaviate
1

旧路径属于早期写法。当前更清晰的方式是 langchain-weaviate 加 weaviate-client v4。

# 连接 Weaviate

连接本地服务:

import weaviate


client = weaviate.connect_to_local(
    host="localhost",
    port=8080,
    grpc_port=50051,
)
1
2
3
4
5
6
7
8

连接 Weaviate Cloud:

import os

import weaviate
from weaviate.auth import AuthApiKey


client = weaviate.connect_to_weaviate_cloud(
    cluster_url=os.environ["WEAVIATE_URL"],
    auth_credentials=AuthApiKey(os.environ["WEAVIATE_API_KEY"]),
    headers={
        "X-OpenAI-Api-Key": os.environ["OPENAI_API_KEY"],
    },
)
1
2
3
4
5
6
7
8
9
10
11
12
13

如果使用外部 Embedding,headers 里不一定需要传模型供应商密钥,因为向量化发生在业务侧。只有使用 Weaviate 内置 vectorizer 或 generative module 时,才需要把相应供应商密钥传给 Weaviate。

服务关闭时要释放连接:

client.close()
1

# 创建 Collection

Weaviate Python client v4.16.0 之后,向量配置 API 有过更新。新项目应使用 vector_config,自带向量模式使用 Configure.Vectors.self_provided()。

from weaviate.classes.config import Configure, DataType, Property, VectorDistances


if not client.collections.exists("HelpCenter"):
    client.collections.create(
        name="HelpCenter",
        vector_config=Configure.Vectors.self_provided(
            vector_index_config=Configure.VectorIndex.hnsw(
                distance_metric=VectorDistances.COSINE,
            )
        ),
        properties=[
            Property(name="text", data_type=DataType.TEXT),
            Property(name="tenant_id", data_type=DataType.TEXT),
            Property(name="knowledge_base_id", data_type=DataType.TEXT),
            Property(name="document_id", data_type=DataType.TEXT),
            Property(name="status", data_type=DataType.TEXT),
            Property(name="page", data_type=DataType.INT),
            Property(name="source", data_type=DataType.TEXT),
        ],
    )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

生产里不建议在 Web 服务启动时自动创建 collection。更稳的是把 schema 创建放到基础设施脚本或发布流程中,并把 collection schema 版本写入 manifest。

# 外部 Embedding 还是内置 Vectorizer

Weaviate 支持两类模式。

模式 做法 适合场景
外部 Embedding 业务侧生成向量,写入 Weaviate 模型版本可控、跨库迁移、统一缓存和评估
内置 Vectorizer Weaviate 根据配置调用模型模块 快速接入、希望简化入库链路

生产 RAG 更常见的是外部 Embedding。这样可以把文档切分、Embedding 缓存、限流、重试、模型版本、向量维度和评估集放在自己的数据流水线里管理。

使用内置 vectorizer 时,要确认服务端模块、供应商密钥、模型维度、地域、限流和账单。不要只看能不能写入成功,还要看后续是否能迁移、回放和离线评估。

# 接入 LangChain

用 langchain-weaviate 连接已有 collection:

import weaviate
from langchain_openai import OpenAIEmbeddings
from langchain_weaviate import WeaviateVectorStore


client = weaviate.connect_to_local()

embeddings = OpenAIEmbeddings(model="text-embedding-3-small")

vector_store = WeaviateVectorStore(
    client=client,
    index_name="HelpCenter",
    text_key="text",
    embedding=embeddings,
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

写入文本:

texts = [
    "企业用户可以在控制台申请发票,审批通过后进入开票流程。",
    "退款申请需要提交订单号、付款凭证和问题描述。",
    "知识库索引更新后,需要通过评估集验证召回质量。",
]

metadatas = [
    {
        "tenant_id": "tenant-a",
        "knowledge_base_id": "kb-help-center",
        "document_id": "invoice-policy",
        "status": "published",
        "page": 1,
        "source": "invoice.md",
    },
    {
        "tenant_id": "tenant-a",
        "knowledge_base_id": "kb-help-center",
        "document_id": "refund-policy",
        "status": "published",
        "page": 2,
        "source": "refund.md",
    },
    {
        "tenant_id": "tenant-a",
        "knowledge_base_id": "kb-rag",
        "document_id": "rag-eval",
        "status": "draft",
        "page": 3,
        "source": "rag.md",
    },
]

ids = [
    "invoice-policy:v1:chunk-0001",
    "refund-policy:v1:chunk-0001",
    "rag-eval:v1:chunk-0001",
]

vector_store.add_texts(
    texts=texts,
    metadatas=metadatas,
    ids=ids,
)
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
35
36
37
38
39
40
41
42
43
44

生产里强烈建议显式传 ids。稳定 id 能让文档更新、删除、去重、重放和审计变得可控。

# 相似度搜索与分数

普通检索:

docs = vector_store.similarity_search(
    "发票怎么申请",
    k=5,
)
1
2
3
4

带分数:

results = vector_store.similarity_search_with_score(
    "发票怎么申请",
    k=5,
)

for doc, score in results:
    print(score, doc.page_content, doc.metadata)
1
2
3
4
5
6
7

不要把分数当成全局绝对阈值。Weaviate 的结果分数会受到检索模式、距离策略、Embedding 模型、是否混合检索、查询语种和数据分布影响。生产里要用固定评估集校准阈值,而不是凭一次试问决定。

# metadata 过滤

Weaviate Python v4 的过滤使用 Filter 对象。

from weaviate.classes.query import Filter


filters = (
    Filter.by_property("tenant_id").equal("tenant-a")
    & Filter.by_property("knowledge_base_id").equal("kb-help-center")
    & Filter.by_property("status").equal("published")
)

docs = vector_store.similarity_search(
    "发票怎么申请",
    k=5,
    filters=filters,
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

数值范围:

filters = Filter.by_property("page").greater_or_equal(1) & Filter.by_property("page").less_or_equal(10)

docs = vector_store.similarity_search(
    "售后流程",
    k=5,
    filters=filters,
)
1
2
3
4
5
6
7

多值条件:

filters = (
    Filter.by_property("tenant_id").equal("tenant-a")
    & Filter.by_property("knowledge_base_id").contains_any(["kb-help-center", "kb-product"])
    & Filter.by_property("status").equal("published")
)
1
2
3
4
5

权限过滤必须由服务端生成。前端可以传“想查哪个知识库”,但服务端要基于登录态和授权表重新计算可访问范围,不能把用户传来的 filter 原样交给 Weaviate。

# 混合检索

Weaviate 的强项之一是混合检索。它可以把关键词检索和向量检索结合起来,适合产品名、术语、编号、错误码、合同条款这类既需要字面命中又需要语义泛化的场景。

LangChain 的 similarity_search 可以把额外参数传给底层检索,例如调整 alpha:

docs = vector_store.similarity_search(
    "ERR_401 如何处理",
    k=5,
    alpha=0.5,
    filters=filters,
)
1
2
3
4
5
6

alpha 越接近 1,越偏向向量语义;越接近 0,越偏向关键词。生产里不要拍脑袋固定一个值,建议按评估集分别测试纯向量、纯关键词、混合检索和 reranker 后的效果。

# 原生 Collection 操作

LangChain 封装适合 RAG 检索,但 Weaviate 原生 client 能力更完整。可以通过 client 获取 collection:

from weaviate.classes.query import MetadataQuery


collection = client.collections.get("HelpCenter")

response = collection.query.near_text(
    query="invoice process",
    limit=5,
    return_metadata=MetadataQuery(distance=True),
)

for item in response.objects:
    print(item.properties)
    print(item.metadata.distance)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

如果 collection 使用 self_provided 向量而没有配置内置 vectorizer,就不要调用 near_text,而应该使用向量检索:

query_vector = embeddings.embed_query("invoice process")

response = collection.query.near_vector(
    near_vector=query_vector,
    limit=5,
    filters=filters,
    return_metadata=MetadataQuery(distance=True),
)
1
2
3
4
5
6
7
8

这点很重要。很多错误来自“collection 没有 vectorizer,却调用了 near_text”。外部 Embedding 模式下,查询侧也要自己生成 query vector。

# 多租户设计

Weaviate 支持多租户,同一个 collection schema 下可以隔离多个 tenant。

LangChain 接入时可以传 tenant:

tenant_store = WeaviateVectorStore.from_documents(
    documents,
    embeddings,
    client=client,
    index_name="HelpCenter",
    text_key="text",
    tenant="tenant-a",
)

docs = tenant_store.similarity_search(
    "发票怎么申请",
    tenant="tenant-a",
)
1
2
3
4
5
6
7
8
9
10
11
12
13

多租户不是越早越复杂越好。可以按数据规模和安全边界选择:

方案 适用场景
metadata 过滤 小规模租户、权限风险可控、查询需要跨知识库
Weaviate tenant SaaS 多用户隔离、同 schema 多租户
独立 collection 大客户、高敏数据、独立生命周期
独立集群 强合规、独立运维、资源隔离要求高

# 删除与更新

LangChain VectorStore 可以覆盖常见写入和检索,但批量删除、按条件删除、更新属性、备份恢复,建议使用原生 collection。

按 id 删除:

collection = client.collections.get("HelpCenter")
collection.data.delete_by_id("invoice-policy:v1:chunk-0001")
1
2

按条件删除要非常谨慎:

collection.data.delete_many(
    where=Filter.by_property("document_id").equal("invoice-policy")
)
1
2
3

生产里删除必须有审计:记录操作者、租户、知识库、删除条件、任务 id、影响数量和执行时间。重要知识库更新更推荐“新 collection 构建、评估、切流、旧 collection 下线”的版本化流程。

# 和 FAISS 的区别

维度 FAISS Weaviate
形态 本地向量检索库 独立向量数据库服务
部署 单机文件或进程内 Cloud、Docker、Kubernetes
metadata 过滤 主要靠封装层 原生过滤和倒排索引
混合检索 需要额外组合 BM25 原生支持关键词和向量结合
多租户 自己拆索引 支持 tenant 和 collection 设计
运维 自己维护文件和发布 需要服务运维或使用云托管

FAISS 适合轻量、本地、离线和小中规模。Weaviate 更像完整在线检索服务,适合多人、多租户、在线更新和混合检索。

# 和 Pinecone、TCVectorDB 的区别

维度 Weaviate Pinecone TCVectorDB
开源属性 开源,可自建 托管服务 腾讯云托管服务
部署选择 Cloud、Docker、Kubernetes 云端托管 腾讯云环境
LangChain 包 langchain-weaviate langchain-pinecone Community 集成
特色能力 混合检索、schema、模块生态 托管弹性、namespace 国内云、腾讯云生态
运维责任 自建时自己负责 平台负责 平台负责

如果团队想要开源可控、私有化部署、混合检索和较完整的数据模型,Weaviate 很值得考虑。如果希望少运维,托管产品会更省心。

# 生产封装建议

建议把 Weaviate 封装成工厂和服务层,不要让业务代码到处散落连接、collection 名称和 filter 拼接。

from dataclasses import dataclass

import weaviate
from langchain_weaviate import WeaviateVectorStore


@dataclass(frozen=True)
class WeaviateSettings:
    url: str
    api_key: str | None
    collection_name: str
    text_key: str
    embedding_model: str
    dimension: int
    distance_metric: str


def build_weaviate_store(settings: WeaviateSettings, embeddings):
    client = weaviate.connect_to_local()

    store = WeaviateVectorStore(
        client=client,
        index_name=settings.collection_name,
        text_key=settings.text_key,
        embedding=embeddings,
    )

    return client, store
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

同时保存 manifest:

{
    "collection_name": "HelpCenter",
    "text_key": "text",
    "embedding_model": "text-embedding-3-small",
    "dimension": 1536,
    "distance_metric": "cosine",
    "chunk_version": "chunk-v3",
    "schema_version": "schema-v2"
}
1
2
3
4
5
6
7
8
9

manifest 不是形式主义。线上召回变差时,你需要快速知道是哪次 schema、chunk、Embedding 或索引参数变化引入了问题。

# 上线前检查清单

  • Weaviate 服务是否开启并暴露 HTTP 和 gRPC 端口。
  • Cloud 或自建集群是否配置认证、网络访问控制和备份。
  • Collection schema 是否固定并版本化。
  • text_key 是否和 collection 的正文属性一致。
  • 外部 Embedding 的维度是否和 collection 向量配置一致。
  • 是否明确使用 near_vector 还是 near_text。
  • metadata 字段是否能支撑租户、知识库、状态、来源、页码过滤。
  • 多租户隔离使用 metadata、tenant、collection 还是独立集群。
  • 写入 id 是否稳定可重放。
  • 是否记录 query、filters、alpha、k、score、latency 和命中文档 id。
  • 是否有评估集验证 Recall@K、MRR、答案忠实度和延迟。

# 问题

Weaviate 常见问题集中在版本、向量化和 schema。

第一,旧代码路径过时。新项目应使用 langchain-weaviate,不要继续沿用早期 langchain.vectorstores.Weaviate。

第二,v3 client 和 v4 client API 混用。v4 是 collection-based API,过滤、创建 collection、查询方式都和旧写法不同。

第三,没有配置 vectorizer 却调用 near_text。外部 Embedding 模式下应先生成 query vector,再走 near_vector 或通过 LangChain embedding 封装检索。

第四,Docker 本地启动没有持久化卷。容器删除后数据会丢,不适合生产。

第五,metadata 字段设计随意。过滤字段、权限字段、状态字段、版本字段不稳定,会让检索治理变得很痛苦。

# 拓展

Weaviate 值得继续深入几个方向。

第一,混合检索。调优 vector、keyword、alpha 和 reranker,解决专业术语和语义泛化之间的冲突。

第二,多租户。比较 metadata 过滤、tenant、collection、cluster 四种隔离方式的成本和安全边界。

第三,多向量。给标题、正文、摘要、图片等字段配置不同向量,适合复杂文档和多模态检索。

第四,备份与迁移。把 collection schema、数据对象、向量版本和评估结果一起纳入发布流程。

# 实际生产是否使用

会使用。

Weaviate 在生产里适合企业知识库、智能客服、语义搜索、推荐召回、多模态检索和需要混合检索的 RAG 系统。它的优势是开源、可自建、schema 能力完整、过滤和混合检索能力强。

但生产里不会只跑一个默认容器。自建 Weaviate 要补齐持久化、认证、备份、监控、容量规划、滚动升级和故障恢复。使用 Cloud 则要重点关注地域、账单、密钥、网络和数据合规。

# 现在是否抛弃

没有抛弃。

Weaviate 仍然是主流向量数据库之一,LangChain 当前也有独立的 langchain-weaviate 集成。真正应该抛弃的是旧导入路径、v3 client 写法、无持久化 Docker 玩法,以及不区分 near_text 和 near_vector 的示例式接入。

当前更值得注意的是 Weaviate Python client v4.16.0 之后 collection 向量配置 API 的变化。新代码应按当前官方文档使用 vector_config 和 Configure.Vectors.self_provided() 等新接口。

# 最新生产如何实现

当前更推荐这样落地:

第一,使用 Weaviate Python v4 client,collection schema 由发布流程创建和审计。

第二,使用 langchain-weaviate 的 WeaviateVectorStore 接入 RAG 检索链路。

第三,外部 Embedding 由业务侧统一生成、缓存、限流和评估。

第四,正文存入稳定的 text_key,metadata 明确包含租户、知识库、文档、状态、来源和版本字段。

第五,权限过滤由服务端根据认证态生成 Filter,不接受客户端直接传入过滤对象。

第六,复杂数据治理走原生 collection API,LangChain 只负责在线检索和 retriever 抽象。

最小生产查询结构:

from weaviate.classes.query import Filter


def build_acl_filter(auth_context, knowledge_base_id: str):
    if knowledge_base_id not in auth_context.allowed_knowledge_base_ids:
        raise PermissionError("knowledge base not allowed")

    return (
        Filter.by_property("tenant_id").equal(auth_context.tenant_id)
        & Filter.by_property("knowledge_base_id").equal(knowledge_base_id)
        & Filter.by_property("status").equal("published")
    )


def search_knowledge(vector_store: WeaviateVectorStore, query: str, auth_context, knowledge_base_id: str):
    return vector_store.similarity_search_with_score(
        query,
        k=5,
        filters=build_acl_filter(auth_context, knowledge_base_id),
        alpha=0.75,
    )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

真实上线时,还要把 alpha、k、过滤条件、耗时、命中文档、score 和最终答案质量写入 trace,配合固定评估集持续回归。

# 总结

Weaviate 的优势是开源、可自建、可上云、schema 能力完整、混合检索强、LangChain 集成清晰。它适合从本地实验走向线上 RAG 服务,尤其适合需要私有化部署和混合检索的团队。

但 Weaviate 不会自动解决知识库工程问题。生产质量仍然取决于 schema 设计、Embedding 版本、稳定 id、权限过滤、索引版本、备份恢复、评估集和可观测闭环。

参考: