Nâng cao Amazon Lex bằng LLM và cải thiện trải nghiệm Câu hỏi thường gặp bằng cách nhập URL | Dịch vụ web của Amazon

Nâng cao Amazon Lex bằng LLM và cải thiện trải nghiệm Câu hỏi thường gặp bằng cách nhập URL | Dịch vụ web của Amazon

Trong thế giới kỹ thuật số ngày nay, hầu hết người tiêu dùng muốn tự mình tìm câu trả lời cho các câu hỏi về dịch vụ khách hàng hơn là dành thời gian để liên hệ với các doanh nghiệp và/hoặc nhà cung cấp dịch vụ. Bài đăng trên blog này khám phá một giải pháp sáng tạo để xây dựng một chatbot hỏi đáp trong Amazon sử dụng Câu hỏi thường gặp hiện có từ trang web của bạn. Công cụ hỗ trợ AI này có thể cung cấp phản hồi nhanh chóng, chính xác cho các yêu cầu trong thế giới thực, cho phép khách hàng giải quyết các vấn đề phổ biến một cách nhanh chóng và dễ dàng.

Nhập một URL

Nhiều doanh nghiệp đã công bố bộ câu trả lời cho các câu hỏi thường gặp dành cho khách hàng trên trang web của họ. Trong trường hợp này, chúng tôi muốn cung cấp cho khách hàng một chatbot có thể trả lời các câu hỏi của họ từ các Câu hỏi thường gặp đã xuất bản của chúng tôi. Trong bài đăng trên blog có tiêu đề Nâng cao Amazon Lex với các tính năng Câu hỏi thường gặp về đàm thoại bằng LLM, chúng tôi đã trình bày cách bạn có thể sử dụng kết hợp Amazon Lex và LlamaIndex để xây dựng một chatbot được cung cấp bởi các nguồn kiến ​​thức hiện có của bạn, chẳng hạn như tài liệu PDF hoặc Word. Để hỗ trợ Câu hỏi thường gặp đơn giản, dựa trên trang web Câu hỏi thường gặp, chúng tôi cần tạo quy trình nhập có thể thu thập dữ liệu trang web và tạo phần nhúng mà LlamaIndex có thể sử dụng để trả lời câu hỏi của khách hàng. Trong trường hợp này, chúng tôi sẽ xây dựng trên bot được tạo trong bài blog trước, truy vấn các phần nhúng đó bằng cách nói của người dùng và trả về câu trả lời từ Câu hỏi thường gặp của trang web.

Sơ đồ sau đây cho thấy quy trình nhập và bot Amazon Lex phối hợp với nhau như thế nào cho giải pháp của chúng tôi.

Nâng cao Amazon Lex bằng LLM và cải thiện trải nghiệm Câu hỏi thường gặp bằng cách nhập URL | Dịch vụ web của Amazon PlatoThông minh dữ liệu Blockchain. Tìm kiếm dọc. Ái.

Trong quy trình giải pháp, trang web có Câu hỏi thường gặp được nhập thông qua AWS Lambda. Hàm Lambda này thu thập dữ liệu trang web và lưu trữ văn bản kết quả trong một Dịch vụ lưu trữ đơn giản của Amazon (Amazon S3) xô. Sau đó, bộ chứa S3 sẽ kích hoạt một hàm Lambda sử dụng LlamaIndex để tạo các phần nhúng được lưu trữ trong Amazon S3. Khi có câu hỏi từ người dùng cuối, chẳng hạn như “Chính sách hoàn trả của bạn là gì?”, bot Amazon Lex sử dụng chức năng Lambda của nó để truy vấn các phần nhúng bằng cách sử dụng phương pháp dựa trên RAG với LlamaIndex. Để biết thêm thông tin về phương pháp này và các điều kiện tiên quyết, hãy tham khảo bài đăng trên blog, Nâng cao Amazon Lex với các tính năng Câu hỏi thường gặp về đàm thoại bằng LLM.

Sau khi các điều kiện tiên quyết từ blog đã nói ở trên hoàn tất, bước đầu tiên là nhập Câu hỏi thường gặp vào kho lưu trữ tài liệu có thể được LlamaIndex lập chỉ mục và lập chỉ mục. Đoạn mã sau chỉ ra cách thực hiện điều này:

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)

Trong ví dụ trước, chúng tôi lấy một URL trang web Câu hỏi thường gặp được xác định trước từ Zappos và nhập nó bằng cách sử dụng EZWebLoader lớp học. Với lớp này, chúng tôi đã điều hướng đến URL và tải tất cả các câu hỏi trong trang vào một chỉ mục. Bây giờ chúng ta có thể đặt câu hỏi như “Zappos có thẻ quà tặng không?” và nhận câu trả lời trực tiếp từ Câu hỏi thường gặp của chúng tôi trên trang web. Ảnh chụp màn hình sau đây cho thấy bảng điều khiển thử nghiệm bot Amazon Lex trả lời câu hỏi đó từ Câu hỏi thường gặp.

Nâng cao Amazon Lex bằng LLM và cải thiện trải nghiệm Câu hỏi thường gặp bằng cách nhập URL | Dịch vụ web của Amazon PlatoThông minh dữ liệu Blockchain. Tìm kiếm dọc. Ái.

Chúng tôi có thể đạt được điều này vì chúng tôi đã thu thập thông tin URL trong bước đầu tiên và tạo các phần nhúng mà LlamaIndex có thể sử dụng để tìm kiếm câu trả lời cho câu hỏi của chúng tôi. Hàm Lambda của bot của chúng tôi cho thấy cách chạy tìm kiếm này bất cứ khi nào ý định dự phòng được trả về:

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

Giải pháp này hoạt động tốt khi một trang web có tất cả các câu trả lời. Tuy nhiên, hầu hết các trang FAQ không được xây dựng trên một trang duy nhất. Chẳng hạn, trong ví dụ về Zappos của chúng tôi, nếu chúng tôi đặt câu hỏi “Bạn có chính sách khớp giá không?”, thì chúng tôi sẽ nhận được câu trả lời không thỏa đáng, như thể hiện trong ảnh chụp màn hình sau.

Nâng cao Amazon Lex bằng LLM và cải thiện trải nghiệm Câu hỏi thường gặp bằng cách nhập URL | Dịch vụ web của Amazon PlatoThông minh dữ liệu Blockchain. Tìm kiếm dọc. Ái.

Trong lần tương tác trước, câu trả lời về chính sách khớp giá không hữu ích cho người dùng của chúng tôi. Câu trả lời này ngắn vì Câu hỏi thường gặp được tham chiếu là một liên kết đến một trang cụ thể về chính sách khớp giá và việc thu thập dữ liệu web của chúng tôi chỉ dành cho một trang. Đạt được câu trả lời tốt hơn cũng có nghĩa là thu thập dữ liệu các liên kết này. Phần tiếp theo cho biết cách nhận câu trả lời cho các câu hỏi yêu cầu độ sâu của trang từ hai cấp độ trở lên.

Thu thập thông tin cấp độ N

Khi chúng tôi thu thập dữ liệu một trang web để biết kiến ​​thức về Câu hỏi thường gặp, thông tin chúng tôi muốn có thể được chứa trong các trang được liên kết. Ví dụ: trong ví dụ về Zappos của chúng tôi, chúng tôi đặt câu hỏi “Bạn có chính sách khớp giá không?” và câu trả lời là “Có, vui lòng truy cập để tìm hiểu thêm.” Nếu ai đó hỏi “Chính sách khớp giá của bạn là gì?” sau đó chúng tôi muốn đưa ra một câu trả lời hoàn chỉnh với chính sách. Đạt được điều này có nghĩa là chúng tôi có nhu cầu duyệt qua các liên kết để lấy thông tin thực tế cho người dùng cuối của chúng tôi. Trong quá trình nhập, chúng tôi có thể sử dụng trình tải web của mình để tìm các liên kết neo đến các trang HTML khác rồi duyệt qua chúng. Thay đổi mã sau đây đối với trình thu thập dữ liệu web của chúng tôi cho phép chúng tôi tìm các liên kết trong các trang mà chúng tôi thu thập dữ liệu. Nó cũng bao gồm một số logic bổ sung để tránh thu thập thông tin vòng tròn và cho phép lọc theo tiền tố.

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)

Trong đoạn mã trước, chúng tôi giới thiệu khả năng thu thập dữ liệu sâu N cấp độ và chúng tôi đưa ra một tiền tố cho phép chúng tôi hạn chế việc thu thập dữ liệu chỉ những thứ bắt đầu bằng một mẫu URL nhất định. Trong ví dụ Zappos của chúng tôi, tất cả các trang dịch vụ khách hàng đều bắt nguồn từ zappos.com/c, vì vậy chúng tôi bao gồm tiền tố đó làm tiền tố để giới hạn số lần thu thập dữ liệu của chúng tôi ở một tập hợp con nhỏ hơn và có liên quan hơn. Đoạn mã này cho thấy cách chúng ta có thể nhập sâu tới hai cấp độ. Logic Lambda của bot của chúng tôi vẫn giữ nguyên vì không có gì thay đổi ngoại trừ trình thu thập thông tin nhập nhiều tài liệu hơn.

Bây giờ chúng tôi có tất cả các tài liệu được lập chỉ mục và chúng tôi có thể đặt câu hỏi chi tiết hơn. Trong ảnh chụp màn hình sau đây, bot của chúng tôi cung cấp câu trả lời chính xác cho câu hỏi “Bạn có chính sách khớp giá không?”

Nâng cao Amazon Lex bằng LLM và cải thiện trải nghiệm Câu hỏi thường gặp bằng cách nhập URL | Dịch vụ web của Amazon PlatoThông minh dữ liệu Blockchain. Tìm kiếm dọc. Ái.

Bây giờ chúng ta đã có câu trả lời đầy đủ cho câu hỏi về khớp giá. Thay vì chỉ được thông báo “Có, hãy xem chính sách của chúng tôi”, nó cung cấp cho chúng tôi thông tin chi tiết từ quá trình thu thập dữ liệu cấp hai.

Làm sạch

Để tránh phát sinh chi phí trong tương lai, hãy tiến hành xóa tất cả các tài nguyên đã được triển khai như một phần của bài tập này. Chúng tôi đã cung cấp một tập lệnh để tắt điểm cuối Sagemaker một cách duyên dáng. Chi tiết sử dụng có trong README. Ngoài ra, để xóa tất cả các tài nguyên khác mà bạn có thể chạy cdk destroy trong cùng thư mục với các lệnh cdk khác để hủy cấp phép tất cả các tài nguyên trong ngăn xếp của bạn.

Kết luận

Khả năng nhập một bộ Câu hỏi thường gặp vào chatbot cho phép khách hàng của bạn tìm thấy câu trả lời cho câu hỏi của họ bằng các truy vấn ngôn ngữ tự nhiên, đơn giản. Bằng cách kết hợp hỗ trợ tích hợp trong Amazon Lex để xử lý dự phòng với giải pháp RAG chẳng hạn như LlamaIndex, chúng tôi có thể cung cấp một cách nhanh chóng để khách hàng của mình nhận được câu trả lời thỏa mãn, được tuyển chọn và phê duyệt cho các Câu hỏi thường gặp. Bằng cách áp dụng thu thập thông tin cấp độ N vào giải pháp của mình, chúng tôi có thể cho phép các câu trả lời có thể mở rộng trên nhiều liên kết Câu hỏi thường gặp và cung cấp câu trả lời sâu hơn cho các truy vấn của khách hàng. Bằng cách làm theo các bước này, bạn có thể kết hợp liền mạch các chức năng Q và A dựa trên LLM mạnh mẽ cũng như khả năng nhập URL hiệu quả vào chatbot Amazon Lex của mình. Điều này dẫn đến các tương tác với người dùng chính xác, toàn diện và theo ngữ cảnh hơn.


Giới thiệu về tác giả

Nâng cao Amazon Lex bằng LLM và cải thiện trải nghiệm Câu hỏi thường gặp bằng cách nhập URL | Dịch vụ web của Amazon PlatoThông minh dữ liệu Blockchain. Tìm kiếm dọc. Ái.Max Henkel-Wallace là Kỹ sư phát triển phần mềm tại AWS Lex. Anh ấy thích làm việc tận dụng công nghệ để tối đa hóa thành công của khách hàng. Ngoài công việc, anh ấy đam mê nấu ăn, dành thời gian cho bạn bè và phượt.

Nâng cao Amazon Lex bằng LLM và cải thiện trải nghiệm Câu hỏi thường gặp bằng cách nhập URL | Dịch vụ web của Amazon PlatoThông minh dữ liệu Blockchain. Tìm kiếm dọc. Ái.song phong là Nhà khoa học ứng dụng cấp cao tại AWS AI Labs, chuyên về Xử lý ngôn ngữ tự nhiên và Trí tuệ nhân tạo. Nghiên cứu của cô khám phá các khía cạnh khác nhau của các lĩnh vực này bao gồm mô hình đối thoại dựa trên tài liệu, lập luận cho các cuộc đối thoại theo định hướng nhiệm vụ và tạo văn bản tương tác bằng cách sử dụng dữ liệu đa phương thức.

Nâng cao Amazon Lex bằng LLM và cải thiện trải nghiệm Câu hỏi thường gặp bằng cách nhập URL | Dịch vụ web của Amazon PlatoThông minh dữ liệu Blockchain. Tìm kiếm dọc. Ái.John Baker là SDE chính tại AWS, nơi anh ấy làm việc về Xử lý ngôn ngữ tự nhiên, Mô hình ngôn ngữ lớn và các dự án liên quan đến ML/AI khác. Anh ấy đã gắn bó với Amazon hơn 9 năm và đã làm việc trên AWS, Alexa và Amazon.com. Khi rảnh rỗi, John thích trượt tuyết và các hoạt động ngoài trời khác trên khắp vùng Tây Bắc Thái Bình Dương.

Dấu thời gian:

Thêm từ Học máy AWS