向量数据库与RAG实战:用Chroma搭建AI知识库

发布时间:2026/8/26 8:28:48
向量数据库与RAG实战:用Chroma搭建AI知识库 先说一个普遍遇到的场景公司内部有两百份运维文档当同事问“电脑蓝屏怎么办”时传统站内搜索往往会返回标题或正文里刚好包含“蓝屏”字样的结果而像“系统崩溃”“开机黑屏”“dump文件”这类语义接近但字面不同的提问经常什么都搜不到。这就是关键词检索的“词不达意”问题。要让机器理解问题背后的意图而不是单纯匹配字符就涉及 Embedding、向量数据库、语义搜索和 RAG 这一整套技术栈。本文会把这几个概念串起来讲明白并提供一个可以直接跑通的 Python 实战示例帮你快速搭出一个 AI 知识库的最小系统。1. 为什么需要向量数据库传统搜索的瓶颈1.1 传统关键词搜索无法解决的语义问题传统搜索引擎和数据库的检索方式本质上是“字符串匹配”。你输入一个词系统在数据中找出包含这个词的文本。这个方案对精确查询有效但面对真实业务场景时问题很明显同义词无法关联。用户搜“工资怎么算”文档里写的是“薪酬计算规则”字面不匹配。表达方式无法对齐。用户问“如何重置密码”文档里写的是“修改登录凭证并重新初始化”字面差异很大。多语言、口语化文本难以处理。“咋登录不上去”“Connection failed”可能描述同一件事但关键词匹配完全失效。短查询容易出噪音。输入“Java 内存”返回的结果可能包含大量无关内容因为没有理解用户想找的是内存模型、内存泄漏还是 JVM 参数。传统方案也能通过分词、同义词词典、布尔查询做一定程度的增强但这种方式维护成本高且无法覆盖变化的、模糊的自然语言表达。当我们要构建的是 AI 知识库、智能客服、企业问答系统时检索就必须从“字面匹配”升级为“语义匹配”。1.2 向量数据库的核心能力向量数据库并不是一个全新的数据库种类而是一类专门为“存储向量 计算相似度”而优化的数据库。它的核心工作方式是把文本、图片、音视频等数据通过 Embedding 模型转化为高维向量。将向量连同原始数据、元数据一起存储。用户查询时也把查询语句转化为向量。数据库基于向量距离返回最相似的前 N 条数据。相比普通数据库向量数据库在索引结构和距离计算上做了大量优化。它能支撑数百万甚至数十亿级别的向量检索并提供毫秒级响应。常见的索引算法包括 HNSW、IVF、PQ 等本文后面会结合实战解释。向量数据库解决的不只是“换个搜索方式”它让数据能被大模型理解和引用。这也是 RAG 技术能落地的基础之一。1.3 AI知识库技术栈总览一个完整的 AI 知识库系统通常由四层组成数据层原始文档、数据库记录、网页内容。向量化层Embedding 模型负责把数据转换为向量。存储检索层向量数据库存储向量并支持快速检索必要时配合关键词检索做混合召回。生成层大语言模型接收检索到的上下文生成最终答案。围绕这一技术栈我们可以看到很多相关名词Embedding、语义搜索、RAG、向量数据库选型、Agentic RAG、GraphRAG 等。它们不是相互独立的概念而是一条流水线上的不同环节。后续章节会逐个拆开讲。2. 彻底搞懂Embedding2.1 Embedding的本质Embedding 翻译成中文常称为“嵌入”或“向量化”。它做的事情是把文字、图片等非结构化数据映射到一组实数数组也就是向量。例如一句话“系统启动失败”可能被转换成一个 768 维或 1024 维的向量[0.012, -0.034, 0.087, ..., 0.056]这个向量不是随便生成的它是 Embedding 模型根据大量语料训练出来的结果。向量的空间位置包含了语义信息语义相近的文本在向量空间中的距离更近语义无关的文本距离较远。我们可以这样理解普通数据库保存的是“文本本身”向量数据库保存的是“文本的意思”。这个区别看起来简单但它是语义搜索和大模型知识库的根基。2.2 Embedding是怎么生成的Embedding 模型有很多种。常见的有BGE 系列如 BAAI/bge-small-zh、BAAI/bge-m3中文语义理解表现稳定。OpenAI 的 text-embedding 系列。其他开源模型text2vec、m3e、GTE 等。以 BGE-M3 为例它支持长文本、多语言和多种检索方式适合中英文混合的知识库场景。实际项目中模型的选择取决于语言、领域、硬件资源和成本。使用 Python 加载一个文本 Embedding 模型通常只需要几行代码。以 sentence-transformers 为例from sentence_transformers import SentenceTransformer model SentenceTransformer(BAAI/bge-small-zh-v1.5) text 系统启动失败 vector model.encode(text) print(vector.shape) print(vector[:10])运行这段代码会输出向量的维度以及向量前 10 个数值。这里需要注意的是模型首次加载会从网络下载权重具体大小取决于模型版本建议在项目初始化阶段预先下载并缓存。2.3 向量相似度如何计算向量存储好之后如何判断“相似”最常用的是余弦相似度和欧氏距离。余弦相似度计算的是两个向量之间的夹角取值范围在 -1 到 1 之间值越大表示方向越一致、语义越接近。欧氏距离计算的是向量在高维空间中的直线距离距离越小越相似。在实际向量数据库中我们通常会在创建集合时指定距离函数。例如使用余弦相似度还是内积还是欧氏距离。选择哪种取决于 Embedding 模型训练时的归一化方式。大多数情况下余弦相似度是比较稳妥的默认选择。一个直观的类比把“苹果”“香蕉”“汽车”想象成三维空间中的点。“苹果”和“香蕉”距离很近因为它们同属水果“汽车”则离它们很远。高维向量空间也是同理只是无法直接可视化了。3. 语义搜索向量检索的核心场景3.1 语义搜索工作流程语义搜索不是传统搜索的替代品那么简单。它与 RAG 知识库结合后工作流程通常如下预处理把文档按结构或固定大小切块。离线向量化用 Embedding 模型把每个文本块转换成向量。写入向量库保存向量、文本内容、来源路径、标题等元数据。在线检索用户输入问题后对问题做同样的向量化。相似度召回向量数据库返回与问题最相似的前 K 个文本块。后处理排序可选的 Rerank 环节对召回结果做更精细的排序。在很多生产系统中第 6 步非常重要。召回阶段为了速度往往只做粗略筛选Rerank 模型会结合用户问题与候选文档做交叉编码打分进一步修正排队顺序。3.2 语义搜索与关键词搜索的对比为了更直观地理解我们把两种方式放到一起对比维度关键词搜索语义搜索匹配基础字面字符语义向量同义词处理依赖词典模型天然支持多语言理解困难跨语言模型可处理索引难度较低需要向量化流程适合场景精确查询、代码搜索问答、知识库、智能推荐需要说明的是这两者并不是互斥的。企业知识库往往采用“关键词 向量”的混合检索方式先用关键词召回精确匹配结果再用向量召回语义相似结果最后用 Rerank 模型统一排序。这样能兼顾精确性和模糊语义理解。3.3 影响检索效果的关键点语义搜索的效果不只看向量数据库本身以下几个因素往往影响更大Embedding 模型是否适合当前语言和领域。中文场景用英文原版模型效果通常差一截。切块粒度是否合理。块太大语义混杂块太小上下文不完整。是否保留了结构信息。切块时直接切在正文中间可能把标题和正文内容分开。召回数量设置。返回太少容易漏返回太多容易引入噪音。很多刚接触向量数据库的开发者第一反应是换更强的模型但实际操作中“切块策略不合理”是更常见的原因。4. RAG大模型如何借助知识库回答4.1 为什么大模型需要RAG大语言模型虽然知识丰富但有几个明显问题知识有截止日期无法自动获取最新信息。企业内部私密知识不在训练数据中。对精确数据、数字、事件细节容易编造。长尾业务问题容易出现“一本正经地胡说”。RAG全称 Retrieval-Augmented Generation也就是检索增强生成。核心思路是不直接让大模型硬答而是先从知识库中检索出相关内容把它拼进提示词让大模型基于这些资料作答。这样做的好处很多答案有据可依降低幻觉可以及时更新知识库而不用重新训练模型还能在回答中附上来源方便用户溯源验证。4.2 RAG的核心链路一个最小可用的 RAG 系统包含以下环节文档导入与切块。Embedding 向量化入库。用户问题向量化。向量库检索 Top-K 文档。将文档拼接到 Prompt 中。大模型生成回答。从第 3 步到第 6 步是在线链路延迟要求较高第 1、2 步是离线准备可以批量执行。目前社区也出现了 Agentic RAG、GraphRAG 等进阶形态。Agentic RAG 让大模型自主决定检索什么、检索几次、是否追问GraphRAG 则把知识图谱与向量检索结合处理多跳关系和全局性问题。但无论形态怎么变底层的检索与生成框架仍是核心。4.3 向量数据库在RAG中的角色在 RAG 链路中向量数据库承担的是“记忆存储”的作用。大模型本身没有长期记忆也没有项目专属知识向量数据库补上的正是这个缺口。可以这样理解向量数据库不是给用户搜索用的后台系统而是给大模型提供“外部资料”的检索层。它决定了模型能看到哪些信息从而直接决定回答质量。如果检索阶段返回的内容不相关那么再强的大模型也答不出好东西。因此“检索质量 向量数据库性能 Embedding模型质量 切块策略 排序策略”这个公式是 RAG 工程优化的基本框架。5. 向量数据库选型从轻量到生产5.1 常见向量数据库对比目前向量数据库生态已经非常丰富不同定位各有侧重数据库定位适合场景Chroma轻量级嵌入式向量库本地开发、学习原型、小型知识库Milvus / Zilliz Cloud大规模分布式向量库生产环境、海量向量检索Qdrant向量检索服务中小规模生产部署Weaviate带模式定义的向量搜索需要丰富元数据过滤的场景pgvectorPostgreSQL 扩展已有 PostgreSQL 体系需要复用Elasticsearch全文搜索引擎扩展向量能力已有 ES 体系需要混合检索这里并没有“哪个最好”的答案。开源与云服务版本也在持续迭代选择前需要结合团队技术栈、数据规模、运维能力综合判断。5.2 选型建议如果你只是学习 RAG、验证想法Chroma 是最低门槛的选择。它安装简单可以直接嵌入 Python 进程数据存在本地文件免去部署服务器的时间。如果你的知识库文档数量达到百万级或需要高并发查询建议关注 Milvus、Qdrant 这类独立向量数据库服务。它们的索引构建、分片、副本管理更成熟。如果你已经在使用 PostgreSQL且数据量不大可以先用 pgvector 验证效果避免引入额外中间件。但要注意向量检索与业务查询混在同一个数据库资源竞争问题需要提前评估。如果你的搜索场景本身就有大量关键词查询需求还需要同时支持向量检索可以考虑 Elasticsearch 的向量能力统一检索入口。5.3 引入前要评估的维度真正做技术选型时要从以下维度评估数据规模向量条数、每个向量的维度。查询并发QPS 要求。过滤需求是否频繁按来源、类型、时间过滤。运维复杂度能否接受额外部署一个数据库服务。数据更新频率是离线批量导入还是频繁增量更新。技术栈契合度团队成员是否熟悉该工具的 API 和生态。选型没有绝对标准核心是“在可维护的前提下先跑通最小系统再根据瓶颈演进”。6. 实战用Chroma搭建一个AI知识库检索系统6.1 环境准备本文示例将以 Python 3.9 环境为例使用了以下依赖chromadb轻量级向量数据库。sentence-transformers加载本地 Embedding 模型。安装命令如下pip install chromadb sentence-transformers注意sentence-transformers 会依赖 PyTorch安装体积较大。如果你的机器不方便安装也可以改用其他 Embedding 服务只需在代码中替换 Embedding 函数即可。本文示例中我们使用 BGE 中文模型演示中文知识库场景。版本方面chromadb 和 sentence-transformers 迭代较快建议以你安装时官方文档的最新稳定版本为准。6.2 项目结构一个最小项目可以这样组织ai_kb/ ├── docs/ # 原始文档目录 │ ├── 运维手册.md │ └── 产品常见问题.md ├── vector_store/ # Chroma 持久化目录 ├── chunk.py # 文档读取与切块 ├── build_index.py # 向量化入库脚本 ├── search.py # 语义检索脚本 └── rag_answer.py # RAG 问答脚本6.3 文档读取与切块切块是决定语义检索质量的重要环节。下面实现一个简单的文档加载和切块函数# 文件路径chunk.py from pathlib import Path def load_docs_from_dir(dir_path: str): docs [] for path in Path(dir_path).glob(*.md): docs.append({ path: str(path), text: path.read_text(encodingutf-8) }) return docs def chunk_text(text: str, chunk_size: int 200, overlap: int 50): 按固定字符长度切块overlap 是相邻块之间的重叠字符数。 重叠部分能减少切在语义边界导致的上下文丢失问题。 if chunk_size 0: raise ValueError(chunk_size 必须大于 0) if overlap chunk_size: raise ValueError(overlap 必须小于 chunk_size) chunks [] start 0 while start len(text): end start chunk_size chunks.append(text[start:end]) if end len(text): break start chunk_size - overlap return chunks这里需要注意按固定长度切分是通用兜底方案。对中文文档按字符切分比较直接对英文文档建议基于句子或段落切分避免把单词从中间断开。如果文档自带 Markdown 标题结构可以按二级标题或章节切块效果通常更好。6.4 生成Embedding并写入向量库将文本切块后接下来生成向量并写入 Chroma。Chroma 的常用写法如下# 文件路径build_index.py import chromadb from chromadb.utils.embedding_functions import SentenceTransformerEmbeddingFunction from chunk import chunk_text, load_docs_from_dir client chromadb.PersistentClient(path./vector_store) embedding_fn SentenceTransformerEmbeddingFunction( model_nameBAAI/bge-small-zh-v1.5 ) collection client.get_or_create_collection( nameit_kb, embedding_functionembedding_fn, metadata{hnsw:space: cosine} ) docs load_docs_from_dir(./docs) ids [] documents [] metadatas [] for doc in docs: chunks chunk_text(doc[text], chunk_size200, overlap50) source_name doc[path].replace(.md, ).replace(\\, /) for idx, chunk in enumerate(chunks): ids.append(f{source_name}#{idx}) documents.append(chunk) metadatas.append({ source: doc[path], chunk_index: idx, length: len(chunk) }) collection.upsert( idsids, documentsdocuments, metadatasmetadatas ) print(f写入完成共 {len(ids)} 个文本块)这里有几个关键点PersistentClient(path./vector_store)表示数据会持久化到本地目录。get_or_create_collection第一次运行创建集合之后重复运行会复用。metadata{hnsw:space: cosine}指定索引空间为余弦相似度适合文本语义检索。upsert按 id 插入或更新重复执行不会产生重复数据。运行入库脚本python build_index.py如果没有报错输出如下写入完成共 27 个文本块具体块数取决于你的文档长度和切块参数。6.5 语义检索测试入库后我们可以写一个检索脚本验证效果# 文件路径search.py import chromadb from chromadb.utils.embedding_functions import SentenceTransformerEmbeddingFunction client chromadb.PersistentClient(path./vector_store) embedding_fn SentenceTransformerEmbeddingFunction( model_nameBAAI/bge-small-zh-v1.5 ) collection client.get_or_create_collection( nameit_kb, embedding_functionembedding_fn ) query 电脑蓝屏怎么解决 results collection.query( query_texts[query], n_results3 ) for i, doc in enumerate(results[documents][0]): metadata results[metadatas][0][i] print(f\n第 {i 1} 条结果来源{metadata[source]}) print(doc)运行后会输出与问题最相似的三个文本块。如果你输入的文档中包含“蓝屏”“系统崩溃”等内容即使问题里没有出现这些精确字样向量检索也能把它们召回。这种能力本质上来自 Embedding 模型的语义理解而不是向量数据库本身。但向量数据库保证了高维空间中的检索效率。6.6 对接大模型一个最小RAG问答实现有了检索结果再接入大模型就构成了一个最小 RAG 问答链路。下面以 OpenAI 兼容接口为例你可以把base_url和api_key替换成自己使用的模型服务# 文件路径rag_answer.py import chromadb from chromadb.utils.embedding_functions import SentenceTransformerEmbeddingFunction from openai import OpenAI # 1. 检索 client chromadb.PersistentClient(path./vector_store) embedding_fn SentenceTransformerEmbeddingFunction( model_nameBAAI/bge-small-zh-v1.5 ) collection client.get_or_create_collection( nameit_kb, embedding_functionembedding_fn ) query 电脑蓝屏怎么解决 results collection.query(query_texts[query], n_results3) context \n\n.join(results[documents][0]) # 2. 构造提示词 prompt f你是一个企业知识库助手。请基于下面的资料回答用户问题。 如果资料中没有答案请直接说“知识库中未找到相关信息”不要编造。 资料 {context} 问题{query} # 3. 调用大模型 llm OpenAI( api_keysk-your-api-key, base_urlhttps://your-model-endpoint ) resp llm.chat.completions.create( modelyour-model-name, messages[ {role: system, content: 回答要准确、简洁并尽量给出依据。}, {role: user, content: prompt} ], temperature0.2 ) print(resp.choices[0].message.content)运行说明你需要先在环境变量或代码中配置可用的模型服务。如果你使用的是 OpenAI 官方服务需要自行确认网络与账户权限如果使用国内大模型平台通常也提供 OpenAI 兼容接口把base_url和model换成对应值即可。到这里一个“文档切片 → 向量化 → 相似度检索 → 上下文增强 → 大模型回答”的最小 RAG 系统就完成了。7. 常见问题与排查思路7.1 高频问题清单问题现象常见原因解决思路检索结果不相关切块太大块内包含多主题缩小 chunk_size或按章节、段落切块中文效果差使用了英文预训练模型换成 bge-small-zh、bge-m3 等中文模型模型下载失败网络环境无法访问模型仓库提前下载模型权重到本地或使用模型推理服务查询速度慢数据量大且未优化索引参数调整 HNSW 参数增加元数据过滤条件更新文档后仍检索到旧内容旧向量未删除upsert id 不固定使用稳定且唯一的文档块 id并清理旧节点返回结果中同一篇文档占据多个名额相邻文本块重复度高按 source 对结果做去重或降低 overlap接入大模型后回答仍然不对检索本身不准确prompt 设计不够清晰先单独检查检索结果再分析 prompt 问题7.2 排查思路遇到“回答不对”的问题不要先怀疑大模型先按下面顺序排查打印检索结果看返回的上下文是否相关。如果检索结果不相关检查切块策略和 Embedding 模型。如果检索结果相关但回答错误检查 Prompt 是否明确要求“仅基于资料回答”。如果回答中包含大量无关信息考虑增加 Rerank 环节或减少 Top-K。如果是性能问题检查是否有慢查询、索引是否生效、数据分布是否倾斜。关键理念是RAG 系统是“检索 生成”的流水线上游的检索质量决定了下游回答质量的上限。因此不建议跳过检索效果直接调 Prompt。8. 最佳实践与工程建议8.1 切块策略最容易被忽视的一环切块是 RAG 项目中最容易踩坑的地方。经验上可以遵循几个原则优先按文档结构切块。Markdown 的二级标题、HTML 的段落标签都是天然的边界。固定大小切块时保留 10% 到 20% 的重叠降低切断语义的风险。块大小需要考虑 Embedding 模型的输入上限。BGE 系列通常可以接受较长的文本但超长输入会稀释语义。对 FAQ 型文档最好以“一问一答”为单位切块不要把多个问题混在一个块里。对超长表格或代码块需要单独处理不要与正文混在一起。切块参数没有标准答案需要结合自己的数据做小规模实验。可以在一个测试集上对比不同参数下的召回准确率。8.2 元数据过滤与混合检索向量检索返回结果时不要只返回相似内容还可以充分利用元数据过滤。例如按部门过滤只检索“运维部”的文档。按时间过滤只检索最近 30 天更新的内容。按文档类型过滤区分操作手册、产品 FAQ、会议纪要。在生产环境中建议同时维护关键词索引和向量索引。先用关键词精确筛选再用向量语义召回最后用 Rerank 模型统一排序。这样能兼顾“精确”与“模糊”。8.3 更新、删除与数据一致性知识库不是一次写完就结束的文档会持续更新。要做好文档切块后为每个块生成稳定的 id最好包含文档级版本号。全量更新时先删除旧文档所有分块再写入新分块。增量更新时只对变更文档重新切块和向量化。如果有多个服务同时对同一集合写入需要注意向量数据库的并发一致性能力。如果使用 Chroma 这类嵌入式数据库建议由单一写入方负责索引更新避免并发写冲突。8.4 性能与成本向量检索的性能受多个因素影响索引类型HNSW 在查询速度和构建成本之间比较均衡。向量的维度维度越高占用的内存和计算越多。数据量尽量为低频查询数据添加过滤条件减少候选集。查询并发服务端向量数据库通常比嵌入式库更适合高并发。成本控制方面Embedding 模型的向量化过程通常比大模型推理便宜但当文档量非常大时也需要关注存储成本和离线批处理耗时。8.5 安全与合规企业知识库往往包含敏感信息。接入 RAG 系统时要注意数据脱敏文档入库前先去除身份证号、手机号、密钥等敏感信息。权限控制向量检索接口需要做鉴权不能让用户检索超越权限的文档。日志审计记录用户查询和系统返回结果便于事后追溯。合规审查确认数据存储在合规区域不将敏感数据发送到未批准的模型服务。这里有一条基本原则不要把所有数据无条件塞进一个向量库再通过一个普通接口暴露出来。知识库的权限边界必须在检索层就做好控制不能完全信任 Prompt。9. 总结与学习路线9.1 本文核心要点回顾全文我们需要掌握以下几个关键点向量数据库解决的是“语义相似度检索”问题是 AI 知识库的存储底座。Embedding 是连接自然语言与向量空间的桥梁模型选择会影响检索效果。语义搜索让检索从“字面匹配”升级为“意图匹配”但不能完全替代关键词检索。RAG 通过“先检索、再生成”的方式为大模型提供外部知识减少幻觉。一个最小可用的 AI 知识库可以拆成文档切块、向量化、入库、检索、生成这五个环节。实际项目中切块策略、元数据过滤、混合检索、权限控制往往比换更强的模型更优先。9.2 后续学习方向如果你希望继续深入可以按下面几个方向展开使用 Milvus 等分布式向量数据库把知识库从本地单机扩展到生产环境。引入 Rerank 模型优化召回结果排序。研究 GraphRAG让知识库具备多跳关系推理能力。尝试 Agentic RAG让大模型根据问题自主决定检索策略。了解多模态 Embedding把图片、音频也纳入知识库检索范围。向量数据库和 RAG 的技术迭代很快但核心原理相对稳定。你先跑通本文的最小系统再逐步替换组件、调优参数就能形成一个适合自己业务的 AI 知识库。如果觉得这篇教程对你有帮助欢迎收藏备用后续遇到相关项目可以随时回来对照。