Erweitern Sie Amazon Lex mit LLMs und verbessern Sie das FAQ-Erlebnis mithilfe der URL-Aufnahme | Amazon Web Services

Erweitern Sie Amazon Lex mit LLMs und verbessern Sie das FAQ-Erlebnis mithilfe der URL-Aufnahme | Amazon Web Services

In der heutigen digitalen Welt würden die meisten Verbraucher lieber selbst Antworten auf ihre Kundendienstfragen finden, als sich die Zeit zu nehmen, sich an Unternehmen und/oder Dienstleister zu wenden. In diesem Blogbeitrag wird eine innovative Lösung zum Erstellen eines Frage-und-Antwort-Chatbots untersucht Amazon Lex das vorhandene FAQs Ihrer Website nutzt. Dieses KI-gestützte Tool kann schnelle und genaue Antworten auf reale Anfragen liefern und ermöglicht es dem Kunden, häufig auftretende Probleme schnell und einfach selbstständig zu lösen.

Aufnahme einer einzelnen URL

Viele Unternehmen stellen auf ihrer Website eine Reihe veröffentlichter Antworten auf häufig gestellte Fragen (FAQs) für ihre Kunden bereit. In diesem Fall möchten wir den Kunden einen Chatbot anbieten, der ihre Fragen aus unseren veröffentlichten FAQs beantworten kann. Im Blogbeitrag mit dem Titel Erweitern Sie Amazon Lex mit konversationsorientierten FAQ-Funktionen mithilfe von LLMshaben wir gezeigt, wie Sie eine Kombination aus Amazon Lex und LlamaIndex verwenden können, um einen Chatbot zu erstellen, der auf Ihren vorhandenen Wissensquellen wie PDF- oder Word-Dokumenten basiert. Um eine einfache FAQ basierend auf einer Website mit FAQs zu unterstützen, müssen wir einen Aufnahmeprozess erstellen, der die Website crawlen und Einbettungen erstellen kann, die von LlamaIndex zur Beantwortung von Kundenfragen verwendet werden können. In diesem Fall bauen wir auf dem im erstellten Bot auf Vorheriger Blogpost, das diese Einbettungen mit der Äußerung eines Benutzers abfragt und die Antwort aus den FAQs der Website zurückgibt.

Das folgende Diagramm zeigt, wie der Aufnahmeprozess und der Amazon Lex-Bot für unsere Lösung zusammenarbeiten.

Erweitern Sie Amazon Lex mit LLMs und verbessern Sie das FAQ-Erlebnis mithilfe der URL-Aufnahme | Amazon Web Services PlatoBlockchain Data Intelligence. Vertikale Suche. Ai.

Im Lösungsworkflow wird die Website mit FAQs über aufgenommen AWS Lambda. Diese Lambda-Funktion crawlt die Website und speichert den resultierenden Text in einer Amazon Simple Storage-Service (Amazon S3) Eimer. Der S3-Bucket löst dann eine Lambda-Funktion aus, die LlamaIndex verwendet, um Einbettungen zu erstellen, die in Amazon S3 gespeichert werden. Wenn eine Frage eines Endbenutzers eintrifft, beispielsweise „Wie lauten Ihre Rückgabebedingungen?“, verwendet der Amazon Lex-Bot seine Lambda-Funktion, um die Einbettungen mithilfe eines RAG-basierten Ansatzes mit LlamaIndex abzufragen. Weitere Informationen zu diesem Ansatz und den Voraussetzungen finden Sie im Blogbeitrag: Erweitern Sie Amazon Lex mit konversationsorientierten FAQ-Funktionen mithilfe von LLMs.

Nachdem die Voraussetzungen aus dem oben genannten Blog erfüllt sind, besteht der erste Schritt darin, die FAQs in ein Dokumenten-Repository aufzunehmen, das von LlamaIndex vektorisiert und indiziert werden kann. Der folgende Code zeigt, wie dies erreicht wird:

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)

Im vorherigen Beispiel nehmen wir eine vordefinierte FAQ-Website-URL von Zappos und nehmen sie mit auf EZWebLoader Klasse. Mit dieser Klasse haben wir zur URL navigiert und alle Fragen, die sich auf der Seite befinden, in einen Index geladen. Wir können jetzt eine Frage stellen wie „Hat Zappos Geschenkkarten?“ und erhalten Sie die Antworten direkt in unseren FAQs auf der Website. Der folgende Screenshot zeigt, wie die Amazon Lex-Bot-Testkonsole diese Frage aus den FAQs beantwortet.

Erweitern Sie Amazon Lex mit LLMs und verbessern Sie das FAQ-Erlebnis mithilfe der URL-Aufnahme | Amazon Web Services PlatoBlockchain Data Intelligence. Vertikale Suche. Ai.

Dies konnten wir erreichen, weil wir im ersten Schritt die URL gecrawlt und Einbettungen erstellt hatten, anhand derer LlamaIndex nach der Antwort auf unsere Frage suchen konnte. Die Lambda-Funktion unseres Bots zeigt, wie diese Suche immer dann ausgeführt wird, wenn die Fallback-Absicht zurückgegeben wird:

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

Diese Lösung funktioniert gut, wenn eine einzige Webseite alle Antworten enthält. Allerdings sind die meisten FAQ-Seiten nicht auf einer einzigen Seite aufgebaut. Wenn wir beispielsweise in unserem Zappos-Beispiel die Frage „Haben Sie eine Preisanpassungsrichtlinie?“ stellen, erhalten wir eine nicht zufriedenstellende Antwort, wie im folgenden Screenshot gezeigt.

Erweitern Sie Amazon Lex mit LLMs und verbessern Sie das FAQ-Erlebnis mithilfe der URL-Aufnahme | Amazon Web Services PlatoBlockchain Data Intelligence. Vertikale Suche. Ai.

In der vorherigen Interaktion war die Antwort auf die Preisanpassungsrichtlinie für unseren Benutzer nicht hilfreich. Diese Antwort ist kurz, da es sich bei der FAQ, auf die verwiesen wird, um einen Link zu einer bestimmten Seite über die Preisanpassungsrichtlinie handelt und unser Webcrawl nur für diese einzelne Seite durchgeführt wurde. Um bessere Antworten zu erhalten, müssen auch diese Links gecrawlt werden. Im nächsten Abschnitt erfahren Sie, wie Sie Antworten auf Fragen erhalten, die zwei oder mehr Ebenen der Seitentiefe erfordern.

N-Level-Crawling

Wenn wir eine Webseite nach FAQ-Wissen durchsuchen, können die gewünschten Informationen in verlinkten Seiten enthalten sein. In unserem Zappos-Beispiel stellen wir beispielsweise die Frage „Haben Sie eine Preisanpassungsrichtlinie?“ und die Antwort lautet: „Ja, bitte besuchen Sie uns.“ um mehr zu lernen." Wenn jemand fragt: „Was ist Ihre Preisanpassungspolitik?“ dann wollen wir mit der Police eine vollständige Antwort geben. Um dies zu erreichen, müssen wir Links durchlaufen, um die tatsächlichen Informationen für unseren Endbenutzer zu erhalten. Während des Aufnahmeprozesses können wir unseren Webloader verwenden, um die Ankerlinks zu anderen HTML-Seiten zu finden und diese dann zu durchlaufen. Die folgende Codeänderung an unserem Webcrawler ermöglicht es uns, Links auf den von uns gecrawlten Seiten zu finden. Es enthält außerdem einige zusätzliche Logik, um zirkuläres Crawlen zu vermeiden und eine Filterung nach einem Präfix zu ermöglichen.

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)

Im vorherigen Code führen wir die Möglichkeit ein, N Ebenen tief zu crawlen, und geben ein Präfix an, das es uns ermöglicht, das Crawlen nur auf Dinge zu beschränken, die mit einem bestimmten URL-Muster beginnen. In unserem Zappos-Beispiel haben alle Kundendienstseiten ihren Ursprung zappos.com/c, also fügen wir das als Präfix ein, um unsere Crawls auf eine kleinere und relevantere Teilmenge zu beschränken. Der Code zeigt, wie wir bis zu zwei Ebenen tief aufnehmen können. Die Lambda-Logik unseres Bots bleibt dieselbe, da sich nichts geändert hat, außer dass der Crawler mehr Dokumente aufnimmt.

Wir haben nun alle Dokumente indexiert und können eine detailliertere Frage stellen. Im folgenden Screenshot liefert unser Bot die richtige Antwort auf die Frage „Haben Sie eine Preisanpassungsrichtlinie?“

Erweitern Sie Amazon Lex mit LLMs und verbessern Sie das FAQ-Erlebnis mithilfe der URL-Aufnahme | Amazon Web Services PlatoBlockchain Data Intelligence. Vertikale Suche. Ai.

Wir haben jetzt eine vollständige Antwort auf unsere Frage zur Preisanpassung. Anstatt einfach nur zu sagen: „Ja, sehen Sie sich unsere Richtlinien an“, werden uns die Details aus dem Crawl der zweiten Ebene angezeigt.

Aufräumen

Um zukünftige Kosten zu vermeiden, löschen Sie alle Ressourcen, die im Rahmen dieser Übung bereitgestellt wurden. Wir haben ein Skript zum ordnungsgemäßen Herunterfahren des Sagemaker-Endpunkts bereitgestellt. Einzelheiten zur Nutzung finden Sie in der README-Datei. Darüber hinaus können Sie alle anderen Ressourcen entfernen, die Sie ausführen können cdk destroy im selben Verzeichnis wie die anderen CDK-Befehle, um die Bereitstellung aller Ressourcen in Ihrem Stack aufzuheben.

Zusammenfassung

Durch die Möglichkeit, eine Reihe von häufig gestellten Fragen (FAQs) in einen Chatbot einzubinden, können Ihre Kunden die Antworten auf ihre Fragen mit unkomplizierten Abfragen in natürlicher Sprache finden. Durch die Kombination der in Amazon Lex integrierten Unterstützung für die Fallback-Verarbeitung mit einer RAG-Lösung wie einem LlamaIndex können wir unseren Kunden einen schnellen Weg bieten, zufriedenstellende, kuratierte und genehmigte Antworten auf häufig gestellte Fragen zu erhalten. Durch die Anwendung von N-Level-Crawling in unserer Lösung können wir Antworten ermöglichen, die sich möglicherweise über mehrere FAQ-Links erstrecken und tiefergehende Antworten auf die Fragen unserer Kunden liefern. Wenn Sie diese Schritte befolgen, können Sie leistungsstarke LLM-basierte Q&A-Funktionen und eine effiziente URL-Aufnahme nahtlos in Ihren Amazon Lex-Chatbot integrieren. Dies führt zu genaueren, umfassenderen und kontextbezogeneren Interaktionen mit Benutzern.


Über die Autoren

Erweitern Sie Amazon Lex mit LLMs und verbessern Sie das FAQ-Erlebnis mithilfe der URL-Aufnahme | Amazon Web Services PlatoBlockchain Data Intelligence. Vertikale Suche. Ai.Max Henkel-Wallace ist Softwareentwicklungsingenieur bei AWS Lex. Es macht ihm Spaß, Technologie zu nutzen, um den Kundenerfolg zu maximieren. Außerhalb der Arbeit kocht er leidenschaftlich gerne, verbringt Zeit mit Freunden und reist mit dem Rucksack.

Erweitern Sie Amazon Lex mit LLMs und verbessern Sie das FAQ-Erlebnis mithilfe der URL-Aufnahme | Amazon Web Services PlatoBlockchain Data Intelligence. Vertikale Suche. Ai.Lied Feng ist Senior Applied Scientist bei AWS AI Labs und auf die Verarbeitung natürlicher Sprache und künstliche Intelligenz spezialisiert. Ihre Forschung erforscht verschiedene Aspekte dieser Bereiche, darunter dokumentenbasierte Dialogmodellierung, Argumentation für aufgabenorientierte Dialoge und interaktive Textgenerierung unter Verwendung multimodaler Daten.

Erweitern Sie Amazon Lex mit LLMs und verbessern Sie das FAQ-Erlebnis mithilfe der URL-Aufnahme | Amazon Web Services PlatoBlockchain Data Intelligence. Vertikale Suche. Ai.John Baker ist Principal SDE bei AWS, wo er an der Verarbeitung natürlicher Sprache, großen Sprachmodellen und anderen ML/KI-bezogenen Projekten arbeitet. Er ist seit über 9 Jahren bei Amazon und hat bei AWS, Alexa und Amazon.com gearbeitet. In seiner Freizeit fährt John gerne Ski und betreibt andere Outdoor-Aktivitäten im pazifischen Nordwesten.

Zeitstempel:

Mehr von AWS Maschinelles Lernen