Mejore Amazon Lex con LLM y mejore la experiencia de preguntas frecuentes mediante la ingestión de URL | Servicios web de Amazon

Mejore Amazon Lex con LLM y mejore la experiencia de preguntas frecuentes mediante la ingestión de URL | Servicios web de Amazon

En el mundo digital actual, la mayoría de los consumidores prefieren encontrar respuestas a sus preguntas de servicio al cliente por sí mismos en lugar de tomarse el tiempo para comunicarse con empresas y/o proveedores de servicios. Esta publicación de blog explora una solución innovadora para crear un chatbot de preguntas y respuestas en Amazon lex que utiliza las preguntas frecuentes existentes de su sitio web. Esta herramienta impulsada por IA puede proporcionar respuestas rápidas y precisas a consultas del mundo real, lo que permite al cliente resolver problemas comunes de forma rápida y sencilla de forma independiente.

Ingestión de URL única

Muchas empresas tienen un conjunto de respuestas publicadas para las preguntas frecuentes de sus clientes disponibles en su sitio web. En este caso, queremos ofrecer a los clientes un chatbot que pueda responder sus preguntas de nuestras preguntas frecuentes publicadas. En la publicación del blog titulada Mejore Amazon Lex con funciones de preguntas frecuentes conversacionales mediante LLM, demostramos cómo puede usar una combinación de Amazon Lex y LlamaIndex para crear un chatbot con la tecnología de sus fuentes de conocimiento existentes, como documentos PDF o Word. Para respaldar una pregunta frecuente simple, basada en un sitio web de preguntas frecuentes, necesitamos crear un proceso de ingestión que pueda rastrear el sitio web y crear incorporaciones que LlamaIndex pueda usar para responder las preguntas de los clientes. En este caso, nos basaremos en el bot creado en el anterior entrada del blog, que consulta esas incrustaciones con la declaración de un usuario y devuelve la respuesta de las preguntas frecuentes del sitio web.

El siguiente diagrama muestra cómo el proceso de ingestión y el bot de Amazon Lex funcionan juntos para nuestra solución.

Mejore Amazon Lex con LLM y mejore la experiencia de preguntas frecuentes mediante la ingesta de URL | Amazon Web Services PlatoBlockchain Inteligencia de datos. Búsqueda vertical. Ai.

En el flujo de trabajo de la solución, el sitio web con preguntas frecuentes se ingiere a través de AWS Lambda. Esta función de Lambda rastrea el sitio web y almacena el texto resultante en un Servicio de almacenamiento simple de Amazon (Amazon S3) cubeta. Luego, el depósito S3 activa una función Lambda que usa LlamaIndex para crear incrustaciones que se almacenan en Amazon S3. Cuando llega una pregunta de un usuario final, como "¿Cuál es su política de devoluciones?", el bot de Amazon Lex usa su función Lambda para consultar las incrustaciones utilizando un enfoque basado en RAG con LlamaIndex. Para obtener más información sobre este enfoque y los requisitos previos, consulte la publicación del blog, Mejore Amazon Lex con funciones de preguntas frecuentes conversacionales mediante LLM.

Una vez que se completan los requisitos previos del blog mencionado anteriormente, el primer paso es ingerir las preguntas frecuentes en un repositorio de documentos que LlamaIndex puede vectorizar e indexar. El siguiente código muestra cómo lograr esto:

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)

En el ejemplo anterior, tomamos una URL de sitio web de preguntas frecuentes predefinida de Zappos y la ingerimos usando el EZWebLoader clase. Con esta clase, navegamos a la URL y cargamos todas las preguntas que están en la página en un índice. Ahora podemos hacer una pregunta como "¿Zappos tiene tarjetas de regalo?" y obtenga las respuestas directamente de nuestras preguntas frecuentes en el sitio web. La siguiente captura de pantalla muestra la consola de prueba del bot de Amazon Lex respondiendo esa pregunta de las preguntas frecuentes.

Mejore Amazon Lex con LLM y mejore la experiencia de preguntas frecuentes mediante la ingesta de URL | Amazon Web Services PlatoBlockchain Inteligencia de datos. Búsqueda vertical. Ai.

Pudimos lograr esto porque rastreamos la URL en el primer paso y creamos incrustaciones que LlamaIndex podría usar para buscar la respuesta a nuestra pregunta. La función Lambda de nuestro bot muestra cómo se ejecuta esta búsqueda cada vez que se devuelve la intención alternativa:

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

Esta solución funciona bien cuando una sola página web tiene todas las respuestas. Sin embargo, la mayoría de los sitios de preguntas frecuentes no están construidos en una sola página. Por ejemplo, en nuestro ejemplo de Zappos, si hacemos la pregunta "¿Tiene una política de igualación de precios?", Obtenemos una respuesta menos que satisfactoria, como se muestra en la siguiente captura de pantalla.

Mejore Amazon Lex con LLM y mejore la experiencia de preguntas frecuentes mediante la ingesta de URL | Amazon Web Services PlatoBlockchain Inteligencia de datos. Búsqueda vertical. Ai.

En la interacción anterior, la respuesta de la política de igualación de precios no es útil para nuestro usuario. Esta respuesta es breve porque las preguntas frecuentes a las que se hace referencia son un enlace a una página específica sobre la política de igualación de precios y nuestro rastreo web fue solo para una sola página. Lograr mejores respuestas significará rastrear estos enlaces también. La siguiente sección muestra cómo obtener respuestas a preguntas que requieren dos o más niveles de profundidad de página.

rastreo de nivel N

Cuando rastreamos una página web para conocer las preguntas frecuentes, la información que queremos puede estar contenida en páginas vinculadas. Por ejemplo, en nuestro ejemplo de Zappos, hacemos la pregunta "¿Tiene una política de igualación de precios?" y la respuesta es "Sí, por favor visite aprender más." Si alguien pregunta "¿Cuál es su política de igualación de precios?" entonces queremos dar una respuesta completa con la política. Lograr esto significa que tenemos la necesidad de atravesar enlaces para obtener la información real para nuestro usuario final. Durante el proceso de ingestión, podemos usar nuestro cargador web para encontrar los enlaces de anclaje a otras páginas HTML y luego recorrerlos. El siguiente cambio de código en nuestro rastreador web nos permite encontrar enlaces en las páginas que rastreamos. También incluye alguna lógica adicional para evitar el rastreo circular y permitir un filtro por prefijo.

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)

En el código anterior, introducimos la capacidad de rastrear N niveles de profundidad y proporcionamos un prefijo que nos permite restringir el rastreo solo a las cosas que comienzan con un determinado patrón de URL. En nuestro ejemplo de Zappos, todas las páginas de servicio al cliente están enraizadas desde zappos.com/c, por lo que lo incluimos como un prefijo para limitar nuestros rastreos a un subconjunto más pequeño y más relevante. El código muestra cómo podemos ingerir hasta dos niveles de profundidad. La lógica Lambda de nuestro bot sigue siendo la misma porque nada ha cambiado, excepto que el rastreador ingiere más documentos.

Ahora tenemos todos los documentos indexados y podemos hacer una pregunta más detallada. En la siguiente captura de pantalla, nuestro bot proporciona la respuesta correcta a la pregunta "¿Tiene una política de igualación de precios?"

Mejore Amazon Lex con LLM y mejore la experiencia de preguntas frecuentes mediante la ingesta de URL | Amazon Web Services PlatoBlockchain Inteligencia de datos. Búsqueda vertical. Ai.

Ahora tenemos una respuesta completa a nuestra pregunta sobre la igualación de precios. En lugar de simplemente decir "Sí, vea nuestra política", nos brinda los detalles del rastreo de segundo nivel.

Limpiar

Para evitar incurrir en gastos futuros, proceda con la eliminación de todos los recursos que se implementaron como parte de este ejercicio. Hemos proporcionado una secuencia de comandos para cerrar correctamente el punto final de Sagemaker. Los detalles de uso están en el LÉAME. Además, para eliminar todos los demás recursos que puede ejecutar cdk destroy en el mismo directorio que los otros comandos cdk para desaprovisionar todos los recursos en su pila.

Conclusión

La capacidad de ingerir un conjunto de preguntas frecuentes en un chatbot permite a sus clientes encontrar las respuestas a sus preguntas con consultas directas y en lenguaje natural. Al combinar el soporte integrado en Amazon Lex para el manejo de respaldo con una solución RAG como LlamaIndex, podemos proporcionar una ruta rápida para que nuestros clientes obtengan respuestas satisfactorias, seleccionadas y aprobadas a las preguntas frecuentes. Al aplicar el rastreo de nivel N en nuestra solución, podemos permitir respuestas que posiblemente abarquen varios enlaces de preguntas frecuentes y proporcionen respuestas más profundas a las consultas de nuestros clientes. Al seguir estos pasos, puede incorporar sin problemas potentes capacidades de preguntas y respuestas basadas en LLM y una ingestión eficiente de URL en su chatbot de Amazon Lex. Esto da como resultado interacciones más precisas, completas y conscientes del contexto con los usuarios.


Sobre los autores

Mejore Amazon Lex con LLM y mejore la experiencia de preguntas frecuentes mediante la ingesta de URL | Amazon Web Services PlatoBlockchain Inteligencia de datos. Búsqueda vertical. Ai.Max Henkel Wallace es ingeniero de desarrollo de software en AWS Lex. Le gusta trabajar aprovechando la tecnología para maximizar el éxito del cliente. Fuera del trabajo, le apasiona cocinar, pasar tiempo con amigos y hacer mochileros.

Mejore Amazon Lex con LLM y mejore la experiencia de preguntas frecuentes mediante la ingesta de URL | Amazon Web Services PlatoBlockchain Inteligencia de datos. Búsqueda vertical. Ai.Canción feng es científico aplicado sénior en AWS AI Labs, especializado en procesamiento de lenguaje natural e inteligencia artificial. Su investigación explora varios aspectos de estos campos, incluido el modelado de diálogo basado en documentos, el razonamiento para diálogos orientados a tareas y la generación de texto interactivo utilizando datos multimodales.

Mejore Amazon Lex con LLM y mejore la experiencia de preguntas frecuentes mediante la ingesta de URL | Amazon Web Services PlatoBlockchain Inteligencia de datos. Búsqueda vertical. Ai.John Baker es un SDE principal en AWS, donde trabaja en procesamiento de lenguaje natural, modelos de lenguaje grande y otros proyectos relacionados con ML/AI. Ha estado en Amazon durante más de 9 años y ha trabajado en AWS, Alexa y Amazon.com. En su tiempo libre, a John le gusta esquiar y realizar otras actividades al aire libre en el noroeste del Pacífico.

Sello de tiempo:

Mas de Aprendizaje automático de AWS