Wyświetl na stronie ai.google.dev | Wypróbuj notatnik Colab | Wyświetl notatnik na GitHubie |
Omówienie
Duże modele językowe (LLM) mogą uczyć się nowych umiejętności bez bezpośredniego trenowania na ich podstawie. Jednak zdarza się, że LLM „halucynują”, gdy mają udzielić odpowiedzi na pytania, na które nie były trenowane. Wynika to częściowo z tego, że duże modele językowe nie wiedzą o zdarzeniach po trenowaniu. Trudno też jest zidentyfikować źródła, z których modele LLM czerpią odpowiedzi. W przypadku niezawodnych, skalowanych aplikacji ważne jest, aby model LLM dostarczał odpowiedzi opartych na faktach i był w stanie podać źródła informacji.
Typowym podejściem do pokonywania tych ograniczeń jest generowanie rozszerzone przez wyszukiwanie (RAG), które wzbogaca prompt wysyłany do modelu LLM o odpowiednie dane pobrane z zewnętrznej bazy wiedzy za pomocą mechanizmu wyszukiwania informacji (IR). Baza wiedzy może być Twoim własnym zbiorem dokumentów, baz danych lub interfejsów API.
Ten notatnik zawiera omówienie procesu, który pozwala poprawić odpowiedź LLM poprzez rozszerzenie jej wiedzy o zewnętrzne korpusy tekstowe i wyszukiwanie informacji semantycznych w celu udzielenia odpowiedzi na pytania za pomocą interfejsów Semantic Retriever i Attributed Question Answering (AQA) interfejsu Generative Language API.
Konfiguracja
Importowanie interfejsu Generative Language API
# Install the Client library (Semantic Retriever is only supported for versions >0.4.0)
pip install -U google.ai.generativelanguage
Uwierzytelnij
Interfejs Semantic retriever API umożliwia wyszukiwanie semantyczne własnych danych. Ponieważ to Twoje dane, wymaga to bardziej rygorystycznej kontroli dostępu niż klucze interfejsu API. Uwierzytelniaj za pomocą protokołu OAuth, używając kont usługi lub danych logowania użytkownika.
Ten krótki przewodnik korzysta z uproszczonego podejścia do uwierzytelniania, które jest przeznaczone do środowiska testowego. Konfiguracja kont usługi jest zwykle łatwiejsza do rozpoczęcia. W przypadku środowiska produkcyjnego przed wybraniem danych dostępu odpowiednich dla aplikacji zapoznaj się z informacjami na temat uwierzytelniania i autoryzacji.
Konfigurowanie OAuth za pomocą kont usługi
Aby skonfigurować OAuth za pomocą kont usługi:
- Włącz Generative Language API.
Utwórz konto usługi, postępując zgodnie z dokumentacją.
- Po utworzeniu konta usługi wygeneruj klucz konta usługi.
Prześlij plik konta usługi, klikając ikonę pliku na pasku bocznym po lewej stronie, a potem ikonę przesyłania, jak pokazano na poniższym zrzucie ekranu.
- Zmień nazwę przesłanego pliku na
service_account_key.json
lub zmiennąservice_account_file_name
w kodzie poniżej.
- Zmień nazwę przesłanego pliku na
pip install -U google-auth-oauthlib
service_account_file_name = 'service_account_key.json'
from google.oauth2 import service_account
credentials = service_account.Credentials.from_service_account_file(service_account_file_name)
scoped_credentials = credentials.with_scopes(
['https://www.googleapis.com/auth/cloud-platform', 'https://www.googleapis.com/auth/generative-language.retriever'])
Zainicjuj bibliotekę klienta za pomocą danych logowania konta usługi.
import google.ai.generativelanguage as glm
generative_service_client = glm.GenerativeServiceClient(credentials=scoped_credentials)
retriever_service_client = glm.RetrieverServiceClient(credentials=scoped_credentials)
permission_service_client = glm.PermissionServiceClient(credentials=scoped_credentials)
Tworzenie korpusu
Interfejs Semantic retriever API umożliwia zdefiniowanie do 5 niestandardowych korpusów tekstowych w projekcie. Podczas definiowania korpusów możesz podać jedno z tych pól:
name
: nazwa zasobuCorpus
(identyfikator). Musi zawierać maksymalnie 40 znaków alfanumerycznych. Jeśli podczas tworzenia parametrname
jest pusty, wygenerujemy unikalną nazwę o maksymalnej długości 40 znaków z prefiksem z parametrówdisplay_name
i 12-znakowym losowym sufiksem.display_name
: czytelna dla człowieka nazwa wyświetlanaCorpus
. Może zawierać maksymalnie 512 znaków, w tym znaki alfanumeryczne, spacje i myślniki.
example_corpus = glm.Corpus(display_name="Google for Developers Blog")
create_corpus_request = glm.CreateCorpusRequest(corpus=example_corpus)
# Make the request
create_corpus_response = retriever_service_client.create_corpus(create_corpus_request)
# Set the `corpus_resource_name` for subsequent sections.
corpus_resource_name = create_corpus_response.name
print(create_corpus_response)
name: "corpora/google-for-developers-blog-dqrtz8rs0jg" display_name: "Google for Developers Blog" create_time { seconds: 1713497533 nanos: 587977000 } update_time { seconds: 1713497533 nanos: 587977000 }
Pobieranie utworzonego korpusu
Aby uzyskać programowy dostęp do elementu Corpus
utworzonego powyżej, użyj metody GetCorpusRequest
. Wartość parametru name
odnosi się do pełnej nazwy zasobu Corpus
i jest ustawiona w komórce powyżej jako corpus_resource_name
. Oczekiwany format to corpora/corpus-123
.
get_corpus_request = glm.GetCorpusRequest(name=corpus_resource_name)
# Make the request
get_corpus_response = retriever_service_client.get_corpus(get_corpus_request)
# Print the response
print(get_corpus_response)
Utwórz dokument
Element Corpus
może zawierać do 10 000 elementów Document
. Podczas definiowania dokumentów możesz określić jedno z tych pól:
name
: nazwa (identyfikator) zasobuDocument
. Nazwa może zawierać maksymalnie 40 znaków (tylko znaki alfanumeryczne lub łączniki). Identyfikator nie może zaczynać się ani kończyć łącznikiem. Jeśli nazwa jest pusta w momencie tworzenia, zostanie utworzona unikalna nazwa na podstawie ciągu znakówdisplay_name
oraz 12-znakowego losowego sufiksu.display_name
: wyświetlana nazwa w formie czytelnej dla ludzi. Może zawierać maksymalnie 512 znaków, w tym znaki alfanumeryczne, spacje i myślniki.
Document
obsługują też do 20 określonych przez użytkownika pól custom_metadata
określonych jako pary klucz-wartość. Metadane niestandardowe mogą być ciągami znaków, listami ciągów znaków lub wartościami liczbowymi. Listy ciągów znaków mogą zawierać maksymalnie 10 wartości, a wartości liczbowe są w interfejsie API przedstawiane jako liczby zmiennoprzecinkowe.
# Create a document with a custom display name.
example_document = glm.Document(display_name="Introducing Project IDX, An Experiment to Improve Full-stack, Multiplatform App Development")
# Add metadata.
# Metadata also supports numeric values not specified here
document_metadata = [
glm.CustomMetadata(key="url", string_value="https://developers.googleblog.com/2023/08/introducing-project-idx-experiment-to-improve-full-stack-multiplatform-app-development.html")]
example_document.custom_metadata.extend(document_metadata)
# Make the request
# corpus_resource_name is a variable set in the "Create a corpus" section.
create_document_request = glm.CreateDocumentRequest(parent=corpus_resource_name, document=example_document)
create_document_response = retriever_service_client.create_document(create_document_request)
# Set the `document_resource_name` for subsequent sections.
document_resource_name = create_document_response.name
print(create_document_response)
Pobieranie utworzonego dokumentu
Aby uzyskać dostęp do utworzonego powyżej dokumentu za pomocą kodu, użyj metody GetDocumentRequest
. Wartość parametru name
odnosi się do pełnej nazwy zasobu dokumentu i jest ustawiona w komórce powyżej jako document_resource_name
. Oczekiwany format to corpora/corpus-123/documents/document-123
.
get_document_request = glm.GetDocumentRequest(name=document_resource_name)
# Make the request
# document_resource_name is a variable set in the "Create a document" section.
get_document_response = retriever_service_client.get_document(get_document_request)
# Print the response
print(get_document_response)
Przetwarzanie i dzielenie dokumentu na fragmenty
Aby poprawić trafność treści zwracanych przez bazę danych wektorów podczas wyszukiwania semantycznego, podziel duże dokumenty na mniejsze części, czyli fragmenty, podczas przetwarzania dokumentu.
Element Chunk
jest podczęść elementu Document
, która jest traktowana jako niezależna jednostka na potrzeby reprezentacji wektorowej i przechowywania danych. W definicji Chunk
może być maksymalnie 2043 tokenów. Corpus
może zawierać maksymalnie 1 milion Chunk
.
Podobnie jak w przypadku Document
, Chunks
obsługuje też maksymalnie 20 definiowanych przez użytkownika pól custom_metadata
, które są podawane jako pary klucz-wartość. Metadane niestandardowe mogą być ciągami znaków, listami ciągów znaków lub wartościami liczbowymi. Pamiętaj, że listy ciągów znaków mogą zawierać maksymalnie 10 wartości, a wartości liczbowe są w interfejsie API reprezentowane jako liczby zmiennoprzecinkowe.
W tym przewodniku używamy open source HtmlChunker od Google.
Inne fragmenty, których możesz użyć, to LangChain i LlamaIndex.
Przetwarzanie kodu HTML i dzielenie go na fragmenty za pomocą HtmlChunker
!pip install google-labs-html-chunker
from google_labs_html_chunker.html_chunker import HtmlChunker
from urllib.request import urlopen
Pobierz DOM HTML witryny. Tutaj kod HTML jest odczytywany bezpośrednio, ale lepiej jest uzyskać kod HTML po renderowaniu, aby zawierał kod HTML z wstrzykniętym kodem JavaScript, na przykład document.documentElement.innerHTML
.
with(urlopen("https://developers.googleblog.com/2023/08/introducing-project-idx-experiment-to-improve-full-stack-multiplatform-app-development.html")) as f:
html = f.read().decode("utf-8")
Podziel dokument tekstowy na fragmenty i utwórz z nich Chunk
. Na tym etapie tworzone są obiekty Chunk
, a w następnej sekcji są one przesyłane do interfejsu Semantic Retriever API.
# Chunk the file using HtmlChunker
chunker = HtmlChunker(
max_words_per_aggregate_passage=200,
greedily_aggregate_sibling_nodes=True,
html_tags_to_exclude={"noscript", "script", "style"},
)
passages = chunker.chunk(html)
print(passages)
# Create `Chunk` entities.
chunks = []
for passage in passages:
chunk = glm.Chunk(data={'string_value': passage})
# Optionally, you can add metadata to a chunk
chunk.custom_metadata.append(glm.CustomMetadata(key="tags",
string_list_value=glm.StringList(
values=["Google For Developers", "Project IDX", "Blog", "Announcement"])))
chunk.custom_metadata.append(glm.CustomMetadata(key="chunking_strategy",
string_value="greedily_aggregate_sibling_nodes"))
chunk.custom_metadata.append(glm.CustomMetadata(key = "publish_date",
numeric_value = 20230808))
chunks.append(chunk)
print(chunks)
Tworzenie fragmentów wsadowo
Tworzenie fragmentów w partiach. W przypadku żądania zbiorczego możesz określić maksymalnie 100 kawałków.
Użyj aplikacji CreateChunk()
, aby utworzyć pojedynczy fragment.
# Option 1: Use HtmlChunker in the section above.
# `chunks` is the variable set from the section above.
create_chunk_requests = []
for chunk in chunks:
create_chunk_requests.append(glm.CreateChunkRequest(parent=document_resource_name, chunk=chunk))
# Make the request
request = glm.BatchCreateChunksRequest(parent=document_resource_name, requests=create_chunk_requests)
response = retriever_service_client.batch_create_chunks(request)
print(response)
Możesz też tworzyć fragmenty bez użycia komponentu htmlChunker.
# Add up to 100 CreateChunk requests per batch request.
# document_resource_name is a variable set in the "Create a document" section.
chunks = []
chunk_1 = glm.Chunk(data={'string_value': "Chunks support user specified metadata."})
chunk_1.custom_metadata.append(glm.CustomMetadata(key="section",
string_value="Custom metadata filters"))
chunk_2 = glm.Chunk(data={'string_value': "The maximum number of metadata supported is 20"})
chunk_2.custom_metadata.append(glm.CustomMetadata(key = "num_keys",
numeric_value = 20))
chunks = [chunk_1, chunk_2]
create_chunk_requests = []
for chunk in chunks:
create_chunk_requests.append(glm.CreateChunkRequest(parent=document_resource_name, chunk=chunk))
# Make the request
request = glm.BatchCreateChunksRequest(parent=document_resource_name, requests=create_chunk_requests)
response = retriever_service_client.batch_create_chunks(request)
print(response)
Wyświetlanie listy Chunk
i pobieranie stanu
Użyj metody ListChunksRequest
, aby wyświetlić wszystkie dostępne elementy (Chunk
) w postaci listy podzielonej na strony. Limit rozmiaru wynosi 100 elementów Chunk
na stronę, posortowany w kolejności rosnącej według wartości Chunk.create_time
. Jeśli nie określisz limitu, zwrócimy maksymalnie 10 Chunk
.
Aby pobrać kolejną stronę, podaj jako argument kolejnego żądania wartość next_page_token
zwróconą w odpowiedzi ListChunksRequest
. Pamiętaj, że podczas podziału na strony wszystkie inne parametry przekazane do funkcji ListChunks
muszą być zgodne z wywołaniem, które przekazało token strony.
Wszystkie Chunk
zwracają wartość state
. Użyj tego polecenia, aby sprawdzić stan Chunks
przed wysłaniem zapytania Corpus
. Stany Chunk
to: UNSPECIFIED
, PENDING_PROCESSING
, ACTIVE
i FAILED
. Możesz wysyłać tylko zapytania dotyczące ACTIVE
Chunk
.
# Make the request
request = glm.ListChunksRequest(parent=document_resource_name)
list_chunks_response = retriever_service_client.list_chunks(request)
for index, chunks in enumerate(list_chunks_response.chunks):
print(f'\nChunk # {index + 1}')
print(f'Resource Name: {chunks.name}')
# Only ACTIVE chunks can be queried.
print(f'State: {glm.Chunk.State(chunks.state).name}')
Przetwarzanie innego dokumentu
Dodaj kolejne Document
za pomocą htmlChunker i dodaj filtry.
# Create a document with a custom display name.
example_document = glm.Document(display_name="How it’s Made: Interacting with Gemini through multimodal prompting")
# Add document metadata.
# Metadata also supports numeric values not specified here
document_metadata = [
glm.CustomMetadata(key="url", string_value="https://developers.googleblog.com/2023/12/how-its-made-gemini-multimodal-prompting.html")]
example_document.custom_metadata.extend(document_metadata)
# Make the CreateDocument request
# corpus_resource_name is a variable set in the "Create a corpus" section.
create_document_request = glm.CreateDocumentRequest(parent=corpus_resource_name, document=example_document)
create_document_response = retriever_service_client.create_document(create_document_request)
# Set the `document_resource_name` for subsequent sections.
document_resource_name = create_document_response.name
print(create_document_response)
# Chunks - add another webpage from Google for Developers
with(urlopen("https://developers.googleblog.com/2023/12/how-its-made-gemini-multimodal-prompting.html")) as f:
html = f.read().decode("utf-8")
# Chunk the file using HtmlChunker
chunker = HtmlChunker(
max_words_per_aggregate_passage=100,
greedily_aggregate_sibling_nodes=False,
)
passages = chunker.chunk(html)
# Create `Chunk` entities.
chunks = []
for passage in passages:
chunk = glm.Chunk(data={'string_value': passage})
chunk.custom_metadata.append(glm.CustomMetadata(key="tags",
string_list_value=glm.StringList(
values=["Google For Developers", "Gemini API", "Blog", "Announcement"])))
chunk.custom_metadata.append(glm.CustomMetadata(key="chunking_strategy",
string_value="no_aggregate_sibling_nodes"))
chunk.custom_metadata.append(glm.CustomMetadata(key = "publish_date",
numeric_value = 20231206))
chunks.append(chunk)
# Make the request
create_chunk_requests = []
for chunk in chunks:
create_chunk_requests.append(glm.CreateChunkRequest(parent=document_resource_name, chunk=chunk))
request = glm.BatchCreateChunksRequest(parent=document_resource_name, requests=create_chunk_requests)
response = retriever_service_client.batch_create_chunks(request)
print(response)
Przesyłanie zapytań do korpusu
Użyj metody QueryCorpusRequest
, aby przeprowadzić wyszukiwanie semantyczne i uzyskać odpowiednie fragmenty.
results_count
: określ liczbę fragmentów do zwrócenia. Maksymalna wartość to 100. Jeśli nie podasz tej wartości, API zwróci maksymalnie 10 wartościChunk
.metadata_filters
: filtruj wedługchunk_metadata
lubdocument_metadata
. Każdy elementMetadataFilter
musi odpowiadać niepowtarzalnemu kluczowi. Wiele obiektówMetadataFilter
jest połączonych logicznymiAND
. Podobne warunki filtra metadanych są połączone za pomocą operatorów logicznychOR
. Oto kilka przykładów:
(year >= 2020 OR year < 2010) AND (genre = drama OR genre = action)
metadata_filter = [
{
key = "document.custom_metadata.year"
conditions = [
{int_value = 2020, operation = GREATER_EQUAL},
{int_value = 2010, operation = LESS}]
},
{
key = "document.custom_metadata.genre"
conditions = [
{string_value = "drama", operation = EQUAL},
{string_value = "action", operation = EQUAL} }]
}]
Pamiętaj, że w przypadku tego samego klucza operator „AND” obsługuje tylko wartości liczbowe. Pary ciągów znaków obsługują tylko operator „LUB” dla tego samego klucza.
("Google for Developers" in tags) and (20230314 > publish_date)
metadata_filter = [
{
key = "chunk.custom_metadata.tags"
conditions = [
{string_value = 'Google for Developers', operation = INCLUDES},
},
{
key = "chunk.custom_metadata.publish_date"
conditions = [
{numeric_value = 20230314, operation = GREATER_EQUAL}]
}]
user_query = "What is the purpose of Project IDX?"
results_count = 5
# Add metadata filters for both chunk and document.
chunk_metadata_filter = glm.MetadataFilter(key='chunk.custom_metadata.tags',
conditions=[glm.Condition(
string_value='Google For Developers',
operation=glm.Condition.Operator.INCLUDES)])
# Make the request
# corpus_resource_name is a variable set in the "Create a corpus" section.
request = glm.QueryCorpusRequest(name=corpus_resource_name,
query=user_query,
results_count=results_count,
metadata_filters=[chunk_metadata_filter])
query_corpus_response = retriever_service_client.query_corpus(request)
print(query_corpus_response)
Przypisywanie odpowiedzi na pytania
Użyj metody GenerateAnswer
, aby wykonać przypisane pytanie do swojego dokumentu, korpusu lub zbioru fragmentów.
Odpowiadanie na pytania z przypisaniem autorów (AQA) polega na udzielaniu odpowiedzi na pytania w ramach określonego kontekstu i przypisywaniu autorów, przy jednoczesnym minimalizowaniu zjawiska halucynacji.
GenerateAnswer
ma kilka zalet w porównaniu z niedopasowanym LLM, gdy potrzebna jest automatyzacja jakości:
- Model bazowy został wytrenowany tak, aby zwracać tylko odpowiedzi, które są oparte na podanym kontekście.
- Identyfikuje źródła (segmenty podanego kontekstu, które przyczyniły się do odpowiedzi). Dzięki atrybucji użytkownik może zweryfikować odpowiedź.
- Oblicza ona wartość
answerable_probability
dla danej pary (pytanie, kontekst), co pozwala Ci wpływać na działanie usługi w zależności od tego, jak prawdopodobne jest, że zwrócona odpowiedź będzie prawidłowa i poparta dowodami.
answerable_probability
i problem „nie wiem”
W niektórych przypadkach najlepszą odpowiedzią na pytanie jest „Nie wiem”. Jeśli na przykład podany kontekst nie zawiera odpowiedzi na pytanie, jest ono uznawane za „nieodpowiadające”.
Model AQA bardzo dobrze radzi sobie z rozpoznawaniem takich przypadków. Może ona nawet odróżniać stopnie możliwości udzielenia odpowiedzi od braku możliwości udzielenia odpowiedzi.
Interfejs API GenerateAnswer
daje Ci jednak możliwość podjęcia ostatecznej decyzji, ponieważ:
- Zawsze staraj się zwracać wiarygodną odpowiedź – nawet wtedy, gdy jest mało prawdopodobne, że będzie ona wiarygodna i prawidłowa.
- Zwracanie wartości
answerable_probability
– szacowanie przez model prawdopodobieństwa, że odpowiedź jest prawidłowa i poparta dowodami.
Niski współczynnik answerable_probability
może być spowodowany jednym lub kilkoma z tych czynników:
- Model nie jest pewny, czy jego odpowiedź jest prawidłowa.
- Model nie jest pewny, czy jego odpowiedź jest oparta na cytowanych fragmentach; odpowiedź może być zamiast tego wywnioskowana na podstawie ogólnej wiedzy. Przykład:
question="1+1=?", passages=["2+2=4”]
→answer=2, answerable_probability=0.02
- Model dostarczył istotne informacje, które nie odpowiadały w pełni na pytanie. Przykład:
question="Is it available in my size?, passages=["Available in sizes 5-11"]
→answer="Yes it is available in sizes 5-11", answerable_probability=0.03"
- W zapytaniu GenerateAnswerRequest nie ma poprawnie sformułowanego pytania.
Niska wartość answerable_probability
wskazuje, że odpowiedź GenerateAnswer.answer jest prawdopodobnie nieprawidłowa lub nieuzasadniona, dlatego zdecydowanie zalecamy dalsze przetworzenie odpowiedzi przez sprawdzenie answerable_probability
.
Gdy answerable_probability
jest niski, niektórzy klienci mogą chcieć:
- wyświetlić użytkownikowi komunikat „Nie możemy odpowiedzieć na to pytanie”.
- Wróćmy do ogólnego przeznaczenia LLM, które stanowi odpowiedź na pytanie wynikające z wiedzy z całego świata. Wartość progowa i charakter takich rozwiązań zastępczych zależą od konkretnych przypadków użycia. Wartość
answerable_probability
<= 0,5 to dobry próg początkowy.
Przydatne wskazówki dotyczące AQA
Pełne specyfikacje interfejsu API znajdziesz w dokumentacji GenerateAnswerRequest
API Reference.
- Długość fragmentu: zalecamy użycie maksymalnie 300 tokenów na fragment.
- Sortowanie fragmentów:
- Jeśli podasz wartość
GenerateAnswerRequest.inline_passages
, fragmenty powinny być posortowane w kolejności malejącej pod względem trafności w stosunku do zapytania. Jeśli przekroczysz limit długości kontekstu modelu, ostatnie (najmniej trafne) fragmenty zostaną pominięte. - Jeśli podasz
GenerateAnswerRequest.semantic_retriever
, sortowanie według trafności zostanie wykonane automatycznie.
- Jeśli podasz wartość
- Ograniczenia: model AQA jest wyspecjalizowany do odpowiadania na pytania. Do innych zastosowań, takich jak pisanie kreatywne, streszczanie itp., wywołaj model ogólnego przeznaczenia w GenerateContent.
- Czat: jeśli wiadomo, że wpis użytkownika to pytanie, na które można udzielić odpowiedzi w określonym kontekście, AQA może odpowiadać na pytania zadawane na czacie. Jeśli jednak dane wejściowe użytkownika mogą być dowolnego typu, lepszym wyborem może być model ogólnego przeznaczenia.
- Temperatura:
- Ogólnie zalecamy stosowanie stosunkowo niskiej temperatury (około 0,2), aby zapewnić dokładność pomiarów AQA.
- Jeśli Twój przypadek użycia opiera się na wynikach deterministycznych, ustaw wartość temperature=0.
user_query = "What is the purpose of Project IDX?"
answer_style = "ABSTRACTIVE" # Or VERBOSE, EXTRACTIVE
MODEL_NAME = "models/aqa"
# Make the request
# corpus_resource_name is a variable set in the "Create a corpus" section.
content = glm.Content(parts=[glm.Part(text=user_query)])
retriever_config = glm.SemanticRetrieverConfig(source=corpus_resource_name, query=content)
req = glm.GenerateAnswerRequest(model=MODEL_NAME,
contents=[content],
semantic_retriever=retriever_config,
answer_style=answer_style)
aqa_response = generative_service_client.generate_answer(req)
print(aqa_response)
# Get the metadata from the first attributed passages for the source
chunk_resource_name = aqa_response.answer.grounding_attributions[0].source_id.semantic_retriever_chunk.chunk
get_chunk_response = retriever_service_client.get_chunk(name=chunk_resource_name)
print(get_chunk_response)
Więcej opcji: AQA z użyciem ścieżek śródtekstowych
Możesz też użyć punktu końcowego AQA bezpośrednio, bez korzystania z interfejsu Semantic Retriever API, podając parametr inline_passages
.
user_query = "What is AQA from Google?"
user_query_content = glm.Content(parts=[glm.Part(text=user_query)])
answer_style = "VERBOSE" # or ABSTRACTIVE, EXTRACTIVE
MODEL_NAME = "models/aqa"
# Create the grounding inline passages
grounding_passages = glm.GroundingPassages()
passage_a = glm.Content(parts=[glm.Part(text="Attributed Question and Answering (AQA) refers to answering questions grounded to a given corpus and providing citation")])
grounding_passages.passages.append(glm.GroundingPassage(content=passage_a, id="001"))
passage_b = glm.Content(parts=[glm.Part(text="An LLM is not designed to generate content grounded in a set of passages. Although instructing an LLM to answer questions only based on a set of passages reduces hallucination, hallucination still often occurs when LLMs generate responses unsupported by facts provided by passages")])
grounding_passages.passages.append(glm.GroundingPassage(content=passage_b, id="002"))
passage_c = glm.Content(parts=[glm.Part(text="Hallucination is one of the biggest problems in Large Language Models (LLM) development. Large Language Models (LLMs) could produce responses that are fictitious and incorrect, which significantly impacts the usefulness and trustworthiness of applications built with language models.")])
grounding_passages.passages.append(glm.GroundingPassage(content=passage_c, id="003"))
# Create the request
req = glm.GenerateAnswerRequest(model=MODEL_NAME,
contents=[user_query_content],
inline_passages=grounding_passages,
answer_style=answer_style)
aqa_response = generative_service_client.generate_answer(req)
print(aqa_response)
Udostępnianie korpusu
Możesz udostępnić korpus innym osobom, używając interfejsu API CreatePermissionRequest
.
Ograniczenia:
- Istnieją 2 role do udostępniania:
READER
iEDITOR
.READER
może wysyłać zapytania do korpusów.- Użytkownik
WRITER
ma uprawnienia do odczytu i dodatkowo może edytować i udostępniać korpus.
- Korpus może być publiczny, jeśli przyznasz
EVERYONE
jakouser_type
uprawnienia do odczytu.
# Replace your-email@gmail.com with the email added as a test user in the OAuth Quickstart
shared_user_email = "TODO-your-email@gmail.com" # @param {type:"string"}
user_type = "USER"
role = "READER"
# Make the request
# corpus_resource_name is a variable set in the "Create a corpus" section.
request = glm.CreatePermissionRequest(
parent=corpus_resource_name,
permission=glm.Permission(grantee_type=user_type,
email_address=shared_user_email,
role=role))
create_permission_response = permission_service_client.create_permission(request)
print(create_permission_response)
Usuwanie zbioru
Użyj polecenia DeleteCorpusRequest
, aby usunąć korpus użytkownika i wszystkie powiązane z nim Document
e i Chunk
.
Pamiętaj, że niepusty korpus wywoła błąd bez określenia flagi force=True
. Jeśli ustawisz force=True
, wszystkie Chunk
i obiekty powiązane z tym Document
zostaną również usunięte.
Jeśli force=False
(wartość domyślna) i Document
zawierają jakiekolwiek wartości Chunk
, zwracany jest błąd FAILED_PRECONDITION
.
# Set force to False if you don't want to delete non-empty corpora.
req = glm.DeleteCorpusRequest(name=corpus_resource_name, force=True)
delete_corpus_response = retriever_service_client.delete_corpus(req)
print("Successfully deleted corpus: " + corpus_resource_name)
Podsumowanie i dalsze informacje
W tym przewodniku przedstawiliśmy interfejsy API (AQA) służącego do pobierania semantycznego i przypisanego pytań i odpowiedzi w interfejsie Generative Language API oraz pokazaliśmy, jak używać tego interfejsu do pobierania informacji semantycznych z niestandardowych danych tekstowych. Ten interfejs API działa też z ramówkami danych LlamaIndex. Więcej informacji znajdziesz w samouczku.
Więcej informacji o dostępnych funkcjach znajdziesz też w dokumentacji interfejsu API.
Załącznik: konfigurowanie OAuth za pomocą danych logowania użytkownika
Aby skonfigurować uwierzytelnianie OAuth, wykonaj czynności podane poniżej w krótkim wprowadzeniu do OAuth.
Autoryzowanie danych logowania w przypadku aplikacji na komputer. Aby uruchomić ten notebook w Colab, najpierw zmień nazwę pliku z danymi logowania (zwykle
client_secret_*.json
) naclient_secret.json
. Następnie prześlij plik, klikając ikonę pliku na pasku bocznym po lewej stronie, a potem ikonę przesyłania, jak pokazano na poniższym zrzucie ekranu.
# Replace TODO-your-project-name with the project used in the OAuth Quickstart
project_name = "TODO-your-project-name" # @param {type:"string"}
# Replace TODO-your-email@gmail.com with the email added as a test user in the OAuth Quickstart
email = "TODO-your-email@gmail.com" # @param {type:"string"}
# Rename the uploaded file to `client_secret.json` OR
# Change the variable `client_file_name` in the code below.
client_file_name = "client_secret.json"
# IMPORTANT: Follow the instructions from the output - you must copy the command
# to your terminal and copy the output after authentication back here.
!gcloud config set project $project_name
!gcloud config set account $email
# NOTE: The simplified project setup in this tutorial triggers a "Google hasn't verified this app." dialog.
# This is normal, click "Advanced" -> "Go to [app name] (unsafe)"
!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"
Zainicjuj bibliotekę klienta i ponownie uruchom notatnik, zaczynając od tworzenia korpusu.
import google.ai.generativelanguage as glm
generative_service_client = glm.GenerativeServiceClient()
retriever_service_client = glm.RetrieverServiceClient()
permission_service_client = glm.PermissionServiceClient()