谷歌生成语义检索器¶
在这个笔记本中,我们将向您展示如何快速开始使用谷歌的生成语义检索器,该检索器提供了专门针对高质量检索的嵌入模型,以及一个经过调整的模型,用于生成具有可定制安全设置的基于实际情况的输出。我们还将向您展示一些高级示例,演示如何结合LlamaIndex的强大功能和谷歌的这一独特提供。
安装说明¶
%pip install llama-index-llms-gemini
%pip install llama-index-vector-stores-google
%pip install llama-index-indices-managed-google
%pip install llama-index-response-synthesizers-google
%pip install llama-index
%pip install "google-ai-generativelanguage>=0.4,<=1.0"
%pip install google-auth-oauthlib
from google.oauth2 import service_account
from llama_index.vector_stores.google import set_google_config
credentials = service_account.Credentials.from_service_account_file(
"service_account_key.json",
scopes=[
"https://www.googleapis.com/auth/generative-language.retriever",
],
)
set_google_config(auth_credentials=credentials)
下载数据¶
!mkdir -p 'data/paul_graham/'
!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham/paul_graham_essay.txt'
设置¶
首先,让我们在幕后创建一些辅助函数。
import llama_index.core.vector_stores.google.generativeai.genai_extension as genaix
from typing import Iterable
from random import randrange
LLAMA_INDEX_COLAB_CORPUS_ID_PREFIX = f"llama-index-colab"
SESSION_CORPUS_ID_PREFIX = (
f"{LLAMA_INDEX_COLAB_CORPUS_ID_PREFIX}-{randrange(1000000)}"
)
def corpus_id(num_id: int) -> str:
return f"{SESSION_CORPUS_ID_PREFIX}-{num_id}"
SESSION_CORPUS_ID = corpus_id(1)
def list_corpora() -> Iterable[genaix.Corpus]:
client = genaix.build_semantic_retriever()
yield from genaix.list_corpora(client=client)
def delete_corpus(*, corpus_id: str) -> None:
client = genaix.build_semantic_retriever()
genaix.delete_corpus(corpus_id=corpus_id, client=client)
def cleanup_colab_corpora():
for corpus in list_corpora():
if corpus.corpus_id.startswith(LLAMA_INDEX_COLAB_CORPUS_ID_PREFIX):
try:
delete_corpus(corpus_id=corpus.corpus_id)
print(f"Deleted corpus {corpus.corpus_id}.")
except Exception:
pass
# 从此Colab中删除任何先前残留的语料库。
cleanup_colab_corpora()
基本用法¶
一个corpus
是一组document
的集合。一个document
是一段被分成chunk
的文本。
from llama_index.core import SimpleDirectoryReader
from llama_index.indices.managed.google import GoogleIndex
from llama_index.core import Response
import time
# 创建一个语料库。
index = GoogleIndex.create_corpus(
corpus_id=SESSION_CORPUS_ID, display_name="我的第一个语料库!"
)
print(f"新创建的语料库ID是 {index.corpus_id}。")
# 摄入。
documents = SimpleDirectoryReader("./data/paul_graham/").load_data()
index.insert_documents(documents)
让我们检查一下我们已经摄入了什么。
for corpus in list_corpora():
print(corpus)
让我们向索引提出一个问题。
# 查询。
query_engine = index.as_query_engine()
response = query_engine.query("保罗·格雷厄姆在成长过程中做了什么?")
assert isinstance(response, Response)
# 显示响应。
print(f"响应为 {response.response}")
# 显示被引用的段落,用于构建响应。
for cited_text in [node.text for node in response.source_nodes]:
print(f"被引用的文本:{cited_text}")
# 显示可回答性。0 表示无法从段落中得到答案。
# 1 表示模型确定可以从段落中提供答案。
if response.metadata:
print(
f"可回答性:{response.metadata.get('answerable_probability', 0)}"
)
创建语料库¶
有多种方法可以创建语料库。
# Google服务器将为您提供一个语料库ID。
index = GoogleIndex.create_corpus(display_name="我的第一个语料库!")
print(index.corpus_id)
# 您也可以提供自己的语料库ID。但是,此ID需要在全局范围内是唯一的。
# 如果其他人已经使用了这个ID,您将收到一个异常。
index = GoogleIndex.create_corpus(
corpus_id="my-first-corpus", display_name="我的第一个语料库!"
)
# 如果您不提供任何参数,Google将为您提供ID和默认的显示名称。
index = GoogleIndex.create_corpus()
重用语料库¶
您创建的语料库将在您的Google账户下的服务器上保留。 您可以使用其ID来重新获取一个句柄。 然后,您可以查询它,添加更多文档等。
# 使用先前创建的语料库。
index = GoogleIndex.from_corpus(corpus_id=SESSION_CORPUS_ID)
# 再次查询!
query_engine = index.as_query_engine()
response = query_engine.query("Paul Graham建立了哪家公司?")
assert isinstance(response, Response)
# 显示响应。
print(f"响应是 {response.response}")
列出和删除语料库¶
有关更多文档,请参阅Python库google-generativeai。
加载文档¶
LlamaIndex中的许多节点解析器和文本分割器会自动为每个节点添加一个source_node,以将其与文件关联起来,例如:
relationships={
NodeRelationship.SOURCE: RelatedNodeInfo(
node_id="abc-123",
metadata={"file_name": "文档的标题"},
)
},
GoogleIndex
和GoogleVectorStore
都识别这个源节点,并将自动在Google服务器上的语料库下创建文档。
如果您正在编写自己的分块器,您也应该像下面这样提供这个源节点关系:
from llama_index.core.schema import NodeRelationship, RelatedNodeInfo, TextNode
index = GoogleIndex.from_corpus(corpus_id=SESSION_CORPUS_ID)
index.insert_nodes(
[
TextNode(
text="It was the best of times.",
relationships={
NodeRelationship.SOURCE: RelatedNodeInfo(
node_id="123",
metadata={"file_name": "Tale of Two Cities"},
)
},
),
TextNode(
text="It was the worst of times.",
relationships={
NodeRelationship.SOURCE: RelatedNodeInfo(
node_id="123",
metadata={"file_name": "Tale of Two Cities"},
)
},
),
TextNode(
text="Bugs Bunny: Wassup doc?",
relationships={
NodeRelationship.SOURCE: RelatedNodeInfo(
node_id="456",
metadata={"file_name": "Bugs Bunny Adventure"},
)
},
),
]
)
如果您的节点没有源节点,那么谷歌服务器将会将您的节点放在您语料库下的默认文档中。
列出和删除文档¶
请参阅Python库google-generativeai获取更多文档。
查询语料库¶
谷歌的查询引擎由一个经过特别调整的LLM支持,它根据检索到的段落来确定其响应。对于每个响应,都会返回一个“可回答概率”,以指示LLM在从检索到的段落中回答问题时的信心程度。
此外,谷歌的查询引擎支持回答风格,例如ABSTRACTIVE
(简洁但抽象)、EXTRACTIVE
(非常简要和提取式)和VERBOSE
(额外细节)。
该引擎还支持安全设置。
from google.ai.generativelanguage import (
GenerateAnswerRequest,
HarmCategory,
SafetySetting,
)
index = GoogleIndex.from_corpus(corpus_id=SESSION_CORPUS_ID)
query_engine = index.as_query_engine(
# 我们建议温度在0到0.2之间。
temperature=0.2,
# 查看`google-generativeai`包以获取其他语音风格。
answer_style=GenerateAnswerRequest.AnswerStyle.ABSTRACTIVE,
# 查看`google-generativeai`包以获取其他安全设置。
safety_setting=[
SafetySetting(
category=HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
threshold=SafetySetting.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE,
),
SafetySetting(
category=HarmCategory.HARM_CATEGORY_VIOLENCE,
threshold=SafetySetting.HarmBlockThreshold.BLOCK_ONLY_HIGH,
),
],
)
response = query_engine.query("What was Bugs Bunny's favorite saying?")
print(response)
请查看Python库google-generativeai获取更多文档。
解释响应¶
from llama_index.core import Response
response = query_engine.query("Paul Graham的成就是什么?")
assert isinstance(response, Response)
# 显示响应。
print(f"响应为 {response.response}")
# 显示用于构建响应的引用段落。
for cited_text in [node.text for node in response.source_nodes]:
print(f"引用文本:{cited_text}")
# 显示可回答性。0表示无法从段落中回答。
# 1表示模型确定可以从段落中提供答案。
if response.metadata:
print(
f"可回答性:{response.metadata.get('answerable_probability', 0)}"
)
高级RAG¶
GoogleIndex
是基于GoogleVectorStore
和GoogleTextSynthesizer
构建的。这些组件可以与LlamaIndex中的其他强大构造相结合,以生成高级的RAG应用程序。
下面我们展示一些例子。
from llama_index.llms.gemini import Gemini
GEMINI_API_KEY = "" # @param {type:"string"}
gemini = Gemini(api_key=GEMINI_API_KEY)
重新排名器 + Google 检索器¶
将内容转换为向量是一个有损的过程。基于LLM的重新排名通过使用LLM重新排名检索到的内容,从而弥补了这一缺陷,因为LLM具有更高的保真度,因为它可以访问实际查询和段落。
from llama_index.response_synthesizers.google import GoogleTextSynthesizer
from llama_index.vector_stores.google import GoogleVectorStore
from llama_index.core import VectorStoreIndex
from llama_index.core.postprocessor import LLMRerank
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.retrievers import VectorIndexRetriever
# 使用GoogleTextSynthesizer设置响应合成器。
store = GoogleVectorStore.from_corpus(corpus_id=SESSION_CORPUS_ID)
index = VectorStoreIndex.from_vector_store(
vector_store=store,
)
response_synthesizer = GoogleTextSynthesizer.from_defaults(
temperature=0.2,
answer_style=GenerateAnswerRequest.AnswerStyle.ABSTRACTIVE,
)
reranker = LLMRerank(
top_n=10,
llm=gemini,
)
query_engine = RetrieverQueryEngine.from_args(
retriever=VectorIndexRetriever(
index=index,
similarity_top_k=20,
),
node_postprocessors=[reranker],
response_synthesizer=response_synthesizer,
)
# 查询。
response = query_engine.query("What were Paul Graham's achievements?")
print(response)
多查询 + Google 检索器¶
有时,用户的查询可能过于复杂。如果将原始查询分解为更小、更专注的查询,可能会获得更好的检索结果。
from llama_index.core.indices.query.query_transform.base import (
StepDecomposeQueryTransform,
)
from llama_index.core.query_engine import MultiStepQueryEngine
# 使用多轮查询重写设置查询引擎。
store = GoogleVectorStore.from_corpus(corpus_id=SESSION_CORPUS_ID)
index = VectorStoreIndex.from_vector_store(
vector_store=store,
)
response_synthesizer = GoogleTextSynthesizer.from_defaults(
temperature=0.2,
answer_style=GenerateAnswerRequest.AnswerStyle.ABSTRACTIVE,
)
single_step_query_engine = index.as_query_engine(
similarity_top_k=10,
response_synthesizer=response_synthesizer,
)
step_decompose_transform = StepDecomposeQueryTransform(
llm=gemini,
verbose=True,
)
query_engine = MultiStepQueryEngine(
query_engine=single_step_query_engine,
query_transform=step_decompose_transform,
response_synthesizer=response_synthesizer,
index_summary="Ask me anything.",
num_steps=6,
)
# 查询。
response = query_engine.query("What were Paul Graham's achievements?")
print(response)
HyDE + Google Retriever¶
当你可以编写提示来产生与真实答案共享许多特征的虚假答案时,你可以尝试使用HyDE!
from llama_index.core.indices.query.query_transform import HyDEQueryTransform
from llama_index.core.query_engine import TransformQueryEngine
# 使用多轮查询重写器设置查询引擎。
store = GoogleVectorStore.from_corpus(corpus_id=SESSION_CORPUS_ID)
index = VectorStoreIndex.from_vector_store(
vector_store=store,
)
response_synthesizer = GoogleTextSynthesizer.from_defaults(
temperature=0.2,
answer_style=GenerateAnswerRequest.AnswerStyle.ABSTRACTIVE,
)
base_query_engine = index.as_query_engine(
similarity_top_k=10,
response_synthesizer=response_synthesizer,
)
hyde = HyDEQueryTransform(
llm=gemini,
include_original=False,
)
hyde_query_engine = TransformQueryEngine(base_query_engine, hyde)
# 查询。
response = query_engine.query("What were Paul Graham's achievements?")
print(response)
多查询 + 重新排序 + HyDE + Google检索器¶
或者将它们全部结合起来!
# 谷歌的检索器和AQA模型设置。
store = GoogleVectorStore.from_corpus(corpus_id=SESSION_CORPUS_ID)
index = VectorStoreIndex.from_vector_store(
vector_store=store,
)
response_synthesizer = GoogleTextSynthesizer.from_defaults(
temperature=0.2, answer_style=GenerateAnswerRequest.AnswerStyle.ABSTRACTIVE
)
# 重新排序器设置。
reranker = LLMRerank(
top_n=10,
llm=gemini,
)
single_step_query_engine = index.as_query_engine(
similarity_top_k=20,
node_postprocessors=[reranker],
response_synthesizer=response_synthesizer,
)
# HyDE设置。
hyde = HyDEQueryTransform(
llm=gemini,
include_original=False,
)
hyde_query_engine = TransformQueryEngine(single_step_query_engine, hyde)
# 多查询设置。
step_decompose_transform = StepDecomposeQueryTransform(
llm=gemini, verbose=True
)
query_engine = MultiStepQueryEngine(
query_engine=hyde_query_engine,
query_transform=step_decompose_transform,
response_synthesizer=response_synthesizer,
index_summary="Ask me anything.",
num_steps=6,
)
# 查询。
response = query_engine.query("What were Paul Graham's achievements?")
print(response)
清理在colab中创建的语料库¶
cleanup_colab_corpora()
# 用OAuth快速入门中使用的项目替换TODO-your-project-name
project_name = "TODO-your-project-name" # @param {type:"string"}
# 用作OAuth快速入门中添加的测试用户的电子邮件替换TODO-your-email@gmail.com
email = "TODO-your-email@gmail.com" # @param {type:"string"}
# 用上传的client_secret_*文件名替换client_secret.json
client_file_name = "client_secret.json"
# 重要提示:按照输出中的说明操作 - 您必须将命令复制到您的终端,并将身份验证后的输出复制回这里。
!gcloud config set project $project_name
!gcloud config set account $email
# 注意:本教程中简化的项目设置会触发“Google尚未验证此应用程序。”对话框。
# 这是正常的,请单击“高级” -> “转到[应用程序名称](不安全)”
!gcloud auth application-default login --no-browser --client-id-file=$client_file_name --scopes="https://www.googleapis.com/auth/generative-language.retriever,https://www.googleapis.com/auth/cloud-platform"
这将为您提供一个URL,您应该在本地浏览器中输入该URL。 按照指示完成认证和授权。