
最近在尝试将公司内部文档接入大模型问答系统时发现一个核心痛点传统的全文检索在面对大模型时经常出现“答非所问”或“胡编乱造”的情况。问题的根源在于大模型无法直接“理解”和“记住”海量的私有知识。这正是 RAG检索增强生成技术要解决的核心问题而向量数据库则是 RAG 系统中承上启下的关键组件负责将非结构化文本转化为机器能“理解”的向量并进行高效检索。本文将围绕“向量数据库”这一核心组件结合 Cursor 这一 AI 编程神器带你从零搭建一个可运行的 RAG 原型。无论你是想了解 RAG 技术栈的初学者还是正在为项目选型向量数据库的开发者都能从本文获得一套从概念到实战的完整方案。我们将重点拆解向量数据库的工作原理、主流选型对比并通过一个完整的 Python 示例演示如何使用 Chroma 向量数据库构建一个简易的知识库问答系统。1. 背景与核心概念为什么需要向量数据库在深入代码之前我们必须先理解几个核心概念这能帮助你在后续的选型和调试中做出正确决策。RAGRetrieval-Augmented Generation检索增强生成是一种让大语言模型LLM能够利用外部知识库来生成更准确、更相关答案的技术范式。其核心流程可以简化为三步检索Retrieval当用户提出问题时系统从外部知识库如文档、数据库中查找与问题最相关的信息片段。增强Augmentation将检索到的相关片段与用户原始问题一起组合成一个新的、信息更丰富的提示Prompt。生成Generation将这个增强后的提示输入给大语言模型由模型生成最终答案。在这个过程中向量数据库扮演了“检索”环节的核心角色。那么为什么不能用传统的 MySQL、Elasticsearch 直接检索呢传统检索 vs. 语义检索传统关键词检索依赖于精确的词条匹配如LIKE ‘%关键词%’或倒排索引。它无法理解“苹果公司”和“水果苹果”之间的语义差异也无法处理“如何优化代码性能”和“让程序跑得更快的方法”这类语义相同但表述不同的查询。语义检索向量检索其核心是将文本无论是文档还是问题通过一个嵌入模型Embedding Model转换为一个高维空间中的点即向量。这个向量包含了文本的语义信息。语义相似的文本其向量在空间中的距离如余弦相似度、欧氏距离也会很近。检索过程就变成了在高维向量空间中寻找“距离”最近的向量。向量数据库的核心价值向量数据库就是专门为存储、索引和快速检索海量向量数据而设计的数据库。它解决了两个关键问题高效相似度搜索当向量维度很高如 768、1536 维且数量巨大时暴力计算所有向量间的距离是不可行的。向量数据库使用诸如 HNSW近似最近邻搜索、IVF倒排文件等算法建立索引能在毫秒级内从百万甚至千万级向量中找出最相似的 Top-K 个结果。数据管理提供了类似传统数据库的增删改查CRUD能力并能与向量检索有机结合管理向量及其关联的原始文本元数据。简单来说向量数据库是 RAG 系统的“记忆中枢”它让大模型具备了快速、准确从私有知识库中“回忆”相关事实的能力。2. 环境准备与版本说明为了完成后续的实战我们需要准备一个 Python 开发环境。本文将使用Chroma作为向量数据库的示例因为它轻量、易用且完全开源非常适合学习和原型开发。基础环境操作系统Windows 10/11, macOS 或 Linux (本文命令以 macOS/Linux 为例Windows 用户可在 PowerShell 或 WSL 中运行)Python 版本 3.8 (推荐 3.9 或 3.10)包管理工具pip开发工具推荐CursorCursor 是一款集成了 AI 辅助编程的 IDE基于 VS Code 内核。它在 RAG 开发中尤其有用AI 自动补全与解释能帮你快速生成代码片段或解释复杂库的用法。内置聊天功能可以直接询问技术问题例如“ChromaDB 如何持久化存储”它能结合你的项目上下文给出答案。项目感知AI 能理解你的整个项目结构提供更准确的建议。设置中文在 Cursor 中按Cmd/Ctrl Shift P输入Configure Display Language选择zh-cn即可切换界面语言对英文文档阅读有困难的开发者非常友好。项目依赖我们将创建一个新的 Python 项目并安装必要的库。首先建议创建一个虚拟环境来隔离依赖。# 1. 创建项目目录并进入 mkdir rag-vector-db-demo cd rag-vector-db-demo # 2. 创建虚拟环境 (可选但推荐) python -m venv venv # 3. 激活虚拟环境 # macOS/Linux: source venv/bin/activate # Windows: # venv\Scripts\activate # 4. 安装核心依赖 pip install chromadb langchain sentence-transformers openai tiktoken依赖库说明chromadb: 轻量级、嵌入优先的向量数据库我们将用它存储和检索向量。langchain: 用于构建 LLM 应用的主流框架它提供了连接各种组件模型、向量库、文本分割器等的统一接口。虽然本文会部分使用其概念但为了更清晰地理解底层原理我们会尽量展示原生操作。sentence-transformers: 一个用于生成句子、段落嵌入向量的库。我们将使用其内置的all-MiniLM-L6-v2模型这是一个在本地运行的轻量级嵌入模型无需 API 密钥。openaitiktoken: 用于调用 OpenAI 的 GPT 模型生成最终答案以及计算 Token 数量。注意使用 OpenAI API 会产生费用本文示例会提供替代方案版本说明本文示例基于以下近似版本不同版本间 API 可能有细微差异请以官方文档为准。chromadb0.4.22 sentence-transformers2.2.2 langchain0.1.0 openai1.12.0如果你的环境已有其他版本核心逻辑通常兼容但若遇到问题可尝试指定上述版本安装pip install chromadb0.4.22。3. 核心组件与原理拆解在动手编码前我们需要对 RAG 中与向量数据库交互的几个关键环节有清晰的认识。3.1 嵌入模型文本到向量的翻译官嵌入模型是将文本转换为向量的函数。一个好的嵌入模型应该能确保语义相似的文本其向量表示也相似。选择你可以使用云服务如 OpenAI 的text-embedding-ada-002效果好但需付费和网络也可以使用本地模型如sentence-transformers系列免费、离线但性能稍逊。维度模型输出的向量维度是固定的如all-MiniLM-L6-v2是 384 维text-embedding-3-small是 1536 维。向量数据库的索引结构需要与之匹配。本文选择为了演示的完整性和零成本我们选用sentence-transformers库中的all-MiniLM-L6-v2模型。3.2 文本分割知识库的“切片”艺术原始文档如 PDF、Word可能很长直接整篇编码成向量会丢失细节且检索效率低。因此需要将长文档分割成较小的、语义完整的“块”。策略简单的按字符数分割如每 500 字符可能会切断句子。更佳的策略是使用“递归字符分割器”它优先在段落、句子等自然分隔符处切割并保持一定的重叠度以避免上下文断裂。块大小与重叠度这是两个关键超参数。块太小可能信息不完整太大则包含噪声。重叠度确保了边界信息不会完全丢失。3.3 向量数据库索引快速查找的“地图”这是向量数据库的“引擎”。主流的索引算法有HNSW (Hierarchical Navigable Small World)一种基于图的算法搜索速度快、精度高但建索引耗时较长且占用内存较多。适合读多写少、对延迟敏感的场景。Chroma 默认使用 HNSW。IVF (Inverted File Index)一种基于聚类的算法先对向量进行聚类搜索时只在最相关的几个聚类中查找。建索引快内存占用相对小但精度可能略低于 HNSW。Faiss 库对此有高效实现。PQ (Product Quantization)一种压缩技术通过压缩向量来大幅减少内存占用适合海量数据但会损失一些精度。选型考虑Chroma vs. Faiss vs. Milvus/QdrantChroma轻量、易用、一体化。它内置了简单的嵌入函数、文档存储和检索逻辑开箱即用非常适合原型、学习和中小型项目。本文选用它。FaissFacebook 开源的向量检索库不是完整的数据库。它专注于索引算法性能极致但需要自己处理元数据存储、并发等。常作为底层引擎被集成。Milvus/Qdrant/Weaviate生产级、功能全面的向量数据库。支持分布式、持久化、多租户、丰富的过滤条件、数据管理等高级特性适合大规模、高并发的生产环境。部署和维护相对复杂。对于初学者和大多数中小型应用从 Chroma 开始是绝佳的选择。4. 完整实战构建本地知识库问答系统现在让我们用代码串联起所有概念。我们将构建一个简单的系统向知识库添加几段关于“Python 编程”的文本然后通过提问来检索并生成答案。4.1 项目结构初始化在项目根目录下创建以下文件rag-vector-db-demo/ ├── venv/ # 虚拟环境目录 ├── data/ # 存放原始文档可选 ├── main.py # 主程序入口 ├── vector_store.py # 向量数据库操作封装 └── requirements.txt # 依赖列表首先生成requirements.txt文件pip freeze requirements.txt4.2 封装向量数据库操作创建vector_store.py这里我们将封装 Chroma 的初始化、文档添加和检索功能。# vector_store.py import chromadb from chromadb.config import Settings from sentence_transformers import SentenceTransformer import uuid from typing import List, Dict, Any class VectorStore: 向量数据库操作类封装 ChromaDB 的基本功能。 def __init__(self, persist_directory: str ./chroma_db, collection_name: str knowledge_base): 初始化向量存储。 Args: persist_directory: 数据持久化目录。 collection_name: Chroma 集合的名称类似于数据库的表。 # 初始化嵌入模型本地 print(正在加载嵌入模型...) self.embed_model SentenceTransformer(all-MiniLM-L6-v2) # 初始化 Chroma 客户端设置持久化路径 self.client chromadb.PersistentClient(pathpersist_directory) # 获取或创建集合。embedding_function 需要自定义因为我们要用本地模型。 self.collection self.client.get_or_create_collection( namecollection_name, # 注意这里传入一个函数Chroma 在需要时会调用它来生成向量。 # 但我们为了演示清晰将在外部显式调用模型所以这里先传一个空函数。 # 更优的做法是实现一个适配器这里为了简化我们直接在 add_documents 中计算向量。 embedding_functionNone # 我们自行处理嵌入 ) print(f向量存储初始化完成持久化目录: {persist_directory}) def _get_embeddings(self, texts: List[str]) - List[List[float]]: 使用本地模型生成文本嵌入向量。 # sentence-transformers 模型直接返回 numpy array需要转换为 list of list of float embeddings self.embed_model.encode(texts, convert_to_numpyTrue) return embeddings.tolist() def add_documents(self, documents: List[Dict[str, Any]]): 向向量数据库添加文档。 Args: documents: 字典列表每个字典应包含 text 键文本内容 并可包含其他元数据如 source, page 等。 if not documents: print(文档列表为空跳过添加。) return # 提取纯文本用于生成向量 texts [doc[text] for doc in documents] # 生成嵌入向量 embeddings self._get_embeddings(texts) # 生成唯一 ID ids [str(uuid.uuid4()) for _ in documents] # 提取元数据 metadatas [{k: v for k, v in doc.items() if k ! text} for doc in documents] # 添加到集合 self.collection.add( embeddingsembeddings, documentstexts, metadatasmetadatas, idsids ) print(f成功添加 {len(documents)} 个文档到向量数据库。) def search(self, query: str, n_results: int 3) - List[Dict[str, Any]]: 在向量数据库中搜索与查询最相关的文档。 Args: query: 查询字符串。 n_results: 返回的最相关结果数量。 Returns: 包含相关文档信息文本、元数据、相似度分数的字典列表。 # 将查询文本转换为向量 query_embedding self._get_embeddings([query])[0] # 执行相似度搜索 results self.collection.query( query_embeddings[query_embedding], n_resultsn_results, # include 参数指定返回哪些数据 include[documents, metadatas, distances] ) # 整理返回结果 retrieved_docs [] if results[documents]: for i in range(len(results[documents][0])): doc_info { text: results[documents][0][i], metadata: results[metadatas][0][i] if results[metadatas] else {}, # Chroma 返回的是距离如欧氏距离越小越相似。我们将其转换为相似度分数越大越相似。 score: 1 - results[distances][0][i] if results[distances] else 0 } retrieved_docs.append(doc_info) return retrieved_docs # 简单文本分割函数按字符数实际项目建议使用 LangChain 的 RecursiveCharacterTextSplitter def simple_text_splitter(text: str, chunk_size: int 500, chunk_overlap: int 50) - List[str]: 简单的按字符数分割文本。 chunks [] start 0 text_length len(text) while start text_length: end start chunk_size # 如果重叠且不是第一块则回退 chunk_overlap 个字符 if start 0: start start - chunk_overlap chunk text[start:end] chunks.append(chunk) start end return chunks4.3 编写主程序逻辑创建main.py这里我们将模拟一个完整的“添加知识-提问-回答”流程。# main.py from vector_store import VectorStore, simple_text_splitter import os def init_knowledge_base(): 初始化知识库添加示例文档。 # 示例文档关于 Python 的几段知识 raw_documents [ { text: Python是一种高级、解释型的通用编程语言。由吉多·范罗苏姆创造第一版发布于1991年。Python的设计哲学强调代码的可读性和简洁的语法尤其是使用空格缩进来划分代码块。, source: python_wiki_intro, type: concept }, { text: 列表是Python中最常用的数据结构之一。它是一个可变的有序序列可以包含任意类型的元素。列表通过方括号[]定义元素之间用逗号分隔。例如my_list [1, 2, hello, True]。, source: python_data_structures, type: syntax }, { text: 使用pip可以安装和管理Python包。例如要安装requests库可以在命令行中运行pip install requests。通常建议在虚拟环境中安装包以避免不同项目间的依赖冲突。, source: python_pip_guide, type: tool }, { text: 在Python中可以使用open()函数来读写文件。基本的模式有r用于读取默认w用于写入会覆盖文件a用于追加。操作完成后务必使用close()方法关闭文件或使用with语句自动管理。, source: python_file_io, type: syntax } ] # 对长文本进行分割本例中文档较短实际中可能需要对长文档分割 documents_to_add [] for doc in raw_documents: # 如果文本较长则分割 if len(doc[text]) 300: # 假设超过300字符就分割 chunks simple_text_splitter(doc[text], chunk_size200, chunk_overlap30) for i, chunk in enumerate(chunks): new_doc { text: chunk, source: doc[source], type: doc[type], chunk_index: i } documents_to_add.append(new_doc) else: documents_to_add.append(doc) # 初始化向量存储 vector_store VectorStore(persist_directory./chroma_db) # 添加文档 vector_store.add_documents(documents_to_add) print(知识库初始化完成) return vector_store def rag_query(vector_store, question: str, use_openai: bool False): 执行 RAG 查询检索 生成。 Args: vector_store: 向量存储实例。 question: 用户问题。 use_openai: 是否使用 OpenAI GPT 生成答案。如果为 False则仅返回检索结果。 print(f\n用户问题: {question}) print(- * 50) # 1. 检索相关文档 retrieved_docs vector_store.search(question, n_results2) if not retrieved_docs: print(未检索到相关文档。) return print(检索到的相关文档片段) for i, doc in enumerate(retrieved_docs): print(f[片段 {i1}, 相似度: {doc[score]:.4f}] {doc[text][:150]}...) if doc[metadata]: print(f 元数据: {doc[metadata]}) # 2. 构建增强提示 context \n\n.join([doc[text] for doc in retrieved_docs]) if use_openai: # 使用 OpenAI GPT 生成答案需要设置环境变量 OPENAI_API_KEY from openai import OpenAI import os api_key os.getenv(OPENAI_API_KEY) if not api_key: print(未设置 OPENAI_API_KEY 环境变量无法调用 OpenAI API。) print(以下为仅基于检索内容的回答拼接) print(context) return client OpenAI(api_keyapi_key) prompt f请根据以下上下文信息回答用户的问题。如果上下文信息不足以回答问题请直接说“根据提供的信息我无法回答这个问题”。 上下文信息 {context} 用户问题{question} 请给出准确、简洁的回答 try: response client.chat.completions.create( modelgpt-3.5-turbo, messages[{role: user, content: prompt}], temperature0.1, # 低温度使输出更确定 max_tokens500 ) answer response.choices[0].message.content print(\n RAG 系统生成的答案 ) print(answer) except Exception as e: print(f调用 OpenAI API 时出错: {e}) print(\n 检索到的原始内容 ) print(context) else: # 仅返回检索到的内容模拟生成 print(\n 基于检索内容的回答模拟) print(f根据知识库相关信息如下\n{context}) print(\n提示设置 use_openaiTrue 并配置 API Key 可获得 GPT 生成的连贯答案。) def main(): 主函数 # 检查是否已存在向量存储若不存在则初始化 if not os.path.exists(./chroma_db): print(未检测到已有知识库开始初始化...) vector_store init_knowledge_base() else: print(检测到已有知识库直接加载...) vector_store VectorStore(persist_directory./chroma_db) # 示例查询 questions [ Python 是什么, 如何安装 Python 的包, 怎么用 Python 读取文件, ] for q in questions: rag_query(vector_store, q, use_openaiFalse) # 设置为 True 并使用真实 API Key 来调用 GPT # 你也可以进行交互式提问 print(\n *60) print(进入交互模式输入 quit 退出。) while True: user_question input(\n请输入你的问题: ).strip() if user_question.lower() in [quit, exit, q]: print(再见) break if user_question: rag_query(vector_store, user_question, use_openaiFalse) if __name__ __main__: main()4.4 运行与验证在项目根目录下运行主程序python main.py预期输出首次运行会初始化知识库并创建chroma_db目录然后依次回答预设的问题。正在加载嵌入模型... 向量存储初始化完成持久化目录: ./chroma_db 成功添加 X 个文档到向量数据库。 知识库初始化完成 用户问题: Python 是什么 -------------------------------------------------- 检索到的相关文档片段 [片段 1, 相似度: 0.8321] Python是一种高级、解释型的通用编程语言。由吉多·范罗苏姆创造第一版发布于1991年。Python的设计哲学强调代码的可读性和简洁的语法尤其是使用空格缩进来划分代码块。... 元数据: {source: python_wiki_intro, type: concept, chunk_index: 0} ... 基于检索内容的回答模拟 根据知识库相关信息如下 Python是一种高级、解释型的通用编程语言。由吉多·范罗苏姆创造第一版发布于1991年。Python的设计哲学强调代码的可读性和简洁的语法尤其是使用空格缩进来划分代码块。 ...程序会进入交互模式你可以输入自己的问题例如“什么是列表”系统会从向量数据库中检索最相关的片段并返回。4.5 结果说明向量化存储运行后项目根目录下会生成一个chroma_db文件夹里面以 Chroma 的格式存储了所有文档的向量、原始文本和元数据。即使重启程序也会直接加载这个持久化的数据库无需重新计算向量。语义检索生效当你问“如何安装包”时即使原文是“使用pip可以安装和管理Python包”系统也能正确检索到这证明了基于向量的语义检索能力。RAG 流程闭环我们完成了从文档预处理分割、向量化、存储到检索的完整流程。通过将use_openai参数改为True并配置有效的OPENAI_API_KEY即可接入 GPT 模型实现真正的“检索增强生成”。5. 常见问题与排查思路在实际开发中你可能会遇到以下典型问题问题现象常见原因解决思路ModuleNotFoundError: No module named chromadb依赖未正确安装。1. 确认虚拟环境已激活。2. 运行pip install chromadb。3. 检查 Python 解释器路径是否正确在 Cursor 或 IDE 中。添加文档或查询时速度非常慢1. 首次运行需下载嵌入模型。2. 文档数量大且未使用持久化每次重启都重新计算向量。3. HNSW 索引在首次添加大量数据时构建较慢。1. 首次加载模型是正常的模型文件会缓存。2. 确保使用了PersistentClient和持久化目录避免重复计算。3. 对于批量初始化可接受首次耗时。生产环境可考虑异步或离线构建索引。检索结果不相关1. 嵌入模型不适合你的领域如中文、专业领域。2. 文本分割不合理导致语义碎片化。3. 查询语句与文档表述差异太大。1. 尝试更换嵌入模型如paraphrase-multilingual-MiniLM-L12-v2对多语言支持更好。2. 调整分割策略块大小、重叠度或尝试按句、按段分割。3. 对查询语句进行简单的同义改写或扩展后再检索。OpenAI API调用失败1. API Key 未设置或错误。2. 网络问题。3. 额度不足。1. 检查环境变量OPENAI_API_KEY。2. 使用curl测试 API 连通性。3. 登录 OpenAI 平台检查余额和用量。也可先使用本地模型如ollamallama3进行测试。Chroma 客户端连接错误持久化目录权限问题或文件损坏。1. 检查目录读写权限。2. 尝试删除chroma_db目录重新初始化。3. 考虑使用chromadb.HttpClient连接远程 Chroma 服务。内存占用过高1. 加载的嵌入模型较大。2. 向量数据全部加载到内存。1. 使用更轻量的嵌入模型如all-MiniLM-L6-v2已很轻量。2. Chroma 持久化模式会按需加载通常问题不大。若数据量极大100万需考虑 Milvus/Qdrant 等支持磁盘索引的数据库。6. 最佳实践与工程建议将原型推进到生产环境需要注意以下关键点1. 文本预处理与分割优化清洗去除 HTML 标签、无关字符、乱码。分段策略不要简单按字符分割。使用LangChain的RecursiveCharacterTextSplitter并合理设置chunk_size(如 500-1000) 和chunk_overlap(如 100-200)。元数据丰富为每个文本块添加丰富的元数据如source文件名/URL、page、section_title、created_date等。这在后续过滤和溯源时至关重要。2. 嵌入模型选型匹配领域通用模型如text-embedding-ada-002在大多数场景表现良好。对于特定领域法律、医学、代码寻找或微调领域专用模型效果会显著提升。权衡速度与质量本地模型sentence-transformers延迟低、零成本但语义捕捉能力可能弱于顶级云服务。云服务OpenAI, Cohere质量高但有网络延迟和成本。统一向量维度确保索引构建和查询时使用同一个嵌入模型否则向量空间不一致检索无效。3. 向量数据库生产级部署从 Chroma 迁移当数据量超过百万或需要高并发、高可用时应考虑Milvus、Qdrant、Weaviate或PgvectorPostgreSQL 扩展。索引参数调优生产环境需根据数据规模和查询模式调整索引参数。例如在 Milvus 中调整HNSW的M连通性和efConstruction索引精度参数。持久化与备份确保向量数据库的数据有可靠的备份机制尤其是云托管服务。4. 检索环节的增强混合搜索结合向量相似度搜索和关键词搜索BM25。例如先用关键词过滤出一个候选集再用向量搜索进行精排。LangChain 的EnsembleRetriever支持此功能。重排序向量检索返回的 Top-K 结果可以使用一个更精细的但更慢的交叉编码器模型进行重排序以提升最终精度。元数据过滤在检索时加入元数据过滤条件如collection.query(..., where{source: user_manual_v2})可以精确控制检索范围。5. 系统监控与评估关键指标检索延迟、召回率检索到的相关文档比例、准确率检索结果中相关文档的比例、GPT 调用成本与延迟。AB 测试对比不同嵌入模型、分割策略、检索参数对最终问答质量的影响。反馈闭环收集用户对生成答案的“点赞/点踩”反馈用于优化检索和提示工程。6. 安全与权限数据安全确保存入向量数据库的文本不包含敏感信息PII。必要时在嵌入前进行数据脱敏。访问控制生产系统中向量数据库的访问应有严格的权限控制避免未授权访问或数据泄露。7. 总结与学习路线通过本文的实战我们完成了 RAG 系统中向量数据库组件从理论到实践的完整穿越。你应当已经掌握了核心概念理解了向量数据库在 RAG 中解决语义检索问题的核心价值。工具链搭建学会了使用 Chroma 这一轻量级向量数据库并配合本地嵌入模型搭建可运行的环境。完整流程实现亲手编写了文档加载、分割、向量化、存储、检索的每一行代码构成了一个简易知识库问答系统。问题排查与优化方向了解了常见坑点及其解决方案以及从原型到生产环境所需考虑的优化维度。下一步深入学习路线建议深入 LangChain本文为了揭示底层原理部分操作是手写的。在实际项目中强烈建议深入学习LangChain或LlamaIndex框架。它们提供了更高级、更统一的抽象如DocumentLoader,TextSplitter,VectorStore接口能极大提升开发效率。尝试用LangChain重构本文示例感受其便捷性。尝试不同的向量数据库在本地用 Docker 快速体验Milvus、Qdrant或Weaviate。了解它们的客户端 API、性能特点和适用场景。优化检索质量这是 RAG 的永恒课题。尝试不同的文本分割策略。不同的嵌入模型如bge、e5系列。实现混合检索关键词向量或重排序。构建完整应用为你的系统添加一个 Web 界面如使用Gradio或Streamlit支持上传 PDF/Word 文档并提供一个聊天式的问答界面。探索高级模式了解 “Agentic RAG”即让 LLM 主动决定何时检索、检索什么、如何迭代检索使系统更智能。向量数据库是 RAG 的基石但 RAG 本身是一个复杂的系统工程涉及文档处理、检索算法、提示工程、大模型调用等多个环节。建议你以本文的向量数据库部分为起点逐步扩展和深化对其他环节的理解与实践。