1. 从零认识 Chroma:为什么新手做向量检索首选它
先说结论:如果你刚开始接触向量数据库,想在本地快速跑通一套“文档问答”“图片相似度匹配”或者“RAG 检索增强”的原型,Chroma 是当下所有选项里上手成本最低、坑最少的一个。我前前后后试过 Milvus、Qdrant、pgvector,最后在不少个人项目和中小型内部工具里都固定用了 Chroma,原因就一句话:它把“能用”和“好用”之间的路铺平了。
很多人第一次听到“向量数据库”这个概念,会觉得很高大上。其实拆开看,它就是一个专门存“向量”的仓库。向量是什么?简单说就是一组浮点数,比如 [0.12, 0.85, 0.33, ...],用来表示一段文本、一张图片或者一段音频的“语义特征”。你可以把它理解成坐标——在某些高维空间里,语义相近的内容离得也近。向量数据库干的事就是:把海量向量存起来,然后给你提供“谁离我最近”的快速查询能力。
Chroma 在这个赛道里属于轻量级选手,特别适合下面几类人:
- 刚接触 RAG(检索增强生成)或者语义搜索的新手,需要一个能跑通流程的环境;
- 个人开发者和独立项目作者,不想折腾复杂集群,希望在本地快速验证 idea;
- 团队内部搭建知识库、客服问答、内容推荐等中小规模应用,数据量在几百万条以内;
- 教学、演示、Demo 场景,需要快速部署且方便讲解。
它的定位和 Milvus 有明显区别。Milvus 是重型武器,适合亿级向量、高并发生产环境,但部署起来要 ZooKeeper、MinIO、Pulsar 等组件配合,本地开发机直接吓退一半人。Qdrant 的 Rust 实现性能很好,也有 Docker 化方案,但配置理念更偏生产。pgvector 是在 PostgreSQL 里加扩展,适合已经有 PG 体系、不想引入新组件的团队,但查询语法和索引调优需要额外学习成本。
Chroma 的做法更“平易近人”:直接装在项目里,数据默认落在本地目录,Python API 清晰,几行代码就能完成入库和查询。它不仅能存向量,还能顺带存 metadata(元数据)和文档原文,这意味着你可以做到“检索到向量后,直接取出对应的文档内容”,不需要再做一次 id 映射回查。
从我实际的开发体验来说,Chroma 更像是一个“中间态”工具:前期做原型验证、快速试错,效果特别好;后期如果数据量涨上来了,再平滑迁移到 Milvus 或者把数据导到 pgvector 也方便,因为它的数据模型足够通用。用一句话总结——上手无脑,弃坑不难,进退都有空间。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心概念与原理:Collection、Embedding 与相似度检索
2.1 三个必须弄懂的抽象概念
我第一次用 Chroma 的时候,官方文档里蹦出来一堆名词:Collection、Embedding、Distance Function、Metadata。看文档每个词都认识,拼在一起就不知道从哪下手。等真正用熟了,我意识到只需要先抓住三个最核心的概念,其余都是围绕它们转。
Collection(集合):可以理解为传统数据库里的“表”。你往里面装的数据,都归属于某个 Collection。每个 Collection 有自己的名字、距离计算方式(比如余弦距离、欧氏距离)和向量维度配置。你可以在一个项目里建多个 Collection,比如一个存用户偏好,一个存商品描述,彼此互不干扰。
Document(文档):一条原始内容,可以是文本、标题、段落,甚至一串 JSON 字符串。Chroma 支持把原始文档直接存进去,后面查询到相关结果时能直接拿出来用。这对于 RAG 场景很关键,因为你需要把检索到的内容拼进大模型的 prompt 里。
Vector(向量):文档被 Embedding 模型转换后得到的浮点数数组。向量维度取决于你用的模型(比如 OpenAI 的 text-embedding-3-small 是 1536 维,本地常用的 all-MiniLM-L6-v2 是 384 维)。Collection 要求同一个集合内所有向量维度一致,这好理解——你不能让一个 768 维的向量去和 384 维的向量计算相似度。
Metadata(元数据):附加到每一条记录上的结构化信息,可以是标题、作者、日期、分类、价格等任何字段。它是后面的过滤查询利器,比如“只搜索 2024 年之后发布的文章”或者“只搜索价格区间在 100 到 200 之间的商品”。
2.2 Embedding:让文本变成机器能理解的坐标
Embedding 可以说是整个向量检索体系里最重要的环节。它做的一件事是:把一个文本变成一个定长的数值数组,让“语义相近的文本在向量空间中距离更近”。
打个比方,你把“我今天心情很好”和“我眼下感到非常愉快”这两句话扔给一个好的 Embedding 模型,产出的两个向量余弦相似度会非常高——哪怕两句话里没有一个相同的词。反过来,“我今天心情很好”和“我昨晚失眠了”之间的距离就明显远一些。这就是模型学习的语义关系。
Chroma 默认支持的 Embedding 方式有好几种:
- 自己提供向量数组,完全绕开 Chroma 的 Embedding 功能,自己维护模型;
- 用
chromadb.utils.embedding_functions里内置的 OpenAI、Cohere、HuggingFace 等封装; - 自己实现一个
EmbeddingFunction的子类,调用任意模型接口。
我强烈建议新手不要一开始就折腾本地大模型做 Embedding。最省事的路径是用 OpenAI 的 API,质量高、参数少;如果不想付费或者有数据隐私要求,就用 HuggingFace 的 all-MiniLM-L6-v2,这是社区里最常用的轻量模型,384 维,中文效果凑合能用,英文效果不错,在普通 CPU 机器上也能跑得动。
python复制from chromadb.utils import embedding_functions
# 使用 OpenAI Embedding
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
api_key="sk-xxx",
model_name="text-embedding-3-small"
)
# 使用本地 HuggingFace 模型
hf_ef = embedding_functions.HuggingFaceEmbeddingFunction(
api_key="hf_xxx", # 某些模型需要 token
model_name="sentence-transformers/all-MiniLM-L6-v2"
)
注意一点,Embedding 模型一旦选了,尽量不要中途更换。因为不同模型产出的向量空间分布不同,一个 Collection 里的数据如果混合了不同模型的向量,检索结果的相似度是不具备可比性的。这个坑我在早期踩过——先用了 OpenAI 的向量,后来为了省成本换成 HuggingFace 的,同一条数据查询结果完全变了,之前建立的索引基本等于废了。
2.3 距离度量:余弦距离、欧氏距离与内积怎么选
Chroma 的 Collection 创建时可以指定 metadata 里的 hnsw:space 参数,决定用哪种距离计算方式,默认是 l2(欧氏距离)。可选的还有 cosine(余弦距离)和 ip(内积)。
这里很多人会困惑:到底该选哪种?我的经验如下:
- 余弦距离:最常用的选择。它只关注向量方向,不关注向量长度,适合文本语义相似度检索。对 Embedding 向量来说,几乎总是最好的起点。
- L2 欧氏距离:看重向量在空间中的绝对距离。当你明确知道向量长度有意义时(比如某些用户行为特征向量),可以考虑这个。
- 内积(IP):在推荐系统场景中用得比较多。它同时考虑方向和长度,适合评分型的向量化表示。
python复制clie
