首页
/ 在 generative-ai-for-beginners 中构建基于 RAG 与向量数据库的知识库问答应用

在 generative-ai-for-beginners 中构建基于 RAG 与向量数据库的知识库问答应用

2026-09-09 19:18:01作者:牧宁李

本文基于 translations/hi/15-rag-and-vector-databases/README.md 课程第 15 课整理,讲解如何在大型语言模型(LLM)应用中落地检索增强生成(RAG)与向量数据库:从文本分块、嵌入、向量检索到端到端聊天机器人,并给出可运行的 Python 代码与底层原理。读完本文,你将能够独立构建一个将私有文档"接地"到 LLM 的问答应用,并掌握检索质量评估方法。

RAG 是什么:为什么要把数据"接地"到 LLM

LLM 驱动的聊天机器人通过处理用户提示词来生成回复,其能力上限受限于上下文与预训练数据。例如 GPT-4 的知识截止于 2021 年 9 月,此后发生的事件它无从知晓;同时,用于训练 LLM 的数据通常不包含个人笔记、公司产品手册这类私密信息。因此,仅靠预训练权重无法回答私有领域问题。

检索增强生成(Retrieval Augmented Generation,RAG)正是为此而生:在生成前先从你的知识库中检索相关内容,把检索结果作为额外上下文注入提示词,再交给 LLM 生成回答。这样生成的回复既基于预训练能力,又基于你提供的真实数据。

RAG 的工作流程

RAG 工作流程示意图

RAG 的核心流程包含四个环节:

  • 知识库(Knowledge base):检索发生前,文档需要被摄取并预处理——通常将大文档切分成小块(chunk)、转换为文本嵌入(text embedding)并存入数据库;
  • 用户提问(User query):用户提出一个问题;
  • 检索(Retrieval):当用户提问时,嵌入模型从知识库中检索相关信息,为提示词补充上下文;
  • 增强生成(Augmented generation):LLM 基于检索到的数据增强其回复,使回复不只依赖预训练数据,还融合新增上下文的关联信息,最后把答案返回给用户。

RAG 的架构与两种实现范式

RAG 架构示意图

RAG 的架构基于 Transformer,包含编码器(encoder)与解码器(decoder)两部分:用户提问时,输入文本被"编码"为捕获词义的向量,这些向量在文档索引中被"解码",并基于用户查询生成新文本。

根据原论文提出的两种实现方式:

  • RAG-Sequence:使用检索到的文档预测用户查询的最佳答案(整段生成基于检索结果);
  • RAG-Token:使用文档生成下一个 token,再检索以继续回答用户查询(逐 token 结合检索)。

为什么使用 RAG

  • 信息丰富性:保证文本回复是及时、最新的,通过访问内部知识库提升领域特定任务的表现;
  • 减少幻觉(fabrication):利用知识库中可验证的数据为用户查询提供上下文,降低编造风险;
  • 成本效益高:相比对 LLM 做微调(fine-tuning),RAG 更经济。

场景设定:把课程笔记变成可问答的知识库

本课场景是教育类初创应用:把自有学习笔记加入聊天机器人,让它在不同学科上提供更多信息。实现方案由三部分组成:

用户将能基于笔记生成练习测验、复习闪卡,并把内容概括成简明要点。完整可执行示例见 15-rag-and-vector-databases/notebook-rag-vector-databases.ipynb

构建知识库

向量数据库

与传统数据库不同,向量数据库是专门用于存储、管理和检索嵌入向量的数据库,保存的是文档的数值化表示。把数据拆解为数值嵌入,能让 AI 系统更容易理解与处理数据。

之所以把嵌入存进向量数据库,是因为 LLM 对输入 token 数量有上限——你无法把全部嵌入一次性交给 LLM,需要将其切块;当用户提问时,与问题最相似的嵌入会和提示词一起返回。分块同时降低了 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>

创建完成后,在 Azure 门户的 Data Explorer 中新建数据库和容器。notebook 中随后用 CosmosClient 通过环境变量 COSMOS_DB_ENDPOINTCOSMOS_DB_KEY 建立连接(数据库名 rag-cosmos-db、容器名 data,见 notebook-rag-vector-databases.ipynb)。

从文本到嵌入

存储前,需先把数据转换为向量嵌入。处理大文档或长文本时,可按预期问题将内容分块;分块可以在句子级或段落级进行。由于块的语义来源于周围词汇,可以给块补充上下文,例如附加文档标题,或在块前后包含一些文本。分块函数示例:

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 中通过 splitted_df['chunks'] = splitted_df['text'].apply(lambda x: split_text(x, 400, 300)) 应用分块(max_length=400min_length=300),再用 flattened_df = splitted_df.explode('chunks') 把每个块展开为独立行,形成包含 pathtextchunks 列的数据帧。

分块后可选用不同嵌入模型将文本向量化,例如 word2vec、OpenAI 的 ada-002、Azure Computer Vision 等。模型选择取决于:使用的语言、编码内容类型(文本/图像/音频)、可编码的输入大小以及嵌入输出长度。

cat 一词的嵌入示意

notebook 中封装了统一的嵌入函数(调用 client.embeddings.create,模型取环境变量配置的 AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT):

def create_embeddings(text, model=None):
    # 使用嵌入部署为每个文档块创建嵌入
    model = model or embeddings_deployment
    embeddings = client.embeddings.create(input=text, model=model).data[0].embedding
    return embeddings

随后遍历所有块生成嵌入并写回数据帧:flattened_df['embeddings'] = embeddings

检索与向量搜索

用户提问时,检索器先用查询编码器把它转换为向量,再在文档搜索索引中查找与输入相关的向量;完成后,把输入向量与文档向量都转回文本,交给 LLM。

检索的目标是快速找出满足搜索条件、可用于提供上下文并把 LLM 接地到你的数据上的文档。数据库内搜索方式有:

  • 关键词搜索(keyword search):用于文本搜索;
  • 向量搜索(vector search):用嵌入模型把文档从文本转换为向量表示,借助词义实现语义搜索——检索时查询那些向量表示与用户问题最接近的文档;
  • 混合搜索(hybrid):关键词与向量搜索的组合。

当数据库中没有与查询相似的答案时,系统会返回可得的最佳信息;为控制相关性,可以设置最大距离阈值,或采用关键词+向量的混合搜索。本课采用混合搜索,并把数据存入包含块与嵌入列的数据帧中。

向量相似度度量

检索器会在知识库中寻找彼此接近的嵌入(最近邻),因为它们代表相似的文本。用户查询首先被嵌入,再与相似嵌入匹配。衡量向量相似度最常用的是余弦相似度(基于两个向量夹角的余弦值);替代方案包括:

  • 欧几里得距离(Euclidean distance):向量端点之间的直线距离;
  • 点积(dot product):两个向量对应元素乘积之和。

构建搜索索引

执行检索前,需要先为知识库建立搜索索引。索引存储嵌入,即使数据库很大也能快速取回最相似的块。本地可用 scikit-learn 构建:

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 会把返回的索引与距离写回数据帧(flattened_df['indices']flattened_df['distances']),用于后续检索与重排。

重排(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")

实际运行中,对问题 "what is a perceptron?",检索结果确实命中了 data/perceptron.md 中的感知机介绍块,验证了整条检索链路。

端到端:把所有环节串起来

最后一步是引入 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) }
    ]

    # 使用 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)

notebook 中客户端配置基于 Azure OpenAI(Microsoft Foundry)v1 端点,通过环境变量 AZURE_OPENAI_ENDPOINTAZURE_OPENAI_API_KEYAZURE_OPENAI_EMBEDDINGS_DEPLOYMENTAZURE_OPENAI_DEPLOYMENT 注入;chat_deploymentAZURE_OPENAI_DEPLOYMENT。代码路径见 notebook-rag-vector-databases.ipynb 的 "Putting it all together to answer a question" 小节。

关于 temperaturemax_output_tokenstemperature=0.7 在 0~1 之间,数值越高回复越随机、越低越确定;max_output_tokens=800 限制生成的最大 token 数,二者是生成阶段可调的核心参数。

评估应用与检索质量

评估指标

  • 回复质量(Quality):确保回复听起来自然、流畅、像人话;
  • 数据接地性(Groundedness):评估回复是否来源于所提供的文档;
  • 相关性(Relevance):评估回复是否与所问问题匹配、相关;
  • 流畅性(Fluency):回复在语法上是否通顺合理。

用 MAP 做量化评估

notebook 的 "Testing and evaluation" 小节给出了一个基于**平均精度均值(Mean Average Precision,MAP)**的量化评估示例:为每个测试查询准备相关与不相关回复,调用 chatbot(query) 生成回复,用 sklearn.metrics.average_precision_score 计算单查询平均精度,再对所有查询取平均,得到 mean_average_precision(示例输出为 0.5)。这为"检索质量可度量"提供了可直接套用的模板。

RAG 与向量数据库的应用场景

  • 问答(Question and Answering):把公司数据接地到聊天应用,供员工提问;
  • 推荐系统(Recommendation Systems):构建匹配最相似值的系统,如电影、餐厅推荐等;
  • 聊天机器人服务(Chatbot services):存储聊天历史,基于用户数据个性化对话;
  • 基于向量嵌入的图像搜索:适用于图像识别与异常检测。

总结与练习

本文覆盖了 RAG 的三大基础环节:把数据加入应用、用户查询、输出生成。为简化 RAG 构建,可借助 Semantic Kernel、LangChain 或 Autogen 等框架;更完整的可运行示例可参考 15-rag-and-vector-databases/notebook-rag-vector-databases.ipynb,样本数据位于 15-rag-and-vector-databases/data

动手练习建议:

  • 使用自己选择的框架为应用构建前端;
  • 选用 LangChain 或 Semantic Kernel 之一,重建你的 RAG 应用。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
900
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
927
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
603
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
397
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
525