שפר את Amazon Lex עם LLMs ושפר את חוויית השאלות הנפוצות באמצעות הטמעת כתובת URL | שירותי האינטרנט של אמזון

שפר את Amazon Lex עם LLMs ושפר את חוויית השאלות הנפוצות באמצעות הטמעת כתובת URL | שירותי האינטרנט של אמזון

בעולם הדיגיטלי של היום, רוב הצרכנים מעדיפים למצוא תשובות לשאלות שירות הלקוחות שלהם בעצמם במקום להקדיש זמן לפנות לעסקים ו/או לספקי שירותים. פוסט זה בבלוג חוקר פתרון חדשני לבניית צ'אטבוט של שאלה ותשובות אמזון לקס שמשתמש בשאלות נפוצות קיימות מהאתר שלך. כלי זה מופעל בינה מלאכותית יכול לספק תשובות מהירות ומדויקות לפניות מהעולם האמיתי, ולאפשר ללקוח לפתור במהירות ובקלות בעיות נפוצות באופן עצמאי.

הטמעת כתובת אתר בודדת

לארגונים רבים יש סט תשובות לשאלות נפוצות עבור הלקוחות שלהם זמין באתר האינטרנט שלהם. במקרה זה, אנו רוצים להציע ללקוחות צ'אטבוט שיוכל לענות על שאלותיהם מהשאלות הנפוצות שפורסמו. בפוסט בבלוג שכותרתו שפר את Amazon Lex עם תכונות שאלות נפוצות לשיחה באמצעות LLMs, הדגמנו כיצד אתה יכול להשתמש בשילוב של Amazon Lex ו-LlamaIndex כדי לבנות צ'טבוט המופעל על ידי מקורות הידע הקיימים שלך, כגון מסמכי PDF או Word. כדי לתמוך בשאלות נפוצות פשוטות, המבוססות על אתר של שאלות נפוצות, עלינו ליצור תהליך הטמעה שיכול לסרוק את האתר וליצור הטמעות שיכולות לשמש את LlamaIndex כדי לענות על שאלות לקוחות. במקרה זה, נבנה על הבוט שנוצר ב- פוסט בלוג קודם, אשר מבצעת שאילתות באותן הטמעות עם אמירה של משתמש ומחזירה את התשובה מהשאלות הנפוצות באתר.

התרשים הבא מראה כיצד תהליך הבליעה והבוט של Amazon Lex פועלים יחד לפתרון שלנו.

שפר את Amazon Lex עם LLMs ושפר את חוויית השאלות הנפוצות באמצעות הטמעת כתובת URL | Amazon Web Services PlatoBlockchain Data Intelligence. חיפוש אנכי. איי.

בזרימת העבודה של הפתרון, האתר עם השאלות הנפוצות נקלט באמצעות AWS למבדה. פונקציית Lambda זו סורקת את האתר ומאחסנת את הטקסט המתקבל ב- שירות אחסון פשוט של אמזון דלי (Amazon S3). לאחר מכן, דלי S3 מפעיל פונקציית Lambda שמשתמשת ב-LlamaIndex ליצירת הטבעות המאוחסנות באמזון S3. כאשר מגיעה שאלה ממשתמש קצה, כגון "מהי מדיניות ההחזרה שלך?", הבוט של Amazon Lex משתמש בפונקציית Lambda שלו כדי לבצע שאילתות על ההטמעות באמצעות גישה מבוססת RAG עם LlamaIndex. למידע נוסף על גישה זו והדרישות המוקדמות, עיין בפוסט בבלוג, שפר את Amazon Lex עם תכונות שאלות נפוצות לשיחה באמצעות LLMs.

לאחר השלמת הדרישות המוקדמות מהבלוג האמור לעיל, הצעד הראשון הוא להטמיע את השאלות הנפוצות לתוך מאגר מסמכים שניתן לווקטור ולהוסיף לאינדקס על ידי LlamaIndex. הקוד הבא מראה כיצד לבצע זאת:

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)

בדוגמה הקודמת, אנו לוקחים כתובת אתר של שאלות נפוצות מוגדרות מראש מ-Zappos ובולעים אותה באמצעות EZWebLoader מעמד. עם השיעור הזה, ניווטנו לכתובת ה-URL וטענו את כל השאלות שנמצאות בדף לאינדקס. כעת אנו יכולים לשאול שאלה כמו "האם יש ל-Zappos כרטיסי מתנה?" וקבל את התשובות ישירות מהשאלות הנפוצות שלנו באתר. צילום המסך הבא מציג את קונסולת הבדיקה של אמזון לקס עונה על השאלה הזו מהשאלות הנפוצות.

שפר את Amazon Lex עם LLMs ושפר את חוויית השאלות הנפוצות באמצעות הטמעת כתובת URL | Amazon Web Services PlatoBlockchain Data Intelligence. חיפוש אנכי. איי.

הצלחנו להשיג זאת מכיוון שסרקנו את כתובת האתר בשלב הראשון ויצרנו הטמעות שבהן LlamaIndex יכול להשתמש כדי לחפש את התשובה לשאלה שלנו. פונקציית Lambda של הבוט שלנו מראה כיצד החיפוש הזה מתנהל בכל פעם שמוחזרת כוונת החזרה:

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

פתרון זה עובד היטב כאשר דף אינטרנט בודד מכיל את כל התשובות. עם זאת, רוב אתרי השאלות הנפוצות אינם בנויים על דף אחד. לדוגמה, בדוגמה שלנו ב-Zappos, אם נשאל את השאלה "האם יש לך מדיניות התאמת מחיר?", אז נקבל תשובה פחות מספקת, כפי שמוצג בצילום המסך הבא.

שפר את Amazon Lex עם LLMs ושפר את חוויית השאלות הנפוצות באמצעות הטמעת כתובת URL | Amazon Web Services PlatoBlockchain Data Intelligence. חיפוש אנכי. איי.

באינטראקציה הקודמת, התשובה של מדיניות התאמת המחירים אינה מועילה למשתמש שלנו. תשובה זו קצרה מכיוון שהשאלות הנפוצות המוזכרות הן קישור לדף ספציפי על מדיניות התאמת המחירים וסריקת האינטרנט שלנו הייתה רק עבור הדף היחיד. השגת תשובות טובות יותר פירושה סריקת קישורים אלה גם כן. הסעיף הבא מראה כיצד לקבל תשובות לשאלות הדורשות שתי רמות או יותר של עומק עמוד.

זחילה ברמת N

כאשר אנו סורקים דף אינטרנט לצורך ידע בשאלות נפוצות, המידע שאנו רוצים יכול להכיל בדפים מקושרים. לדוגמה, בדוגמה שלנו ב-Zappos, אנו שואלים את השאלה "האם יש לך מדיניות התאמת מחירים?" והתשובה היא "כן בבקשה בקר ללמוד 'יותר." אם מישהו שואל "מהי מדיניות התאמת המחירים שלך?" אז אנחנו רוצים לתת תשובה מלאה עם הפוליסה. השגת זאת פירושה שיש לנו את הצורך לעבור בקישורים כדי לקבל את המידע האמיתי עבור משתמש הקצה שלנו. במהלך תהליך ההטמעה, אנו יכולים להשתמש בטוען האינטרנט שלנו כדי למצוא את קישורי העוגן לדפי HTML אחרים ולאחר מכן לעבור אותם. שינוי הקוד הבא לסורק האינטרנט שלנו מאפשר לנו למצוא קישורים בדפים שאנו סורקים. הוא כולל גם היגיון נוסף כדי למנוע זחילה מעגלית ולאפשר סינון לפי קידומת.

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)

בקוד הקודם, אנו מציגים את היכולת לסרוק N רמות לעומק, ונותנים קידומת המאפשרת לנו להגביל את הסריקה רק לדברים שמתחילים בתבנית כתובת URL מסוימת. בדוגמה שלנו ב-Zappos, דפי שירות הלקוחות מקורם כולם zappos.com/c, אז אנחנו כוללים את זה בתור קידומת כדי להגביל את הסריקה שלנו לתת-קבוצה קטנה ורלוונטית יותר. הקוד מראה כיצד אנו יכולים לבלוע עד שתי רמות עמוקות. ההיגיון של ה-Lambda של הבוט שלנו נשאר זהה מכיוון ששום דבר לא השתנה מלבד הסורק קולט יותר מסמכים.

כעת יש לנו את כל המסמכים באינדקס ונוכל לשאול שאלה מפורטת יותר. בצילום המסך הבא, הבוט שלנו מספק את התשובה הנכונה לשאלה "האם יש לך מדיניות התאמת מחירים?"

שפר את Amazon Lex עם LLMs ושפר את חוויית השאלות הנפוצות באמצעות הטמעת כתובת URL | Amazon Web Services PlatoBlockchain Data Intelligence. חיפוש אנכי. איי.

כעת יש לנו תשובה מלאה לשאלתנו לגבי התאמת מחירים. במקום פשוט לומר "כן ראה את המדיניות שלנו", זה נותן לנו את הפרטים מהסריקה ברמה השנייה.

לנקות את

כדי להימנע מהוצאות עתידיות, המשך למחיקת כל המשאבים שנפרסו כחלק מתרגיל זה. סיפקנו תסריט לסגור את נקודת הקצה של Sagemaker בחן. פרטי השימוש נמצאים ב-README. בנוסף, כדי להסיר את כל המשאבים האחרים שאתה יכול להפעיל cdk destroy באותה ספרייה כמו פקודות cdk האחרות כדי לבטל את התצורה של כל המשאבים בערימה שלך.

סיכום

היכולת להטמיע קבוצה של שאלות נפוצות בצ'אטבוט מאפשרת ללקוחות שלך למצוא את התשובות לשאלותיהם באמצעות שאילתות שפה טבעיות פשוטות. על ידי שילוב התמיכה המובנית באמזון לקס לטיפול ב-fallback עם פתרון RAG כגון LlamaIndex, נוכל לספק ללקוחותינו נתיב מהיר לקבל תשובות מספקות, מאושרות ומאושרות לשאלות נפוצות. על ידי החלת זחילה ברמת N לתוך הפתרון שלנו, נוכל לאפשר תשובות שיכולות להשתרע על פני מספר קישורי שאלות נפוצות ולספק תשובות עמוקות יותר לשאלות הלקוח שלנו. על ידי ביצוע שלבים אלה, אתה יכול לשלב בצורה חלקה יכולות חזקות מבוססות LLM Q ו-A והטמעת URL יעילה בצ'אטבוט של Amazon Lex שלך. זה מביא לאינטראקציות מדויקות יותר, מקיפות יותר ומודעות להקשר עם משתמשים.


על המחברים

שפר את Amazon Lex עם LLMs ושפר את חוויית השאלות הנפוצות באמצעות הטמעת כתובת URL | Amazon Web Services PlatoBlockchain Data Intelligence. חיפוש אנכי. איי.מקס הנקל-וואלאס הוא מהנדס פיתוח תוכנה ב-AWS Lex. הוא נהנה לעבוד במינוף טכנולוגיה כדי למקסם את הצלחת הלקוח. מחוץ לעבודה הוא נלהב מבישול, בילוי עם חברים ותרמילאות.

שפר את Amazon Lex עם LLMs ושפר את חוויית השאלות הנפוצות באמצעות הטמעת כתובת URL | Amazon Web Services PlatoBlockchain Data Intelligence. חיפוש אנכי. איי.סונג פנג הוא מדען יישומי בכיר במעבדות AWS AI, המתמחה בעיבוד שפה טבעית ובינה מלאכותית. המחקר שלה בוחן היבטים שונים של תחומים אלה, לרבות מודלים של דיאלוגים מבוססי מסמך, הנמקה לדיאלוגים מוכווני משימות ויצירת טקסט אינטראקטיבי באמצעות נתונים רב-מודאליים.

שפר את Amazon Lex עם LLMs ושפר את חוויית השאלות הנפוצות באמצעות הטמעת כתובת URL | Amazon Web Services PlatoBlockchain Data Intelligence. חיפוש אנכי. איי.ג'ון בייקר הוא SDE ראשי ב-AWS שם הוא עובד על עיבוד שפה טבעית, מודלים של שפה גדולה ופרויקטים אחרים הקשורים ל-ML/AI. הוא עובד באמזון כבר 9 שנים ומעלה ועבד ב-AWS, Alexa ו-Amazon.com. בזמנו הפנוי, ג'ון נהנה מסקי ומפעילויות חוצות אחרות ברחבי צפון מערב האוקיינוס ​​השקט.

בול זמן:

עוד מ למידת מכונות AWS