RAG企业知识库项目
RAG的原理
针对大模型,补充大模型的外部数据库,避免大模型在生成数据时产生幻觉
Embeddings
将文本、图像和音频等非结构化数据格式转换为向量
Milvus支持三种部署模式
Milvus Lite是一个Python库,百万向量级别
Milvus Standalone是单机部署,十亿向量级别
Milvus Distributed可部署到k8s上,十亿以上向量级别
Milvus知识点
milvus数据库不支持修改数据操作,只支持删除后新增来代替修改
在milvus数据库中collections等价于关系型数据库中的表
schema定义了collectios的数据结构,即表结构,schema只能有一个主键
最多四个向量字段(xxx_vector)和几个标量字段
向量之间的距离越短,代表两个向量的相似度越高,一般使用两个向量夹角的余弦值计算
只要创建了向量字段就必须创建索引,index_type是向量索引类型,一般为AUTOINDEX,milvus数据库会自动选择最优索引
pdf解析器(简单的解析,一般不用)
pypdf可以抽取pdf中文本,基于langchain的解析返回结果为Document
pypdf是将每一页切成一个document,会将语义切断
Unstructured对pdf进行更加精细的分割(公司使用)
这种方式并不会将语义切断,并且每个document之间还有id关联层级
需要安装langchain-unstructured
有远程调用api和私有化部署两种调用方式
私有化部署时要配置huggingface镜像,因为解析图片时会调用国外大模型识别
document中有两部分:page_content内容数据和metadata元数据
metadata是字典,可以随意增加key
Unstructured对markdown进行拆分
使用unstructured拆分markdown后会发现每一段文字被拆分成一个document,document数量太多
->根据小标题合并document,合并后有些标题文本太长
->遍历合并后的document,当内容长度超过5000,则根据语义再切割(使用百分位进行切割)
代码位置:RAG_PROJECT->document->markdown_parser.py
混合检索:密集嵌入和稀疏嵌入
密集嵌入:语义检索,bge-large,密集向量需要归一化
稀疏嵌入:关键词匹配,BM25
混合检索:密集嵌入+稀疏嵌入
def __init__(self):
"""自定义collection的索引"""
self.vector_store_saved:Milvus = None
self.index_params = [
{ #HNSW+IP组合适合高精度,中等规模的RAG项目
"field_name":"dense", #密集向量
"index_name":"dense_inverted_index",
"index_type":IndexType.HNSW, # 基于图的近似最近邻搜索算法
"metric_type":MetricType.IP, # 按照什么规则来判断两个向量的相似度,余弦相似度计算
"params":{"M": 16, "efConstruction": 64} # M :邻接节点数,可以连接多少个相邻的点(4-64), efConstruction: 搜索范围(50-200)
},
{
"field_name":"sparse", #稀疏向量,这个稀疏向量是milvus数据库自带的
"index_name":"sparse_inverted_index",
"index_type":"SPARSE_INVERTED_INDEX",# Inverted index type for sparse vectors
"metric_type":"BM25",
"params":{
"inverted_index_algo": "DAAT_MAXSCORE",
# Algorithm for building and querying the index. Valid values: DAAT_MAXSCORE, DAAT_WAND, TAAT_NAIVE.
"bm25_k1": 1.2,
"bm25_b": 0.75
}
}
]
创建milvus数据库
只有在第一次创建collection时才需要删除,在删除collection之前要先释放内存中数据(缓存或索引数据)再删除索引
#判断collection是否存在,如果存在先释放再删除
if COLLECTION_NAME in client.list_collections():
client.release_collection(collection_name=COLLECTION_NAME) #在删除之前要释放内存中的数据库表信息
client.drop_index(collection_name=COLLECTION_NAME, index_name="dense_inverted_index")
client.drop_index(collection_name=COLLECTION_NAME, index_name="sparse_inverted_index")
client.drop_collection(collection_name=COLLECTION_NAME)
创建数据库
self.vector_store_saved = Milvus(
embedding_function=bge_embedding, #密集向量
collection_name=COLLECTION_NAME,
builtin_function=BM25BuiltInFunction, #稀疏向量
vector_field=['dense', 'sparse'], #向量字段,密集向量在前
index_params=self.index_params, #索引
consistency_level="Strong", #最高一致性,向量数据插入那一刻就可以立刻读取
auto_id=True, #自增主键
connection_args={"uri": MILVUS_URI}
)
使用langchain-milvus中,document中page-content数据会自动存到milvus数据库的text字段中,metadata中数据类型为字典,这些数据会根据字典key动态创建字段
根据稀疏向量查询milvus数据库
milvus = MilvusVectorSave()
client = milvus.vector_store_saved.client
result = client.query(
collection_name=COLLECTION_NAME,
filter="category == 'Title", #查询category==Title的所有数据
output_fields=['text', 'sparse', 'category', 'filename'] #指定要返回的字段
)
RAG的相似性检索和过滤检索
相似性检索ANN:近似近邻检索
def test1():
mv = MilvusVectorSave()
mv.create_connection(is_first=False)
#result = mv.vector_store_saved.similarity_search( #相似度检索
result = mv.vector_store_saved.similarity_search_with_score( # 相似度检索并显示分数,分数越高越相似
# similarity_search_with_score:返回的是一个二元组的列表,二元组中第二个值:分数
query='现在,最先进的纳米级清洗技术是什么?',
k=2, #返回几条数据
expr='category == "content"', #过滤检索
)
#在过滤检索和相似度检索同时存在时,先进行过滤检索,后进行相似检索
全文检索
RAG高级检索(三)、RAG的高级检索(四)
混合检索:密集向量+稀疏向量
pyMilvus(RAG高级检索(五))
langchain-Milvus(RAG高级检索(六))
RAG+Agent
RAG是不具备决策能力的,Agent具备决策能力,当不需要进行搜索时Agent会判断
#提示词模板
prompt = ChatPromptTemplate.from_messages([
('system', '你是一个智能助手,尽可能的调用工具回答用户的问题'),
#存放历史记录消息
MessagesPlaceholder(variable_name='chat_history', optional=True),
('human', '{input}'),
#存放agent的中间思考信息,因为中间信息也可能会对agent判断有好处
#该参数会在create_tool_calling_agent创建智能体时自动传入
MessagesPlaceholder(variable_name='agent_scratchpad', optional=True),
])
#第一个参数是大模型,第二个参数是自定义工具
agent = create_tool_calling_agent(llm, [retriever_tool], prompt)
#要将agent放到AgentExecutor中
executor = AgentExecutor(agent=agent, tools=[retriever_tool])
resp = executor.invoke({'input':'什么是EUV光刻机?'})
print(resp)
store = {}
def get_session_history(session_id: str) -> BaseChatMessageHistory:
if session_id not in store:
store[session_id] = ChatMessageHistory()
return store[session_id]
agent_with_history = RunnableWithMessageHistory(
executor,
get_session_history,
input_messages_key='input',
history_messages_key='chat_history',
)
reps2 = agent_with_history.invoke(
{'input':'什么是EUV光刻机?'},
config={
'configurable':{"session_id":'zs123'}
}
)
print(reps2)
mv = MilvusVectorSave()
mv.create_connection()
#创建向量检索器
retriever = mv.vector_store_saved.as_retriever(
search_type = 'similarity', #余弦相似度搜索
search_kwargs = {
"k": 3,
"score_threshold":0.1,
"ranker_type":"rrf", #结果重排算法
"ranker_params":{"k":100},
"filter":{"category":"content"}
}
)
retriever_tool = create_retriever_tool(
retriever,
#工具名称
'rag_retriever',
#工具解释,agent会根据工具解释来判断是否调用工具
'搜索并返回关于‘半导体和芯片’的信息,内容涵盖:半导体和芯片的封装测试,光刻胶等'
)
向量数据库检索出结果后需要自我纠正
自我纠正会让结果更准确,若自我纠正仍有问题,要去排查向量数据库的问题
作者:http://cnblogs.com/lyc-code/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权力。

浙公网安备 33010602011771号