向量数据库基础与最小检索示例:用 Chroma 找回相似片段

举报
时光不写 发表于 2026/08/27 17:00:13 2026/08/27
【摘要】 前面我们已经把文档切分成带有来源信息的片段,也知道 Embedding 可以把文本变成可比较的向量。下一步是把这些向量保存起来,并在用户提问时快速找出最相近的片段。向量数据库就是为这件事提供的数据层。本篇使用 Chroma 介绍集合、向量、文档和元数据的关系,并用预先写好的小向量完成一次无需模型 API 的本地检索;这样可以先验证检索流程,再接入真正的 Embedding 服务。 向量数据库...

前面我们已经把文档切分成带有来源信息的片段,也知道 Embedding 可以把文本变成可比较的向量。下一步是把这些向量保存起来,并在用户提问时快速找出最相近的片段。向量数据库就是为这件事提供的数据层。本篇使用 Chroma 介绍集合、向量、文档和元数据的关系,并用预先写好的小向量完成一次无需模型 API 的本地检索;这样可以先验证检索流程,再接入真正的 Embedding 服务。

向量数据库解决什么问题

普通数据库擅长精确条件,例如 section = '安装'id = 42。向量数据库则保存高维向量,并根据距离寻找“最相似”的记录。文本经过同一个 Embedding 模型编码后,意思相近的片段通常会落在向量空间中较近的位置,因此“如何配置缓存”可以召回没有使用完全相同词语的“缓存参数设置”。

一个最小记录通常有四部分:唯一的 id,用于相似度计算的 embedding,便于阅读或最终交给模型的 document,以及来源、版本、权限等 metadata。向量数据库的职责是存储、建立索引和返回候选片段;它不会自动判断答案是否正确,也不会替代权限检查和最终生成。

本篇选用 Chroma 的本地持久化客户端。官方 Python API 提供 PersistentClientget_or_create_collectionaddquery 等接口,适合先在单机上理解数据流。代码显式传入向量,不依赖默认 Embedding 模型下载,因此示例可以离线运行。

安装与最小检索程序

在项目自己的虚拟环境中安装依赖:

python -m venv .venv
source .venv/bin/activate
python -m pip install -U chromadb

下面的向量是教学用的二维坐标:第一维粗略表示“部署/运维”,第二维粗略表示“接口/开发”。真实项目不能手工指定它们,而应使用同一个 Embedding 模型编码入库文本和查询文本。

from pathlib import Path
import shutil

import chromadb


DB_PATH = Path("./chroma-demo")
if DB_PATH.exists():
    shutil.rmtree(DB_PATH)  # 仅为让示例每次从空库开始

client = chromadb.PersistentClient(path=str(DB_PATH))
collection = client.get_or_create_collection(name="notes")

collection.add(
    ids=["note-1", "note-2", "note-3"],
    embeddings=[
        [0.95, 0.10],  # 部署配置
        [0.10, 0.95],  # Python 接口
        [0.80, 0.25],  # 运维排错
    ],
    documents=[
        "生产环境应通过环境变量加载数据库连接配置。",
        "Python 程序可以使用上下文管理器管理文件资源。",
        "服务异常时先检查日志、端口和最近一次配置变更。",
    ],
    metadatas=[
        {"topic": "deployment", "source": "ops.md"},
        {"topic": "python", "source": "python.md"},
        {"topic": "operations", "source": "troubleshooting.md"},
    ],
)

result = collection.query(
    query_embeddings=[[0.90, 0.15]],
    n_results=2,
)

for doc_id, text, distance, metadata in zip(
    result["ids"][0],
    result["documents"][0],
    result["distances"][0],
    result["metadatas"][0],
):
    print(f"{doc_id} distance={distance:.3f} {metadata['source']}: {text}")

运行脚本后,返回的两个候选应优先接近第一条和第三条记录。这里的 distance 是距离,通常数值越小表示越相近;不要把它直接当成百分比或“答案正确率”。返回结果按相似度排序,外层列表对应一次查询,内层列表对应这次查询的 n_results 条结果。

PersistentClient 会把数据写入指定目录,所以进程退出后仍可重新打开。get_or_create_collection 避免重复初始化集合;add 要求每条记录有稳定且不重复的 ID。生产导入时,建议使用文档版本或内容哈希生成 ID,这样可以明确处理更新和去重,而不是随机生成后无法定位旧数据。

从示例向真实 Embedding 过渡

实际流程可以拆成四步:先读取原文并按上一课的规则切分;再调用 Embedding API 为每个片段生成向量;把向量、正文和元数据批量写入集合;收到用户问题后,用同一个模型生成查询向量并调用 query。入库和查询必须使用相同的向量空间,不能用模型 A 写入、模型 B 查询而不做迁移验证。

本地原型可以显式传入 embeddings,从而完全控制向量化过程;如果让 Chroma 根据 documents 自动生成向量,则要确认当前客户端使用的 Embedding 函数、模型文件和网络行为,并在部署环境中固定版本。无论选择哪种方式,都应把模型名称、维度和版本记录到集合或数据处理配置中。向量维度不一致时,写入或查询会失败;模型升级后也不应悄悄混用新旧向量。

检索结果交给生成模型前,还要做两项工作。第一,按租户、权限和文档版本过滤元数据,不能先召回敏感内容再让模型“自行忽略”。第二,保留 source、章节和片段序号,最终回答时展示可追溯引用。向量检索只是召回候选,不是事实核验;对关键业务仍应增加阈值、重排或人工确认。

常见问题

为什么不用关键词搜索? 关键词搜索对专有名词、错误码和精确短语很有优势,向量搜索对改写和同义表达更有优势。实际系统常把两者结合,而不是认为向量检索可以替代所有搜索。

n_results 设置得越大越好吗? 不是。结果太少可能漏掉证据,太多会带入噪声并占用上下文。应使用一组已知问题和期望片段测试召回数量,再决定默认值。

为什么相似片段没有被召回? 先确认入库文本与查询文本经过同一模型编码,再检查切分边界、元数据过滤、距离度量和查询向量维度。不要一看到错误答案就直接改提示词,召回阶段可能根本没有提供正确片段。

示例为什么删除数据库目录? 为了让脚本重复运行时结果确定。真实程序不应在启动时删除持久化目录,而应使用稳定集合名、稳定 ID 和明确的增量更新策略。

小结

向量数据库的核心不是“替模型回答”,而是保存向量及其可追溯信息,并按距离返回相似候选。本文用 Chroma 的本地持久化客户端完成了创建集合、写入向量、保存元数据和查询结果的最小闭环。教学向量验证的是数据库操作流程;接入真实项目时,还要补上统一的 Embedding 模型、版本管理、权限过滤、召回评估和引用展示。下一步可以在此基础上学习如何构建一个完整的本地 RAG 问答程序。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。