“搞了10年软件测试,我以为自己见多识广。直到第一次用ChromaDB做语义检索,看着它从2万字的文档里精准捞出答案,我才意识到:传统关键词搜索,真的老了。”
一、为什么测试工程师需要懂向量数据库?
自己搭建知识库项目,要求能从产品手册里自动找答案。我第一反应是:用Elasticsearch做全文检索呗。
结果demo一出来,直接摇头:
- 用户问"怎么退款",搜出来的是"退款政策在第3章"
- 用户问"钱什么时候到账",搜出来的是"财务流程说明"
关键词匹配,不懂人话。
向量数据库的核心价值就在这儿——它存储的不是文字本身,而是文字的"意思"。两个句子只要语义相近,即使用词完全不同,也能被找出来。
ChromaDB是目前最轻量、最易上手的向量数据库之一。不用搭集群,不用配环境,pip install就能跑起来。
二、ChromaDB核心概念(3个必须搞懂)
1. Collection(集合)
可以理解为关系型数据库里的"表"。一个collection存一类数据,比如"产品手册"、“用户FAQ”。
2. Embedding(嵌入向量)
把文字变成一串数字。这串数字的神奇之处在于:语义相近的文字,它们的数字串也相近。
ChromaDB本身不做向量化,需要调用OpenAI、阿里通义等Embedding模型。
3. Similarity Search(相似度检索)
用户提问 → 转成向量 → 在数据库里找最相近的向量 → 返回对应原文。
整个过程就是"找意思最接近的"。
三、实战代码解析
我写了两个版本的代码,分别对应两种典型场景。
场景一:长文档问答系统
第一个脚本解决的是:如何把一篇长文档(比如2万字的DeepSeek百科)切成块,存入向量库,然后回答用户问题。
python# 核心类:封装ChromaDB操作classMyVectorDBConnector:def__init__(self, collection_name):# 内存模式,数据不持久化 chroma_client = chromadb.Client(Settings(allow_reset=True))# 如需持久化,改用:# chroma_client = chromadb.PersistentClient(path="./chroma_data")self.collection = chroma_client.get_or_create_collection( name=collection_name, metadata={'hnsw:space': 'l2'} # 相似度算法:l2/cosine/ip )
关键设计1:文档切分
大模型有上下文限制,不能把2万字一次性塞进去。需要用RecursiveCharacterTextSplitter做智能切分:
pythonsplitter = RecursiveCharacterTextSplitter( chunk_size=500, # 每块500字 chunk_overlap=50, # 重叠50字,避免断句 separators=["\n\n", "\n", "。", "?", ",", ""])
切分策略有讲究:优先按段落(\n\n),其次按句子(。),保证语义完整。
关键设计2:批量向量化
Embedding API有调用限制,不能一股脑全扔过去。需要分批处理:
pythondefget_embeddings_batch(self, texts, batch_size=10): all_embeddings = []for i inrange(0, len(texts), batch_size): batch = texts[i:i+batch_size] data = self.client.embeddings.create(input=batch, model=model).data all_embeddings.extend([x.embedding for x in data])return all_embeddings
关键设计3:RAG流程组装
检索到相关文档后,拼成prompt喂给大模型:
pythonprompt = f"""你是一个问答机器人。根据下述已知信息回答用户问题。如果已知信息不足以回答,请直接回复"我无法回答"。已知信息:{contents}用户问:{user_query}"""
这就是经典的RAG(检索增强生成)模式。
场景二:问答对检索
第二个脚本处理的是另一种常见场景:有一堆"问题-答案"对,用户问新问题,找出最相似的历史问题,直接返回答案。
python# 数据格式:instruction(问题)+ output(答案)data = json.loads(line)instructions = [d['instruction'] for d in data] # 需要向量化的查询字段outputs = [d['output'] for d in data] # 对应的答案# 存入向量库vector_db.add_documents(instructions, outputs)
注意这里的设计:只对instruction做向量化,但存储的是output。这样检索时按问题匹配,返回的是答案。
四、踩坑记录
坑1:维度不一致报错
第一次运行时报了Dimensionality of vectors does not match。查了半天发现:创建collection时没指定维度,但不同Embedding模型输出的维度不一样(通义是1536维,我代码里写了64维)。
解决:要么统一模型,要么在metadata里指定维度。
坑2:内存模式数据丢失
调试时重启了脚本,发现之前存的数据没了。才想起来用的是chromadb.Client()内存模式,进程结束数据就没了。
解决:正式环境一定要用PersistentClient持久化到磁盘。
坑3:相似度阈值调优
刚开始检索结果总是不太准,查出来一堆无关内容。后来发现是n_results设得太大(默认10),其实前3条最准,后面的都是干扰。
解决:根据业务场景调整top_k,不是越大越好。
五、性能与成本考量
ChromaDB的优势在于轻量。单机版能撑百万级向量,响应毫秒级。对于中小项目,完全够用。
六、思考总结
搞完这个项目,我对"测试工程师学AI"有了新理解:
不是要去搞算法,而是要懂工程化。
向量数据库、文档切分、RAG流程——这些都不是AI算法,而是把AI能力落地的基础设施。测试工程师的优势在于:我们懂业务、懂数据、懂异常场景。把这些能力迁移到AI项目,比从头学Transformer架构更实际。
ChromaDB只是起点。生产环境可能会换Milvus、Pinecone,但核心逻辑是一样的:向量化 → 存储 → 相似度检索。
搞懂这一套,你就迈出了从"传统测试"到"AI测试"的第一步。
互动问题
你在工作中遇到过"关键词搜索找不到答案"的痛点吗?有没有试过向量检索方案?欢迎在评论区聊聊。
我是大熊,一个正在转型AI的测试老兵。记录真实的踩坑经历,分享能落地的工程经验。