Ulepsz Amazon Lex za pomocą LLM i popraw jakość FAQ dzięki przetwarzaniu adresów URL | Usługi sieciowe Amazona

Ulepsz Amazon Lex za pomocą LLM i popraw jakość FAQ dzięki przetwarzaniu adresów URL | Usługi sieciowe Amazona

W dzisiejszym cyfrowym świecie większość konsumentów woli samodzielnie znaleźć odpowiedzi na pytania dotyczące obsługi klienta, niż poświęcać czas na kontakt z firmami i/lub usługodawcami. W tym poście na blogu omówiono innowacyjne rozwiązanie umożliwiające zbudowanie chatbota z pytaniami i odpowiedziami Amazonka Lex który wykorzystuje istniejące często zadawane pytania z Twojej witryny. To narzędzie oparte na sztucznej inteligencji może zapewniać szybkie i dokładne odpowiedzi na zapytania w świecie rzeczywistym, umożliwiając klientowi szybkie i łatwe samodzielne rozwiązywanie typowych problemów.

Przetwarzanie pojedynczego adresu URL

Wiele przedsiębiorstw opublikowało na swoich stronach internetowych zestaw odpowiedzi na często zadawane pytania (FAQ) swoich klientów. W tym przypadku chcemy zaoferować klientom chatbota, który będzie w stanie odpowiedzieć na ich pytania zawarte w opublikowanych przez nas często zadawanych pytaniach. W poście na blogu pt Ulepsz Amazon Lex dzięki funkcjom konwersacyjnym FAQ za pomocą LLM, pokazaliśmy, jak można wykorzystać kombinację Amazon Lex i LlamaIndex do zbudowania chatbota opartego na istniejących źródłach wiedzy, takich jak dokumenty PDF lub Word. Aby obsługiwać proste odpowiedzi na często zadawane pytania w oparciu o witrynę z często zadawanymi pytaniami, musimy stworzyć proces przetwarzania, który umożliwi indeksowanie witryny i tworzenie osadzonych elementów, które będą mogły być wykorzystywane przez LlamaIndex do odpowiadania na pytania klientów. W tym przypadku będziemy bazować na bocie stworzonym w pliku poprzedni post na blogu, który odpytuje te osadzenia za pomocą wypowiedzi użytkownika i zwraca odpowiedź z często zadawanych pytań w witrynie.

Poniższy diagram pokazuje, jak proces pozyskiwania i bot Amazon Lex współpracują w naszym rozwiązaniu.

Ulepsz Amazon Lex za pomocą LLM i usprawnij obsługę często zadawanych pytań, korzystając z pozyskiwania adresów URL | Amazon Web Services PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

W przepływie pracy rozwiązania strona internetowa z często zadawanymi pytaniami jest pobierana za pośrednictwem AWS Lambda. Ta funkcja Lambda przeszukuje witrynę i zapisuje wynikowy tekst w pliku Usługa Amazon Simple Storage Łyżka (Amazon S3). Następnie segment S3 uruchamia funkcję Lambda, która wykorzystuje LlamaIndex do tworzenia osadów przechowywanych w Amazon S3. Kiedy pojawia się pytanie od użytkownika końcowego, takie jak „Jakie są Twoje zasady zwrotów?”, Bot Amazon Lex wykorzystuje swoją funkcję Lambda do wysyłania zapytań o osadzenia przy użyciu podejścia opartego na RAG i LlamaIndex. Więcej informacji na temat tego podejścia i wymagań wstępnych można znaleźć w poście na blogu, Ulepsz Amazon Lex dzięki funkcjom konwersacyjnym FAQ za pomocą LLM.

Po spełnieniu wymagań wstępnych z wyżej wymienionego bloga, pierwszym krokiem jest przyjęcie często zadawanych pytań do repozytorium dokumentów, które może być wektoryzowane i indeksowane przez LlamaIndex. Poniższy kod pokazuje, jak to osiągnąć:

import logging
import sys
import requests
import html2text
from llama_index.readers.schema.base import Document
from llama_index import GPTVectorStoreIndex
from typing import List logging.basicConfig(stream=sys.stdout, level=logging.INFO)
logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout)) class EZWebLoader: def __init__(self, default_header: str = None): self._html_to_text_parser = html2text() if default_header is None: self._default_header = {"User-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36"} else: self._default_header = default_header def load_data(self, urls: List[str], headers: str = None) -> List[Document]: if headers is None: headers = self._default_header documents = [] for url in urls: response = requests.get(url, headers=headers).text response = self._html2text.html2text(response) documents.append(Document(response)) return documents url = "http://www.zappos.com/general-questions"
loader = EZWebLoader()
documents = loader.load_data([url])
index = GPTVectorStoreIndex.from_documents(documents)

W poprzednim przykładzie pobieramy predefiniowany adres URL witryny FAQ z Zappos i przetwarzamy go za pomocą EZWebLoader klasa. W przypadku tych zajęć przeszliśmy do adresu URL i załadowaliśmy wszystkie pytania znajdujące się na stronie do indeksu. Możemy teraz zadać pytanie typu „Czy Zappos ma karty podarunkowe?” i uzyskaj odpowiedzi bezpośrednio z często zadawanych pytań na naszej stronie internetowej. Poniższy zrzut ekranu przedstawia konsolę testową bota Amazon Lex odpowiadającą na to pytanie z często zadawanych pytań.

Ulepsz Amazon Lex za pomocą LLM i usprawnij obsługę często zadawanych pytań, korzystając z pozyskiwania adresów URL | Amazon Web Services PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Udało nam się to osiągnąć, ponieważ w pierwszym kroku zaindeksowaliśmy adres URL i utworzyliśmy osady, których LlamaIndex mógł użyć do wyszukania odpowiedzi na nasze pytanie. Funkcja Lambda naszego bota pokazuje, jak uruchamiane jest to wyszukiwanie po zwróceniu intencji zastępczej:

import time
import json
import os
import logging
import boto3
from llama_index import StorageContext, load_index_from_storage logger = logging.getLogger()
logger.setLevel(logging.DEBUG) def download_docstore(): # Create an S3 client s3 = boto3.client('s3') # List all objects in the S3 bucket and download each one
try: bucket_name = 'faq-bot-storage-001' s3_response = s3.list_objects_v2(Bucket=bucket_name) if 'Contents' in s3_response: for item in s3_response['Contents']: file_name = item['Key'] logger.debug("Downloading to /tmp/" + file_name) s3.download_file(bucket_name, file_name, '/tmp/' + file_name) logger.debug('All files downloaded from S3 and written to local filesystem.') except Exception as e: logger.error(e)
raise e #download the doc store locally
download_docstore() storage_context = StorageContext.from_defaults(persist_dir="/tmp/")
# load index
index = load_index_from_storage(storage_context)
query_engine = index.as_query_engine() def lambda_handler(event, context): """
Route the incoming request based on intent.
The JSON body of the request is provided in the event slot. """ # By default, treat the user request as coming from the America/New_York time zone. os.environ['TZ'] = 'America/New_York' time.tzset() logger.debug("===== START LEX FULFILLMENT ====") logger.debug(event) slots = {} if "currentIntent" in event and "slots" in event["currentIntent"]: slots = event["currentIntent"]["slots"] intent = event["sessionState"]["intent"] dialogaction = {"type": "Delegate"} message = [] if str.lower(intent["name"]) == "fallbackintent": #execute query from the input given by the user response = str.strip(query_engine.query(event["inputTranscript"]).response) dialogaction["type"] = "Close" message.append({'content': f'{response}', 'contentType': 'PlainText'}) final_response = { "sessionState": { "dialogAction": dialogaction, "intent": intent }, "messages": message } logger.debug(json.dumps(final_response, indent=1)) logger.debug("===== END LEX FULFILLMENT ====") return final_response

To rozwiązanie sprawdza się dobrze, gdy na jednej stronie znajdują się wszystkie odpowiedzi. Jednak większość witryn z często zadawanymi pytaniami nie jest zbudowana na jednej stronie. Na przykład w naszym przykładzie Zappos, jeśli zadamy pytanie „Czy masz politykę dopasowywania cen?”, wówczas otrzymamy odpowiedź niezadowalającą, jak pokazano na poniższym zrzucie ekranu.

Ulepsz Amazon Lex za pomocą LLM i usprawnij obsługę często zadawanych pytań, korzystając z pozyskiwania adresów URL | Amazon Web Services PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

W poprzedniej interakcji odpowiedź dotycząca zasad dopasowywania cen nie była pomocna dla naszego użytkownika. Ta odpowiedź jest krótka, ponieważ często zadawane pytania, o których mowa, to link do konkretnej strony dotyczącej zasad dopasowywania cen, a nasze przeszukiwanie sieci dotyczyło tylko jednej strony. Uzyskanie lepszych odpowiedzi będzie oznaczać także przeszukiwanie tych linków. W następnej sekcji pokazano, jak uzyskać odpowiedzi na pytania wymagające dwóch lub więcej poziomów głębi strony.

Indeksowanie na poziomie N

Kiedy indeksujemy stronę internetową w celu uzyskania wiedzy na temat często zadawanych pytań, potrzebne informacje mogą być zawarte na stronach, do których prowadzą linki. Na przykład w naszym przykładzie Zappos zadajemy pytanie „Czy masz politykę dopasowywania cen?” a odpowiedź brzmi: „Tak, proszę odwiedzić uczyć się więcej." Jeśli ktoś zapyta: „Jaka jest Twoja polityka dopasowywania cen?” wtedy chcemy udzielić pełnej odpowiedzi wraz z polityką. Osiągnięcie tego oznacza, że ​​musimy przeglądać łącza, aby uzyskać rzeczywiste informacje dla naszego użytkownika końcowego. Podczas procesu przyjmowania możemy użyć naszego modułu ładującego, aby znaleźć linki zakotwiczone do innych stron HTML, a następnie je przeglądać. Następująca zmiana w kodzie naszego robota indeksującego pozwala nam znajdować linki na przeszukiwanych stronach. Zawiera także dodatkową logikę, która pozwala uniknąć przeszukiwania cyklicznego i umożliwia filtrowanie według prefiksu.

import logging
import requests
import html2text
from llama_index.readers.schema.base import Document
from typing import List
import re def find_http_urls_in_parentheses(s: str, prefix: str = None): pattern = r'((https?://[^)]+))' urls = re.findall(pattern, s) matched = [] if prefix is not None: for url in urls: if str(url).startswith(prefix): matched.append(url) else: matched = urls return list(set(matched)) # remove duplicates by converting to set, then convert back to list class EZWebLoader: def __init__(self, default_header: str = None): self._html_to_text_parser = html2text if default_header is None: self._default_header = {"User-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36"} else: self._default_header = default_header def load_data(self, urls: List[str], num_levels: int = 0, level_prefix: str = None, headers: str = None) -> List[Document]: logging.info(f"Number of urls: {len(urls)}.") if headers is None: headers = self._default_header documents = [] visited = {} for url in urls: q = [url] depth = num_levels for page in q: if page not in visited: #prevent cycles by checking to see if we already crawled a link logging.info(f"Crawling {page}") visited[page] = True #add entry to visited to prevent re-crawling pages response = requests.get(page, headers=headers).text response = self._html_to_text_parser.html2text(response) #reduce html to text documents.append(Document(response)) if depth > 0: #crawl linked pages ingest_urls = find_http_urls_in_parentheses(response, level_prefix) logging.info(f"Found {len(ingest_urls)} pages to crawl.") q.extend(ingest_urls) depth -= 1 #reduce the depth counter so we go only num_levels deep in our crawl else: logging.info(f"Skipping {page} as it has already been crawled") logging.info(f"Number of documents: {len(documents)}.") return documents url = "http://www.zappos.com/general-questions"
loader = EZWebLoader()
#crawl the site with 1 level depth and prefix of "/c/" for customer service root
documents = loader.load_data([url], num_levels=1, level_prefix="https://www.zappos.com/c/")
index = GPTVectorStoreIndex.from_documents(documents)

W powyższym kodzie wprowadzamy możliwość indeksowania N poziomów w głąb i podajemy przedrostek, który pozwala nam ograniczyć indeksowanie tylko do rzeczy rozpoczynających się od określonego wzorca adresu URL. W naszym przykładzie Zappos wszystkie strony obsługi klienta są zrootowane zappos.com/c, dlatego dodajemy to jako przedrostek, aby ograniczyć indeksowanie do mniejszego i bardziej odpowiedniego podzbioru. Kod pokazuje, jak możemy spożyć do dwóch poziomów głęboko. Logika Lambda naszego bota pozostaje taka sama, ponieważ nic się nie zmieniło poza tym, że robot pobiera więcej dokumentów.

Mamy już zindeksowane wszystkie dokumenty i możemy zadać bardziej szczegółowe pytanie. Na poniższym zrzucie ekranu nasz bot udziela prawidłowej odpowiedzi na pytanie „Czy masz politykę dopasowywania cen?”

Ulepsz Amazon Lex za pomocą LLM i usprawnij obsługę często zadawanych pytań, korzystając z pozyskiwania adresów URL | Amazon Web Services PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Mamy teraz pełną odpowiedź na nasze pytanie dotyczące dopasowywania cen. Zamiast po prostu powiedzieć „Tak, zapoznaj się z naszymi zasadami”, podaje nam szczegóły z indeksowania drugiego poziomu.

Sprzątać

Aby uniknąć przyszłych wydatków, usuń wszystkie zasoby wdrożone w ramach tego ćwiczenia. Udostępniliśmy skrypt umożliwiający bezpieczne zamknięcie punktu końcowego Sagemaker. Szczegóły użycia znajdują się w pliku README. Dodatkowo, aby usunąć wszystkie inne zasoby, które możesz uruchomić cdk destroy w tym samym katalogu, co inne polecenia cdk, aby anulować obsługę administracyjną wszystkich zasobów na twoim stosie.

Wnioski

Możliwość wprowadzenia zestawu często zadawanych pytań do chatbota umożliwia Twoim klientom znalezienie odpowiedzi na swoje pytania za pomocą prostych zapytań w języku naturalnym. Łącząc wbudowaną obsługę Amazon Lex do obsługi awarii z rozwiązaniem RAG, takim jak LlamaIndex, możemy zapewnić naszym klientom szybką ścieżkę do uzyskania satysfakcjonujących, wyselekcjonowanych i zatwierdzonych odpowiedzi na często zadawane pytania. Stosując indeksowanie na poziomie N w naszym rozwiązaniu, możemy pozwolić na odpowiedzi, które mogą obejmować wiele łączy z często zadawanymi pytaniami i zapewnić głębsze odpowiedzi na zapytania naszych klientów. Wykonując te kroki, możesz bezproblemowo włączyć potężne funkcje Q i A oparte na LLM oraz wydajne pozyskiwanie adresów URL do chatbota Amazon Lex. Dzięki temu interakcje z użytkownikami są dokładniejsze, kompleksowe i świadome kontekstowo.


O autorach

Ulepsz Amazon Lex za pomocą LLM i usprawnij obsługę często zadawanych pytań, korzystając z pozyskiwania adresów URL | Amazon Web Services PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.Maxa Henkla-Wallace'a jest inżynierem rozwoju oprogramowania w AWS Lex. Lubi pracować nad wykorzystaniem technologii, aby zmaksymalizować sukces klienta. Poza pracą pasjonuje się gotowaniem, spędzaniem czasu z przyjaciółmi i podróżowaniem z plecakiem.

Ulepsz Amazon Lex za pomocą LLM i usprawnij obsługę często zadawanych pytań, korzystając z pozyskiwania adresów URL | Amazon Web Services PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.Piosenka Fenga jest starszym naukowcem stosowanym w AWS AI Labs, specjalizującym się w przetwarzaniu języka naturalnego i sztucznej inteligencji. Jej badania badają różne aspekty tych dziedzin, w tym modelowanie dialogu opartego na dokumentach, rozumowanie dialogów zorientowanych na zadania oraz interaktywne generowanie tekstu przy użyciu multimodalnych danych.

Ulepsz Amazon Lex za pomocą LLM i usprawnij obsługę często zadawanych pytań, korzystając z pozyskiwania adresów URL | Amazon Web Services PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.John Baker jest głównym SDE w AWS, gdzie pracuje nad przetwarzaniem języka naturalnego, modelami dużego języka i innymi projektami związanymi z ML/AI. Pracuje w Amazonie od ponad 9 lat i pracował w AWS, Alexa i Amazon.com. W wolnym czasie John lubi jeździć na nartach i uprawiać inne zajęcia na świeżym powietrzu na północno-zachodnim wybrzeżu Pacyfiku.

Znak czasu:

Więcej z Uczenie maszynowe AWS