Chroma

Chroma 是嵌入式向量库:数据落在本地目录里,不必先起 Docker 或 Postgres。适合本机开发、工作坊、中小文档集。官方文档:docs.trychroma.com

生产上若已有 PostgreSQL,下一章用 pgvector;需要独立服务、强过滤 / 混合检索时用 Qdrant


安装

python -m venv .venv
source .venv/bin/activate
pip install chromadb
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install chromadb

需要自备向量时,再装 openaiollama,见 Embeddings。Python 3.10+


PersistentClient

PersistentClient(path="...") 把库写到磁盘,进程重启后仍在。默认路径在文档里写的是 .chroma;教学示例用 ./chroma,和仓库根目录分清。

import chromadb

client = chromadb.PersistentClient(path="./chroma")
collection = client.get_or_create_collection(name="faq")

内存版 chromadb.Client() 一关进程数据就没了,只适合试 API。heartbeat() 可确认客户端还活着;reset() 会清空整个库,不可恢复。


add:ids、documents、可选 embeddings

每条记录需要唯一字符串 id。必须提供 documentsembeddings 或两者。只给 documents 时,Chroma 用 collection 的 embedding function 自动计算。已有向量则一并传入,不会再算一遍

collection.add(
    ids=["refund-0", "hours-0"],
    documents=[
        "退款须在到货 7 日内凭订单号 KH-8842 申请。",
        "工作日客服在线 09:00–18:00(北京时间)。",
    ],
    metadatas=[
        {"source": "refund.md", "lang": "zh"},
        {"source": "hours.md", "lang": "zh"},
    ],
)

自备嵌入(推荐中文):

from embeddings_util import embed_openai  # 见 embeddings 章

texts = ["退款须在到货 7 日内凭订单号 KH-8842 申请。"]
collection.add(
    ids=["refund-0"],
    documents=texts,
    embeddings=embed_openai(texts),
    metadatas=[{"source": "refund.md"}],
)

同一 idadd 会被忽略;要覆盖请用 update / upsert(以当前版本文档为准)。向量维数必须和集合里已有的一致。


query

results = collection.query(
    query_texts=["订单 KH-8842 怎么退款?"],
    n_results=2,
    where={"lang": "zh"},
)
print(results["ids"])
print(results["documents"])
print(results["distances"])
print(results["metadatas"])

已有问题向量时用 query_embeddings=[vec]不要混用另一个嵌入模型。where 按元数据过滤(部门、语言、来源文件)。返回结构是「列表的列表」:一次可以查多条 query_texts


接到 RAG

def retrieve(question: str, k: int = 4) -> str:
    hit = collection.query(query_texts=[question], n_results=k)
    docs = hit["documents"][0]
    metas = hit["metadatas"][0]
    parts = []
    for doc, meta in zip(docs, metas):
        parts.append(f"[{meta.get('source', '')}]\n{doc}")
    return "\n\n".join(parts)

context = retrieve("退款期限是几天?")
prompt = f"只根据上下文回答。没有依据就说不知道。\n\n{context}\n\n问题:退款期限是几天?"

prompt 交给任意 Chat API。框架封装见 LangChain RAG;无代码控制台见 Dify 知识库


何时换库

现象考虑
只要本机目录、文档量不大留下 Chroma
用户、权限、事务已经在 Postgrespgvector
要 payload 过滤、混合检索、多客户端Qdrant

Windows 把 ./chroma 加进 .gitignore。不要把库目录提交进 Git。


下一步

评论