在本笔记本中,我们将深入探讨如何使用亚马逊 Bedrock 的知识库构建 Q&A 应用程序 - Retrieve API。 我们将查询知识库以获得基于相似性搜索的所需数量的文档块。 然后,我们将使用相关文档和查询来增强提示,这将作为输入传递给 Anthropic Claude V3 以生成响应。
使用知识库,我们可以安全地将基础模型 (FM) 在亚马逊 Bedrock 中连接到我们公司的数据,用于检索增强生成 (RAG)。 访问额外数据可帮助模型生成更相关、更具上下文针对性和更准确的响应,而无需不断重新训练 FM。 从知识库检索的所有信息都附有源属性,以提高透明度并最大限度地减少幻觉。 有关使用控制台创建知识库的更多信息,请参阅此帖子 。 我们将在笔记本中涵盖 2 个部分:
RetrieveAPI
与亚马逊 Bedrock 的基础模型。 我们将使用 anthropic.claude-3-sonnet-20240229-v1:0
模型。我们可以使用检索增强生成 (RAG) 模式来实现解决方案。 RAG 从语言模型 (非参数) 之外检索数据,并通过添加相关检索数据来增强提示。 在这里,我们正在有效地对使用控制台/sdk 创建的知识库执行 RAG。
在回答问题之前,必须处理和摄取文档。
对于我们的笔记本,我们将使用亚马逊 Bedrock 知识库提供的 Retreive API
,它将用户查询转换为嵌入,搜索知识库,并返回相关结果,为我们提供更多控制权来构建基于语义搜索结果的自定义工作流程。 Retrieve API
的输出包括 retrieved text chunks
、源数据的 location type
和 URI
,以及检索的相关性 scores
。
然后,我们将使用生成的文本块并将其与原始提示结合,并通过使用基于我们的用例的提示工程模式将其传递给 anthropic.claude-3-sonnet-20240229-v1:0
模型。
在这个例子中,我们将使用多年来的亚马逊股东信作为文本语料库来执行问答。 这些数据已经被摄取到亚马逊 Bedrock 的知识库中。 我们将需要 knowledge base id
来运行这个例子。
在我们的特定用例中,我们可以同步不同领域主题的不同文件,并以相同的方式查询此笔记本,以使用知识库的检索 API 评估模型响应。
⚠ 对于这个实验室,我们需要基于 Python 3.10 运行时运行笔记本。 ⚠
如果我们在 Amazon SageMaker studio 之外的本地环境中进行研讨会,请确保我们正在运行 Python 运行时 > 3.10。
要运行此笔记本,我们需要安装以下软件包。
%pip install --force-reinstall -q -r ./requirements.txt
# restart kernel
from IPython.core.display import HTML
HTML("<script>Jupyter.notebook.kernel.restart()</script>")
导入必要的库,包括 langchain 用于 bedrock 模型选择,llama index 用于存储包含 llm 和嵌入模型实例的服务上下文。 我们将在笔记本的后续部分使用这个服务上下文来评估我们 Q&A 应用程序的响应。
将 anthropic.claude-3-sonnet-20240229-v1:0
初始化为我们的大型语言模型,以使用给定知识库的 RAG 模式执行查询完成。
%store -r
import boto3
import pprint
from botocore.client import Config
import json
pp = pprint.PrettyPrinter(indent=2)
session = boto3.session.Session()
region = session.region_name
bedrock_config = Config(connect_timeout=120, read_timeout=120, retries={'max_attempts': 0})
bedrock_client = boto3.client('bedrock-runtime', region_name = region)
bedrock_agent_client = boto3.client("bedrock-agent-runtime",
config=bedrock_config, region_name = region)
print(region)
定义一个检索函数,它调用亚马逊 Bedrock 知识库提供的 Retrieve API
,该 API 将用户查询转换为嵌入,搜索知识库,并返回相关结果,为我们提供更多控制权来构建基于语义搜索结果的自定义工作流程。 Retrieve API
的输出包括 retrieved text chunks
、源数据的 location type
和 URI
,以及检索的相关性 scores
。 我们还可以在 retrievalConfiguration
中使用 overrideSearchType
选项,它提供了使用 HYBRID
或 SEMANTIC
的选择。 默认情况下,它将为我们选择正确的策略以获得最相关的结果,如果我们想覆盖默认选项以使用混合或语义搜索,可以将值设置为 HYBRID/SEMANTIC
。
def retrieve(query, kbId, numberOfResults=5):
return bedrock_agent_client.retrieve(
retrievalQuery= {
'text': query
},
knowledgeBaseId=kbId,
retrievalConfiguration= {
'vectorSearchConfiguration': {
'numberOfResults': numberOfResults,
'overrideSearchType': "HYBRID", # optional
}
}
)
接下来,我们将调用 Retrieve API
,并将 knowledge base id
、number of results
和 query
作为参数传递。
score
: 我们可以查看每个返回的文本块的相关联分数,该分数描述了它与查询的相关性有多高。
query = "What is Amazon doing in the field of Generative AI?"
response = retrieve(query, kb_id, 5)
retrievalResults = response['retrievalResults']
pp.pprint(retrievalResults)
在下面的单元格中,我们将从检索结果中获取上下文。
# fetch context from the response
def get_contexts(retrievalResults):
contexts = []
for retrievedResult in retrievalResults:
contexts.append(retrievedResult['content']['text'])
return contexts
contexts = get_contexts(retrievalResults)
pp.pprint(contexts)
在这里,我们将使用下面的特定提示,让模型充当一个财务顾问 AI 系统,在可能的情况下使用事实性和统计信息来回答问题。 我们将上面的 Retrieve API
响应作为 {contexts}
的一部分提供给提示,以及用户 query
。
prompt = f"""
Human: You are a financial advisor AI system, and provides answers to questions by using fact based and statistical information when possible.
Use the following pieces of information to provide a concise answer to the question enclosed in <question> tags.
If you don't know the answer, just say that you don't know, don't try to make up an answer.
<context>
{contexts}
</context>
<question>
{query}
</question>
The response should be specific and use statistics or numbers when possible.
A:"""
在这个例子中,我们将使用 anthropic.claude-3-sonnet-20240229-v1:0
基础模型从亚马逊 Bedrock。
# payload with model paramters
messages=[{ "role":'user', "content":[{'type':'text','text': prompt.format(contexts, query)}]}]
sonnet_payload = json.dumps({
"anthropic_version": "bedrock-2023-05-31",
"max_tokens": 512,
"messages": messages,
"temperature": 0.5,
"top_p": 1
} )
modelId = 'anthropic.claude-3-sonnet-20240229-v1:0' # change this to use a different version from the model provider
accept = 'application/json'
contentType = 'application/json'
response = bedrock_client.invoke_model(body=sonnet_payload, modelId=modelId, accept=accept, contentType=contentType)
response_body = json.loads(response.get('body').read())
response_text = response_body.get('content')[0]['text']
pp.pprint(response_text)
在这个笔记本中,我们将深入探讨使用亚马逊 Bedrock 的 Retrieve API 和 LangChain 构建 Q&A 应用程序。 我们将查询知识库以获得基于相似性搜索的所需数量的文档块,将其与 LangChain 检索器集成,并使用 Anthropic Claude 3 Sonnet
模型来回答问题。
from langchain_aws import ChatBedrock
from langchain.retrievers.bedrock import AmazonKnowledgeBasesRetriever
llm = ChatBedrock(model_id=modelId,
client=bedrock_client)
从 LangChain 创建一个 AmazonKnowledgeBasesRetriever
对象,它将调用亚马逊 Bedrock 知识库提供的 Retreive API
,该 API 将用户查询转换为嵌入,搜索知识库,并返回相关结果,为我们提供更多控制权来构建基于语义搜索结果的自定义工作流程。 Retrieve API
的输出包括 retrieved text chunks
、源数据的 location type
和 URI
,以及检索的相关性 scores
。
query = "What is Amazon doing in the field of Generative AI?"
retriever = AmazonKnowledgeBasesRetriever(
knowledge_base_id=kb_id,
retrieval_config={"vectorSearchConfiguration":
{"numberOfResults": 4,
'overrideSearchType': "SEMANTIC", # optional
}
},
# endpoint_url=endpoint_url,
# region_name=region,
# credentials_profile_name="<profile_name>",
)
docs = retriever.invoke(
input=query
)
pp.pprint(docs)
在这里,我们将使用两个帮助函数来构建调用模型的链:
create_stuff_documents_chain
指定如何将检索到的上下文馈入提示和 LLM。 在这种情况下,我们将"填充"内容 - 即,我们将包含所有检索到的上下文,而不进行任何总结或其他处理。 它主要实现了我们上面的 rag_chain,输入键为 context 和 input – 它使用检索到的上下文和查询生成答案。create_retrieval_chain
添加检索步骤并将检索到的上下文传播到链中,将其与最终答案一起提供。 它有输入键 input,并在输出中包含 input、context 和 answer。from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate
system_prompt = (
"You are an assistant for question-answering tasks. "
"Use the following pieces of retrieved context to answer "
"the question. If you don't know the answer, say that you "
"don't know. Use three sentences maximum and keep the "
"answer concise."
"\n\n"
"{context}"
)
prompt = ChatPromptTemplate.from_messages(
[
("system", system_prompt),
("human", "{input}"),
]
)
question