TellWorldAI 世界档案
问档案English

首页›实践›实践

实践

RAG 与向量数据库入门

RAG 让大模型基于你自己的文档回答:切块、向量化、存进向量数据库,按查询检索最相似的片段作为上下文。看完能搭一个小型 RAG 聊天机器人,知道怎么评估效果。

聊天模型只认两样东西:训练数据和你塞进提示的内容。更新一点的知识、私人笔记、公司内部文档它都不知道,硬答就会编造。RAG(检索增强生成)的思路是:先把你的文档放进知识库,提问时检索出最相关的片段,连同问题一起交给模型。这篇以一个视频课程库为例,从切块、嵌入讲到向量检索和重排,最后拼出一个完整的 RAG 聊天机器人,并给出评估效果的四把尺子。

为什么需要 RAG

GPT-4 的知识截止到 2021 年 9 月,训练数据也不包含个人笔记、公司产品手册这类保密内容 [1]。RAG 用四步补上这两个缺口 [1]:

  1. 知识库:文档先被摄取和预处理——切小块、转成文本嵌入(embedding)、存进数据库;
  2. 用户提问;
  3. 检索:嵌入模型从知识库里取回相关信息,并入提示;
  4. 增强生成:模型基于检索到的数据组织回答。

架构上,RAG 把检索器(retriever)和生成器(generator)接在一起:问题转成向量,到文档索引里匹配相关文本块,再作为上下文喂给大模型。两者可以用不同的模型,RAG 也不要求编码器-解码器结构的 transformer [1]。提出 RAG 的论文给了两种做法:RAG-Sequence 用检索到的文档直接预测问题的最佳答案;RAG-Token 逐 token 生成、边生成边检索 [1]。

选 RAG 而不是微调,理由有三 [1]:信息新鲜——靠内部知识库保证回答与时俱进,领域任务表现更好;减少编造——上下文来自可验证的数据;省钱——比微调大模型经济得多。还有一条隐性的工程优势:知识库更新只需要重新摄取文档,不用重训模型——产品手册改版、笔记增补,当天就能反映到回答里。

向量数据库与切块

向量数据库专门用来存储、管理和检索嵌入向量——文档的数值化表示,把数据变成数字向量之后,AI 系统才好理解和处理 [1]。因为大模型能接受的输入 token 数有限,文档要先切块再嵌入;与问题最相似的块会随提示返回,切块同时也减少了传给模型的 token 数,降低调用成本 [1]。常见选择有 Azure Cosmos DB、Clarifyai、Pinecone、Chromadb、ScaNN、Qdrant、DeepLake [1]。Azure Cosmos DB 用四条 CLI 命令就能建好 [1]:

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>

切块的粒度比想象中重要:可以按句子切,也可以按段落切;由于一个块的含义来自上下文,给它补充背景有帮助——比如带上文档标题,或把块前后的文字一并纳入 [1]。选粒度时从检索场景倒推:用户的问题通常多大、答案一般多长,块就应该差不多大——块太小语义不完整,太大则检索不精准、白耗 token。一个按词数切块的最小实现 [1]:

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 the last chunk didn't reach the minimum length, add it anyway
    if current_chunk:
        chunks.append(' '.join(current_chunk))

    return chunks

嵌入模型可选 word2vec、OpenAI 的 ada-002、Azure Computer Vision 等;按语言、内容类型(文本/图像/音频)、能编码的输入大小和嵌入输出长度来选 [1]。

检索与向量搜索

用户提问时,检索器先把问题编码成向量,再到文档索引里找相关的文档向量,最后把两者都转回文字传给大模型 [1]。这条链路的每一环都可能丢信息:问题编码得准不准、索引建得好不好、返回的块排序对不对,排查回答质量问题时按这个顺序逐环检查。搜索方式有三种:关键词搜索针对文本;向量搜索用嵌入模型把文档变成向量,按语义检索——取与问题向量最近的文档;混合检索则是两者的结合 [1]。一个要防的坑:数据库里没有相似内容时,系统照样返回「最像」的结果——可以设置相关性的最大距离阈值,或者直接用混合检索兜底 [1]。

相似度最常用余弦相似度,基于两个向量的夹角;欧氏距离(向量端点间的直线距离)和点积(对应元素乘积之和)也可以 [1]。三种度量的适用场合不同:文本语义检索一般从余弦相似度起步,它对向量长度不敏感;换成别的嵌入模型时,记得确认文档推荐的度量方式,两者要配套。搜索索引负责把「最相似的块」快速取出来,数据库再大也不怕;本地建索引用 scikit-learn 几行就够 [1]:

from sklearn.neighbors import NearestNeighbors

embeddings = flattened_df['embeddings'].to_list()

# Create the search index
nbrs = NearestNeighbors(n_neighbors=5, algorithm='ball_tree').fit(embeddings)

# To query the index, you can use the kneighbors method
distances, indices = nbrs.kneighbors(embeddings)

查出来的结果还可以按相关度重排(re-ranking):重排模型会把最相关的排到前面;Azure AI Search 用语义重排器自动完成这一步 [1]:

# Find the most similar documents
distances, indices = nbrs.kneighbors([query_vector])

# Print the three most similar documents with their distance to the question
for distance, index in zip(distances[0][:3], indices[0][:3]):
    print(flattened_df['chunks'].iloc[index])
    print(flattened_df['path'].iloc[index])
    print(distance)

拼装完整应用

最后把大模型接进来。聊天机器人先把问题转成向量,取最近的块堆进上下文,再生成回答 [1]:

user_input = "what is a perceptron?"

def chatbot(user_input):
    # Convert the question to a query vector
    query_vector = create_embeddings(user_input)

    # Find the most similar documents
    distances, indices = nbrs.kneighbors([query_vector])

    # add documents to query  to provide context
    history = []
    for index in indices[0]:
        history.append(flattened_df['chunks'].iloc[index])

    # combine the history and the user input
    history.append(user_input)
    # create a message object
    messages=[
        {"role": "system", "content": "You are an AI assistant that helps with AI questions."},
        {"role": "user", "content": "\n\n".join(history) }
    ]

    # use the Responses API to generate a response
    response = client.responses.create(
        model="gpt-5-mini",
        max_output_tokens=800,
        input=messages,
        store=False,
    )

    return response.output_text

chatbot(user_input)

效果从四个维度评估:回答质量(自然、流畅、像人话);忠实度(groundedness,回答是否真的来自提供的文档);相关性(回答是否切题);流利度(语法是否通顺)[1]。典型场景包括:把公司数据接进员工问答、按相似度匹配的电影餐厅推荐系统、存聊天记录做个性化的客服机器人,以及基于向量嵌入的图像搜索(图像识别、异常检测)[1]。不想从零拼装的话,Semantic Kernel、LangChain、AutoGen 这些框架把大部分管道工作都封装好了 [1]。上线前拿四个评估维度各设计一组测试问题——特别是忠实度:准备一些知识库里根本没有答案的问题,看应用是老实承认不知道,还是照样编一个。

本文改编自 Microsoft 开源课程《Generative AI for Beginners》第 15 课[1],原文以 MIT 许可证发布。

来源

  1. 1

引用本页: RAG 与向量数据库入门. TellWorld, https://www.tellworld.net/zh/practice/practice-rag-vector-databases. 更新于 2026-11-14

相关动态