微信扫码
与创始人交个朋友
我要投稿
我们在开发RAG增加检索应用时,总会遇到数据隔离的问题,比如,你上传的资料数据,不能让别人检索到,不然会存在数据安全问题。所以我们得为每个用户的数据进行隔离, 他们都不应该看到对方的数据,除非数据已经授权或者分配权限给他们访问。
本文主要实现该功能,只有进行了分配权限才能访问数据,该功能在企业或者RAG增强检索当中是比较常用的。
不清楚RAG增强检索的可以看之前的文章
1.先加载文档
2.对文档数据进行分块
3.分块之后增加role
权限字段,用于过滤权限
4.在检索文档数据时,会按role
的值进行过滤
5.把过滤好后的文档数据,加上用户提的问题一起发给llm模型处理(通义千问)
6.LLM处理后,返回结果
该功能实现的核心是增加role
权限字段过滤,在用户提问的时候,就分配好了他能检索哪方面的数据。
为了以后能够检索大量的文档,我们需要把文档数据存储起来,这里会用到矢量数据库。
矢量数据库目前暂定为qdrant
,选它的原因主要是因为它是开源的,能兼容多平台,在windows
系统下也能快速安装,使用起来很方便。
也挺想用milvus
矢量数据库的,它也是开源的,文档也挺全面,在windows
下使用相对麻烦,就放弃了。
langchain
+qwen
+qdrant
通义千问API-KEY
一个
# 如果缺少了依赖请参考之前的文章,这里只安装了qdrant相关的
pip install --upgrade --quiet qdrant-client
from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_community.vectorstores import Qdrant
from langchain_community.document_loaders import PyPDFLoader
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
from qdrant_client.http import models as rest
from langchain.prompts import PromptTemplate
from langchain.chains.retrieval_qa.base import RetrievalQA
import os
qwen_api_key = "你的通义千问API-KEY"
os.environ["DASHSCOPE_API_KEY"] = qwen_api_key
embeddings = DashScopeEmbeddings(
model="text-embedding-v1", dashscope_api_key=qwen_api_key
)
读取文档数据的方法,并定义角色metadata.roles
字段,分块后的文档都会有该字段,表示这个文档有哪些角色可以访问。
def readPdfData(documents):
page = []
for document_path, roles in documents.items():
# 读取当前目录下文件名为test.pdf和byd.pdf的文件
pdf_loader = PyPDFLoader(document_path, extract_images=True)
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, chunk_overlap=200, add_start_index=True
)
loaded_documents = pdf_loader.load_and_split()
for doc in loaded_documents:
doc.metadata["roles"] = roles
# 对文档进行分块
split_documents = text_splitter.split_documents(loaded_documents)
page.extend(split_documents)
return page
读取test
文件,并设置角色过滤字段roles
为ali
,意思是检索文档数据时,参数中roles
字段包含ali
的时候才能访问这个文档数据
# 该pdf为阿里的财报
split_documents = readPdfData({"test.pdf": ["ali"]})
qdrant
矢量数据库对象存储数据的集合名称为my_documents
,构建的方式是把文档数据加载到内存,仅用于测试,想构成存储到磁盘或者使用本地服务器的话参考官方提供的例子。
# 内存方式
qdrant = Qdrant.from_documents(
split_documents,
embeddings,
prefer_grpc=True,
location=":memory:", # 加载到内存
collection_name="my_documents",
)
读取maotai
文件,并也为该文件分配了maotai
权限
# 该文档为茅台的财报,可多个pdf
documents = {
"maotai.pdf": ["maotai"],
}
split_documents = readPdfData(documents)
# 追加新的文档
qdrant.add_documents(split_documents, batch_size=20)
定义检索对象
检索文档数据库时,只会检索metadata.roles
字段为maotai
、ali
的数据,其它数据都会过滤掉。
user_roles = ["maotai", "ali"]
qdrant_retriever = qdrant.as_retriever(
search_kwargs={
"filter": rest.Filter(
must=[
rest.FieldCondition(
key="metadata.roles",
match=rest.MatchAny(any=user_roles)
)
]
)
}
)
构建大语言模型对象
llm = ChatTongyi(model="qwen-plus")
向qwen模型提问
根据用户提的问题,先去文档数据库中检索, 检索时会按我们定义的user_roles
过滤掉数据,拿到相似的结果后,会根据用户的问题+相似的结果,一起发送给qwen
模型,模型处理后会把最终的结果返回给我们。
prompt_template = """
Question: {question}
使用源回答问题。如果没有答案,请说"文本中没有答案".
Source: {context}
### Response:
"""
# 构建提问模板
prompt = PromptTemplate(
template=prompt_template, input_variables=["context", "question"]
)
# 构建过滤请求对象
retrieval_qa = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=qdrant_retriever,
return_source_documents=True,
chain_type_kwargs={"prompt": prompt},
)
# 发送请求
response = retrieval_qa.invoke({"query": "贵州茅台?"})
print(response["result"])
以下是返回的结果,可以看出我们已经能访问到maotai.pdf
文件的数据了
在2023年第三季度报告中,贵州茅台的主要财务数据显示:
1. 营业收入为103,268,354,688.44元,同比增长18.48%。
2. 归属于上市公司股东的净利润为52,876,217,064.12元,同比增长19.09%。
3. 流动资产中,货币资金为70,641,010,014.72元,拆出资金为95,625,606,731.69元。
4. 负债和所有者权益总计为262,076,424,771.47元,所有者权益合计为225,018,799,759.41元。
此外,报告还列出了贵州茅台的前10名无限售条件股东,其中中国贵州茅台酒厂(集团)有限责任公司是最大股东,持有679,211,576股。其他股东包括香港中央结算有限公司、贵州省国有资本运营有限责任公司等。
还是提同样的问题,我们把该访问maotai.pdf
的角色授权roles
字段改为a
,这里我们就不会访问到数据了,因为我们没有maotai
权限,我们定义了只有这个权限才能访问该文件。
把上面【定义检索对象】这个代码改为以下代码,执行,然后再重新执行【向qwen模型提问】中的代码进行提问
# 改为a权限
user_roles = ["a", "ali"]
qdrant_retriever = qdrant.as_retriever(
search_kwargs={
"filter": rest.Filter(
must=[
rest.FieldCondition(
key="metadata.roles",
match=rest.MatchAny(any=user_roles)
)
]
)
}
)
最终返回的结果如下:
贵州茅台在上述文本中没有被提及。
最后总结:本次我们实现了用户之间的数据隔离,在存储文档时我们用到了qdrant
开源矢量数据库,通过保存文档时定义权限字段,用户在检索文档时,只有请求参数中含有我们的文档权限时,才会访问到我们的数据,主要是通过检索时按指定字段来过滤实现该功能的。
53AI,企业落地应用大模型首选服务商
产品:大模型应用平台+智能体定制开发+落地咨询服务
承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-11-22
如何使用 RAG 提高 LLM 成绩
2024-11-21
提升RAG性能的全攻略:优化检索增强生成系统的策略大揭秘 | 深度好文
2024-11-20
FastGraphRAG 如何做到高达 20%优化检索增强生成(RAG)性能优化
2024-11-20
为裸奔的大模型穿上"防护服":企业AI安全护栏设计指南
2024-11-20
RAG-Fusion技术在产品咨询中的实践与分析
2024-11-19
构建高性能RAG:文本分割核心技术详解
2024-11-19
【RAG竞赛获奖方案】CCF第七届AIOps国际挑战赛季军方案分享EasyRAG:一个面向AIOps的简洁RAG框架
2024-11-19
企业RAG构建中,如何用“行级别权限管控”避免数据泄露
2024-07-18
2024-05-05
2024-07-09
2024-07-09
2024-05-19
2024-06-20
2024-07-07
2024-07-07
2024-07-08
2024-07-09
2024-11-06
2024-11-06
2024-11-05
2024-11-04
2024-10-27
2024-10-25
2024-10-21
2024-10-21