建立使用亚马逊 Bedrock 知识库的 Q&A 应用程序 - Retrieve API

背景

在本笔记本中,我们将深入探讨如何使用亚马逊 Bedrock 的知识库构建 Q&A 应用程序 - Retrieve API。 我们将查询知识库以获得基于相似性搜索的所需数量的文档块。 然后,我们将使用相关文档和查询来增强提示,这将作为输入传递给 Anthropic Claude V3 以生成响应。

使用知识库,我们可以安全地将基础模型 (FM) 在亚马逊 Bedrock 中连接到我们公司的数据,用于检索增强生成 (RAG)。 访问额外数据可帮助模型生成更相关、更具上下文针对性和更准确的响应,而无需不断重新训练 FM。 从知识库检索的所有信息都附有源属性,以提高透明度并最大限度地减少幻觉。 有关使用控制台创建知识库的更多信息,请参阅此帖子 。 我们将在笔记本中涵盖 2 个部分:

  • 第 1 部分,我们将分享如何使用 RetrieveAPI 与亚马逊 Bedrock 的基础模型。 我们将使用 anthropic.claude-3-sonnet-20240229-v1:0 模型。
  • 第 2 部分,我们将展示 langchain 集成。

模式

我们可以使用检索增强生成 (RAG) 模式来实现解决方案。 RAG 从语言模型 (非参数) 之外检索数据,并通过添加相关检索数据来增强提示。 在这里,我们正在有效地对使用控制台/sdk 创建的知识库执行 RAG。

先决条件

在回答问题之前,必须处理和摄取文档。

  1. 通过连接我们的 s3 存储桶(数据源)将文档加载到知识库中。
  2. 摄取 - 知识库将它们分成更小的块(基于所选的策略),生成嵌入并将其存储在相关的矢量存储中,笔记本 0_create_ingest_documents_test_kb.ipynb 会为我们处理这个问题。

data_ingestion

笔记本演练

对于我们的笔记本,我们将使用亚马逊 Bedrock 知识库提供的 Retreive API,它将用户查询转换为嵌入,搜索知识库,并返回相关结果,为我们提供更多控制权来构建基于语义搜索结果的自定义工作流程。 Retrieve API 的输出包括 retrieved text chunks、源数据的 location typeURI,以及检索的相关性 scores

然后,我们将使用生成的文本块并将其与原始提示结合,并通过使用基于我们的用例的提示工程模式将其传递给 anthropic.claude-3-sonnet-20240229-v1:0 模型。

用例:

数据集

在这个例子中,我们将使用多年来的亚马逊股东信作为文本语料库来执行问答。 这些数据已经被摄取到亚马逊 Bedrock 的知识库中。 我们将需要 knowledge base id 来运行这个例子。 在我们的特定用例中,我们可以同步不同领域主题的不同文件,并以相同的方式查询此笔记本,以使用知识库的检索 API 评估模型响应。

Python 3.10

⚠ 对于这个实验室,我们需要基于 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>")

按照以下步骤初始化 bedrock 客户端:

  1. 导入必要的库,包括 langchain 用于 bedrock 模型选择,llama index 用于存储包含 llm 和嵌入模型实例的服务上下文。 我们将在笔记本的后续部分使用这个服务上下文来评估我们 Q&A 应用程序的响应。

  2. 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)

第 1 部分 - 使用亚马逊 Bedrock 的基础模型的 Retrieve API

定义一个检索函数,它调用亚马逊 Bedrock 知识库提供的 Retrieve API,该 API 将用户查询转换为嵌入,搜索知识库,并返回相关结果,为我们提供更多控制权来构建基于语义搜索结果的自定义工作流程。 Retrieve API 的输出包括 retrieved text chunks、源数据的 location typeURI,以及检索的相关性 scores。 我们还可以在 retrievalConfiguration 中使用 overrideSearchType 选项,它提供了使用 HYBRIDSEMANTIC 的选择。 默认情况下,它将为我们选择正确的策略以获得最相关的结果,如果我们想覆盖默认选项以使用混合或语义搜索,可以将值设置为 HYBRID/SEMANTIC

retrieveAPI

def retrieve(query, kbId, numberOfResults=5):
    return bedrock_agent_client.retrieve(
        retrievalQuery= {
            'text': query
        },
        knowledgeBaseId=kbId,
        retrievalConfiguration= {
            'vectorSearchConfiguration': {
                'numberOfResults': numberOfResults,
                'overrideSearchType': "HYBRID", # optional
            }
        }
    )

在查询 LLM 的响应之前,请先初始化我们的知识库 id

接下来,我们将调用 Retrieve API,并将 knowledge base idnumber of resultsquery 作为参数传递。

score: 我们可以查看每个返回的文本块的相关联分数,该分数描述了它与查询的相关性有多高。

query = "What is Amazon doing in the field of Generative AI?"
response = retrieve(query, kb_id, 5)
retrievalResults = response['retrievalResults']
pp.pprint(retrievalResults)

从 retrieveAPI 响应中提取文本块

在下面的单元格中,我们将从检索结果中获取上下文。

# 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:"""

调用亚马逊 Bedrock 的基础模型

在这个例子中,我们将使用 anthropic.claude-3-sonnet-20240229-v1:0 基础模型从亚马逊 Bedrock。

  • 它在较低价格的情况下提供最大效用,并经过设计可成为可靠的高耐用性工作马,用于扩展的 AI 部署。 Claude 3 Sonnet 可以处理图像并返回文本输出,并具有 200K 上下文窗口。
  • 模型属性
    • 图像到文本和代码、多语言对话、复杂推理和分析
# 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)

第 2 部分 - LangChain 集成

在这个笔记本中,我们将深入探讨使用亚马逊 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 typeURI,以及检索的相关性 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