Pierwsze kroki z pobieraniem semantycznym

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:

  1. Włącz Generative Language API.

  1. Utwórz konto usługi, postępując zgodnie z dokumentacją.

    • Po utworzeniu konta usługi wygeneruj klucz konta usługi.

  1. 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.

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 zasobu Corpus (identyfikator). Musi zawierać maksymalnie 40 znaków alfanumerycznych. Jeśli podczas tworzenia parametr name jest pusty, wygenerujemy unikalną nazwę o maksymalnej długości 40 znaków z prefiksem z parametrów display_name i 12-znakowym losowym sufiksem.
  • display_name: czytelna dla człowieka nazwa wyświetlana Corpus. 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) zasobu Document. 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ów display_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ści Chunk.
  • metadata_filters: filtruj według chunk_metadata lub document_metadata. Każdy element MetadataFilter musi odpowiadać niepowtarzalnemu kluczowi. Wiele obiektów MetadataFilter jest połączonych logicznymi AND. Podobne warunki filtra metadanych są połączone za pomocą operatorów logicznych OR. 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.
  • 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 i EDITOR.
    • 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 jako user_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 Documente 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.

  1. Skonfiguruj ekran zgody OAuth.

  2. 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) na client_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()