news 2026/9/8 21:38:04

用 RAG 与向量数据库打造私有知识库问答应用:generative-ai-for-beginners 第 15 课实战解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 RAG 与向量数据库打造私有知识库问答应用:generative-ai-for-beginners 第 15 课实战解析

用 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)的核心机制、向量数据库的设计思路,以及如何把「自有私有数据」嵌入 LLM 应用以获得可验证、可溯源、低成本的知识问答能力。完成本课你将掌握:RAG 的完整工作链路(知识库构建 → 文本分块 → Embedding → 向量检索 → 重排 → 增强生成)、向量数据库(以 Azure Cosmos DB 为例)的创建方法,以及一份可直接在仓库 notebook-rag-vector-databases.ipynb 中逐格运行的端到端代码实现。

注:本仓库包含 60+ 语言翻译。本指南内容基线取自 translations/el/15-rag-and-vector-databases/README.md(希腊语版),同时对照根目录英文原版 15-rag-and-vector-databases/README.md 与配套 notebook,确保信息最新且可复现。


一、本课的出发点:把「自己的数据」接进 LLM

在课程的搜索应用章节中,我们初步接触了「将自有数据整合进大语言模型(LLM)」;本课则深入三层问题:

  1. 什么是 RAG,为何 AI 应用中需要它;
  2. 向量数据库是什么,如何为应用搭建一个;
  3. 如何把一个 RAG 应用完整集成进项目。

学习目标

完成本课后,你将能够:

  • 解释 RAG 在数据检索与处理中的重要性;
  • 搭建 RAG 应用并把自有数据锚定(grounding)到 LLM 上;
  • 在 LLM 应用中高效整合 RAG 与向量数据库。

教学场景:用 AI for Beginners 神经网络课程数据喂饱聊天机器人

本课设定在一个教育类创业公司场景中:希望把课程自有讲义接入聊天机器人,让它能回答更多学科问题,学生据此可生成随堂测验(practice quizzes)、复习闪卡(revision flash cards)或浓缩要点综述。该场景由以下三部分构成:

组件在本场景中的角色
Azure OpenAI用于构建聊天机器人的 LLM(对话生成与 Embedding 生成)
AI for Beginners 神经网络课用于锚定(grounding)LLM 的私有数据源
Azure AI Search+Azure Cosmos DB向量数据库,负责存储数据并建立检索索引

课程正文实际引用的数据就是仓库里的三份神经网络讲义,notebook 中通过data_paths依次读入:

  • data/frameworks.md
  • data/own_framework.md
  • data/perceptron.md

notebook 里加载代码与说明(见 notebook-rag-vector-databases.ipynb):它们以pathtext两列存进 pandas DataFrame,text保留原始 Markdown 全文,便于后续切片。


二、RAG 原理:为什么 LLM 需要「临时外挂」知识

2.1 LLM 的固有局限

LLM 驱动的聊天机器人虽然擅长交互式问答,但它的回答被严格限制在两处:提供的上下文预训练数据。典型例证是 GPT-4 的知识截止日期(knowledge cutoff)为 2021 年 9 月——此后的新事件它一概不知。更关键的是,训练数据里永远不会包含私有、保密的信息:比如你的个人笔记,或某家公司的产品手册。

这正是 RAG 存在的根本理由:不重训、不微调,而是把外部知识在推理时动态「接」进来。

2.2 RAG 的四步工作流

假设你想部署一个「根据自己笔记生成测验题」的聊天机器人,就必须打通它和知识库的连接——这就是 RAG 的用武之地。它的运转机制如下:

  • 知识库(Knowledge base):检索发生之前,文档必须先被摄入(ingest)并预处理,通常做法是把大文档拆成小块(chunk)、转成文本 Embedding,再存入数据库。
  • 用户查询(User query):用户提出一个问题。
  • 检索(Retrieval):当用户提问时,Embedding 模型从知识库检索相关信息,作为更多上下文注入 prompt。
  • 增强生成(Augmented generation):LLM 依据检索到的数据强化回答。最终答案不只基于预训练知识,还参考了额外上下文;LLM 随后把答案返回给用户。

2.3 Transformer 编码器-解码器架构视角

RAG 的架构由 Transformer 的两部分组成——编码器(encoder)与解码器(decoder)。举例:用户提问后,输入文本被「编码」成捕捉词汇含义的向量;这些向量再在文档索引中被「解码」,基于用户查询生成新文本。LLM 正是依靠这种 encoder-decoder 模型产出最终输出。

2.4 两种实现范式:RAG-Sequence 与 RAG-Token

依据提出 RAG 的论文《Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks》(Lewis 等,2020),实现上有两种范式:

  • RAG-Sequence:用检索到的文档直接预测用户查询的最佳答案(检索整段文档 → 一次生成整段序列)。
  • RAG-Token:用文档生成下一个 token,随后检索并以 token 粒度应答用户查询(生成与检索按 token 交替进行)。

二者的取舍本质是「检索结果的粒度」与「生成流程的可控性」之间的平衡:前者更省调用,后者更精细,可逐 token 引用不同证据。

2.5 为什么值得用 RAG

  • 信息富集(Information richness):保证文本回答实时、不过时;通过访问内部知识库,可显著提升特定领域任务的表现。
  • 抑制幻觉(Reduces fabrication):用知识库中可验证的数据为用户查询提供上下文,让生成内容有据可依。
  • 成本可控(Cost effective):相比对 LLM 做精细微调(fine-tuning),RAG 性价比高得多——不需要训练算力,只需按检索与推理计费。

三、构建知识库:向量数据库与「文本 → Embedding」

本课的应用建立在私有数据之上,也就是 AI For Beginners 课程中的神经网络章节。第一步是把文档安全地落库。

3.1 什么是向量数据库

与存储行/列的传统关系型数据库不同,向量数据库是一类专门设计来存储、管理与检索 embedding 向量的数据库。它保存的是文档的数值化表示。把数据拆成数值 Embedding,能让 AI 系统更容易理解和处理。

为什么不能把 Embedding 一股脑塞进 LLM?因为LLM 对输入 token 数有硬上限。你无法把整份 Embedding 全部传给模型,必须切块存储;用户提问时,最接近问题的那些 Embedding 块会连同 prompt 一起返回。同时,分块还能降低流过 LLM 的 token 数量,从而降低成本

常见向量数据库有:Azure Cosmos DB、Clarifai、Pinecone、ChromaDB、ScaNN、Qdrant、DeepLake 等。本课采用Azure Cosmos DB作为存储 +Azure AI Search建检索索引。

3.2 用 Azure CLI 创建 Cosmos DB

课程与 notebook 给出了用 Azure CLI 创建资源的完整命令序列(notebook-rag-vector-databases.ipynb):

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>

各命令作用与占位符说明:

命令作用
az login登录 Azure CLI 并完成身份认证
az group create -n <rg> -l <loc>在指定区域<location>创建资源组<resource-group-name>
az cosmosdb create -n <name> -r <rg>在资源组中创建 Cosmos DB 账号(注意此处使用-r指定资源组,部分 CLI 版本需写为-g
az cosmosdb list-keys -n <name> -g <rg>列出账号密钥,供后续 SDK 连接鉴权

创建完成后,需到门户(Portal)的 Data Explorer 中新建数据库(database)与容器(container)。notebook 中随后用环境变量 + Python SDK 建立连接,数据库/容器名与配置示例为(见 notebook):

from azure.cosmos import CosmosClient url = os.getenv('COSMOS_DB_ENDPOINT') key = os.getenv('COSMOS_DB_KEY') client = CosmosClient(url, credential=key) database_name = 'rag-cosmos-db' database = client.get_database_client(database_name) # 依据你在 Data Explorer 里创建的容器名继续操作 # container = database.get_container_client('<container-name>')

运行前提:本课示例依赖azure-cosmosopenaipandasnumpyscikit-learn等 Python 包,notebook 首格即执行!pip install openai,后续还有pip install azure-cosmos。运行前请先完成az login并配置COSMOS_DB_ENDPOINTCOSMOS_DB_KEYAZURE_OPENAI_ENDPOINTAZURE_OPENAI_API_KEYAZURE_OPENAI_EMBEDDINGS_DEPLOYMENTAZURE_OPENAI_DEPLOYMENT等环境变量。

3.3 文本分块:把长文档切成可检索的小段

数据入库之前,必须先把原始文本转成向量 Embedding。面对大文档/长文本,应按「预期会遇到的查询」来分块;分块粒度可以是句子级段落级。由于分块需要依靠上下文词义,建议在块内补充额外语境——例如拼上文档标题,或在块首尾带上少量前后文,避免语义被拦腰截断。

课程给出的朴素分块函数(word-based,按max_length/min_length字符区间切块)如下:

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

在 notebook 中,该函数对三份讲义逐行应用、参数取max_length=400, min_length=300(notebook):

splitted_df = df.copy() splitted_df['chunks'] = splitted_df['text'].apply(lambda x: split_text(x, 400, 300))

chunks列会以列表形式存在每行中,随后用 pandas 的explode('chunks')把块列表拍平成行——每个块单独成行,这正是后续逐块生成 Embedding 的前提(notebook):

flattened_df = splitted_df.explode('chunks')

3.4 从文本到 Embedding:选模型的关键考量

切片完成后,可用多种 Embedding 模型将文本向量化,例如:word2vec、OpenAI 的ada-002text-embedding-ada-002)、Azure Computer Vision 等。选型时需权衡四个因素:

  1. 使用的语言(模型的多语言覆盖度);
  2. 编码内容的类型(文本 / 图像 / 音频);
  3. 模型可编码的输入尺寸上限
  4. Embedding 输出向量的长度(维度直接决定存储与检索开销)。

notebook 中先配置 Azure OpenAI 兼容客户端,再读取AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT作为 Embedding 部署名(notebook):

from openai import OpenAI endpoint = os.getenv("AZURE_OPENAI_ENDPOINT") client = OpenAI( api_key=os.getenv("AZURE_OPENAI_API_KEY"), base_url=f"{endpoint.rstrip('/')}/openai/v1/", ) embeddings_deployment = os.getenv("AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT") chat_deployment = os.getenv("AZURE_OPENAI_DEPLOYMENT")

封装「文本 → 向量」的辅助函数与单块调用示例(notebook):

def create_embeddings(text, model=None): # 使用 Embedding 部署为每个文档块生成向量 model = model or embeddings_deployment embeddings = client.embeddings.create(input=text, model=model).data[0].embedding return embeddings # 为第一个块生成向量 create_embeddings(flattened_df['chunks'][0])

课程用单词"cat"直观展示了什么叫「文本被映射成一组浮点向量」——输出是数百维的数值数组,机器正是用这些数字之间的距离来「理解」语义(cat.png 演示)。

对所有块批量生成向量并回填 DataFrame(notebook):

embeddings = [] for chunk in flattened_df['chunks']: embeddings.append(create_embeddings(chunk)) flattened_df['embeddings'] = embeddings

最终flattened_df形成四列结构:path(来源文件)、text(原文)、chunks(切片文本)、embeddings(向量)。这既是课程反复强调的hybrid 检索数据底座——既保留可做关键词匹配的文本列,也保留可做语义匹配的向量列。


四、检索与向量搜索:如何从库里捞出「最相关」

当用户提问时,检索器(retriever)先把它经query encoder转成向量,随后在文档检索索引里寻找与输入相关的向量,最后把输入向量与文档向量一起还原为文本喂给 LLM。

4.1 检索的三种搜索方式

  • 关键词搜索(Keyword search):用于纯文本检索,擅长精确术语、代码符号匹配。
  • 向量搜索(Vector search):先用 Embedding 模型把文档从文本转成向量表示,从而支持基于词义的语义搜索(semantic search)——检索目标是「向量表示离用户问题最近」的文档。
  • 混合检索(Hybrid):关键词搜索与向量搜索的组合。

检索的难点:当数据库里没有与查询真正相似的答案时,系统只能返回「最接近」的内容。缓解策略包括设置最大相关性距离阈值,以及使用混合检索扬长避短。本课采用后者。

4.2 向量相似度度量

检索器在知识库中寻找**彼此靠近(最近邻)**的 Embedding——它们代表语义相似的文本。最常用的度量是余弦相似度(cosine similarity),它基于两个向量之间的夹角判定相似程度,与向量长度无关。

除余弦相似度外,还有两种备选度量:

  • 欧氏距离(Euclidean distance):向量端点间的直线距离;
  • 点积(dot product):两个向量对应元素乘积之和,常配合归一化向量近似余弦。

4.3 构建本地检索索引

真正检索前,必须先为知识库构建检索索引:索引保存全部 Embedding,即使面对海量库也能快速返回最相似块。课程用 scikit-learn 的NearestNeighbors在本地构建索引,取k=5ball_tree算法(notebook):

from sklearn.neighbors import NearestNeighbors embeddings = flattened_df['embeddings'].to_list() # 构建检索索引 nbrs = NearestNeighbors(n_neighbors=5, algorithm='ball_tree').fit(embeddings) # 查询索引可用 kneighbors 方法 distances, indices = nbrs.kneighbors(embeddings)

notebook 随后把indicesdistances两列写回 DataFrame,让每条 chunk 都能定位自己的最近邻与距离分数,便于检视检索质量。

4.4 重排(Re-ranking):让最相关结果排最前

查询数据库后,通常还需要把结果按相关性排序。重排 LLM借助机器学习按相关性重排搜索结果。在 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(f"Index {index} not found in DataFrame")

从源码结构看,notebook 中同样以「查询 →create_embeddings(question)nbrs.kneighbors→ 打印前三块」的方式验证检索器是否命中 perceptron / 多层感知机等真实讲义内容。注意该示例的内外层循环仅为教学演示检索效果,生产实现通常取indices[0][:k]循环即可。


五、串起全链路:把 LLM 接进来

最后一步是把 LLM 加入管道,获得真正锚定在自己数据上的回答。完整流程是:用户输入 → 转 query 向量 → 最近邻检索 → 命中的文档块拼入上下文 → 调对话模型 → 返回回答

根目录 README 与 notebook 当前采用的Responses API版本如下(notebook):

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)} ] # 使用 Responses API 生成回答 response = client.responses.create( model=chat_deployment, temperature=0.7, max_output_tokens=800, input=messages, store=False, ) return response.output_text chatbot(user_input)

参数速查:

参数含义本课取值
model对话部署名(来自AZURE_OPENAI_DEPLOYMENTchat_deployment
temperature采样随机性,越高越发散0.7
max_output_tokens单次输出 token 上限800
input消息序列(system + user)拼接后的上下文与问题
store=False关闭服务端会话存储

history变量承载「检索块 + 用户问题」的拼接上下文:检索块提供事实依据,追加的用户问题让模型以问答格式组织答案。在 notebook 的执行结果里,提问"what is a perceptron?"时模型基于讲义给出了「感知机是神经网络的基本单元、用于二分类、输出由加权和的阶跃激活决定」的回答,这正是 grounding 生效的直接证据。

版本说明:本课希腊语译文 translations/el/15-rag-and-vector-databases/README.md 中的对话示例仍为旧版openai.chat.completions.create(model="gpt-4", temperature=0.7, max_tokens=800, messages=messages)写法。若使用旧版 openai SDK,请保留该写法;若跟随本仓库根目录 README 与 notebook 的当前实现,则使用上述 Responses API 版本(二者仅调用接口不同,RAG 流程完全一致)。


六、应用评估:怎么判断 RAG 效果好不好

6.1 定性评估指标

课程归纳了四个观测维度:

  • 回答质量(Quality):答案是否自然、流畅、像人话;
  • 数据锚定(Groundedness):回答内容是否确实来自所提供的文档;
  • 相关性(Relevance):回答是否切题、与所问问题强相关;
  • 流畅度(Fluency):回答在语法上是否通顺、自洽。

6.2 定量评估:Mean Average Precision(MAP)

notebook 的「Testing and evaluation」一节给出了一个可运行的定量评估雏形——用平均精度均值(MAP)衡量回答相关性(notebook)。它先为每个测试问题准备「相关/不相关参考答案」两组标签,再把 RAG 生成的回答与参考答案比对打点,最后调用sklearn.metrics.average_precision_score求单查询平均精度、对所有测试用例求均值:

from sklearn.metrics import average_precision_score test_cases = [ { "query": "What is a perceptron?", "relevant_responses": ["A perceptron is a type of artificial neuron.", "It's a binary classifier used in machine learning."], "irrelevant_responses": ["A perceptron is a type of fruit.", "It's a type of car."] }, # ……更多查询:machine learning / deep learning / neural network ] total_average_precision = 0 for test_case in test_cases: query = test_case["query"] relevant_responses = test_case["relevant_responses"] irrelevant_responses = test_case["irrelevant_responses"] response = chatbot(query) # 用你的 RAG 应用生成回答 all_responses = relevant_responses + irrelevant_responses true_labels = [1] * len(relevant_responses) + [0] * len(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)

需要说明:该 MAP 示例是「演示型」评估,它假设检索/生成结果能与预置参考答案完全一致地命中,因此 notebook 运行结果为 0.5。生产环境更常见的做法是人工标注相关性等级,或借助 LLM-as-a-judge 对回答打分后再计算排序类指标。


七、RAG 与向量数据库的典型应用场景

课程指出,RAG + 向量数据库可以显著扩展的应用包括:

  • 企业知识问答(Q&A):把公司数据锚定到聊天机器人,供员工随时提问;
  • 推荐系统(Recommendation systems):匹配最相似对象,如电影、餐厅等;
  • 聊天机器人服务(Chatbot services):存储会话历史,基于用户数据实现个性化对话;
  • 基于向量 Embedding 的图像搜索:适用于图像识别与异常检测等场景。

八、总结与动手练习

本课完整覆盖了 RAG 从「自有数据接入」到「用户查询」再到「最终输出」的基本面。如果要加速 RAG 的工程化搭建,可以使用现成编排框架,例如Semantic Kernel、LangChain 或 AutoGen

动手练习建议:

  1. 用你喜欢的 Web 框架为本应用写一个前端;
  2. 选用 LangChain 或 Semantic Kernel 重建整个 RAG 应用(替换手工 DataFrame + scikit-learn 的实现,用框架内置的文档加载、文本切分、向量存储与检索抽象)。

仓库内的配套可运行资源如下,建议按顺序对照阅读:

  • 本课详细文档:15-rag-and-vector-databases/README.md(含本课希腊语译版 translations/el/15-rag-and-vector-databases/README.md)
  • 端到端可运行 notebook:15-rag-and-vector-databases/notebook-rag-vector-databases.ipynb
  • 示例知识库数据(本课 grounding 数据源):data/frameworks.md、data/own_framework.md、data/perceptron.md

【免费下载链接】generative-ai-for-beginners21 Lessons, Get Started Building with Generative AI项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai-for-beginners

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 21:36:20

液冷板热流耦合仿真实战:从传热机理到工程排查的完整指南

接手第一个液冷板项目时&#xff0c;我把热流耦合仿真算出来的芯片最高温捧给客户看——52.3℃&#xff0c;客户现场实测却接近60℃。差了将近8度&#xff0c;这个数字放在发热功率400W的功率模块上&#xff0c;意味着热阻预测偏差超过20%&#xff0c;几乎可以直接否定整个散热…

作者头像 李华
网站建设 2026/9/8 21:35:49

SVM实战:基于银行客户流失预测的分类模型全流程解析

简介&#xff1a;面向机器学习初学者与银行数据分析人员&#xff0c;该压缩包围绕银行客户流失预测场景&#xff0c;完整演示了SVM分类模型的构建流程&#xff0c;可帮助读者将算法理论落地到真实的二分类任务中。压缩包共含4个文件&#xff1a;两个CSV文件分别存放客户特征与标…

作者头像 李华
网站建设 2026/9/8 21:35:40

PCRE2 10.36编译安装实战:解决pcre2-config未找到等高频构建问题

简介&#xff1a;本资源为PCRE2正则表达式库的官方源码发布包&#xff08;v10.36&#xff09;&#xff0c;面向GIS开发、C/C底层库编译及跨平台项目集成工程师&#xff0c;尤其适用于需与proj等地理空间库协同构建的低版本VS&#xff08;如VS2015及以下&#xff09;开发环境。资…

作者头像 李华