本文记录一次完整的本地向量检索实验,使用 ChromaDB 存储中文文档切片,BGE embedding 模型编码语义,并测量检索准确率与延迟。代码、数据和指标均可复现。

实验环境

软件版本:

  • Python 3.11.15
  • ChromaDB 1.5.9
  • sentence-transformers 6.1.0
  • BAAI/bge-small-zh-v1.5 (HuggingFace 中文 embedding 模型)

配置:

  • 距离度量: cosine (余弦相似度)
  • 文档切片: chunk_size=300, overlap=50
  • 测试文档: 3 个中文 TXT 文件,共 1262 字符,切分为 6 个 chunk

文档准备与向量化

实验使用 3 个中文文本文件,内容涵盖深度学习、向量数据库和评估方法:

doc1.txt: 349 字符 → 2 chunks
doc2.txt: 466 字符 → 2 chunks
doc3.txt: 447 字符 → 2 chunks

切片策略: 固定 300 字符窗口,50 字符重叠,保留上下文连续性。

Embedding 耗时: 78.8 ms (6 个 chunk 的向量化时间)
总 Ingestion 耗时: 159 ms (包括文件读取、切片、向量化和写入 ChromaDB)

检索测试

可回答问题 (4 个)

查询 预期文档 Top-1 Top-3 距离 延迟
什么是检索增强生成? doc2.txt doc3.txt ✗ doc3, doc2, doc3 ✓ 0.4955, 0.5150, 0.5185 11.15 ms
Transformer 的核心组件是什么? doc1.txt doc1.txt ✓ doc1, doc2, doc2 ✓ 0.4473, 0.5736, 0.5769 8.16 ms
评估检索系统的常用指标有哪些? doc3.txt doc3.txt ✓ doc3, doc3, doc2 ✓ 0.3126, 0.4240, 0.5028 8.85 ms
中文文本适合用什么 embedding 模型? doc2.txt doc2.txt ✓ doc2, doc2, doc1 ✓ 0.3269, 0.4381, 0.5067 8.42 ms

实测指标 (基于 6 chunks 的小样本):

  • Top-1 准确率: 3/4 = 75%
  • Top-3 召回率: 4/4 = 100%
  • 平均查询延迟: 9.14 ms

不可回答问题 (1 个)

查询 "deepseek-flash 的推理延迟是多少?" 在文档集中无答案,检索返回 Top-3 上下文供后续生成模型判断拒答。

重要声明: 上述指标为 6 个切片的观察值,样本量极小,不可外推为生产性能。真实应用需要在目标数据规模和查询分布上重新测量。

完整代码

以下是可直接运行的实验脚本 (需提前准备 ./docs/*.txt):

#!/usr/bin/env python3
import sys, time, json, hashlib
from pathlib import Path
from datetime import datetime
import chromadb
from chromadb.utils import embedding_functions

def chunk_text(text, chunk_size=300, overlap=50):
    chunks, start, chunk_idx = [], 0, 0
    while start < len(text):
        end = start + chunk_size
        chunk = text[start:end]
        if chunk.strip():
            chunks.append({'text': chunk.strip(), 'start': start,
                          'end': min(end, len(text)), 'index': chunk_idx})
            chunk_idx += 1
        start += chunk_size - overlap
    return chunks

# 配置 BGE 中文 embedding
embedding_fn = embedding_functions.SentenceTransformerEmbeddingFunction(
    model_name="BAAI/bge-small-zh-v1.5"
)

# 初始化 ChromaDB
run_id = hashlib.md5(str(time.time()).encode()).hexdigest()[:8]
client = chromadb.PersistentClient(path=f"./chroma_db_{run_id}")
collection = client.create_collection(
    name="rag_docs",
    metadata={"hnsw:space": "cosine"},
    embedding_function=embedding_fn
)

# 加载文档并切片
all_chunks, all_ids, all_metadatas = [], [], []
for doc_file in sorted(Path("./docs").glob("*.txt")):
    content = open(doc_file, encoding='utf-8').read()
    for chunk_info in chunk_text(content):
        all_chunks.append(chunk_info['text'])
        all_ids.append(f"{doc_file.stem}_chunk_{chunk_info['index']}")
        all_metadatas.append({"source": doc_file.name})

# 添加到 ChromaDB
collection.add(documents=all_chunks, ids=all_ids, metadatas=all_metadatas)

# 查询测试
for q in [
    {"question": "什么是检索增强生成?", "expected": "doc2.txt"},
    {"question": "Transformer 的核心组件是什么?", "expected": "doc1.txt"},
]:
    result = collection.query(query_texts=[q['question']], n_results=3)
    sources = [m['source'] for m in result['metadatas'][0]]
    print(f"查询: {q['question']}")
    print(f"  Top-1: {sources[0]} ({'✓' if sources[0]==q['expected'] else '✗'})")

依赖安装:

pip install chromadb sentence-transformers

检索阶段的局限

  1. 模型 revision 未固定: 使用最新版本,HuggingFace 模型更新可能导致向量不可复现
  2. 小样本: 6 个 chunk 仅供观察原理,指标不代表生产性能
  3. 查询分布: 4 个人工构造的问题无法覆盖真实搜索场景

生成阶段 (未执行)

检索完成后,可将 Top-K 上下文拼接并提交给大语言模型生成答案。典型流程:

from openai import OpenAI

# 检索上下文
result = collection.query(query_texts=["用户问题"], n_results=3)
contexts = result['documents'][0]

# 调用 LLM
client = OpenAI(api_key="YOUR_KEY", base_url="https://api.deepseek.com")
response = client.chat.completions.create(
    model="deepseek-chat",
    messages=[{"role": "user", "content": f"根据上下文回答:\n{contexts}"}]
)
print(response.choices[0].message.content)

注意: 本次实验未配置 API Key,生成阶段未运行。上述代码仅为接入示例,未经实测验证。

可复现性

完整实验代码和结果:

  • run_canonical.py - 实验脚本
  • results_79732dd2.json - 原始结果
  • report_79732dd2.md - 实验报告

下一步

  1. 扩大文档集: 从 6 chunks 扩展到数百或数千
  2. 固定模型版本: 锁定 embedding 模型的 commit hash
  3. 切片策略对比: 测试不同参数对检索准确率的影响
  4. 生成质量评估: 评估 LLM 拒答行为和答案质量
  5. 混合检索: 结合 BM25 等稀疏检索方法

参考资料

  • ChromaDB 文档: https://docs.trychroma.com/
  • BGE Embedding: https://huggingface.co/BAAI/bge-small-zh-v1.5
  • sentence-transformers: https://www.sbert.net/

实验说明: 本文所有数据和指标来自单次本地实验 (Run ID: 79732dd2),环境、配置和结果均已记录。检索阶段完整运行,生成阶段因无 API Key 未执行。

EOF · 全文完 未分类 · · 共 1.2k 字

感谢耐心读到这里。若这篇文字曾带来片刻启发或共鸣,不妨点亮喜欢或分享给同路人。

喜欢 0
DISCUSSION / 读者评论 0 条评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注