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会根据工具解释来判断是否调用工具
    '搜索并返回关于‘半导体和芯片’的信息,内容涵盖:半导体和芯片的封装测试,光刻胶等'
)

向量数据库检索出结果后需要自我纠正

自我纠正会让结果更准确,若自我纠正仍有问题,要去排查向量数据库的问题

 

 

posted @ 2026-01-26 13:55  showMeTheCodes  阅读(6)  评论(0)    收藏  举报