1、RAG: 检索增强生成(Retrieval Augmented Generation),简称 RAG
2、实现原理框架图:

3、流程主要节点:
| 大流程 | 小流程 | 释义 | 涉及的相关技术 | 补充 |
|---|---|---|---|---|
| 提问前 | 切片 | 将文档切分为很多片段。分片可以有很多方式,如按照字数、按照段落、按照标题、按照页码等。 | 常见的切片手段: 1、固定长度切片 2、窗口函数切片 3、标题切片 4、语义切片 | |
| 索引 | 通过Embedding将片段文本转换为向量。并且将文本和向量片段都存储在向量数据库中。 | 向量:有大小和方向的量 示例: [0.5] 这是一个一维向量 ; 数学表示一条横线的坐标轴。 [0.22,1.36] 这是一个二维向量;数学表示x,y坐标系。 [1.0, 23.3 ,5.77, -6.22, -3.6] 这是一个5维向量 ;发挥想象力. Embedding: 将文本转化向量的过程。 这里的算法可以METB排行榜: https://huggingface.co/spaces/mteb/leaderboard
向量数据库:存储原始文本和向量的数据库。
| ||
| 提问后 | 召回 | 搜索与用户问题相关的过程。用户问题发给embedding模型,转化为向量,发给向量数据库,查询最为相关的几个问题答案。 | 向量间的相似度常见的算法: 余弦相似度:测量向量空间中两个向量之间角度的余弦。取值范围为-1到1,其中1表示相同向量,0表示正交向量,-1表示完全相反的向量。角度越小相似度越高。
欧氏距离:测量向量空间中两个向量之间的直线距离。它的范围从 0 到无穷大,其中 0 表示相同的向量,较大的值表示越来越不相似的向量。距离越小,相似度越高。
点积:测量两个向量的幅值与它们之间角度的余弦的乘积。范围为-∞到∞,其中正值表示指向相同方向的向量,0表示正交向量,负值表示指向相反方向的向量。乘积越大,相似度越高。
| 召回阶段的相似度算法成本低、耗时短、准确率低,适合做初步筛选 |
| 重排 | 基于召回的10个片段中,选择2-3个与用户问题最相似的作为重拍的结果。(为了提升查找效率) | 使用cross-encoder的算法 | cross-encoder算法成本高、耗时长、准确率高 | |
| 生成 | 结合LLM大模型,prompt提示词生成用户需要的答案。 |
4、采用ChromaDB向量数据库的示例代码
原始语料:
#中华人民共和国的国都
中华人民共和国的国都现在迁都在长沙。长沙是一座没有历史的新的城市,在沙漠地带上建立起来的。
#美食
长沙的美食有仙人掌、仙人球、还有嫩叶子。
#娱乐
长沙的娱乐只有骑单车这一项活动,这里的人民都热爱骑自行车。
切片代码:
from typing import Any
from typing_extensions import Literal
def read_data() -> str:
with open("./data.md","r",encoding="utf-8") as file:
return file.read()
def get_chunkds() -> list[str]:
content: str = read_data()
print(str)
chunks: list[str] = content.split('\n\n')
result: list[Any] = []
header: Literal[''] = ""
for chunk in chunks:
if chunk.startswith('#'):
header += f"{chunk}\n"
else:
result.append(f"{header}{chunk}")
header: Literal[''] = ""
return chunks
if __name__ == "__main__":
chunks: list[str] = get_chunkds()
for c in chunks:
print(c)
print("---------------------")
存入向量数据库chromadb代码:
import os
import chunk
import chromadb
chromadb_client = chromadb.PersistentClient("./chroma2.db")
chromadb_collection = chromadb_client.get_or_create_collection("changshacity2")
def create_database() -> None:
for idx,c in enumerate(chunk.get_chunkds()):
print(f"Process: {c}")
# embedding = embed(c,store=True)
# print(embedding)
try:
chromadb_collection.upsert(
ids=[str(idx)],
documents=[c]
)
print(f"第 {idx} 条数据插入成功")
except Exception as e:
print(f"第 {idx} 条数据插入失败: {str(e)}")
raise
if __name__ == "__main__":
create_database()
print("执行完毕")
召回片段向量:
import chromadb
from chromadb.config import Settings
# 初始化 ChromaDB 客户端(0.5.3 版本推荐显式指定设置)
client = chromadb.Client(
Settings(
persist_directory="./chroma2.db", # 数据存储路径
is_persistent=True # 启用持久化存储
)
)
# 获取已存在的集合(假设集合名为"my_collection")
collection = client.get_collection(name="changshacity2")
def query_with_distance(query_text: str, n_results: int = 3) -> list[dict]:
"""
在 ChromaDB 0.5.3 中查询并返回包含距离的结果
参数:
query_text: 查询文本
n_results: 期望返回的结果数量
返回:
包含 id、文档内容和距离的字典列表
"""
# 执行查询,通过 include 参数指定返回距离
results = collection.query(
query_texts=[query_text], # 查询文本(列表形式)
n_results=n_results # 返回的结果数量
)
# 格式化结果:将原始结果转换为更易读的字典列表
formatted_results = []
# 0.5.3 版本中,results 的每个字段是二维列表(外层对应查询文本索引)
for i in range(len(results["ids"][0])):
formatted_results.append({
"id": results["ids"][0][i],
"document": results["documents"][0][i],
"distance": results["distances"][0][i] # 距离值(越小相似度越高)
})
return formatted_results
# 示例用法
if __name__ == "__main__":
# 要查询的文本
query_text = "中国的国都在哪"
# 获取查询结果(包含距离)
similar_docs = query_with_distance(query_text, n_results=3)
# 打印结果
print(f"查询文本: {query_text}\n")
for idx, doc in enumerate(similar_docs, 1):
print(f"结果 {idx}:")
print(f"ID: {doc['id']}")
print(f"文档内容: {doc['document'][:100]}...") # 只显示前100个字符
print(f"距离(相似度): {doc['distance']:.4f}") # 保留4位小数
print("-" * 60)
召回输出的结果:

使用Chromadb的关键点在于依赖,注意以下几个版本安装
pip install numpy==1.26.4
pip install onnxruntime==1.16.3
pip install chromadb==0.5.3






444

被折叠的 条评论
为什么被折叠?



