Article
第一章:Chroma 概述与核心概念
1.1 什么是 Chroma
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| Chroma | Chroma 是一个开源的向量数据库(Vector Database),专为 AI 应用(如语义搜索、RAG 系统)设计,用于高效存储、索引和检索高维向量数据。 | Chroma 不仅支持向量,还支持关联的元数据(metadata)和原始文档(documents),便于构建端到端 AI 应用。 |
| 向量数据库 | 一种专门用于存储和查询嵌入向量(embedding vectors)的数据库,支持近似最近邻(ANN)搜索。 | 与传统关系型数据库不同,向量数据库优化的是”相似性”而非”精确匹配”。 |
| 嵌入(Embedding) | 将文本、图像等非结构化数据转换为固定维度的数值向量,保留语义信息。 | Chroma 本身不生成嵌入,但可集成嵌入模型自动完成转换。 |
1.2 Chroma 的核心特性
| 特性名称 | 说明 | 注意事项 |
|---|---|---|
| 开源免费 | Chroma 采用 Apache 2.0 许可证,完全开源,可自由使用和修改。 | 社区版功能已足够强大,企业级功能(如分布式部署)仍在演进中。 |
| 内置嵌入支持 | 支持自动调用 Sentence Transformers 等模型生成嵌入,无需手动预处理。 | 首次使用内置嵌入函数时会自动下载模型,需联网且占用磁盘空间(约 500MB+)。 |
| 多客户端模式 | 支持内存模式(In-memory)、本地持久化(PersistentClient)和远程 HTTP 客户端(HttpClient)。 | 内存模式适合开发测试;生产环境建议使用持久化或服务化部署。 |
| 元数据过滤 | 可在向量检索时结合 JSON 格式的元数据进行条件过滤(如 where={"category": "tech"})。 | 元数据字段需在插入时定义,且过滤性能依赖底层索引实现。 |
| 轻量易集成 | 提供简洁 Python API,与 LangChain、LlamaIndex 等主流 LLM 框架深度集成。 | 当前主要语言支持为 Python,JavaScript/TypeScript 支持处于实验阶段。 |
| 自动索引管理 | 默认使用 HNSW 算法构建近似最近邻索引,插入数据后自动更新索引。 | 索引参数(如 ef_construction、M)可通过 Collection 配置调整,影响精度与性能。 |
1.3 Chroma 与其他向量数据库对比
| 对比维度 | Chroma | Pinecone | Milvus | Weaviate |
|---|---|---|---|---|
| 开源状态 | ✅ 完全开源(Apache 2.0) | ❌ 闭源(托管服务为主) | ✅ 开源(Apache 2.0) | ✅ 开源(BSD-3) |
| 部署复杂度 | ⭐ 极简(单机 Python 包即可运行) | ⭐⭐⭐ 需注册账号,依赖云服务 | ⭐⭐⭐⭐ 需 Docker/K8s,组件多 | ⭐⭐ 可容器化,配置较复杂 |
| 嵌入集成 | ✅ 内置 Sentence Transformers 等 | ❌ 需自行提供向量 | ❌ 需自行提供向量 | ✅ 内置多种嵌入模块 |
| 元数据过滤 | ✅ 支持 where 和 where_document | ✅ 支持 metadata 过滤 | ✅ 强大标量/向量混合查询 | ✅ GraphQL + 语义过滤 |
| 适用场景 | 本地开发、原型验证、小型 RAG 应用 | 云端生产级应用 | 大规模、高性能企业级应用 | 语义知识图谱、混合搜索 |
| 社区生态 | 快速增长,LangChain 官方推荐 | 商业驱动,文档完善 | 成熟,CNCF 项目 | 活跃,强调语义层 |
注意事项:
- Chroma 当前(截至 2026 年)仍以单机架构为主,不原生支持分布式集群,不适合超大规模(亿级向量)场景。
- 若需横向扩展,可考虑将其作为缓存层,或等待官方 Chroma Cloud / 分布式版本成熟。
- 对于快速搭建 RAG 原型,Chroma 是目前最轻量、集成最便捷的选择。
第二章:环境准备与快速上手
2.1 安装 Chroma
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 安装核心包 | 在终端执行:pip install chromadb | 推荐使用 Python 3.8+ 环境;若网络较慢,可使用国内镜像源(如 -i https://pypi.tuna.tsinghua.edu.cn/simple) |
| 安装嵌入依赖(可选) | 若使用内置嵌入模型,首次运行会自动安装 sentence-transformers 和 torch;也可提前手动安装:pip install sentence-transformers torch | torch 体积较大(约 500MB–1GB),若仅使用 CPU 可安装 torch --extra-index-url https://download.pytorch.org/whl/cpu 减少体积 |
| 验证安装 | 在 Python 中执行:import chromadb; print(chromadb.__version__) | 若报错 No module named 'chromadb',请检查虚拟环境是否激活或 pip 是否指向正确 Python 版本 |
2.2 创建第一个 Collection
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
chromadb.Client() | client = chromadb.Client() | 创建一个内存模式的 Chroma 客户端实例 | import chromadbclient = chromadb.Client() | 默认为内存模式,程序退出后数据丢失;适用于开发测试 |
client.create_collection() | collection = client.create_collection(name="my_collection") | 创建一个名为 my_collection 的集合(Collection) | collection = client.create_collection(name="docs") | 集合名必须全局唯一;重复创建同名集合会报错 |
create_collection() 参数:embedding_function | create_collection(name="...", embedding_function=fn) | 指定自定义或内置嵌入函数 | from chromadb.utils import embedding_functionsef = embedding_functions.SentenceTransformerEmbeddingFunction(model_name="all-MiniLM-L6-v2")collection = client.create_collection(name="docs", embedding_function=ef) | 若不指定 embedding_function,则插入数据时必须手动提供 embeddings 参数 |
create_collection() 参数:metadata | create_collection(name="...", metadata={"hnsw:space": "cosine"}) | 配置 HNSW 索引的相似度度量方式 | collection = client.create_collection(name="docs", metadata={"hnsw:space": "l2"}) | 支持 "cosine"(默认)、"l2"、"ip"(内积);一旦创建不可修改 |
2.3 插入与查询向量数据
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
collection.add() | add(ids, documents=None, embeddings=None, metadatas=None) | 向集合中添加文档、向量和元数据 | collection.add( ids=["id1", "id2"], documents=["Hello world", "Chroma is great"], metadatas=[{"source": "user"}, {"source": "doc"}]) | - ids 必须唯一且非空 - 若未设 embedding_function,则必须提供 embeddings - documents 和 embeddings 维度需一致 |
collection.query() | query(query_texts=None, query_embeddings=None, n_results=10, where=None, where_document=None) | 执行相似性搜索 | results = collection.query( query_texts=["What is Chroma?"], n_results=2) | - 必须提供 query_texts 或 query_embeddings 之一 - 返回结果包含 ids, distances, metadatas, documents |
query() 返回结构 | — | 查询结果字段说明 | print(results["ids"]) # [['id2', 'id1']]print(results["documents"]) # [['Chroma is great', 'Hello world']] | 结果按相似度降序排列(距离越小越相似);distances 数值含义取决于 hnsw:space 配置 |
| 自动嵌入生成示例 | 使用内置函数时无需传 embeddings | 简化插入流程 | collection.add( ids=["1"], documents=["Machine learning is fun"]) # 自动调用 embedding_function | 首次调用会下载模型(如 all-MiniLM-L6-v2),需联网;后续调用离线可用 |
注意事项补充:
- 所有输入(ids, documents, metadatas, embeddings)必须是列表,且长度一致。
- ids 建议使用字符串类型(如 UUID),避免数字 ID 被误解析。
- 查询时若同时传
query_texts和query_embeddings,以query_embeddings为准。
第三章:Collection 管理
3.1 创建 Collection(含元数据与嵌入函数)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
create_collection() | client.create_collection(name, metadata=None, embedding_function=None) | 创建新集合,可指定索引参数和嵌入函数 | collection = client.create_collection( name="articles", metadata={"hnsw:space": "cosine"}, embedding_function=ef) | - name 必须唯一,长度 ≤ 64 字符,仅允许字母、数字、下划线、连字符 - 若已存在同名集合,抛出 ValueError |
| metadata 参数配置 | metadata={"hnsw:space": "cosine", "hnsw:M": 16, "hnsw:ef_construction": 100} | 配置 HNSW 索引的超参数 | metadata={"hnsw:space": "l2", "hnsw:M": 32} | - hnsw:space:相似度度量("cosine"、"l2"、"ip")- hnsw:M:每个节点连接数(默认 16)- hnsw:ef_construction:建图时候选集大小(默认 100)⚠️ 一旦创建不可修改 |
| 内置嵌入函数 | embedding_functions.SentenceTransformerEmbeddingFunction(model_name="...") | 使用 Sentence Transformers 模型自动嵌入 | from chromadb.utils import embedding_functionsef = embedding_functions.SentenceTransformerEmbeddingFunction( model_name="all-MiniLM-L6-v2") | - 首次使用会自动下载模型(约 80MB) - 支持 Hugging Face 上任意兼容模型 |
| 自定义嵌入函数 | 传入可调用对象(Callable) | 集成私有或第三方嵌入模型 | def my_embed(texts): return [[0.1, 0.9] for _ in texts] # 示例collection = client.create_collection("test", embedding_function=my_embed) | - 函数必须接受 List[str],返回 List[List[float]]- 向量维度需一致且匹配模型输出 |
3.2 获取与列出 Collection
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
get_collection() | client.get_collection(name, embedding_function=None) | 获取已存在的集合实例 | coll = client.get_collection("articles") | - 若集合不存在,抛出 ValueError - 可重新指定 embedding_function(仅用于后续 add/query,不影响已有数据) |
list_collections() | client.list_collections() | 列出所有集合的简要信息 | collections = client.list_collections()for c in collections: print(c.name, c.metadata) | 返回 List[CollectionMetadata],包含 name 和 metadata 字段不包含数据内容,仅元信息 |
get_or_create_collection() | client.get_or_create_collection(name, ...) | 若存在则获取,否则创建 | coll = client.get_or_create_collection("logs") | 避免重复创建错误;常用于初始化逻辑 若已存在,忽略 metadata 和 embedding_function 参数 |
3.3 修改与删除 Collection
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
modify() | collection.modify(name=new_name, metadata=new_metadata) | 修改集合名称或元数据 | collection.modify(name="new_articles") | - 仅支持修改 name 和 metadata - metadata 不能修改 hnsw:space 等索引参数(会报错) - 修改后原变量仍有效,但建议重新获取 |
delete_collection() | client.delete_collection(name) | 永久删除整个集合及其所有数据 | client.delete_collection("temp_data") | ⚠️ 不可逆操作!删除后无法恢复 若集合不存在,抛出 ValueError |
| 清空集合内容(变通方法) | 通过 delete(ids=...) 删除所有 ID | 实现”清空”效果 | all_ids = collection.get()["ids"]if all_ids: collection.delete(ids=all_ids) | Chroma 无原生 clear() 方法 需先 get() 获取全部 ID 再批量删除 |
补充说明:
- Collection 是 Chroma 中的顶层容器,类似传统数据库中的”表”。
- 所有数据操作(add/query/update/delete)都必须通过 Collection 实例进行。
- 修改集合名称后,旧名称不可再用,需使用新名称重新获取实例。
第四章:数据操作(CRUD)
4.1 添加文档与向量(add)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
collection.add() | add(ids, embeddings=None, documents=None, metadatas=None) | 向集合中插入新数据项 | collection.add( ids=["doc1", "doc2"], documents=["AI is powerful", "Chroma stores vectors"], metadatas=[{"type": "intro"}, {"type": "db"}]) | - ids 必须为非空字符串列表,且全局唯一 - 若未配置 embedding_function,必须提供 embeddings - 所有参数(除 ids)均可为 None,但至少需提供 documents 或 embeddings 之一 |
| 提供显式嵌入向量 | add(ids, embeddings=[[0.1,0.9], [0.8,0.2]], ...) | 手动传入预计算的向量 | collection.add( ids=["v1"], embeddings=[[0.5, -0.3, 0.7]], documents=["Custom vector"]) | - 向量维度必须一致(如均为 384 维) - 维度必须与集合已有数据或嵌入函数输出一致,否则报错 |
| 批量插入优化 | 单次调用插入多条(推荐 ≤ 10,000 条) | 提高写入效率 | ids = [f"id_{i}" for i in range(1000)]docs = [f"Document {i}" for i in range(1000)]collection.add(ids=ids, documents=docs) | - 避免在循环中逐条调用 add() - 超大批次可能导致内存溢出,建议分批(如每批 5k) |
4.2 查询相似内容(query)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
collection.query() | query(query_texts=None, query_embeddings=None, n_results=10, where=None, where_document=None) | 基于语义相似性检索最相近的文档 | results = collection.query( query_texts=["What can Chroma do?"], n_results=3, where={"type": "db"}) | - 必须提供 query_texts 或 query_embeddings 之一 - 返回字典包含:ids, distances, metadatas, documents - 结果按相似度排序(距离越小越相关) |
| 使用嵌入向量查询 | query(query_embeddings=[[0.6, 0.4, ...]]) | 用预计算向量进行检索 | emb = model.encode(["My query"])results = collection.query(query_embeddings=emb.tolist()) | 向量维度必须与集合一致;适用于已在外部分词/嵌入的场景 |
| 元数据过滤 | where={"category": "tech", "year": {"$gte": 2023}} | 限制结果范围 | collection.query( query_texts=["AI trends"], where={"domain": "artificial_intelligence"}) | 支持 $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin 等操作符不支持复杂嵌套逻辑(如 AND/OR 混合) |
| 文档内容过滤 | where_document={"$contains": "vector"} | 根据原始文档文本过滤 | collection.query( query_texts=["database"], where_document={"$contains": "Chroma"}) | 仅支持 $contains 操作符(子串匹配)大小写敏感,不支持正则 |
4.3 更新已有数据(update)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
collection.update() | update(ids, embeddings=None, documents=None, metadatas=None) | 修改指定 ID 的字段值 | collection.update( ids=["doc1"], metadatas=[{"type": "updated_intro"}]) | - 仅更新非 None 的字段 - 若提供 documents,会重新生成嵌入向量(若配置了 embedding_function) - 不支持部分字段更新(如只改 metadata 中一个 key),需传入完整新值 |
| 更新文档触发重嵌入 | 提供新 documents | 自动更新向量表示 | collection.update( ids=["doc1"], documents=["AI is transformative"]) | ⚠️ 嵌入会变化,影响后续查询结果 若手动提供 embeddings,则跳过自动嵌入 |
| 批量更新 | 一次更新多个 ID | 提高效率 | collection.update( ids=["id1", "id2"], metadatas=[{"status": "active"}, {"status": "archived"}]) | 所有参数列表长度必须与 ids 一致 缺失字段保持原值不变 |
4.4 删除数据(delete)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
collection.delete() | delete(ids=None, where=None, where_document=None) | 删除满足条件的数据项 | collection.delete(ids=["doc1", "doc2"]) | - 至少提供 ids、where、where_document 之一 - 多条件组合时为 AND 关系 |
| 按元数据删除 | delete(where={"status": "deprecated"}) | 批量清理特定类型数据 | collection.delete(where={"source": "temp"}) | 支持与 query() 相同的 where 语法 慎用无条件删除(如 where={} 会删全部) |
| 按文档内容删除 | delete(where_document={"$contains": "test"}) | 清理含特定关键词的文档 | collection.delete(where_document={"$contains": "DRAFT"}) | 仅支持 $contains删除后无法恢复 |
| 获取后再删除(安全模式) | 先 get() 确认再 delete() | 避免误删 | to_delete = collection.get(where={"flag": "delete_me"})["ids"]if to_delete: collection.delete(ids=to_delete) | 推荐在生产环境中使用此模式 可打印 to_delete 进行人工确认 |
通用注意事项:
- 所有 CRUD 操作均为同步阻塞,大数据量时可能耗时较长。
- Chroma 不支持事务,操作不可回滚。
- 删除或更新后,HNSW 索引不会立即重建,但查询结果会正确反映变更(通过内部标记机制)。
第五章:嵌入(Embedding)与自定义模型
5.1 使用内置嵌入函数(如 Sentence Transformers)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| SentenceTransformerEmbeddingFunction | embedding_functions.SentenceTransformerEmbeddingFunction(model_name="...") | 使用 Hugging Face 上的 Sentence Transformers 模型自动嵌入文本 | from chromadb.utils import embedding_functionsef = embedding_functions.SentenceTransformerEmbeddingFunction( model_name="all-MiniLM-L6-v2")collection = client.create_collection("docs", embedding_function=ef) | - 首次调用会自动下载模型(约 80–500MB) - 需联网;可提前下载至本地并指定路径 - 默认使用 CPU 推理 |
| 支持的常用模型 | "all-MiniLM-L6-v2", "multi-qa-MiniLM-L6-cos-v1", "paraphrase-multilingual-MiniLM-L12-v2" | 轻量级、多语言、问答优化等场景 | ef = embedding_functions.SentenceTransformerEmbeddingFunction( model_name="paraphrase-multilingual-MiniLM-L12-v2") | - 模型维度需一致(如 L6-v2 为 384 维) - 多语言模型适合非英文文本 - 可在 Hugging Face Sentence Transformers 查看完整列表 |
| OpenAI 嵌入函数(实验性) | embedding_functions.OpenAIEmbeddingFunction(api_key="...", model_name="text-embedding-ada-002") | 使用 OpenAI API 生成嵌入 | ef = embedding_functions.OpenAIEmbeddingFunction( api_key="sk-...", model_name="text-embedding-3-small") | - 需安装 openai 包:pip install openai- 产生 API 调用费用 - 需设置环境变量或显式传入 api_key |
5.2 集成自定义嵌入模型
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 自定义 Callable 函数 | 定义接受 List[str] 返回 List[List[float]] 的函数 | 集成私有模型、ONNX 模型、API 服务等 | def my_embed(texts: list[str]) -> list[list[float]]: # 示例:调用本地 ONNX 模型 return [[0.1 * len(t)] * 384 for t in texts]collection = client.create_collection("custom", embedding_function=my_embed) | - 必须严格匹配输入输出类型 - 向量维度必须固定(如 384、768) - 函数需处理批量输入(非单条) |
| 集成 transformers 管道 | 使用 Hugging Face transformers 库 | 使用 BERT、RoBERTa 等模型生成嵌入 | from transformers import AutoTokenizer, AutoModelimport torchtokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")model = AutoModel.from_pretrained("bert-base-uncased")def bert_embed(texts): inputs = tokenizer(texts, return_tensors="pt", padding=True, truncation=True) with torch.no_grad(): outputs = model(**inputs) embeddings = outputs.last_hidden_state.mean(dim=1).numpy() return embeddings.tolist()collection = client.create_collection("bert_docs", embedding_function=bert_embed) | - 需安装 transformers 和 torch - 注意内存和 GPU 显存占用 - 建议添加 truncation=True 防止超长文本报错 |
| 封装为类(推荐) | 实现 __call__ 方法的类 | 更灵活地管理模型状态(如加载、缓存) | class MyEmbedder: def __init__(self, model_path): self.model = load_my_model(model_path) def __call__(self, texts): return self.model.encode(texts)embedder = MyEmbedder("my_model.onnx")collection = client.create_collection("onnx_docs", embedding_function=embedder) | - 类实例可携带模型、tokenizer 等状态 - 适用于复杂预处理/后处理逻辑 |
5.3 手动提供嵌入向量
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
collection.add(embeddings=...) | add(ids, embeddings=[[...], [...]], documents=None, metadatas=None) | 插入时直接传入预计算的向量 | collection.add( ids=["m1"], embeddings=[[0.2, -0.5, 0.9]], documents=["Manual vector example"]) | - 向量必须为 List[List[float]]- 维度必须与集合中其他数据一致(若已有数据) - 若集合无数据,则以此维度为准 |
collection.update(embeddings=...) | update(ids, embeddings=[[...]]) | 更新现有记录的向量表示 | collection.update( ids=["m1"], embeddings=[[0.3, -0.4, 0.8]]) | - 不触发自动嵌入(即使配置了 embedding_function) - 可用于修正错误嵌入或迁移向量 |
| 查询时手动提供查询向量 | query(query_embeddings=[[...]]) | 使用外部系统生成的查询向量 | query_vec = external_model.encode("What is AI?")results = collection.query(query_embeddings=[query_vec]) | - 适用于跨系统语义对齐场景 - 查询向量维度必须与集合嵌入维度一致,否则报错 |
| 维度一致性校验 | — | 确保所有向量维度统一 | # 首次插入决定维度collection.add(ids=["init"], embeddings=[[0]*384])# 后续必须为 384 维 | ⚠️ Chroma 不支持混合维度 若尝试插入不同维度向量,将抛出 InvalidDimensionException |
通用建议:
- 开发阶段推荐使用内置 SentenceTransformerEmbeddingFunction,快速验证流程。
- 生产环境中若需高性能或私有化部署,建议使用 ONNX 或 TensorRT 优化的自定义模型。
- 手动提供向量适用于已有嵌入流水线(如 Spark + FAISS 预计算)的迁移场景。
第六章:元数据过滤与高级查询
6.1 使用 where 过滤元数据
| 操作名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 等值过滤 | where={"key": "value"} | 筛选元数据中某字段等于指定值的记录 | collection.query( query_texts=["AI"], where={"category": "technology"}) | - 仅支持顶层字段(不支持嵌套 JSON) - 值类型需匹配(字符串、数字、布尔) |
| 数值范围过滤 | where={"year": {"$gt": 2020}} | 筛选数值型字段满足不等式的记录 | collection.query( query_texts=["models"], where={"year": {"$gte": 2022, "$lt": 2025}}) | 支持操作符:$gt(大于)、$gte(大于等于)、$lt(小于)、$lte(小于等于) |
| 多值匹配 | where={"tag": {"$in": ["nlp", "cv"]}} | 字段值在给定列表中的记录 | collection.query( query_texts=["deep learning"], where={"domain": {"$in": ["vision", "speech"]}}) | $in 和 $nin(不在)仅适用于数组或标量若字段为字符串, $in 要求完全匹配 |
| 不等于过滤 | where={"status": {"$ne": "archived"}} | 排除特定值的记录 | collection.query( query_texts=["active projects"], where={"status": {"$ne": "deprecated"}}) | $ne 可用于任何类型字段 |
| 布尔值过滤 | where={"is_public": True} | 筛选布尔字段 | collection.query( query_texts=["open research"], where={"is_public": True}) | Python 中使用 True/False,非字符串 “true” |
限制说明:
- 不支持正则表达式、模糊匹配、全文搜索等复杂文本操作。
- 所有 where 条件作用于元数据(metadatas),而非文档内容或向量本身。
6.2 使用 where_document 过滤文档内容
| 操作名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 子串包含过滤 | where_document={"$contains": "keyword"} | 筛选原始文档中包含指定子串的记录 | collection.query( query_texts=["vector DB"], where_document={"$contains": "Chroma"}) | - 仅支持 $contains 操作符- 区分大小写(“chroma” ≠ “Chroma”) - 不支持通配符或正则 |
| 与 where 联用 | 同时使用 where 和 where_document | 多维度联合过滤 | collection.query( query_texts=["database"], where={"type": "tool"}, where_document={"$contains": "open source"}) | 两个条件为 AND 关系 即:元数据匹配 且 文档包含关键词 |
| 性能影响 | — | 文档过滤需扫描原始文本 | - 大集合中频繁使用 where_document 可能变慢 | Chroma 对 documents 未建索引 建议仅在小规模数据或必要时使用 |
重要提醒:
- where_document 仅作用于插入时提供的 documents 字段。
- 若未提供 documents(仅存向量和元数据),此过滤无效。
6.3 多条件组合查询
| 操作名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 单层 AND 组合 | where={"field1": "A", "field2": {"$gt": 10}} | 多个元数据条件同时满足 | collection.query( query_texts=["recent AI paper"], where={ "category": "AI", "year": {"$gte": 2023}, "peer_reviewed": True }) | 所有键值对自动按 AND 逻辑组合 不支持显式的 $and 语法 |
| 不支持 OR 逻辑 | — | 无法直接表达”或”关系 | - 不支持 $or、$and 显式逻辑操作符 | Chroma 当前不支持 $or变通方案:分别查询后合并结果(需去重) |
| 嵌套条件限制 | — | 元数据必须为扁平结构 | - 无效:metadatas=[{"author": {"name": "Alice"}}]- 有效: metadatas=[{"author_name": "Alice"}] | 不支持嵌套对象(如 {"a": {"b": 1}})建议将嵌套结构拍平为 a_b 形式 |
| 查询 + 过滤完整示例 | 综合使用所有参数 | 构建精准语义检索 | results = collection.query( query_texts=["How to use vector DB?"], n_results=5, where={ "language": "en", "relevance_score": {"$gte": 0.8} }, where_document={"$contains": "example"}) | 返回结果同时满足: 1. 语义最相似 2. 英文文档 3. 相关性评分 ≥ 0.8 4. 文档含 “example” |
最佳实践建议:
- 将高频过滤字段放入 metadatas(可高效过滤),而非依赖 where_document。
- 避免在 metadatas 中存储大文本;应仅存分类、标签、时间戳等结构化信息。
- 若业务强依赖
$or逻辑,可考虑在应用层合并多次查询结果,或评估 Milvus/Weaviate 等支持更复杂过滤的数据库。
第七章:持久化与客户端模式
7.1 内存模式 vs 持久化模式
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| 内存模式(In-Memory) | 使用 chromadb.Client() 创建的默认客户端,所有数据存储在 Python 进程内存中 | - 程序退出后数据完全丢失 - 适合快速原型开发、单元测试 - 无法跨进程共享数据 |
| 持久化模式(Persistent) | 使用 chromadb.PersistentClient(path=...) 将数据写入本地磁盘(SQLite + Parquet) | - 数据在程序重启后自动恢复 - 默认存储路径为 ./chroma.sqlite3 和 ./chroma_data/- 单机单写,不支持并发写入 |
| 存储结构 | 持久化模式使用 SQLite 存元数据,Parquet 文件存向量和文档 | - 向量数据以列式格式高效存储 - 可直接查看 chroma_data/ 目录下的 Parquet 文件(需工具解析) |
| 性能对比 | 内存模式读写最快;持久化模式首次加载稍慢(需读磁盘) | - 持久化模式插入速度略低于内存模式 - 查询性能几乎一致(索引仍加载到内存) |
| 适用阶段 | 内存:开发/调试;持久化:本地演示、小型应用 | - 生产环境若需高可用,应使用 HTTP Client + Chroma Server(见 7.3) |
7.2 使用 PersistentClient 实现本地存储
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| PersistentClient 初始化 | client = chromadb.PersistentClient(path="./my_db") | 创建指向指定目录的持久化客户端 | import chromadbclient = chromadb.PersistentClient(path="/data/chroma_db") | - path 必须为绝对路径或相对于当前工作目录 - 首次运行会自动创建目录和文件 |
| 创建集合(持久化) | client.create_collection("my_coll") | 在持久化存储中创建集合 | coll = client.create_collection("articles")coll.add(ids=["1"], documents=["Persisted doc"]) | - 集合元数据和数据均写入磁盘 - 重启后通过相同 path 可恢复 |
| 重启后恢复数据 | 重新初始化 PersistentClient 并 get_collection() | 验证数据持久性 | # 重启脚本后client = chromadb.PersistentClient(path="./my_db")coll = client.get_collection("articles")print(coll.peek()) | - 无需重新插入数据 - 集合名称、嵌入函数、元数据均保留 |
| 多进程限制 | — | 同一持久化目录不允许多个写入进程 | - SQLite 不支持并发写 - 两个 Python 脚本同时写入 ./my_db 危险 | 可能导致数据库锁或损坏 建议单写多读,或使用服务模式 |
目录结构示例(持久化后):
./my_db/
├── chroma.sqlite3 # 元数据(集合名、ID 映射等)
└── chroma_data/
└── <collection_id>/
├── embeddings.parquet
├── documents.parquet
├── metadatas.parquet
└── ...
7.3 使用 HTTP Client 连接远程服务
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 启动 Chroma Server | 命令行:chroma run --host 0.0.0.0 --port 8000 | 启动独立的 Chroma 服务进程 | # 安装 server 组件pip install chromadb[server]# 启动服务chroma run --host 0.0.0.0 --port 8000 | - 需额外安装 [server] 依赖- 默认使用内存存储(可配置持久化) - 服务端不自动保存数据(除非启用持久化) |
| HttpClient 初始化 | client = chromadb.HttpClient(host="localhost", port=8000) | 从 Python 客户端连接远程 Chroma 服务 | import chromadbclient = chromadb.HttpClient(host="192.168.1.10", port=8000) | - 客户端不加载模型,仅转发请求 - 所有嵌入计算在服务端完成(若配置了 embedding_function) |
| 创建远程集合 | client.create_collection(...) | 操作由服务端执行 | coll = client.create_collection("remote_docs")coll.add(ids=["r1"], documents=["From client"]) | - 客户端代码与本地模式完全一致 - 网络延迟会影响性能 |
| 服务端持久化配置 | 启动时指定 --persist-directory | 使远程服务具备持久能力 | chroma run \ --host 0.0.0.0 \ --port 8000 \ --persist-directory /mnt/chroma_data | - 重启服务后数据可恢复 - 多客户端可共享同一服务端数据 |
| 安全与生产部署 | — | 当前无认证/加密机制 | ⚠️ 不要暴露 8000 端口到公网 | - 官方暂未提供 TLS、API Key 等安全功能 - 建议配合 Nginx/API 网关做鉴权 - 生产环境需自行封装或等待企业版 |
典型架构:
[Python App] --(HTTP)--> [Chroma Server (with persistent storage)]
↑
[LangChain / FastAPI / Streamlit]
第八章:性能调优与最佳实践
8.1 批量插入优化
| 操作名称 | 操作细节 | 注意事项 |
|---|---|---|
| 单次批量插入(推荐) | 将多条数据一次性传入 add(),而非循环逐条插入 | - 单次建议 ≤ 10,000 条(视内存而定) - 过大批次可能导致 OOM(Out of Memory) - 示例: ids = [f"id_{i}" for i in range(5000)]docs = [f"Document {i}" for i in range(5000)]collection.add(ids=ids, documents=docs) |
| 分批插入策略 | 对超大数据集(>10万条)分块处理 | batch_size = 2000for i in range(0, len(all_docs), batch_size): batch_ids = all_ids[i:i+batch_size] batch_docs = all_docs[i:i+batch_size] collection.add(ids=batch_ids, documents=batch_docs) |
| 预分配 ID 与避免重复 | 使用 UUID 或确定性 ID 防止冲突 | import uuidids = [str(uuid.uuid4()) for _ in docs] |
| 禁用自动嵌入(如已预计算) | 插入时直接提供 embeddings,跳过模型调用 | collection.add(ids=ids, embeddings=precomputed_embs, documents=docs) |
8.2 索引类型与 HNSW 参数配置
| 参数名称 | 说明 | 推荐值 | 注意事项 |
|---|---|---|---|
hnsw:space | 相似度度量方式 | "cosine"(文本常用)、"l2"(欧氏距离)、"ip"(内积) | - 必须在 create_collection() 时指定- 一旦创建不可更改 - 与嵌入模型训练目标一致(如 Sentence Transformers 多用 cosine) |
hnsw:M | HNSW 图中每个节点的连接数 | 默认 16;高精度场景用 32~64 | - 值越大,索引越大,查询越准,构建越慢 - 内存占用 ≈ M × 向量数 × 向量维度 × 4 字节 |
hnsw:ef_construction | 构建索引时的候选集大小 | 默认 100;高召回用 200~500 | - 影响索引构建质量和速度 - 对查询性能无直接影响 |
hnsw:ef(查询时) | 查询时的候选集大小(动态参数) | 通过 query() 的 include 无法设置;需修改底层(暂不开放) | ⚠️ Chroma 当前不支持运行时调整 ef 查询精度由索引构建质量决定 |
| 索引重建限制 | — | 不支持 | - Chroma 无法重建或重配已有集合的 HNSW 索引 - 若需调整参数,必须创建新集合并迁移数据 |
HNSW 参数影响总结:
| 目标 | 调整方向 |
|---|---|
| 更高召回率 | ↑ M,↑ ef_construction |
| 更快插入速度 | ↓ M,↓ ef_construction |
| 更低内存占用 | ↓ M |
| 更快查询速度 | ↑ M(但收益递减),需权衡 |
8.3 内存与磁盘使用建议
| 场景 | 建议措施 | 注意事项 |
|---|---|---|
| 控制内存峰值 | 使用持久化模式 + 分批插入 | - 内存模式下,所有向量常驻 RAM - 100 万条 384 维 float32 向量 ≈ 1.5 GB 内存 - 持久化模式可显著降低常驻内存 |
| 磁盘空间管理 | 定期清理无用集合 | client.delete_collection("temp_data") |
| 嵌入模型缓存 | 预下载模型至固定路径 | from sentence_transformers import SentenceTransformerSentenceTransformer("all-MiniLM-L6-v2", cache_folder="/models") |
| 避免冗余文档存储 | 仅存必要字段到 documents | - 若原始文本已存于其他系统(如 S3、PostgreSQL),documents 可存摘要或空字符串 - 减少 Parquet 文件体积 |
| 监控资源使用 | 使用系统工具(htop, du -sh) | - 持久化目录增长 = 数据量增长 - 内存泄漏通常源于客户端未释放(罕见) |
容量估算参考(384 维 float32 向量):
| 数据量 | 向量内存 | 磁盘占用(持久化) |
|---|---|---|
| 10,000 条 | ~15 MB | ~20 MB |
| 100,000 条 | ~150 MB | ~200 MB |
| 1,000,000 条 | ~1.5 GB | ~2 GB |
重要提醒:
- Chroma 不是为十亿级向量设计,单机建议上限为 500 万~1000 万条。
- 超出此规模应考虑 Milvus、Qdrant 或 Pinecone 等分布式向量数据库。
第九章:应用场景与集成示例
9.1 RAG(检索增强生成)集成
| 集成步骤 | 操作细节 | 注意事项 |
|---|---|---|
| 构建知识库 | 将文档分块后存入 Chroma 集合 | from langchain.text_splitter import RecursiveCharacterTextSplittertexts = text_splitter.split_documents(raw_docs)collection.add( ids=[f"doc_{i}" for i in range(len(texts))], documents=[t.page_content for t in texts], metadatas=[t.metadata for t in texts]) |
| 检索相关上下文 | 用户提问 → Chroma 查询 → 返回 top-k 文档 | results = collection.query( query_texts=["How does Chroma work?"], n_results=3)context = "\n".join(results["documents"][0]) |
| 注入 LLM Prompt | 将检索结果拼接到提示词中 | prompt = f"""Use the following context to answer the question:{context}“ Question: How does Chroma work?"""response = llm(prompt) |
| 端到端流程封装 | 使用 LangChain 的 RetrievalQA 链 | from langchain.chains import RetrievalQAqa = RetrievalQA.from_chain_type( llm=llm, retriever=chroma.as_retriever(), chain_type="stuff")qa.run("What is Chroma?") |
RAG 性能关键点:
- 嵌入模型应与 LLM 语义空间对齐(如都使用英文模型)
- 避免在 documents 中存储冗余或噪声文本
9.2 与 LangChain / LlamaIndex 集成
LangChain 集成
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
Chroma.from_documents() | Chroma.from_documents(docs, embedding, persist_directory=...) | 从 LangChain Document 列表创建 Chroma 集合 | from langchain_community.vectorstores import Chromadb = Chroma.from_documents( documents=texts, embedding=embedding_func, persist_directory="./rag_db") | - 自动处理 ID 生成、分块嵌入 - 支持持久化路径 |
as_retriever() | retriever = db.as_retriever(search_kwargs={"k": 4}) | 获取检索器用于 RAG 链 | retriever = db.as_retriever( search_type="similarity", search_kwargs={"k": 3, "filter": {"source": "manual"}}) | - search_kwargs 支持 k, filter(即 where) - 不支持 where_document |
| 直接查询 | db.similarity_search("query", k=2) | 快速语义搜索 | docs = db.similarity_search("vector DB", k=2) | 返回 LangChain Document 对象列表 包含 page_content 和 metadata |
LlamaIndex 集成
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| ChromaVectorStore | vector_store = ChromaVectorStore(chroma_collection=collection) | 将 Chroma 集合作为 LlamaIndex 后端 | from llama_index.vector_stores.chroma import ChromaVectorStorevector_store = ChromaVectorStore(collection)storage_context = StorageContext.from_defaults(vector_store=vector_store)index = VectorStoreIndex(nodes, storage_context=storage_context) | - 需先通过原生 Chroma 创建 collection - 支持增量索引更新 |
| 查询引擎 | query_engine = index.as_query_engine() | 构建问答接口 | response = query_engine.query("Explain Chroma")print(response.response) | - 自动完成检索 + LLM 生成 - 可配置响应模式(如 streaming) |
集成选择建议:
- LangChain:适合快速搭建 RAG pipeline,生态丰富
- LlamaIndex:更适合复杂索引结构(如层次化、图索引)和高级查询策略
9.3 构建语义搜索应用
| 应用组件 | 实现方式 | 代码示例 | 注意事项 |
|---|---|---|---|
| Web API 层 | 使用 FastAPI 提供 REST 接口 | from fastapi import FastAPIapp = FastAPI()@app.post("/search")def search(q: str): results = collection.query(query_texts=[q], n_results=5) return {"results": results["documents"][0]} | - 启动命令:uvicorn main:app --reload- 可添加 CORS、限流等中间件 |
| 前端调用 | JavaScript fetch 调用后端 | const res = await fetch("/search", { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify({q: "What is vector search?"})});const data = await res.json(); | - 前端不直接连 Chroma(无 JS 官方 SDK) - 所有逻辑由后端封装 |
| 元数据展示 | 返回结果包含来源、时间等 | return { "matches": [ { "text": doc, "source": meta["source"], "score": 1 - dist # 转为相似度 } for doc, meta, dist in zip(docs, metas, dists) ]} | - distances 是 HNSW 距离,可转为 0~1 相似度 - 建议过滤低分结果(如 score < 0.3) |
| 本地演示应用 | Streamlit 快速构建 UI | import streamlit as stquery = st.text_input("Ask anything")if query: res = collection.query(query_texts=[query], n_results=3) for doc in res["documents"][0]: st.write(doc) | - 适合内部 demo 或 MVP - 单文件即可运行: streamlit run app.py |
部署建议:
- 开发阶段:内存模式 + Streamlit
- 生产阶段:PersistentClient 或 HTTP Client + FastAPI + Docker
- 高并发场景:前端加缓存(如 Redis 缓存热门查询结果)