导读:这篇要带你做什么?

如果你听说过 RAG(检索增强生成) 但不知道数据到底存在哪——答案就是向量数据库。它不存普通的文本或表格,而是把文字转成一串数字坐标点(叫作 Embedding / 嵌入向量),然后通过"距离近就相似"的规则找到最相关的文档片段。

本文将围绕 Chroma 这款开源向量数据库展开——它只需几行 Python 就能跑起来,不需要 Docker、不需要外部服务。我们从"向量到底是什么"的白话讲起,一步步完成安装 → Collection CRUD(增删改查)→ Embedding 自定义 → 相似检索,最终拼出一个最小 RAG 问答系统:用户提问 → 在向量库里找到相关文档 → 喂给大语言模型 → 得到答案。

💡 本文示例默认使用本地免费模型做 Embedding,零配置即可跑通全文代码。如果你后面需要 LLM 能力来回答用户问题(RAG 部分),可以接入任何 OpenAI 兼容的云端 API——脚本里会提供配置引导。


一、向量是什么?白话版

想象你有一堆书。你想找"如何做番茄炒蛋"的食谱。

传统搜索方式是关键词匹配——你的查询里有"番茄"和"炒蛋"吗?有就返回。但如果一篇教程写的是"西红柿鸡蛋做法",因为字不一样就没命中。

向量搜索的思路完全不同:

  1. 把每段文字通过一个模型(Embedding 模型)变成一组数字。比如:“如何做番茄炒蛋” → [0.12, -0.35, 0.87, ..., 0.04](通常 384 维或更高)。
  2. 这组数字就是这段文字的"坐标点"(也叫向量)。语义相近的文字,生成的坐标点在空间里也会挨得很近。
  3. 当用户问"西红柿怎么做菜"时,同样把它变成向量,然后计算它和库里所有向量的距离——离得最近的那几条就是你想要的结果。
        "番茄炒蛋"      "西红柿鸡蛋做法"
           ●──────────────●          ← 这两个语义接近,距离近
                                    ●
                       ●            ← "机器学习入门"距离很远

这就是向量数据库要做的事:存向量、查最近邻

⚠️ 术语速记

  • Embedding / 嵌入向量:把文字变成坐标点的过程及其结果。
  • Collection(集合):Chroma 中数据的容器,类似数据库中的"表"。
  • Query(检索):传入一段文字,返回语义最相似的 N 条记录。

二、安装 Chroma

Chroma 是一个 Python 库,直接 pip 即可安装(Python 3.9+):

pip install chromadb
网络环境命令
海外直连pip install chromadb
国内(清华镜像)pip install chromadb -i https://pypi.tuna.tsinghua.edu.cn/simple
国内回退(阿里镜像)pip install chromadb -i https://mirrors.aliyun.com/pypi/simple

安装完成后验证:

import chromadb
print(chromadb.__version__)

三、PersistentClient vs Client

Chroma 提供了两种客户端模式——选择哪一种决定了你的数据是内存临时还是落盘持久

① Client() — 内存模式(开发调试用)

import chromadb

# 每次启动都是全新的空库,关掉就没有了
client = chromadb.Client()

适合快速试错、一次性演示。重启后数据丢失。

② PersistentClient(path="/…") — 持久化模式(生产推荐)

import chromadb

# 数据保存到本地磁盘,下次启动还能读到
client = chromadb.PersistentClient(path="./my-chroma-db")

path 可以是任意绝对路径或相对路径。Chroma 会把数据写入该目录下的一组文件里(底层默认使用 SQLite)。

📌 本文后续示例全部使用 PersistentClient


四、Collection 的增删改查

拿到 client 之后,就可以操作数据了。Chroma 的数据容器叫 Collection

4.1 创建 Collection

import chromadb

client = chromadb.PersistentClient(path="./chroma-demo")

# 方式A:创建全新集合(如果已存在会报错)
collection = client.create_collection(name="recipes")

# 方式B:获取已有集合(不存在则自动创建)
collection = client.get_or_create_collection(name="recipes")

创建一个新 Collection 时,如果不指定 embedding 函数(见下一节),Chroma 会使用默认的本地 Embedding 模型。

4.2 插入数据(Add)

每条记录必须有一个唯一 id,可以附带 documents(原始文本)、embeddings(向量)和 metadatas(元数据字典):

collection.add(
    ids=["doc1", "doc2", "doc3"],                          # 唯一标识
    documents=[                                              # 原始文本内容
        "西红柿洗净切块,鸡蛋打散。热锅凉油倒入蛋液煎至凝固后盛出。",
        "锅中留底油,下西红柿翻炒出汁,加适量盐和糖调味。",
        "倒回煎好的鸡蛋,快速翻炒均匀即可出锅。"
    ],
    metadatas=[                                              # 可选:附加标签
        {"cooking_time": "10分钟", "difficulty": "简单"},
        {"cooking_time": "5分钟", "difficulty": "简单"},
        {"cooking_time": "3分钟", "difficulty": "简单"},
    ]
)

🔍 注意:如果只传 documents 不传 embeddings,Chroma 会在内部自动调用默认 Embedding 函数为你生成向量——这就是 Chroma 对小白最友好的设计之一。

4.3 查询相似度(Query)

result = collection.query(
    query_texts=["西红柿怎么做菜"],     # 查询文本(也可用 query_embeddings)
    n_results=2                         # 想要几条结果
)
print(result)

返回值是一个字典,包含 idsdocumentsdistances(距离越小越相似)、metadatas

{
    'ids': [['doc1', 'doc2']],              # 最近的 2 条 ID
    'documents': [['西红柿洗净切块...', '锅中留底油...']],
    'metadatas': [[{'cooking_time': '10分钟', 'difficulty': '简单'}, ...]],
    'distances': [[0.32, 0.58]]             # 距离值,越小越接近
}

Query 支持的参数一览

参数类型说明
query_textsstr[]查询文本列表
query_embeddingsfloat[][]直接用向量查询(跳过文本编码)
n_resultsint返回最相似的 N 条(默认 10)
wheredict按元数据过滤,如 {"difficulty": "简单"}
where_documentdict按原文内容过滤,如 {"$contains": "西红柿"}

例如,只搜"简单"难度且文本中包含"西红柿"的:

result = collection.query(
    query_texts=["西红柿怎么做菜"],
    n_results=5,
    where={"difficulty": "简单"},
    where_document={"$contains": "西红柿"}
)

4.4 获取数据(Get)

如果你已经知道 id,可以用 get() 直接取:

# 按 ID 获取单条或多条
result = collection.get(ids=["doc1"])

# 加上 include 参数控制返回字段
result = collection.get(include=["documents", "metadatas"])

返回值与 query 不同——它是扁平列表而非嵌套结构。

4.5 删除数据(Delete)

# 按 ID 批量删除
collection.delete(ids=["doc3"])

# 也可以配合 where 条件删除
collection.delete(where={"difficulty": "复杂"})

⚠️ 危险操作! 删除是不可逆的,执行前请确认。

4.6 清空整个集合

collection.clear()

清空后 Collection 仍然存在(可以继续 add),但所有数据和向量都消失了。


五、Embedding:默认模型 vs 第三方模型

Embedding 函数就是把文本变成向量的工具。Chroma 提供两层策略:

5.1 默认 Embedding(零配置)

不传 embedding_function 时,Chroma 使用内置的本地模型(基于 sentence-transformersall-MiniLM-L6-v2,输出 384 维向量)。开箱即用,不需要任何 API Key:

# 这样创建 Collection 就用了默认本地 Embedding
collection = client.get_or_create_collection(name="recipes")

适合起步验证、离线开发、不想花钱的场景。缺点是对中文的支持相对一般(MiniLM 主要是英文训练的)。

5.2 第三方 Embedding:OpenAI 示例

如果你想要更好的向量质量,可以接入 OpenAI 的 Embedding API。首先需要额外安装依赖:

pip install openai

然后定义并使用:

from chromadb.utils.embedding_functions import OpenAIEmbeddingFunction

# 指定使用的 OpenAI 模型
ef = OpenAIEmbeddingFunction(
    model_name="text-embedding-3-small",
    api_key="sk-你的密钥"       # 也可直接读环境变量 OPENAI_API_KEY
)

collection = client.get_or_create_collection(
    name="recipes",
    embedding_function=ef         # 传入自定义 Embedding 函数
)

💬 不想用 OpenAI? Chroma 生态还集成了 Cohere、HuggingFace、Cohere、Instructor、Mistral、Ollama 等数十种 Embedding 方案(完整列表见 Chroma Integrations)。比如本地跑免费的 Ollama Embedding、或者用 Cohere 的多语言模型。

在国内如果买不到 OpenAI Key,云间 API 中转站 支持 OpenAI 兼容接口——只需要把你的 Base URL 改成它的地址就行:

ef = OpenAIEmbeddingFunction(
    model_name="text-embedding-3-small",
    api_key="sk-cz-xxxxx",                   # 云间提供的 Key
    base_url="https://cloudzone-api.cyou/v1" # 替换 Base URL 即可适配任何 OpenAI 兼容服务
)

📌 以上为概念写法,具体类名和构造函数随 Chroma 版本可能调整——建议查阅 最新官方文档,拿不准的地方以官方为准。


六、拼一个最小 RAG 问答系统

RAG = Retrieval Augmented Generation(检索增强生成)。思路很简单:

                        ┌─────────────────┐
   用户提问 ─────────▶ │   向量数据库检索   │   ← Chroma 在这里干活
                        └────────┬────────┘
                                 │ 找到最相关的文档片段
                                 ▼
                        ┌─────────────────┐
   LLM 回答 ◀───────── │   拼 Prompt 发送给大模型 │
                        └─────────────────┘

架构图示如下:

RAG 检索架构图

下面用 Chroma + 任意 OpenAI 兼容格式的 LLM 完成一个完整的迷你 demo:

import chromadb
from openai import OpenAI

# ========== 第一步:准备知识库(往 Chroma 里存文档)==========
client = chromadb.PersistentClient(path="./rag-demo")

collection = client.get_or_create_collection("qa-knowledge")

documents = [
    "Chroma 是一个开源的嵌入式向量数据库,安装只需 pip install chromadb。",
    "Chroma 支持持久化存储,使用 PersistentClient(path='/path') 即可。",
    "Chroma 的默认 Embedding 模型是 all-MiniLM-L6-v2,输出 384 维向量。",
    "可以通过 embedding_function 参数接入第三方 Embedding,如 OpenAI、Cohere。",
]

collection.add(
    ids=[f"doc{i}" for i in range(len(documents))],
    documents=documents
)

# ========== 第二步:构建 RAG 推理链路 ==========
# 这里假设你有一个 OpenAI 兼容的 API(本地 vLLM / 云端 CZ 均可)
client_llm = OpenAI(
    api_key="sk-你的Key",
    base_url="https://cloudzone-api.cyou/v1"       # 换成实际地址
)

def rag_ask(question: str) -> str:
    """最小 RAG:先检索相关文档,再拼 Prompt 丢给 LLM"""
    # 1) 在 Chroma 里检索最相关的文档
    result = collection.query(query_texts=[question], n_results=2)
    relevant_docs = result["documents"][0]

    # 2) 拼成一个 Prompt(参考文档 + 用户问题)
    context = "\n".join(relevant_docs)
    prompt = f"""基于以下参考资料回答问题:

参考资料:
{context}

用户问题:{question}

请用简洁的中文回答。"""

    # 3) 调 LLM
    resp = client_llm.chat.completions.create(
        model="text-embedding-3-small",    # 换成可用的模型名
        messages=[{"role": "user", "content": prompt}],
        temperature=0.3,
    )
    return resp.choices[0].message.content

# ========== 第三步:测试 ==========
if __name__ == "__main__":
    answer = rag_ask("Chroma 怎么保存数据到磁盘?")
    print(answer)

运行效果大致如下(因模型而异):

Chroma 使用 PersistentClient 类并将 path 参数指定到一个目录来实现磁盘持久化。例如:
client = chromadb.PersistentClient(path="/path/to/save/to")
这样数据会被保存到该目录下,下次启动时可以重新加载。

整个过程只有 检索 → 拼接 → 生成三步,没有任何框架包袱。你可以把这个逻辑嵌入到任何 Python 项目中。


七、总结 & 下一步

本文覆盖了 Chroma 的核心用法:

步骤关键点
安装pip install chromadb
客户端PersistentClient(path=...) 持久化
Collection CRUDadd() / query() / get() / delete() / clear()
Embedding默认零配置本地模型 ↔ 第三方如 OpenAI
最小 RAG检索相关文档 → 拼 Prompt → LLM 回答

如果想深入,推荐的方向:

欢迎动手试试——把上面的代码复制下来跑一遍,比看十篇文章都有用。


附:双版本一键脚本源码

为方便在本机快速搭建 Chroma 开发环境,下方提供了 Linux/macOS (.sh)Windows PowerShell (.ps1) 两个完整脚本。公开源码,欢迎审查——不方便下载的同学可以直接复制全文,新建文本文档粘贴后改后缀运行。

也可是从以下链接下载:

#!/usr/bin/env bash
set -u
# ============================================================
#  Chroma 向量数据库入门 一键脚本(macOS / Linux / WSL)
#  公开源码,欢迎审查 —— 不放心可先复制给 AI 判断
#  功能:检测环境 → 建 venv → 装 chromadb + openai → 跑 demo
#  默认配置:云间 API 中转站(https://cloudzone-api.cyou/)
# ============================================================

GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; CYAN='\033[0;36m'; NC='\033[0m'
info()  { echo -e "${GREEN}[INFO]${NC} $1"; }
warn()  { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; }
step()  { echo -e "${CYAN}[STEP]${NC} $1"; }

detect_network() {
  step "检测网络环境(国内 / 国外)..."
  if curl -fsI --max-time 5 "https://claude.ai" >/dev/null 2>&1; then
    info "可直连 claude.ai,判定为海外网络"
    echo "overseas"
  else
    warn "无法直连 claude.ai,判定为国内网络环境(将自动切换国内镜像)"
    echo "domestic"
  fi
}

configure_api() {
  step "配置 API Key(可选,仅 RAG 问答部分需要)..."
  echo ""
  echo "是否需要使用 LLM 进行 RAG 问答演示?"
  echo "  Y - 使用云间 API 中转站(https://cloudzone-api.cyou/,注册送额度)"
  echo "  N - 跳过 LLM 部分,只跑向量检索演示"
  echo "  C - 我已有 Key,自行输入"
  read -r -p "请选择 [Y/N/C]: " choice

  if [ "${choice:-N}" = "N" ] || [ "${choice:-N}" = "n" ]; then
    warn "跳过 LLM 配置,将只演示 Chroma 向量检索(不含 RAG 问答)"
    export CHROMADB_USE_LLM="false"
    return 0
  fi

  local API_KEY=""
  local BASE_URL="https://cloudzone-api.cyou/v1"

  if [ "${choice:-N}" = "Y" ] || [ "${choice:-N}" = "y" ]; then
    info "正在打开浏览器跳转注册..."
    if command -v xdg-open >/dev/null 2>&1; then
      xdg-open "https://cloudzone-api.cyou" >/dev/null 2>&1
    elif command -v open >/dev/null 2>&1; then
      open "https://cloudzone-api.cyou" >/dev/null 2>&1
    else
      warn "无法自动打开浏览器,请手动访问:https://cloudzone-api.cyou"
    fi
    echo "注册后在「我的 API Key」页面复制 Key(以 sk- 开头)。"
    read -r -p "粘贴你的 API Key: " API_KEY
  else
    read -r -s -p "请输入你的 API Key (sk-...): " API_KEY
    echo
  fi

  if [ -z "${API_KEY:-}" ]; then
    warn "未输入 API Key,跳过配置。可稍后设置环境变量 CHROMADB_API_KEY。"
    export CHROMADB_API_KEY=""
    export CHROMADB_BASE_URL=""
    export CHROMADB_USE_LLM="false"
    return 0
  fi

  export CHROMADB_API_KEY="$API_KEY"
  export CHROMADB_BASE_URL="$BASE_URL"
  export CHROMADB_USE_LLM="true"

  info "配置完成!"
  echo "  API Key : ${API_KEY:0:10}********"
  echo "  Base URL: $BASE_URL"
  echo ""
}

run_demo() {
  local net="$1"
  step "生成并运行 Chroma 演示程序..."

  cat > chroma_demo.py <<'PYEOF'
"""Chroma 向量数据库最小演示(含可选 RAG 问答)"""
import os
import chromadb

# ===== 1. 初始化持久化客户端 =====
data_dir = "./chroma_rag_demo_db"
client = chromadb.PersistentClient(path=data_dir)

# ===== 2. 创建/获取 Collection =====
collection = client.get_or_create_collection("demo-knowledge")

# 检查是否已有数据,没有则插入
if collection.count() == 0:
    docs = [
        "Chroma 是一个开源的嵌入式向量数据库,安装只需 pip install chromadb。",
        "Chroma 支持持久化存储,使用 PersistentClient(path='/path') 即可把数据保存到磁盘。",
        "Chroma 的默认 Embedding 模型是 all-MiniLM-L6-v2,输出 384 维向量。",
        "可以通过 embedding_function 参数接入第三方 Embedding 如 OpenAI、Cohere、Ollama 等。",
        "RAG = Retrieval Augmented Generation,即检索增强生成:先用向量库找到相关文档,再交给 LLM 回答。",
    ]
    collection.add(
        ids=[f"doc{i}" for i in range(len(docs))],
        documents=docs,
    )
    print(f"[OK] 已插入 {len(docs)} 条知识文档")

# ===== 3. 向量检索演示 =====
print("\n===== 向量检索演示 =====")
queries = [
    "Chroma 怎么保存数据到磁盘?",
    "什么是 RAG?",
]

for q in queries:
    result = collection.query(query_texts=[q], n_results=2)
    print(f"\n问题: {q}")
    for i, doc in enumerate(result["documents"][0]):
        dist = result["distances"][0][i]
        print(f"  [{i+1}] (距离={dist:.3f}) {doc[:80]}...")

# ===== 4. RAG 问答(可选) =====
use_llm = os.environ.get("CHROMADB_USE_LLM", "false").lower()
if use_llm == "true":
    from openai import OpenAI
    api_key = os.environ.get("CHROMADB_API_KEY", "")
    base_url = os.environ.get("CHROMADB_BASE_URL", "https://cloudzone-api.cyou/v1")

    llm_client = OpenAI(api_key=api_key, base_url=base_url)

    print("\n===== RAG 问答演示 =====")
    question = input("请输入你的问题: ").strip()
    if not question:
        question = "Chroma 支持哪些 Embedding 模型?"

    # 检索相关文档
    result = collection.query(query_texts=[question], n_results=2)
    context = "\n".join(result["documents"][0])

    # 拼 Prompt 发给 LLM
    prompt = f"""基于以下参考资料回答问题:

参考资料:
{context}

用户问题:{question}

请用简洁的中文回答。"""

    try:
        resp = llm_client.chat.completions.create(
            model="text-embedding-3-small",
            messages=[{"role": "user", "content": prompt}],
            temperature=0.3,
        )
        print(f"\nAI 回答: {resp.choices[0].message.content}")
    except Exception as e:
        error(f"LLM 调用失败: {e}")
        print("提示:请检查 API Key 和 Base URL 是否正确")
else:
    print("\n[SKIP] 未配置 API Key,跳过 RAG 问答(如需开启请重新运行并选择 Y/C)")

print("\n===== 演示结束 =====")
PYEOF

  if ! python3 chroma_demo.py; then
    error "演示程序运行失败。常见原因:"
    echo "  1. chromadb 未安装:python3 -m pip install chromadb"
    echo "  2. Python 版本过低:需要 3.9+"
    return 1
  fi

  info "演示完成!数据保存在 ./chroma_rag_demo_db/ 目录下"
  warn "想重新演示请先删除该目录:rm -rf chroma_rag_demo_db"
}

main() {
  echo "============================================"
  echo "  Chroma 向量数据库入门 一键脚本"
  echo "  适用于 macOS / Linux / WSL"
  echo "  默认接入:云间 API 中转站(可选)"
  echo "============================================"
  echo ""

  if ! command -v python3 >/dev/null 2>&1; then
    error "未检测到 python3。请先安装 Python 3.9+"
    echo "  Ubuntu/Debian: sudo apt install python3 python3-pip"
    echo "  macOS: brew install python3"
    echo "  WSL: sudo apt update && sudo apt install -y python3 python3-venv python3-pip"
    exit 1
  fi
  info "检测到 Python3: $(python3 --version 2>&1)"

  step "创建虚拟环境..."
  mkdir -p chroma-env && cd chroma-env || exit 1
  python3 -m venv .venv || { error "创建虚拟环境失败"; exit 1; }
  # shellcheck disable=SC1091
  source .venv/bin/activate || { warn "激活虚拟环境失败,继续使用系统 Python"; }
  info "虚拟环境就绪"

  local NET
  NET=$(detect_network)

  step "安装 chromadb 和 openai(${NET} 网络环境)..."
  local PIP_INDEX="https://pypi.org/simple"
  if [ "$NET" = "domestic" ]; then
    PIP_INDEX="https://pypi.tuna.tsinghua.edu.cn/simple"
  fi

  if pip install chromadb openai -i "$PIP_INDEX" --timeout 120 >/dev/null 2>&1; then
    info "安装成功"
  else
    warn "主源安装失败,回退官方源重试..."
    if pip install chromadb openai --timeout 120 >/dev/null 2>&1; then
      info "安装成功(官方源)"
    else
      error "安装失败。请手动执行以下命令:"
      echo "  pip install chromadb openai -i https://pypi.tuna.tsinghua.edu.cn/simple"
      echo "  (海外用户去掉 -i 参数使用官方源)"
      exit 1
    fi
  fi

  configure_api

  run_demo "$NET"

  echo ""
  echo "============================================"
  info "全部完成!"
  echo "  演示数据: ./chroma_rag_demo_db/"
  echo "  脚本位置: chroma-env/chroma_demo.py"
  echo ""
  echo "  想用其他 OpenAI 兼容 API?"
  echo "  试试云间 API 中转站:https://cloudzone-api.cyou/"
  echo "    · OpenAI 兼容 + Anthropic 兼容"
  echo "    · 90+ 模型按量计费"
  echo "    · 国内直连无需翻墙,香港节点"
  echo "    · 价格不足官方两折,0.05x 起"
  echo "============================================"
}

main "$@"
# ============================================================
#  Chroma 向量数据库入门 一键脚本(Windows PowerShell)
#  公开源码,欢迎审查 -- 不放心可先复制给 AI 判断
#  功能:检测环境 -> 建 venv -> 装 chromadb + openai -> 跑 demo
#  默认配置:云间 API 中转站(https://cloudzone-api.cyou/)
# ============================================================

$ErrorActionPreference = "Stop"

function Write-Info  { Write-Host "[INFO] $args" -ForegroundColor Green }
function Write-Warn  { Write-Host "[WARN] $args" -ForegroundColor Yellow }
function Write-Err   { Write-Host "[ERROR] $args" -ForegroundColor Red }
function Write-Step  { Write-Host "[STEP] $args" -ForegroundColor Cyan }

# ===== 0. 前置检查:Python =====
Write-Step "检查 Python 环境..."
try {
    $pyVer = & python3 --version 2>&1
    Write-Info "检测到 Python3: $pyVer"
} catch {
    Write-Err "未检测到 python3。请先安装 Python 3.9+:"
    Write-Host "  官网下载: https://www.python.org/downloads/"
    Write-Host "  Winget:   winget install Python.Python.3.12"
    Write-Host "  Chocolatey: choco install python"
    Write-Host "  安装时请勾选'Add Python to PATH'"
    exit 1
}

# ===== 1. 网络检测 =====
function Detect-Network {
    Write-Step "检测网络环境(国内 / 国外)..."
    try {
        $null = Invoke-WebRequest -Uri "https://claude.ai" -Method Head -TimeoutSec 5 -UseBasicParsing
        Write-Info "可直连 claude.ai,判定为海外网络"
        return "overseas"
    } catch {
        Write-Warn "无法直连 claude.ai,判定为国内网络环境(将自动切换国内镜像)"
        return "domestic"
    }
}

# ===== 2. API Key 配置(可选) =====
function Configure-Api {
    Write-Step "配置 API Key(可选,仅 RAG 问答部分需要)..."
    Write-Host ""
    Write-Host "是否需要使用 LLM 进行 RAG 问答演示?"
    Write-Host "  Y - 使用云间 API 中转站(https://cloudzone-api.cyou/,注册送额度)"
    Write-Host "  N - 跳过 LLM 部分,只跑向量检索演示"
    Write-Host "  C - 我已有 Key,自行输入"
    $choice = Read-Host "请选择 [Y/N/C]"

    if ($choice -eq "N" -or $choice -eq "n") {
        Write-Warn "跳过 LLM 配置,将只演示 Chroma 向量检索(不含 RAG 问答)"
        $env:CHROMADB_USE_LLM = "false"
        return
    }

    $apiKey = ""
    $baseUrl = "https://cloudzone-api.cyou/v1"

    if ($choice -eq "Y" -or $choice -eq "y") {
        Write-Info "正在打开浏览器跳转注册..."
        try { Start-Process "https://cloudzone-api.cyou" } catch {}
        Write-Host "注册后在「我的 API Key」页面复制 Key(以 sk- 开头)。"
        $sec = Read-Host "粘贴你的 API Key" -AsSecureString
        $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
        $apiKey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
        [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
    } else {
        $sec = Read-Host "请输入你的 API Key (sk-...)" -AsSecureString
        $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
        $apiKey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
        [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
    }

    if ([string]::IsNullOrWhiteSpace($apiKey)) {
        Write-Warn "未输入 API Key,跳过配置。可稍后设置环境变量 CHROMADB_API_KEY。"
        $env:CHROMADB_API_KEY = ""
        $env:CHROMADB_BASE_URL = ""
        $env:CHROMADB_USE_LLM = "false"
        return
    }

    $env:CHROMADB_API_KEY = $apiKey
    $env:CHROMADB_BASE_URL = $baseUrl
    $env:CHROMADB_USE_LLM = "true"

    Write-Info "配置完成!"
    Write-Host "  API Key : $($apiKey.Substring(0, [Math]::Min(10, $apiKey.Length)))********"
    Write-Host "  Base URL: $baseUrl"
}

# ===== 3. 生成并运行演示 =====
function Run-Demo {
    param([string]$Net)
    Write-Step "生成并运行 Chroma 演示程序..."

    $demoScript = @'
"""Chroma 向量数据库最小演示(含可选 RAG 问答)"""
import os
import chromadb

# ===== 1. 初始化持久化客户端 =====
data_dir = "./chroma_rag_demo_db"
client = chromadb.PersistentClient(path=data_dir)

# ===== 2. 创建/获取 Collection =====
collection = client.get_or_create_collection("demo-knowledge")

# 检查是否已有数据,没有则插入
if collection.count() == 0:
    docs = [
        "Chroma 是一个开源的嵌入式向量数据库,安装只需 pip install chromadb。",
        "Chroma 支持持久化存储,使用 PersistentClient(path='/path') 即可把数据保存到磁盘。",
        "Chroma 的默认 Embedding 模型是 all-MiniLM-L6-v2,输出 384 维向量。",
        "可以通过 embedding_function 参数接入第三方 Embedding 如 OpenAI、Cohere、Ollama 等。",
        "RAG = Retrieval Augmented Generation,即检索增强生成:先用向量库找到相关文档,再交给 LLM 回答。",
    ]
    collection.add(
        ids=[f"doc{i}" for i in range(len(docs))],
        documents=docs,
    )
    print(f"[OK] 已插入 {len(docs)} 条知识文档")

# ===== 3. 向量检索演示 =====
print("\n===== 向量检索演示 =====")
queries = [
    "Chroma 怎么保存数据到磁盘?",
    "什么是 RAG?",
]

for q in queries:
    result = collection.query(query_texts=[q], n_results=2)
    print(f"\n问题: {q}")
    for i, doc in enumerate(result["documents"][0]):
        dist = result["distances"][0][i]
        print(f"  [{i+1}] (距离={dist:.3f}) {doc[:80]}...")

# ===== 4. RAG 问答(可选) =====
use_llm = os.environ.get("CHROMADB_USE_LLM", "false").lower()
if use_llm == "true":
    from openai import OpenAI
    api_key = os.environ.get("CHROMADB_API_KEY", "")
    base_url = os.environ.get("CHROMADB_BASE_URL", "https://cloudzone-api.cyou/v1")

    llm_client = OpenAI(api_key=api_key, base_url=base_url)

    print("\n===== RAG 问答演示 =====")
    question = input("请输入你的问题: ").strip()
    if not question:
        question = "Chroma 支持哪些 Embedding 模型?"

    # 检索相关文档
    result = collection.query(query_texts=[question], n_results=2)
    context = "\n".join(result["documents"][0])

    # 拼 Prompt 发给 LLM
    prompt = f"""基于以下参考资料回答问题:

参考资料:
{context}

用户问题:{question}

请用简洁的中文回答。"""

    try:
        resp = llm_client.chat.completions.create(
            model="text-embedding-3-small",
            messages=[{"role": "user", "content": prompt}],
            temperature=0.3,
        )
        print(f"\nAI 回答: {resp.choices[0].message.content}")
    except Exception as e:
        print(f"\n[ERROR] LLM 调用失败: {e}")
        print("提示:请检查 API Key 和 Base URL 是否正确")
else:
    print("\n[SKIP] 未配置 API Key,跳过 RAG 问答(如需开启请重新运行并选择 Y/C)")

print("\n===== 演示结束 =====")
'@

    Set-Content -Path "chroma_demo.py" -Value $demoScript -Encoding UTF8

    try {
        python3 chroma_demo.py
        Write-Info "演示完成!数据保存在 ./chroma_rag_demo_db/ 目录下"
        Write-Warn "想重新演示请先删除该目录:Remove-Item -Recurse -Force chroma_rag_demo_db"
    } catch {
        Write-Err "演示程序运行失败。常见原因:"
        Write-Host "  1. chromadb 未安装:python3 -m pip install chromadb"
        Write-Host "  2. Python 版本过低:需要 3.9+"
        exit 1
    }
}

# ===== 主流程 =====
Write-Host "============================================"
Write-Host "  Chroma 向量数据库入门 一键脚本"
Write-Host "  适用于 Windows(PowerShell)"
Write-Host "  默认接入:云间 API 中转站(可选)"
Write-Host "============================================"
Write-Host ""

$net = Detect-Network

Write-Step "创建虚拟环境..."
New-Item -ItemType Directory -Force -Path "chroma-env" | Out-Null
Set-Location chroma-env
& python3 -m venv .venv
Write-Info "虚拟环境就绪"

# 激活 venv(Windows)
& ".\.venv\Scripts\Activate.ps1"

Write-Step "安装 chromadb 和 openai..."
$pipIndex = "https://pypi.org/simple"
if ($net -eq "domestic") {
    $pipIndex = "https://pypi.tuna.tsinghua.edu.cn/simple"
}

try {
    pip install chromadb openai -i $pipIndex --timeout 120 | Out-Null
    Write-Info "安装成功"
} catch {
    Write-Warn "主源安装失败,回退官方源重试..."
    try {
        pip install chromadb openai --timeout 120 | Out-Null
        Write-Info "安装成功(官方源)"
    } catch {
        Write-Err "安装失败。请手动执行:"
        Write-Host "  pip install chromadb openai -i https://pypi.tuna.tsinghua.edu.cn/simple"
        Write-Host "  (海外用户去掉 -i 参数使用官方源)"
        exit 1
    }
}

Configure-Api
Run-Demo -Net $net

Write-Host ""
Write-Host "============================================"
Write-Info "全部完成!"
Write-Host "  演示数据: .\chroma_rag_demo_db\"
Write-Host "  脚本位置: chroma-env\chroma_demo.py"
Write-Host ""
Write-Host "  想用其他 OpenAI 兼容 API?"
Write-Host "  试试云间 API 中转站:https://cloudzone-api.cyou/"
Write-Host "    · OpenAI 兼容 + Anthropic 兼容"
Write-Host "    · 90+ 模型按量计费"
Write-Host "    · 国内直连无需翻墙,香港节点"
Write-Host "    · 价格不足官方两折,0.05x 起"
Write-Host "============================================"

脚本公开源码,欢迎复制给任何 AI 审查。 以上 .sh 和 .ps1 行为一致:检测网络 → 建虚拟环境 → 安装 chromadb + openai → 配置可选 CZ API Key → 运行 Chroma 演示。


本文发布于 清澈解码 CleanResolver.com。本站内容采用 CC BY-NC-SA 4.0 许可。