深入 RAG 与向量数据库:generative-ai-for-beginners 第 15 课检索增强生成的完整实现 📅 发布时间:2026/9/10 18:15:49 👁 浏览次数: 深入 RAG 与向量数据库generative-ai-for-beginners 第 15 课检索增强生成的完整实现【免费下载链接】generative-ai-for-beginners21 Lessons, Get Started Building with Generative AI项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai-for-beginners本篇基于 generative-ai-for-beginners 课程第 15 课《Retrieval Augmented Generation (RAG) and Vector Databases》系统讲解检索增强生成RAG的工作原理、向量数据库的选型与搭建、文本分块与向量化embedding、向量检索与重排序并给出从知识库构建到 LLM 问答闭环的完整可运行代码以及配套的 Jupyter Notebook 与评估方法。读完后你将能够独立搭建一个基于自有数据做“事实锚定”grounding的 RAG 应用并理解每个环节在课程配套代码中的真实实现。课程概述与学习目标在课程第 8 课搜索应用中我们初步了解了如何把自有数据接入大语言模型LLM。第 15 课在此基础上深入三个主题RAG 简介它是什么为什么在 AI 应用中需要使用它向量数据库理解其原理并为应用创建一个向量数据库实战示例如何把 RAG 集成到一个真实应用中。学完本课你将能够解释 RAG 在数据检索与处理中的意义搭建 RAG 应用并把自己的数据锚定ground到 LLM 上在 LLM 应用中高效集成 RAG 与向量数据库。场景设定用自有数据增强 LLM本课的假设场景是一家教育创业公司把学员的学习笔记接入聊天机器人让机器人能够基于笔记回答各个学科的问题。借助这些笔记学员可以更好地理解各主题内容从而更高效地备考。用户可以基于笔记生成练习题quiz、复习闪卡flash card并把内容总结成简洁的综述。实现该场景用到以下组件Azure OpenAI用于构建聊天机器人的 LLMAI for Beginners 课程中的“神经网络”章节作为锚定 LLM 的数据源Azure AI Search与Azure Cosmos DB用于存储数据并创建搜索索引的向量数据库。课程配套的示例笔记本 notebook-rag-vector-databases.ipynb 中知识源正是仓库内的三份 Markdown 文件data/perceptron.md感知器入门、data/frameworks.md神经网络框架与 data/own_framework.md多层感知器。笔记本把它们作为“私有知识库”来构建索引验证问题“what is a perceptron?”。什么是 RAG检索增强生成由 LLM 驱动的聊天机器人会处理用户提示词并生成回答。它被设计为交互式系统可以就广泛的话题与用户交流。但它的回答受限于两方面所提供的上下文以及其基础训练数据。例如 GPT-4 的知识截止于 2021 年 9 月它缺乏该时期之后事件的知识此外用于训练 LLM 的数据不包含机密信息比如个人笔记或公司的产品手册。RAG 是如何工作的如果你要部署一个“从笔记生成测验”的聊天机器人就需要连接到一个知识库——这正是 RAG 的价值所在。RAG 的运行流程分为四个阶段知识库Knowledge base检索之前文档需要被摄取并做预处理通常包括把大文档切分为更小的块chunk、把文本转换为向量嵌入embedding、再存储到数据库中。用户提问User Query用户提出一个问题。检索Retrieval当用户提问时嵌入模型从知识库中检索相关信息以提供将被拼入提示词的额外上下文。增强生成Augmented GenerationLLM 基于检索到的数据来增强自己的回答使生成的响应不仅基于预训练数据还基于所加入上下文中的相关信息随后 LLM 向用户返回答案。RAG 的架构编码器-解码器RAG 的架构使用由两部分组成的 Transformer 实现编码器encoder与解码器decoder。以用户提问为例输入文本先被“编码”为捕捉词语语义的向量这些向量再被“解码”去匹配文档索引并基于用户查询生成新文本。LLM 使用编码器-解码器两类模型协同生成输出。按提出 RAG 的经典论文《Retrieval-Augmented Generation for Knowledge Intensive NLP Tasks》所述实现 RAG 有两种方式RAG-Sequence使用检索到的文档来预测对用户查询的最佳答案一次性对整个回答序列做似然比较RAG-Token使用文档逐个生成下一个 token再结合检索结果回答用户查询。为什么要使用 RAG信息丰富度确保文本响应是最新、准确的通过访问内部知识库来提升领域特定任务上的表现减少捏造幻觉利用知识库中可验证的数据为用户问题提供上下文降低模型“编造”的概率成本效益高相比对 LLM 做微调fine-tuningRAG 在经济上更划算。构建知识库本课的应用基于个人数据即 AI For Beginners 课程中的神经网络章节内容对应仓库中的data/三份 Markdown 文档。向量数据库与传统数据库不同向量数据库是一种专门设计用于存储、管理与检索嵌入向量的数据库它保存文档的数值化表示。把数据拆解为数值嵌入能让 AI 系统更容易理解和处理这些数据。为什么必须存向量数据库而不是直接塞给 LLM因为 LLM 有输入 token 数量的上限无法把全部嵌入一次性传入。因此需要把文档切分成块chunk当用户提问时只有与问题最相似的嵌入连同提示词一起返回。分块还能显著降低流经 LLM 的 token 数量从而降低成本。文档列出的常用向量数据库包括Azure Cosmos DB、Clarifyai、Pinecone、ChromaDB、ScaNN、Qdrant 和 DeepLake。使用 Azure CLI 创建 Azure Cosmos DB 资源的命令如下az login az group create -n resource-group-name -l location az cosmosdb create -n cosmos-db-name -r resource-group-name az cosmosdb list-keys -n cosmos-db-name -g resource-group-name配套笔记本 notebook-rag-vector-databases.ipynb 中展示了与 Cosmos DB 的对接方式创建资源后在数据资源管理器Data Explorer中新建数据库与容器然后安装并初始化azure-cosmos客户端from azure.cosmos import CosmosClient # Initialize Cosmos Client凭据来自环境变量 url os.getenv(COSMOS_DB_ENDPOINT) key os.getenv(COSMOS_DB_KEY) client CosmosClient(url, credentialkey) # Select database database_name rag-cosmos-db database client.get_database_client(database_name) # Select container container_name data container database.get_container_client(container_name)也就是说运行时需要准备COSMOS_DB_ENDPOINT与COSMOS_DB_KEY两个环境变量分别对应 CLI 创建资源后拿到的端点与密钥。从文本到嵌入Embeddings存储数据之前需要先把它转换成向量嵌入。如果处理的是大文档或长文本可以基于预期查询来切块。切块可以按句子级也可以按段落级。由于块的含义依赖于周围词还可以为块追加额外上下文例如加上文档标题或包含块前后的一些文本。课程给出的切块实现如下def split_text(text, max_length, min_length): words text.split() chunks [] current_chunk [] for word in words: current_chunk.append(word) if len( .join(current_chunk)) max_length and len( .join(current_chunk)) min_length: chunks.append( .join(current_chunk)) current_chunk [] # 如果最后一个块未达到最小长度也照样加入 if current_chunk: chunks.append( .join(current_chunk)) return chunks切块之后可以用不同的嵌入模型对文本做向量化。可选模型包括word2vec、OpenAI 的 ada-002、Azure Computer Vision 等等。模型选择取决于所使用的语言、被编码内容的类型文本/图片/音频、可编码的输入规模以及嵌入输出的长度。用 OpenAItext-embedding-ada-002模型嵌入单词 “cat” 的结果示意如下笔记本中对 “cat” 调用create_embeddings(cat)即为同样的演示笔记本中嵌入调用的真实实现值得留意——它基于 Azure OpenAI 的 v1 端点Responses API 底座配置客户端并从环境变量读取端点、密钥与部署名from openai import OpenAI endpoint os.getenv(AZURE_OPENAI_ENDPOINT) client OpenAI( api_keyos.getenv(AZURE_OPENAI_API_KEY), base_urlf{endpoint.rstrip(/)}/openai/v1/, ) embeddings_deployment os.getenv(AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT) chat_deployment os.getenv(AZURE_OPENAI_DEPLOYMENT)def create_embeddings(text, modelNone): # 为每个文档块创建嵌入 model model or embeddings_deployment embeddings client.embeddings.create(inputtext, modelmodel).data[0].embedding return embeddings从源码结构看整个笔记本依赖五个关键环境变量AZURE_OPENAI_ENDPOINT、AZURE_OPENAI_API_KEY、AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT、AZURE_OPENAI_DEPLOYMENT以及 Cosmos DB 侧的COSMOS_DB_ENDPOINT、COSMOS_DB_KEY。运行前需先在 Azure 门户部署好嵌入模型与聊天模型再把这些值配置到环境中。笔记本中对数据的实际处理流程是先把data/下三份文档读入 pandas DataFramepathtext两列再以split_text(x, 400, 300)为每个文档生成块列表最大 400 字符、最小 300 字符随后用df.explode(chunks)把块列表展开为独立行最后逐块调用create_embeddings把embeddings列回填进 DataFrame。这正是上文split_text函数在真实项目中的参数取值与数据流。检索与向量搜索当用户提问时检索器retriever会先用查询编码器把问题转换成向量然后在文档搜索索引中查找与输入相关的相关向量完成后它把输入向量与文档向量都还原为文本并交给 LLM 处理。检索Retrieval检索发生在一个索引中快速查找满足搜索条件的文档。检索器的目标是拿到能为 LLM 提供上下文、把模型锚定到你数据上的文档。数据库中的搜索方式主要有三种关键词搜索Keyword search用于文本字面匹配向量搜索Vector search用嵌入模型把文档从文本转成向量表示实现基于词义的语义搜索——检索时查询那些向量表示与用户问题最接近的文档混合搜索Hybrid关键词搜索与向量搜索的组合。检索的一个难点是当数据库中没有与查询相似的记录时系统只能返回它能拿到的“最好”的信息。缓解手段包括设定相关性的最大距离阈值或使用混合搜索。本课采用混合搜索即向量搜索与关键词搜索的组合并把数据存成包含chunks文本块与embeddings向量等列的数据框。向量相似度检索器会在知识库中寻找彼此接近最近邻的嵌入因为接近意味着文本相似。用户提出查询时查询先被嵌入再与相似嵌入匹配。衡量向量相似度的常用度量是余弦相似度cosine similarity它基于两个向量之间的夹角。其他可选度量包括欧氏距离Euclidean distance向量端点之间的直线距离点积Dot product度量两个向量对应元素乘积之和。搜索索引执行检索前需要为知识库构建搜索索引。索引保存嵌入向量即使在大型数据库中也能快速取出最相似的块。课程给出的本地索引实现如下from sklearn.neighbors import NearestNeighbors embeddings flattened_df[embeddings].to_list() # 创建搜索索引 nbrs NearestNeighbors(n_neighbors5, algorithmball_tree).fit(embeddings) # 查询索引可使用 kneighbors 方法 distances, indices nbrs.kneighbors(embeddings)其中n_neighbors5表示每次查询返回 5 个最近邻algorithmball_tree指定使用球树算法加速近邻查找。笔记本在构建索引后还会把indices与distances回写到 DataFrame 中方便后续逐行查看每个块命中了哪些邻居。重排序Re-ranking查询数据库之后可能需要按相关性对结果重新排序。重排序模型利用机器学习把搜索结果按相关性从高到低排列。使用 Azure AI Search 时重排序由语义重排序器semantic reranker自动完成。基于最近邻的重排序示例# 找到最相似的文档 distances, indices nbrs.kneighbors([query_vector]) index [] # 打印最相似的文档 for i in range(3): index indices[0][i] for index in indices[0]: print(flattened_df[chunks].iloc[index]) print(flattened_df[path].iloc[index]) print(flattened_df[distances].iloc[index]) else: print(fIndex {index} not found in DataFrame)这段代码的意图是对查询向量做一次kneighbors检索取前几名邻居打印出对应的文本块chunks、来源文件path与距离distances从而直观验证“哪些文档块与查询最相关”。把所有环节串起来RAG 聊天机器人最后一步是把 LLM 加进来让回答锚定在自有数据上。课程文档给出的完整实现如下user_input what is a perceptron? def chatbot(user_input): # 把问题转换为查询向量 query_vector create_embeddings(user_input) # 找到最相似的文档 distances, indices nbrs.kneighbors([query_vector]) # 把检索到的文档加入查询以提供上下文 history [] for index in indices[0]: history.append(flattened_df[chunks].iloc[index]) # 合并历史上下文与用户输入 history.append(user_input) # 构造消息对象 messages[ {role: system, content: You are an AI assistant that helps with AI questions.}, {role: user, content: \n\n.join(history) } ] # 使用响应式 API 生成回答 response client.responses.create( modelgpt-4o-mini, temperature0.7, max_output_tokens800, inputmessages, storeFalse, ) return response.output_text chatbot(user_input)调用链可以概括为create_embeddings(user_input)→nbrs.kneighbors([query_vector])→ 用命中的块拼上下文 → 组装messages→ 调用 LLM 返回response.output_text。这里有一个值得注意的源码级细节如果对照 notebook-rag-vector-databases.ipynb 的最后一个聊天单元它同样构建了history但组装消息时user消息的内容只传入了history[-1]即用户问题本身从源码结构看检索到的上下文块并没有真正拼进最终 prompt——这是一个容易踩的坑。正确做法应如上文文档版本用\n\n.join(history)把检索片段与问题一起送入模型否则 RAG 的“增强”就名存实亡了。此外笔记本中 LLM 调用使用的是 Responses APIclient.responses.create参数为modelchat_deployment来自AZURE_OPENAI_DEPLOYMENT环境变量、temperature0.7、max_output_tokens800、storeFalse返回结果为response.output_text字符串与旧版 Chat Completions 接口choices[0].message在取值方式上不同。应用评估评估指标课程给出四个定性评估维度回答质量确保输出自然、流畅、接近人类表达数据锚定性Groundedness评估回答是否确实来自所提供的文档相关性Relevance评估回答是否与所提问题匹配且相关流畅性Fluency回答在语法上是否通顺合理。基于平均精度均值MAP的量化评估配套笔记本在“Testing and evaluation”一节补充了量化手段用 scikit-learn 的average_precision_score计算 Mean Average PrecisionMAP来度量检索/回答的相关性。其做法是为每个查询准备“相关回答”与“不相关回答”两组把 RAG 应用生成的回答与候选列表比对构造二值标签与预测得分再对多个测试用例如“What is a perceptron?”“What is machine learning?”“What is deep learning?”“What is a neural network?”的平均精度求均值from sklearn.metrics import average_precision_score test_cases [ { query: What is a perceptron?, relevant_responses: [A perceptron is a type of artificial neuron., ...], irrelevant_responses: [A perceptron is a type of fruit., ...] }, # ... 更多测试用例 ] total_average_precision 0 for test_case in test_cases: query test_case[query] response chatbot(query) all_responses test_case[relevant_responses] test_case[irrelevant_responses] true_labels [1] * len(test_case[relevant_responses]) [0] * len(test_case[irrelevant_responses]) predicted_scores [1 if resp response else 0 for resp in all_responses] average_precision average_precision_score(true_labels, predicted_scores) total_average_precision average_precision mean_average_precision total_average_precision / len(test_cases)这意味着一个 RAG 应用不仅要做定性检查还可以为每个查询建立“相关/不相关”测试集用 MAP 持续追踪检索质量的变化。RAG 与向量数据库的典型用例问答系统QA把公司数据锚定到一个聊天应用中供员工提问推荐系统构建匹配最相似项的系统例如电影、餐厅等聊天机器人服务存储对话历史并基于用户数据个性化会话基于向量嵌入的图片搜索在图像识别与异常检测场景中很有用。总结与课后任务本课覆盖了 RAG 的基础领域从把数据加入应用、用户查询到最终输出。如果想简化 RAG 的搭建可以使用 Semantic Kernel、LangChain 或 Autogen 等框架。课后任务Assignment用你选择的框架为应用构建一个前端界面使用 LangChain 或 Semantic Kernel 等框架重新实现一遍你的 RAG 应用。延伸学习课程英文原文15-rag-and-vector-databases/README.md完整可运行笔记本15-rag-and-vector-databases/notebook-rag-vector-databases.ipynb知识库样例数据data/perceptron.md、data/frameworks.md、data/own_framework.md本课为“搜索应用”第 8 课的进阶篇可结合 08-building-search-applications/README.md 一起阅读理解从“把数据接入 LLM”到“完整 RAG 流水线”的演进路径。【免费下载链接】generative-ai-for-beginners21 Lessons, Get Started Building with Generative AI项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai-for-beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考