很多人第一次接触“AI 知识库”这个概念时,都会有一个困惑:我明明已经把文档喂给大模型了,为什么它还是答不出来?我自己在最初做客服问答机器人时,也踩过同样的坑。把 PDF、Word、网页内容一股脑丢给大模型,然后问它“如果手机屏幕碎了,保修政策是什么”,模型要么答非所问,要么直接编一个不存在的售后条款。
问题不在大模型,而在我们少做了一层关键工作:把文本转换成计算机能够进行“语义匹配”的形态,也就是向量。而负责管理、检索这些向量的基础设施,就是今天几乎所有 AI 知识库应用都绕不开的向量数据库。
这篇文章会从传统搜索的痛点讲起,把 Embedding、语义搜索、向量数据库、RAG 这四个概念串成一条完整的技术链路。最后会用手写 Python 代码的方式,跑通一个“文档切块 → 向量化 → 入库 → 语义检索 → 大模型回答”的最小 RAG 示例。全文偏实战,适合正在做知识库问答、AI 客服、智能助手,或者想理解 RAG 底层原理的开发者阅读。
1. 为什么要关注向量数据库?先看看传统搜索的痛点
很多人以为向量数据库是一种“更快的关系型数据库”,或者是一个“支持模糊查询的搜索引擎”。这个理解不算全对。向量数据库真正解决的,是传统的关键词匹配在语义理解上的无力和失效。
举一个真实场景。假设客服系统里有一条知识:“碎屏保服务:自签收之日起一年内,因意外跌落导致的屏幕碎裂,可免费维修一次。”如果用户提问是“我的手机不小心摔了,屏幕裂了,还能保修吗?”用传统关系数据库的LIKE '%屏幕%',能查到;但如果你用“误触导致的内屏显示异常算不算外观损坏?”去查,关键词和知识条目几乎没有重合,传统搜索基本束手无策。
更麻烦的是用户的表达习惯。同一个问题,有人会说“申请退款”,有人会说“不想要了,把钱退给我”,还有人会说“七天无理由退货怎么操作”。三者表达不同,语义一致。传统搜索(比如 Elasticsearch 的分词 + BM25)能处理的是“关键词重合”和“词法变体”,它不理解“不想要了”和“退货”是同一个意思。要让系统理解这一点,就得让文本先变成一个“语义坐标”,再通过数学计算比较两条文本的接近程度。这就是 Embedding 和向量检索存在的意义。
所以我的判断是:向量数据库不是来取代传统数据库或搜索引擎的,它补上的是“语义召回”这一层能力。如果你正在做的项目需要处理非结构化文本,并且用户的问题无法用固定关键词覆盖,那么向量数据库几乎是必选项。
2. 基础概念:Embedding、向量与相似度计算
2.1 Embedding 是什么
Embedding 的中文叫“嵌入”,在 NLP 里可以通俗地理解成:把一段文字映射成一个固定长度的数字数组,这个数组就是“向量”。
比如“手机屏幕碎了”经过 Embedding 模型,可能得到这样一个 768 维的向量:
[0.0234, -0.1189, 0.0067, ..., 0.0456] # 长度为768这个数组本身没有直观含义,但它有一个重要特性:语义相近的两句话,转换出来的向量在空间中距离更近;语义无关的文本,向量距离更远。这就像把词汇放到一张多维地图上,“苹果”和“香蕉”靠近,“苹果”和“汽车”远离。Embedding 模型做的是把整个句子放在这样一张“语义地图”上。
给文本做 Embedding 的工具叫 Embedding 模型。中文场景里,目前比较常用的是 BGE 系列,比如BAAI/bge-small-zh-v1.5、BAAI/bge-large-zh-v1.5,以及更新的BAAI/bge-m3。BGE 系列在中文语义匹配上表现较好,也是很多开源项目默认使用的模型之一。实际项目中,也可以直接使用云厂商提供的 Embedding API,比如阿里云百炼平台上的文本向量服务,好处是部署成本低、无需本地 GPU,适合快速验证想法。
2.2 向量之间的距离怎么算
有了向量之后,判断“语义接近”就变成了数学问题。常用的有三种度量方式:
| 度量方式 | 特点 | 常用场景 |
|---|---|---|
| 余弦相似度 | 只关心方向,不受向量长度影响,取值范围 [-1, 1] 或 [0, 1] | 文本语义匹配,最常用 |
| 内积(点积) | 与向量长度相关,适合归一化向量 | 向量已归一化时效率更高 |
| 欧氏距离 | 度量空间中的绝对距离,越小越相似 | 图像、部分推荐场景 |
绝大多数文本向量库默认使用余弦相似度。因为文本向量经过归一化后,内积和余弦相似度在数值上是等价的,所以很多向量数据库内部会做归一化处理来提高计算效率。
2.3 向量数据库是什么
向量数据库是一种专门针对“向量数据”设计存储和检索能力的数据库。它和普通数据库最大的区别在于:它支持高效的近似最近邻搜索(ANN),能够在百万甚至亿级向量中,快速找到与查询向量最接近的前 N 条结果。
数据库内部通常使用 HNSW、IVF 等索引算法,把“全量暴力对比”变成“多层路的近似搜索”。对开发者来说,你不需要理解全部算法细节,只需要知道:向量库让你能够在海量文本中,毫秒级找到语义上最相关的几条内容。
3. 语义搜索与传统搜索的区别
为了更清楚地说明问题,我把传统搜索和语义搜索的差异整理成一张表。
| 对比维度 | 传统搜索(关键词/BM25) | 语义搜索(向量检索) |
|---|---|---|
| 匹配原理 | 分词后做词项匹配 | 通过 Embedding 计算语义距离 |
| 能否处理同义词 | 部分,依赖分词和同义词扩展 | 可以,语义相近即能召回 |
| 口语化表达 | 较弱,用户说法偏离关键词就失效 | 较强,更关注“意思”而不是“字词” |
| 错别字容忍度 | 低,错字可能导致匹配失败 | 相对高,因为向量语义仍可能相近 |
| 索引结构 | 倒排索引 | 向量索引(HNSW、IVF 等) |
| 可解释性 | 高,能讲清楚命中了哪些词 | 低,只能看到排名结果 |
| 适用场景 | 日志检索、精确匹配、结构化过滤 | 知识库问答、推荐、去重、意图识别 |
需要承认的是,语义搜索不是万能药。它的一个明显问题是精确词匹配能力弱。比如用户想搜商品编码“SKU-10086”,向量检索可能因为语义太“抽象”而召回错误。因此,生产环境里的做法通常不是“只用向量检索”,而是“向量检索 + 关键词检索”混合,再通过 Rerank 模型对结果排序。这个后面会讲。
4. RAG:AI 知识库的核心工作流
RAG 的全称是 Retrieval-Augmented Generation,检索增强生成。它的核心思想很简单:大模型回答问题前,先从你自己的知识库里检索出相关内容,再把这些内容拼进提示词,让模型基于给定的资料回答。这样,模型就不再只依赖训练数据里的“记忆”,而是能够使用你提供的实时、私有、垂直领域的内容。
为什么必须用 RAG?两个关键原因。
第一,大模型的知识截止时间是固定的。你问它“今年最新的售后政策”,它不会知道。第二,大模型会“一本正经地胡说八道”,也就是幻觉。当它不知道答案时,它倾向于编造。RAG 通过把答案限制在检索到的资料范围内,显著降低了幻觉风险。
RAG 的典型流程可以拆成这样:
- 文档加载:读取用户提供的 PDF、Word、Markdown、网页等格式的文档。
- 文本切块(Chunking):把长文本拆成多个合适大小的片段。这一步对检索效果影响巨大。
- 向量化(Embedding):用 Embedding 模型把每个文本块转换成向量。
- 向量入库(Ingestion):把向量和原始文本、元数据写入向量数据库。
- 检索(Retrieval):用户提问时,把问题也转成向量,在库里做相似度搜索,得到 top K 相关文本块。
- 重排(Reranking):可选步骤。对初选结果做精细化排序,提升相关性。
- 生成(Generation):把检索结果和用户问题拼成 Prompt,交给大模型生成答案。
这里面有一个非常容易忽视的点:RAG 的效果上限,很大程度由“检索质量”决定,而不是由大模型决定的。如果检索阶段没有把真正相关的段落找出来,后面大模型再强也没用。
另外,最近业界开始讨论 Agentic RAG,即让 AI Agent 自主决定“什么时候检索、检索几次、检索什么”。它可以拆解复杂问题,做多轮检索,甚至调用外部工具。这是 RAG 的发展方向,但本质上还是建立在今天要讲的这套基础能力之上。新手先跑通基础 RAG,再考虑 Agentic 不迟。
5. 向量数据库选型:Chroma、Milvus、pgvector、Qdrant 怎么选
市面上的向量数据库不少,很多新手第一步就卡在选型上。我的建议是:不要一开始就追求分布式和高性能,先看你的数据规模和部署环境。
| 数据库 | 定位 | 优点 | 适合场景 |
|---|---|---|---|
| Chroma | 轻量级嵌入式向量库 | 安装简单、API 友好、适合学习与原型 | 个人项目、快速验证、小规模知识库 |
| Milvus | 分布式向量数据库 | 支持百亿级向量、功能全面、CNCF 项目 | 生产环境、大规模数据、高并发检索 |
| Qdrant | Rust 编写的向量数据库 | 性能好、过滤功能强、部署灵活 | 生产环境、推荐系统、需要复杂过滤 |
| Weaviate | 向量数据库,支持图式对象 | 内置多种模块、与 GraphQL 集成好 | 知识图谱与向量结合的场景 |
| pgvector | PostgreSQL 扩展 | 不引入新组件,直接使用 SQL | 已有 PostgreSQL 的团队,数据量百万内 |
| Elasticsearch | 搜索引擎 + 向量能力 | 既有全文检索又有向量检索,生态成熟 | 需要混合搜索的团队 |
从开源社区的普及度看,Milvus 和 Chroma 的使用者最多。Chroma 的优势在于“零部署”,一个pip install就能跑;Milvus 的优势在于生产可用性和生态完整性,适合规模化建设 AI 知识库。如果你所在团队已经有 PostgreSQL,并且数据量在百万级以内,直接用 pgvector 是最省事的方案,不需要额外维护一套基础设施。
选型的核心判断标准有三个:数据规模、并发量、运维成本。原型阶段选 Chroma/LanceDB,生产阶段选 Milvus/Qdrant/Weaviate,已经有 SQL 体系就选 pgvector。云上部署也可以直接购买向量数据库托管服务,省去运维负担。
6. 环境准备与基础配置
本文的示例代码基于 Python 3.9+。核心依赖有两个:chromadb和sentence-transformers。sentence-transformers用于加载 Embedding 模型,chromadb用于向量存储和检索。
安装命令:
pip install chromadb sentence-transformers如果你本机没有 GPU,也可以运行。BGE small 模型在 CPU 上做 Embedding 的速度可以接受,适合学习。
如果你希望用云厂商的 Embedding API,则可以跳过sentence-transformers,改为直接调用 HTTP 接口或 SDK。为了让本地示例能跑通,我下面以开源模型 BGE 为例。
再准备一份示例文档,我假设它是一段客服 FAQ 文本,内容如下(实际使用时替换成你自己的知识文档):
碎屏保服务:自签收之日起一年内,因意外跌落、碰撞、挤压导致屏幕碎裂, 可享受一次免费维修服务。需要用户提供购买凭证和碎屏照片。 如果屏幕仅有划痕,没有碎裂,不在碎屏保服务范围内。 碎屏保服务不包含电池、主板等内部硬件损坏的维修。下面就用这段文本做大模型知识库的“原始数据”。
7. 完整示例代码实现:从文本切块到 RAG 问答
7.1 第一步:文本切块
切块是 RAG 里最容易被忽略的环节。切得太大,检索时容易把无关内容混进来;切得太小,单个块信息量不足。比较简单的策略是固定长度加重叠窗口。
# 文件路径:rag_demo/chunking.py def split_text(text: str, chunk_size: int = 150, overlap: int = 30) -> list[str]: """ 按固定长度切分文本,相邻切块之间保留部分重叠,避免语义被拦腰截断。 chunk_size:每个文本块的最大字符数 overlap:两个相邻块之间重叠的字符数 """ chunks = [] start = 0 text_len = len(text) while start < text_len: end = start + chunk_size chunk = text[start:end] chunks.append(chunk) if end >= text_len: break start = end - overlap return chunks if __name__ == "__main__": sample = """碎屏保服务:自签收之日起一年内,因意外跌落、碰撞、挤压导致屏幕碎裂, 可享受一次免费维修服务。需要用户提供购买凭证和碎屏照片。 如果屏幕仅有划痕,没有碎裂,不在碎屏保服务范围内。 碎屏保服务不包含电池、主板等内部硬件损坏的维修。""" result = split_text(sample) print(f"切块数量: {len(result)}") for i, chunk in enumerate(result): print(f"--- chunk {i} ---") print(chunk)固定长度切块适合快速跑通流程,但生产环境有更进阶的策略,比如按 Markdown 标题切、按段落切、父子块切分等,这些在后面的最佳实践里会进一步说明。
7.2 第二步:创建向量数据库并写入数据
使用 Chroma 的PersistentClient,可以把数据持久化到本地磁盘,下次启动不需要重新 Embedding。
# 文件路径:rag_demo/ingest.py import chromadb from chromadb.utils import embedding_functions # 1. 选择 Embedding 模型 sentence_transformer_ef = embedding_functions.SentenceTransformerEmbeddingFunction( model_name="BAAI/bge-small-zh-v1.5" ) # 2. 创建持久化客户端,数据保存在 ./chroma_data 目录 client = chromadb.PersistentClient(path="./chroma_data") # 3. 创建或获取集合(Collection),并指定向量距离算法为 cosine collection = client.get_or_create_collection( name="faq_kb", embedding_function=sentence_transformer_ef, metadata={"hnsw:space": "cosine"} ) # 4. 准备文档数据。这里先用一段完整文档,实际项目中通常是切块后的列表。 documents = [ """碎屏保服务:自签收之日起一年内,因意外跌落、碰撞、挤压导致屏幕碎裂, 可享受一次免费维修服务。需要用户提供购买凭证和碎屏照片。 如果屏幕仅有划痕,没有碎裂,不在碎屏保服务范围内。 碎屏保服务不包含电池、主板等内部硬件损坏的维修。""", """七天无理由退货:自签收之日起七日内,如果商品未经使用且包装配件齐全, 可以申请无理由退货。定制类商品、已激活的数码产品不适用七天无理由退货。 退货产生的运费由买家承担,商品质量问题由卖家承担。""", ] metadatas = [ {"source": "售后政策.md", "category": "售后"}, {"source": "购物指南.md", "category": "退货"}, ] ids = [f"chunk_{i}" for i in range(len(documents))] # 5. 写入向量数据库。collection.add 会先调用 embedding_function 生成向量,再存储。 collection.add( documents=documents, metadatas=metadatas, ids=ids ) print(f"集合中已存储 {collection.count()} 条文档")这里有几个细节值得解释:
get_or_create_collection:如果集合已经存在,不会重复创建,避免多次运行脚本产生重复数据。embedding_function:写入和查询必须使用同一个 Embedding 模型,否则向量空间不一致,检索结果会完全失真。metadata={"hnsw:space": "cosine"}:指定使用余弦相似度算法。如果修改这个参数,需要删除旧集合重新创建。
7.3 第三步:语义搜索
数据写入完成后,最核心的验证环节就是查询。我们可以用自然语言问一句库里没有出现完全相同关键词的问题,看看能否正确召回对应片段。
# 文件路径:rag_demo/search.py import chromadb from chromadb.utils import embedding_functions sentence_transformer_ef = embedding_functions.SentenceTransformerEmbeddingFunction( model_name="BAAI/bge-small-zh-v1.5" ) client = chromadb.PersistentClient(path="./chroma_data") collection = client.get_collection( name="faq_kb", embedding_function=sentence_transformer_ef ) query_text = "手机不小心摔坏了,屏幕裂了,能免费修吗?" results = collection.query( query_texts=[query_text], n_results=2 ) print("问题:", query_text) print("-" * 50) for i in range(len(results["ids"][0])): doc_id = results["ids"][0][i] distance = results["distances"][0][i] if "distances" in results else "N/A" document = results["documents"][0][i] metadata = results["metadatas"][0][i] print(f"排名 {i + 1}: 文档ID={doc_id}, 相似度距离={distance}") print(f"元数据: {metadata}") print(f"内容片段: {document}") print("-" * 50)如果一切正常,你会看到“屏幕碎了”这条问题成功命中“碎屏保服务”这段内容,而不是“七天无理由退货”。这就是语义搜索和关键词搜索最大的差别:它靠“意思”找人,而不是靠“字眼”找人。
7.4 第四步:接入大模型完成 RAG 问答
检索只是拿到了“参考资料”,最后一步是把参考内容和用户问题组合成 Prompt,交给大模型生成答案。下面的代码使用 OpenAI 兼容接口,实际项目可以替换为通义千问、DeepSeek、智谱、Ollama 本地模型等任意支持相同协议的服务。
# 文件路径:rag_demo/rag_qa.py import chromadb from chromadb.utils import embedding_functions from openai import OpenAI # 这里替换为你的大模型服务配置 # 如果用 Ollama 本地模型,可以设置 base_url="http://localhost:11434/v1" LLM_CLIENT = OpenAI( api_key="YOUR_API_KEY", base_url="YOUR_LLM_ENDPOINT" ) LLM_MODEL = "your-model-name" sentence_transformer_ef = embedding_functions.SentenceTransformerEmbeddingFunction( model_name="BAAI/bge-small-zh-v1.5" ) client = chromadb.PersistentClient(path="./chroma_data") collection = client.get_collection( name="faq_kb", embedding_function=sentence_transformer_ef ) def rag_answer(question: str) -> str: # 1. 检索 results = collection.query( query_texts=[question], n_results=2 ) context_blocks = results["documents"][0] # 2. 构造 Prompt context = "\n\n".join(f"【资料{i+1}】\n{block}" for i, block in enumerate(context_blocks)) prompt = f"""你是某电商平台的客服助手。请根据以下知识库资料回答用户问题。 如果资料中没有提到相关信息,请直接说明“资料中未找到相关内容”,不要编造。 知识库资料: {context} 用户问题: {question} 请你用简洁、友好的中文回答。""" # 3. 调用大模型 response = LLM_CLIENT.chat.completions.create( model=LLM_MODEL, messages=[ {"role": "system", "content": "你是严谨的客服问答助手。"}, {"role": "user", "content": prompt} ], temperature=0.2 ) return response.choices[0].message.content if __name__ == "__main__": question = "我的手机摔了,屏幕裂了,能不能免费维修?" answer = rag_answer(question) print("问题:", question) print("回答:", answer)这个示例虽然短,却已经具备了一个生产级 RAG 系统的最小骨架:检索 + 提示词约束 + 生成。你后续要做的优化,基本都是在“检索”和“提示词”这两层继续深化。
8. 运行结果与效果验证
为了让整个过程更有底气,我来描述一下验证方法。
先运行切块脚本:
python rag_demo/chunking.py预期输出是切块后的文本片段列表。如果chunk_size和overlap设置得当,最后一个切块不会为空字符串。
再运行入库脚本:
python rag_demo/ingest.py看到控制台输出:
集合中已存储 2 条文档说明写库成功。如果重复运行该脚本,collection.count()会变成 4、6、8……这是因为 Chroma 不检查内容是否重复,只按id去重。这也是为什么要用带有业务含义的 ID(比如docs_xxx_chunk_1),而不是简单的chunk_0。
然后运行检索脚本:
python rag_demo/search.py判断成功的关键信号是:第一条命中的文档必须是“碎屏保服务”,而不是“七天无理由退货”。如果结果反了,或者相似度距离特别大,建议按下面的排查顺序检查:
- Embedding 模型是否一致(写入和查询是否用了同一个模型)。
hnsw:space参数是否设置正确。- 文档内容是否过短或切块过碎,导致语义信息不足。
- 查询语句是否太模糊,换个更直接的说法再试。
最后运行 RAG 问答脚本:
python rag_demo/rag_qa.py如果最终回答能准确提到“一年内”“意外跌落导致屏幕碎裂可免费维修一次”这类关键信息,说明整条链路已经跑通。
9. 常见问题与排查思路
我在实际项目里总结了一些高频问题,列成表供你参考。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
入库后collection.count()不断增加 | 使用了自动生成的递增 ID,导致重复写入 | 检查写入逻辑中 ID 的生成方式 | 使用内容 Hash 或业务标识作为 ID,实现幂等写入 |
| 查询结果语义相关性差 | Embedding 模型不适合你的语言或领域 | 把查询和文档分别打印成向量,检查距离分布 | 换成中文表现更好的模型,如bge-large-zh-v1.5或bge-m3 |
| 写入慢 | 使用 CPU 对长文本做 Embedding | 观察 CPU 占用率和耗时日志 | 批量写入、换 GPU、或使用云上 Embedding API |
| 检索到相似但片段不完整 | 切块策略不合理,语义被截断 | 打印切块内容,检查边界上下文 | 增加重叠窗口,或改用段落级切分 |
| 大模型答案依然在编造 | 检索到的资料里其实没有答案,但模型强行回答 | 检查 RAG 输出中实际传递了哪些上下文 | 在 Prompt 中明确声明“未找到就回答不知道”,或设置更低温度 |
| 向量数据库文件损坏或版本升级后读不了数据 | Chroma 版本更新导致持久化格式不兼容 | 查看启动日志中的兼容性报错 | 保存原始文档,必要时重新入库;升级前先备份chroma_data目录 |
| 删除或修改某条文档后旧数据仍在 | 向量库更新时需要按 ID 执行 upsert/delete | 确认使用的是update、upsert还是add | 根据业务场景显式删除旧 ID,再写入新向量 |
其中最需要提醒的是第一项。很多新手把collection.add理解成“数据库 insert”,会重复写入同一批数据。RAG 的入库链路应该设计成可重复执行的 ETL 任务:先按文档来源和切块序号生成稳定的 ID,再执行 upsert。这样才能保证知识库更新是安全的、可回滚的。
10. 最佳实践与工程建议
跑通最小示例之后,如果你要把它接到真实业务里,下面这些建议会很有用。
10.1 切块策略要跟着文档结构走
固定长度切块适合“快速跑通”,但真实文档往往有结构:标题、段落、列表、表格。粗暴截断可能会把一个问题拆到两个块里。更好的策略是:先识别 Markdown/HTML 的标题层级,按标题切出“语义完整”的段落;如果段落还是太长,再在段落内部按句子边界切小。Chroma、LlamaIndex 等生态里都有对应的文本切分器,不必自己重复造轮子。
10.2 用元数据过滤减少噪音
向量检索适合做“语义召回”,但很多时候你需要配合精确筛选。比如知识库里有多个业务线的文档,回答问题前先确定用户属于哪个业务线,然后用where条件把候选范围限定在对应分类里。Chroma 的collection.query支持where和where_document参数。实际项目里,元数据过滤可以显著提高召回精度。
10.3 混合搜索 + Rerank 是提升效果的关键
纯向量检索在“同义改写”上有优势,在“精确匹配”上有短板。生产级 RAG 通常会把向量检索结果和传统关键词检索结果合并,再用一个 Rerank 模型对合并结果重新打分。Rerank 模型直接对“查询-文档对”做相关性判断,效果通常比单纯计算向量距离更准。代价是多一次模型推理,延迟和成本都会增加。
10.4 数据更新要设计成幂等任务
知识库不是一成不变的。文档会更新、下线、过期。建议每次入库前,用内容 Hash 判断文档是否变化;如果 Hash 相同,直接跳过。如果文档内容变化了,先删除旧 ID 对应的向量,再写入新向量。这样既避免重复数据,也避免旧版本残留。
10.5 权限与安全边界
如果知识库里包含内部资料,要特别注意两点:一是向量数据库本身的访问权限,不要暴露在公网;二是检索结果中可能包含敏感信息,RAG 服务对外输出前要做内容过滤。涉及删除或批量更新操作时,提前备份数据和确认脚本效果,坚持最小权限原则。
10.6 重视日志与可观测性
RAG 链路较长:加载、切块、向量化、检索、重排、生成。任何一个环节出问题,最终答案都会异常。建议在每个环节都输出结构化日志,至少记录:处理了哪些文档、生成了多少切块、检索到了哪些片段、最终 Prompt 是什么。这样一旦线上问答效果不佳,你能快速定位是“没检索到”还是“大模型没理解”。
11. 总结与后续学习方向
这篇文章从传统搜索的局限出发,把 Embedding、语义搜索、向量数据库和 RAG 这条链路完整梳理了一遍。你可以把“向量数据库”理解成 AI 知识库的“记忆仓库”,Embedding 是让文字变成可计算向量的“翻译器”,语义搜索是“找相关记忆”的过程,RAG 则是让大模型“带着参考资料回答问题”的完整工作流。
建议你接下来做两件事。第一,把文章里的最小 RAG 示例跑通,替换成自己的文档,亲手感受一下“语义检索”和“关键词搜索”的结果差异。第二,选择一个方向继续深入:如果你对数据工程感兴趣,可以研究切块、元数据、混合搜索;如果你对算法感兴趣,可以研究 HNSW 索引和向量量化;如果你想做生产应用,可以研究 Milvus 部署、Rerank 模型和 Agentic RAG。
值得记住的是,向量数据库和 RAG 并不是某一款具体产品,而是一套解决“让 AI 使用私有知识”的通用架构。把基础链路理解透,无论是换数据库、换 Embedding 模型,还是换大模型,你都能快速迁移。收藏这篇文章,等真正搭建 AI 知识库时,按着这个思路一步步来,比到处拼凑资料要高效得多。