Verbeter Amazon Lex met LLM's en verbeter de FAQ-ervaring met URL-opname | Amazon-webservices

Verbeter Amazon Lex met LLM's en verbeter de FAQ-ervaring met URL-opname | Amazon-webservices

In de digitale wereld van vandaag vinden de meeste consumenten liever zelf antwoorden op hun klantenservicevragen dan de tijd te nemen om contact op te nemen met bedrijven en/of dienstverleners. Deze blogpost onderzoekt een innovatieve oplossing om een ​​vraag-en-antwoord-chatbot in te bouwen Amazon-Lex die gebruikmaakt van bestaande veelgestelde vragen van uw website. Deze AI-aangedreven tool kan snelle, nauwkeurige antwoorden geven op vragen uit de praktijk, waardoor de klant veelvoorkomende problemen zelfstandig snel en eenvoudig kan oplossen.

Eén URL-opname

Veel bedrijven hebben een gepubliceerde reeks antwoorden op veelgestelde vragen voor hun klanten beschikbaar op hun website. In dit geval willen we klanten een chatbot aanbieden die hun vragen uit onze gepubliceerde FAQ’s kan beantwoorden. In de blogpost met de titel Verbeter Amazon Lex met conversatiefuncties voor veelgestelde vragen met behulp van LLM'shebben we gedemonstreerd hoe je een combinatie van Amazon Lex en LlamaIndex kunt gebruiken om een ​​chatbot te bouwen die wordt aangedreven door je bestaande kennisbronnen, zoals PDF- of Word-documenten. Om een ​​eenvoudige FAQ te ondersteunen, gebaseerd op een website met veelgestelde vragen, moeten we een opnameproces creëren dat de website kan crawlen en insluitingen kan creëren die door LlamaIndex kunnen worden gebruikt om vragen van klanten te beantwoorden. In dit geval bouwen we voort op de bot die is gemaakt in de vorige blogbericht, dat deze insluitingen opvraagt ​​met de uiting van een gebruiker en het antwoord retourneert van de veelgestelde vragen over de website.

Het volgende diagram laat zien hoe het innameproces en de Amazon Lex-bot samenwerken voor onze oplossing.

Verbeter Amazon Lex met LLM's en verbeter de FAQ-ervaring met behulp van URL-opname | Amazon Web Services PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

In de oplossingsworkflow wordt de website met veelgestelde vragen opgenomen via AWS Lambda. Deze Lambda-functie doorzoekt de website en slaat de resulterende tekst op in een Amazon eenvoudige opslagservice (Amazon S3) bak. De S3-bucket activeert vervolgens een Lambda-functie die LlamaIndex gebruikt om insluitingen te maken die zijn opgeslagen in Amazon S3. Wanneer een vraag van een eindgebruiker binnenkomt, zoals “Wat is uw retourbeleid?”, gebruikt de Amazon Lex-bot zijn Lambda-functie om de inbedding te bevragen met behulp van een RAG-gebaseerde aanpak met LlamaIndex. Voor meer informatie over deze aanpak en de vereisten raadpleegt u de blogpost: Verbeter Amazon Lex met conversatiefuncties voor veelgestelde vragen met behulp van LLM's.

Nadat aan de vereisten van de bovengenoemde blog is voldaan, is de eerste stap het opnemen van de veelgestelde vragen in een documentopslagplaats die kan worden gevectoriseerd en geïndexeerd door LlamaIndex. De volgende code laat zien hoe u dit kunt bereiken:

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)

In het voorgaande voorbeeld nemen we een vooraf gedefinieerde FAQ-website-URL van Zappos en nemen deze op met behulp van de EZWebLoader klas. Met deze klasse zijn we naar de URL genavigeerd en alle vragen op de pagina in een index geladen. We kunnen nu een vraag stellen als “Heeft Zappos cadeaubonnen?” en krijg de antwoorden rechtstreeks van onze veelgestelde vragen op de website. De volgende schermafbeelding toont de Amazon Lex-bottestconsole die deze vraag uit de veelgestelde vragen beantwoordt.

Verbeter Amazon Lex met LLM's en verbeter de FAQ-ervaring met behulp van URL-opname | Amazon Web Services PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

We konden dit bereiken omdat we in de eerste stap de URL hadden gecrawld en embedddings hadden gemaakt die LlamaIndex kon gebruiken om naar het antwoord op onze vraag te zoeken. De Lambda-functie van onze bot laat zien hoe deze zoekopdracht wordt uitgevoerd wanneer de fallback-intentie wordt geretourneerd:

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

Deze oplossing werkt goed als één enkele webpagina alle antwoorden bevat. De meeste FAQ-sites zijn echter niet op één pagina gebouwd. Als we in ons Zappos-voorbeeld bijvoorbeeld de vraag stellen: “Heeft u een prijsmatchingsbeleid?”, krijgen we een minder dan bevredigend antwoord, zoals weergegeven in de volgende schermafbeelding.

Verbeter Amazon Lex met LLM's en verbeter de FAQ-ervaring met behulp van URL-opname | Amazon Web Services PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

In de voorgaande interactie is het antwoord op het beleid voor prijsmatching niet nuttig voor onze gebruiker. Dit antwoord is kort omdat de veelgestelde vraag waarnaar wordt verwezen een link is naar een specifieke pagina over het prijsmatchingbeleid en onze webcrawl alleen voor de enkele pagina was. Om betere antwoorden te krijgen, moeten deze links ook worden gecrawld. In het volgende gedeelte wordt uitgelegd hoe u antwoorden kunt krijgen op vragen waarvoor twee of meer niveaus van paginadiepte nodig zijn.

Crawlen op N-niveau

Wanneer we een webpagina crawlen voor kennis van veelgestelde vragen, kan de gewenste informatie op gelinkte pagina's staan. In ons Zappos-voorbeeld stellen we bijvoorbeeld de vraag “Heeft u een prijsmatchingbeleid?” en het antwoord is: “Ja, bezoek alstublieft meer leren." Als iemand vraagt: “Wat is uw beleid voor prijsmatching?” dan willen wij met het beleid een compleet antwoord geven. Om dit te bereiken, moeten we links doorlopen om de feitelijke informatie voor onze eindgebruiker te verkrijgen. Tijdens het opnameproces kunnen we onze weblader gebruiken om de ankerlinks naar andere HTML-pagina's te vinden en deze vervolgens te doorkruisen. Door de volgende codewijziging in onze webcrawler kunnen we links vinden op de pagina's die we crawlen. Het bevat ook wat extra logica om circulair crawlen te voorkomen en een filter op een voorvoegsel mogelijk te maken.

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)

In de voorgaande code introduceren we de mogelijkheid om N niveaus diep te crawlen, en we geven een voorvoegsel waarmee we het crawlen kunnen beperken tot alleen dingen die beginnen met een bepaald URL-patroon. In ons Zappos-voorbeeld zijn de klantenservicepagina's allemaal afkomstig van zappos.com/c, dus we nemen dat op als voorvoegsel om onze crawls te beperken tot een kleinere en relevantere subset. De code laat zien hoe we tot twee niveaus diep kunnen inslikken. De Lambda-logica van onze bot blijft hetzelfde omdat er niets is veranderd, behalve dat de crawler meer documenten opneemt.

We hebben nu alle documenten geïndexeerd en kunnen een meer gedetailleerde vraag stellen. In de volgende schermafbeelding geeft onze bot het juiste antwoord op de vraag “Heeft u een prijsmatchingbeleid?”

Verbeter Amazon Lex met LLM's en verbeter de FAQ-ervaring met behulp van URL-opname | Amazon Web Services PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

We hebben nu een volledig antwoord op onze vraag over prijsmatching. In plaats van eenvoudigweg te zeggen: "Ja, zie ons beleid", geeft het ons de details van de crawl op het tweede niveau.

Opruimen

Om toekomstige uitgaven te voorkomen, gaat u verder met het verwijderen van alle resources die zijn ingezet als onderdeel van deze oefening. We hebben een script geleverd om het Sagemaker-eindpunt op een correcte manier af te sluiten. Gebruiksdetails staan ​​in de README. Bovendien kunt u alle andere bronnen verwijderen die u kunt gebruiken cdk destroy in dezelfde map als de andere cdk-opdrachten om alle bronnen in uw stapel ongedaan te maken.

Conclusie

De mogelijkheid om een ​​reeks veelgestelde vragen in een chatbot op te nemen, stelt uw klanten in staat de antwoorden op hun vragen te vinden met eenvoudige, natuurlijke taalvragen. Door de ingebouwde ondersteuning in Amazon Lex voor fallback-afhandeling te combineren met een RAG-oplossing zoals een LlamaIndex, kunnen we onze klanten een snel pad bieden om bevredigende, samengestelde en goedgekeurde antwoorden op veelgestelde vragen te krijgen. Door N-level crawling in onze oplossing toe te passen, kunnen we antwoorden mogelijk maken die mogelijk meerdere FAQ-links omvatten en diepere antwoorden bieden op de vragen van onze klanten. Door deze stappen te volgen, kunt u naadloos krachtige op LLM gebaseerde vraag- en antwoordmogelijkheden en efficiënte URL-opname integreren in uw Amazon Lex-chatbot. Dit resulteert in nauwkeurigere, uitgebreidere en contextueel bewustere interacties met gebruikers.


Over de auteurs

Verbeter Amazon Lex met LLM's en verbeter de FAQ-ervaring met behulp van URL-opname | Amazon Web Services PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.Max Henkel Wallace is Software Development Engineer bij AWS Lex. Hij geniet van het gebruik van technologie om het succes van de klant te maximaliseren. Buiten zijn werk is hij gepassioneerd door koken, tijd doorbrengen met vrienden en backpacken.

Verbeter Amazon Lex met LLM's en verbeter de FAQ-ervaring met behulp van URL-opname | Amazon Web Services PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.Lied Feng is een Senior Applied Scientist bij AWS AI Labs, gespecialiseerd in natuurlijke taalverwerking en kunstmatige intelligentie. Haar onderzoek verkent verschillende aspecten van deze gebieden, waaronder modellering van op documenten gebaseerde dialogen, redenering voor taakgerichte dialogen en interactieve tekstgeneratie met behulp van multimodale gegevens.

Verbeter Amazon Lex met LLM's en verbeter de FAQ-ervaring met behulp van URL-opname | Amazon Web Services PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.John Baker is Principal SDE bij AWS, waar hij werkt aan Natural Language Processing, Large Language Models en andere ML/AI-gerelateerde projecten. Hij werkt al meer dan 9 jaar bij Amazon en heeft gewerkt bij AWS, Alexa en Amazon.com. In zijn vrije tijd houdt John van skiën en andere buitenactiviteiten in de Pacific Northwest.

Tijdstempel:

Meer van AWS-machine learning