使用PebbloRetrievalQA的身份启用RAG
PebbloRetrievalQA 是一个用于问答的检索链,具有身份和语义强制功能,针对向量数据库。
本笔记本介绍了如何使用身份和语义执行(拒绝主题/实体)来检索文档。 有关Pebblo及其SafeRetriever功能的更多详细信息,请访问Pebblo文档
步骤:
- 加载文档: 我们将加载带有授权和语义元数据的文档到内存中的Qdrant向量存储中。这个向量存储将用作PebbloRetrievalQA中的检索器。
注意:建议使用PebbloSafeLoader作为在数据摄取端加载带有认证和语义元数据的文档的对应工具。
PebbloSafeLoader
保证文档的安全和高效加载,同时保持元数据的完整性。
- 测试执行机制: 我们将分别测试身份和语义执行。对于每个用例,我们将定义一个特定的“ask”函数,并包含所需的上下文(auth_context 和 semantic_context),然后提出我们的问题。
设置
依赖项
在本教程中,我们将使用OpenAI LLM、OpenAI嵌入和Qdrant向量存储。
%pip install --upgrade --quiet langchain langchain_core langchain-community langchain-openai qdrant_client
身份感知数据摄取
这里我们使用Qdrant作为向量数据库;然而,你可以使用任何支持的向量数据库。
PebbloRetrievalQA 链支持以下向量数据库:
- Qdrant
- Pinecone
- Postgres(利用pgvector扩展)
加载带有授权和元数据中语义信息的向量数据库:
在这一步中,我们将源文档的授权和语义信息捕获到每个块的VectorDB条目的元数据中的authorized_identities
、pebblo_semantic_topics
和pebblo_semantic_entities
字段中。
注意:要使用PebbloRetrievalQA链,您必须始终将授权和语义元数据放置在指定的字段中。这些字段必须包含一个字符串列表。
from langchain_community.vectorstores.qdrant import Qdrant
from langchain_core.documents import Document
from langchain_openai.embeddings import OpenAIEmbeddings
from langchain_openai.llms import OpenAI
llm = OpenAI()
embeddings = OpenAIEmbeddings()
collection_name = "pebblo-identity-and-semantic-rag"
page_content = """
**ACME Corp Financial Report**
**Overview:**
ACME Corp, a leading player in the merger and acquisition industry, presents its financial report for the fiscal year ending December 31, 2020.
Despite a challenging economic landscape, ACME Corp demonstrated robust performance and strategic growth.
**Financial Highlights:**
Revenue soared to $50 million, marking a 15% increase from the previous year, driven by successful deal closures and expansion into new markets.
Net profit reached $12 million, showcasing a healthy margin of 24%.
**Key Metrics:**
Total assets surged to $80 million, reflecting a 20% growth, highlighting ACME Corp's strong financial position and asset base.
Additionally, the company maintained a conservative debt-to-equity ratio of 0.5, ensuring sustainable financial stability.
**Future Outlook:**
ACME Corp remains optimistic about the future, with plans to capitalize on emerging opportunities in the global M&A landscape.
The company is committed to delivering value to shareholders while maintaining ethical business practices.
**Bank Account Details:**
For inquiries or transactions, please refer to ACME Corp's US bank account:
Account Number: 123456789012
Bank Name: Fictitious Bank of America
"""
documents = [
Document(
**{
"page_content": page_content,
"metadata": {
"pebblo_semantic_topics": ["financial-report"],
"pebblo_semantic_entities": ["us-bank-account-number"],
"authorized_identities": ["finance-team", "exec-leadership"],
"page": 0,
"source": "https://drive.google.com/file/d/xxxxxxxxxxxxx/view",
"title": "ACME Corp Financial Report.pdf",
},
}
)
]
vectordb = Qdrant.from_documents(
documents,
embeddings,
location=":memory:",
collection_name=collection_name,
)
print("Vectordb loaded.")
Vectordb loaded.
身份强制检索
PebbloRetrievalQA 链使用 SafeRetrieval 来确保用于上下文中的片段仅从用户授权的文档中检索。 为了实现这一点,Gen-AI 应用程序需要为此检索链提供授权上下文。 这个 auth_context 应填充访问 Gen-AI 应用程序的用户的身份和授权组。
以下是带有PebbloRetrievalQA
的示例代码,其中包含从访问RAG应用程序的用户传递的user_auth
(用户授权列表,可能包括他们的用户ID和他们所属的组),并传递到auth_context
中。
from langchain_community.chains import PebbloRetrievalQA
from langchain_community.chains.pebblo_retrieval.models import AuthContext, ChainInput
# Initialize PebbloRetrievalQA chain
qa_chain = PebbloRetrievalQA.from_chain_type(
llm=llm,
retriever=vectordb.as_retriever(),
app_name="pebblo-identity-rag",
description="Identity Enforcement app using PebbloRetrievalQA",
owner="ACME Corp",
)
def ask(question: str, auth_context: dict):
"""
Ask a question to the PebbloRetrievalQA chain
"""
auth_context_obj = AuthContext(**auth_context) if auth_context else None
chain_input_obj = ChainInput(query=question, auth_context=auth_context_obj)
return qa_chain.invoke(chain_input_obj.dict())
1. 授权用户的问题
我们为授权身份 ["finance-team", "exec-leadership"]
摄取了数据,因此具有授权身份/组 finance-team
的用户应该会收到正确的答案。
auth = {
"user_id": "finance-user@acme.org",
"user_auth": [
"finance-team",
],
}
question = "Share the financial performance of ACME Corp for the year 2020"
resp = ask(question, auth)
print(f"Question: {question}\n\nAnswer: {resp['result']}")
Question: Share the financial performance of ACME Corp for the year 2020
Answer:
Revenue: $50 million (15% increase from previous year)
Net profit: $12 million (24% margin)
Total assets: $80 million (20% growth)
Debt-to-equity ratio: 0.5
2. 未授权用户的问题
由于用户的授权身份/组eng-support
未包含在授权身份["finance-team", "exec-leadership"]
中,我们不应收到答案。
auth = {
"user_id": "eng-user@acme.org",
"user_auth": [
"eng-support",
],
}
question = "Share the financial performance of ACME Corp for the year 2020"
resp = ask(question, auth)
print(f"Question: {question}\n\nAnswer: {resp['result']}")
Question: Share the financial performance of ACME Corp for the year 2020
Answer: I don't know.
3. 使用 PromptTemplate 提供额外指令
您可以使用PromptTemplate向LLM提供额外的指令,以生成自定义响应。
from langchain_core.prompts import PromptTemplate
prompt_template = PromptTemplate.from_template(
"""
Answer the question using the provided context.
If no context is provided, just say "I'm sorry, but that information is unavailable, or Access to it is restricted.".
Question: {question}
"""
)
question = "Share the financial performance of ACME Corp for the year 2020"
prompt = prompt_template.format(question=question)
3.1 授权用户的问题
auth = {
"user_id": "finance-user@acme.org",
"user_auth": [
"finance-team",
],
}
resp = ask(prompt, auth)
print(f"Question: {question}\n\nAnswer: {resp['result']}")
Question: Share the financial performance of ACME Corp for the year 2020
Answer:
Revenue soared to $50 million, marking a 15% increase from the previous year, and net profit reached $12 million, showcasing a healthy margin of 24%. Total assets also grew by 20% to $80 million, and the company maintained a conservative debt-to-equity ratio of 0.5.
3.2 未经授权用户的问题
auth = {
"user_id": "eng-user@acme.org",
"user_auth": [
"eng-support",
],
}
resp = ask(prompt, auth)
print(f"Question: {question}\n\nAnswer: {resp['result']}")
Question: Share the financial performance of ACME Corp for the year 2020
Answer:
I'm sorry, but that information is unavailable, or Access to it is restricted.
语义强化的检索
PebbloRetrievalQA 链使用 SafeRetrieval 来确保上下文中使用的片段仅从符合提供的语义上下文的文档中检索。
为了实现这一点,Gen-AI 应用程序必须为此检索链提供语义上下文。
这个 semantic_context
应包括应拒绝访问 Gen-AI 应用程序的用户的主题和实体。
以下是带有topics_to_deny
和entities_to_deny
的PebbloRetrievalQA示例代码。这些通过semantic_context
传递给链输入。
from typing import List, Optional
from langchain_community.chains import PebbloRetrievalQA
from langchain_community.chains.pebblo_retrieval.models import (
ChainInput,
SemanticContext,
)
# Initialize PebbloRetrievalQA chain
qa_chain = PebbloRetrievalQA.from_chain_type(
llm=llm,
retriever=vectordb.as_retriever(),
app_name="pebblo-semantic-rag",
description="Semantic Enforcement app using PebbloRetrievalQA",
owner="ACME Corp",
)
def ask(
question: str,
topics_to_deny: Optional[List[str]] = None,
entities_to_deny: Optional[List[str]] = None,
):
"""
Ask a question to the PebbloRetrievalQA chain
"""
semantic_context = dict()
if topics_to_deny:
semantic_context["pebblo_semantic_topics"] = {"deny": topics_to_deny}
if entities_to_deny:
semantic_context["pebblo_semantic_entities"] = {"deny": entities_to_deny}
semantic_context_obj = (
SemanticContext(**semantic_context) if semantic_context else None
)
chain_input_obj = ChainInput(query=question, semantic_context=semantic_context_obj)
return qa_chain.invoke(chain_input_obj.dict())
1. 无语义强制
由于没有应用语义强制,系统应返回答案,而不排除与上下文相关的语义标签所导致的任何上下文。
topic_to_deny = []
entities_to_deny = []
question = "Share the financial performance of ACME Corp for the year 2020"
resp = ask(question, topics_to_deny=topic_to_deny, entities_to_deny=entities_to_deny)
print(
f"Topics to deny: {topic_to_deny}\nEntities to deny: {entities_to_deny}\n"
f"Question: {question}\nAnswer: {resp['result']}"
)
Topics to deny: []
Entities to deny: []
Question: Share the financial performance of ACME Corp for the year 2020
Answer:
Revenue for ACME Corp increased by 15% to $50 million in 2020, with a net profit of $12 million and a strong asset base of $80 million. The company also maintained a conservative debt-to-equity ratio of 0.5.
2. 拒绝财务报表主题
数据已摄取主题:["financial-report"]
。
因此,拒绝financial-report
主题的应用程序不应收到答案。
topic_to_deny = ["financial-report"]
entities_to_deny = []
question = "Share the financial performance of ACME Corp for the year 2020"
resp = ask(question, topics_to_deny=topic_to_deny, entities_to_deny=entities_to_deny)
print(
f"Topics to deny: {topic_to_deny}\nEntities to deny: {entities_to_deny}\n"
f"Question: {question}\nAnswer: {resp['result']}"
)
Topics to deny: ['financial-report']
Entities to deny: []
Question: Share the financial performance of ACME Corp for the year 2020
Answer:
Unfortunately, I do not have access to the financial performance of ACME Corp for the year 2020.
3. 拒绝美国银行账号实体
由于实体 us-bank-account-number
被拒绝,系统不应返回答案。
topic_to_deny = []
entities_to_deny = ["us-bank-account-number"]
question = "Share the financial performance of ACME Corp for the year 2020"
resp = ask(question, topics_to_deny=topic_to_deny, entities_to_deny=entities_to_deny)
print(
f"Topics to deny: {topic_to_deny}\nEntities to deny: {entities_to_deny}\n"
f"Question: {question}\nAnswer: {resp['result']}"
)
Topics to deny: []
Entities to deny: ['us-bank-account-number']
Question: Share the financial performance of ACME Corp for the year 2020
Answer: I don't have information about ACME Corp's financial performance for 2020.