Creación de un agente de cafetería con Amazon Bedrock y Shopify

ricardoceci - Oct 25 - - Dev Community

Hoy te explicaré cómo poner manos a la obra con Bedrock de manera segura y confiable y de paso, aprender un poco sobre café.

Aprenderás cómo consumir la API de Amazon Bedrock de modelos de Texto y Multimodales utilizando Python para poder generar nombres, logo y menú para tu cafetería y para poder crear un agente que se conecta a una API de Shopify para tomar pedidos.

Shopify es (a mi criterio) la mejor plataforma de eCommerce que existe.

Y así como AWS, Shopify tiene una API para todo y una plataforma para desarrolladores

Por último crearás un frontend utilizando Streamlit para dar una experiencia de usuario única y darle vida a tu agente.

📝 Indice

🧐 Invocando la API de Amazon Bedrock para generar nombres, logo y menú para tu cafetería

El momento de abrir una cafetería o de tener ideas creativas para el negocio que fuese es una excelente oportunidad para apoyarse en la IA Generativa (GenAI) y sacar su máximo provecho.

A través de Amazon Bedrock puedes hacer uso de ella, pero... ¿Cómo se consume ese servicio?

Todo servicio en AWS tiene una API, y Amazon Bedrock no es la excepción, a continuación te explico cómo consumir la API de Amazon Bedrock a través de un ejemplo para generar nombres y un menú para una Cafetería al paso.

Y además te muestro cómo consumir un modelo multimodal capaz de analizar imágenes.

Instrucciones para programar un script en Python para ejecutar localmente o en una función Lambda para invocar a Amazon Bedrock:

Primero debes habilitar el acceso a los modelos en Bedrock Instrucciones aqui

Requisitos:

  • Una cuenta en AWS, si no tienes una cuenta, puedes abrir una aqui
  • AWS CLI Instrucciones aqui
  • Python 3.11 o superior

Paso 1) Crear un entorno virtual de Python Instrucciones aqui

En la carpeta bedrock_examples de este repositorio encontrarás diferentes ejemplos utilizados a continuación para invocar el modelo fundacional.

En la carpeta prompts encontrarás los prompts de ejemplo, que vas a poder utilizar para generar El nombre, el Menú y un prompt para pasarle a un modelo de generación de imágenes que podrás invocar tanto en el playground de Amazon Bedrock cómo invocando la API desde Python.

Paso 2) Instalar los requerimientos

pip install -r requirements.txt
Enter fullscreen mode Exit fullscreen mode

Paso 3) Configurar Boto3 Mas info sobre boto3

Aqui configuro el cliente de AWS indicandole que utilice el perfil genaiday instalado en mi computadora y llamo al cliente de bedrock-runtime que me va a permitir invocar al modelo fundacional.

#Cambiar la region y el perfil de AWS
aws = boto3.session.Session(profile_name='genaiday', region_name=region)
client = aws.client('bedrock-runtime')
Enter fullscreen mode Exit fullscreen mode

Paso 4) Ejemplo: Invocar modelo de texto

Esta función llama al método invoke_model y le paso el prompt indicado por el usuario y le devuelvo la respuesta

La parte más importante son los mensajes enviados:

{
                "role": "user",
                "content": [{
                    "type": "text",
                    "text": prompt
                }]
            }
Enter fullscreen mode Exit fullscreen mode
def call_text(prompt,modelId="anthropic.claude-3-haiku-20240307-v1:0"):
    #esta función es para llamar un modelo de texto
    config = {
        "anthropic_version": "bedrock-2023-05-31",
        "max_tokens": 4096,
        "messages": [
            {
                "role": "user",
                "content": [{
                    "type": "text",
                    "text": prompt
                }]
            }
        ]
    }

    body = json.dumps(config)
    modelId = modelId
    accept = "application/json"
    contentType = "application/json"

    response = client.invoke_model(
        body=body, modelId=modelId, accept=accept, contentType=contentType)
    response_body = json.loads(response.get("body").read())
    results = response_body.get("content")[0].get("text")
    return results
Enter fullscreen mode Exit fullscreen mode

Ejemplo:

print("Haiku")
print(call_text("Estoy buscando armar un local de café al paso, dame 5 nombres para un local.")
Enter fullscreen mode Exit fullscreen mode

Paso 5) Ejemplo: Invocar a un modelo multimodal.

Aquí el proceso es similar, solo que hay que agregar el mime type del archivo enviado, para esto hay una función que en base al nombre del archivo obtiene el mimetype

def read_mime_type(file_path):
    # Este hack es para versiones de python anteriores a 3.13
    # Esta función lee el mime type de un archivo
    mimetypes.add_type('image/webp', '.webp')
    mime_type = mimetypes.guess_type(file_path)
    return mime_type[0]
Enter fullscreen mode Exit fullscreen mode

Luego para invocar al modelo, los mensajes deben ser los siguientes:

 "messages": [
        {
            "role": "user",
            "content": [
                {
                     "type": "image",
                        "source": {
                            "type": "base64",
                            "media_type": read_mime_type(file),
                            "data": base64.b64encode(open(file, "rb").read()).decode("utf-8")
                        }
                },
                {
                    "type": "text",
                    "text": caption
            }]
        }
    ]
Enter fullscreen mode Exit fullscreen mode

La invocación del modelo queda así:

def call_multimodal(file,caption,modelId="anthropic.claude-3-haiku-20240307-v1:0"):
    #esta funcion es para llamar a un modelo multimodal con una imagen y un texto
    config = {
    "anthropic_version": "bedrock-2023-05-31",
    "max_tokens": 4096,
    "messages": [
        {
            "role": "user",
            "content": [
                {
                     "type": "image",
                        "source": {
                            "type": "base64",
                            "media_type": read_mime_type(file),
                            "data": base64.b64encode(open(file, "rb").read()).decode("utf-8")
                        }
                },
                {
                    "type": "text",
                    "text": caption
            }]
        }
    ]
    }

    body = json.dumps(config)
    modelId = modelId
    accept = "application/json"
    contentType = "application/json"

    response = client.invoke_model(
    body=body, modelId=modelId, accept=accept, contentType=contentType)
    response_body = json.loads(response.get("body").read())
    results = response_body.get("content")[0].get("text")
    return results
Enter fullscreen mode Exit fullscreen mode

Ejemplo:

pic_path = "./meetup_test_image.jpg"
caption = "Cuantas personas hay en la imagen? cuantas laptos ves? cuantos usan gorro o sombrero?, de que color es el hoddie de la primer persona a la derecha de la foto?"
print("Haiku")
print(call_image(pic_path,caption,"anthropic.claude-3-haiku-20240307-v1:0"))
print("Sonnet")
print(call_image(pic_path,caption,"anthropic.claude-3-sonnet-20240229-v1:0"))
Enter fullscreen mode Exit fullscreen mode

🏁 Creación de un agente de Amazon Bedrock que interactúa con Shopify

Para crear un agente de Amazon Bedrock:

Asegurate de tener los modelos de Bedrock que quieras usar con el acceso habilitado Instrucciones aqui, en este caso utilizaremos Claude 3 Haiku y Sonnet

Luego crear el agente de Bedrock en la consola de AWS:

1) Ir al servicio Bedrock
2) Agentes
3) Crear agente

Crear agente

4) Darle un nombre al agente, en nuestro caso "Pausa-Cafetera-Agente
5) La descripción es opcional.
6) Uno de los pasos más importantes es elegir el modelo fundacional que va a hacer que nuestro agente funcione adecuadamente, si deseas saber cómo hacer para elegir el mejor modelo que se adapte a tu caso de uso Aqui tienes una guía sobre el servicio Amazon Bedrock Model Evaluation .
7) El siguiente paso es el prompt que va a guiar a tu modelo, aqui tienes que ser lo más preciso posible y sacar a relucir tus habilidades como prompt engineer, si no sabes por donde comenzar, te recomiendo visitar esta guia donde vas a encontrar las mejores guidelines para el modelo que estes utilizando, y además otro recurso muy útil es la consola de anthropic.

Crear agente Paso 2

Este es el prompt que utilicé para el agente de ejemplo, te recomiendo escribir el prompt en inglés dado que los modelos fueron entrenados en inglés y a veces escribir en el idioma de origen de entrenamiento ayuda a evitar comportamientos erroneos.

You are a helpful Bedrock agent working at a coffee shop.

Your goal is to assist customers in placing orders, offering them combos and creating orders by consuming a Shopify API.

When a customer interacts with you, greet them politely and ask how you can help them today.

If they indicate that they want to place an order, start by offering them popular combos or bundles that your coffee shop offers.

Before offering any product make sure to get the list of available products from the API.

Do not offer any product that is not in our list of products, never ask the customer for any recommendations.

If the customer expresses interest in a combo, you have to provide more details about the items included and the price, never ask for details to the customer, you are the one who knows about the products and combos.

Throughout the ordering process, be friendly and patient. If the customer is unsure or has questions, provide clear explanations to help them make a decision. Once the customer has finalized their order, confirm the details with them and let them know you'll be placing the order through the Shopify API.

Before creating the order through the API make sure to ask the customer for his/her name, never assume you know it.

When creating the order through the API, make sure to accurately capture all the items the customer requested, along with any customizations or special instructions they provided.

It's important to note that you should respond to the customer in their preferred language. If they initiate the conversation in a language other than English, reply in that same language to ensure smooth and effective communication.

Your goal is to provide an excellent customer experience by offering helpful recommendations, answering questions, and accurately processing orders through the Shopify API. Remember to be polite, patient, and adapt your language to match the customer's preference.

Enter fullscreen mode Exit fullscreen mode

8) Configuración adicional, debes permitir al agente que capture input del usuario, dado que seguramente le falte información para procesar la orden, por ejemplo: Necesitará preguntar por los productos que el cliente desea, el nombre, entre otras cosas.

Crear agente Paso 3

9) Grupos de acción: Un grupo de acción define las acciones en las que el agente puede ayudar al usuario. Por ejemplo, puedes definir un grupo de acciones que diga TomarPedido que puede tener las siguientes acciones

  • Listar productos
  • Procesar Pedido

Para crear un grupo de accion vas a necesitar para cada acción:

  • El nombre
  • Los parámetros

Los grupos de acción para ejecutarse generalmente invocan una función Lambda, desde Bedrock puedes:

  • Crear una función lambda desde la consola de Bedrock (Seleccionar Creación rápida de una función lambda)

Crear agente Paso 4

  • Elegir una funcion lambda ya creada aqui las instrucciones de cómo es el evento y la respuesta esperada por cada action group (grupo de acción)

Si eliges crear la función lambda desde la consola de Bedrock, se creará una función en python con un código fuente básico que luego deberás modificar, en este repo en el archivo agents/action_group/lambda.py tienes el código de ejemplo modificado para que funcione con el agente.

Estas son las variables que te entregarán la información necesaria:

  • function: es el nombre de la acción invocada, en el caso del ejemplo puede ser: get_products (para listar productos), y place_order (para generar la orden en Shopify)
  • parameters: es un diccionario de parámetros.

En el siguiente ejemplo puedes observar que hay dos acciones:

Crear agente Paso 5

Crear agente Paso 6

  • get_products que no requiere ningun parámetro
  • place_order que lleva 3 parámetros:
Parametro Descripcion Tipo Obligatorio
customerEmail Email of the customer string False
customerName Name of the customer string True
products SKUs and quantities to add to the cart in the format [{ variantId: variantId, quantity: QUANTITY }] array True

Entonces, por ejemplo cuando se llame a la función get_products en la función lambda se maneja de esta manera:

Hay una función get_products definida que será la encargada de hacer la query a la API de Shopify (A fines didácticos retornamos todos los productos)

Si quieres que esto funcione en Shopify debes reemplazar las siguientes variables por las de tu tienda:

access_token = 'shpat_XXXXX'


url = 'https://XXXXXXX.myshopify.com/admin/api/2024-10/graphql.json'
Enter fullscreen mode Exit fullscreen mode
def get_products():

   # Let's query all the products from the Shopify API paginate through the results and store them in a list and return it
    products = []
    cursor = None
    while True:
        query = """
        {
          products(first: 10%s) {
            pageInfo {
              hasNextPage
            }
            edges {
              cursor
              node {
                id
                title
                description
                variants(first: 10) {
                  edges {
                    node {
                        id
                        title
                        sku
                        price
                    }
                  }
                }
              }
            }
          }
        }
        """ % (', after: "%s"' % cursor if cursor else '')
        response = requests.post(url, headers=headers, data=query)

        data = response.json()
        for edge in data['data']['products']['edges']:
            product = edge['node']
            products.append(product)
        if not data['data']['products']['pageInfo']['hasNextPage']:
            break
        cursor = data['data']['products']['edges'][-1]['cursor']
    return products
Enter fullscreen mode Exit fullscreen mode

Luego en el handler de la función lambda, se verifica el nombre de la función llamada y se devuelve la respuesta con el formato que el action_group necesita:

def lambda_handler(event, context):
    agent = event['agent']
    actionGroup = event['actionGroup']
    function = event['function']
    parameters = event.get('parameters', [])

    # Execute your business logic here. For more information, refer to: https://docs.aws.amazon.com/bedrock/latest/userguide/agents-lambda.html

    if(function == 'get_products'):
        products = get_products()
        responseBody =  {
            "TEXT": {
                "body": json.dumps(products)
            }
        }
Enter fullscreen mode Exit fullscreen mode

Los fragmentos de código expuestos anteriormente son parte de la función lambda que se encuentra aqui

10) Presionar Guardar y Salir, y listo!, ya el agente esta listo para ser probado.

El Agente en acción

Lo siguiente es probar el agente y validar que funcione, desde Bedrock puedes hacer las pruebas del agente, y si durante la conversación clickeas "Ver traza o Show Trace" te va a ir mostrando el proceso de razonamiento, aqui es donde debes prestar especial atención y hacer los ajustes que creas necesarios en el prompt o bien buscar otro modelo si ves que el que elgiste no funciona como esperabas.

Una vez que estes conforme con el agente, puedes crear un Alias, un alias es un ID a través del cual vas a poder invocar al agente desde la API de Amazon Bedrock, cuando crees el alias, te va a crear una versión del agente automáticamente, o puedes apuntar a una versión ya existente, tener diferentes alias y diferentes versiones te va a ayudar a controlar el proceso de despliegue del agente, por ejemplo:

  • Puedes tener un alias "development" que va a ir a las ultimas pruebas del Agente
  • Un alias "preprod" que sería el agente en modo pre producción
  • Un alias "prod" y este es el agente live.

Luego solo restaría apuntar el alias de producción correspondiente a la versión que desees que este en vivo.

Cómo invocar el agente

Para esto, en la carpeta agents/frontend he dejado un archivo que se llama agent.py.

Este desarrollo utiliza Streamlit, un poderoso framework para realizar aplicaciones de muestra de machine learning

La parte del código que hace la invocación al agente es la siguiente:

aws = boto3.session.Session(profile_name='genaiday', region_name=region)
client = aws.client('bedrock-agent-runtime')
def invokeAgent(agent_id,agent_alias_id,prompt,session_id):
    response = client.invoke_agent(
        agentId=agent_id,
        agentAliasId=agent_alias_id,
        inputText=prompt,
        sessionId=session_id
    )
    return response
Enter fullscreen mode Exit fullscreen mode

Utilizamos boto3 para consumir la API de AWS, llamamos al bedrock-agent-runtime cliente para poder hacer la invocación del agente.

Los parámetros que necesitamos pasarle son:

  • agentId
  • agentAliasId
  • inputText (el prompt)
  • sessionId (la sesión, para identificar las conversaciones)

En este ejemplo, las variables las estoy definiendo aqui:

with st.sidebar:
    agent_id = st.text_input("Agent ID", key="bedrock_agent_id")
    agent_alias_id = st.text_input("Agent Alias", key="bedrock_agent_alias")
    session_id = st.text_input("Sesion Id", key="session_id")
Enter fullscreen mode Exit fullscreen mode

Instalación:

Primero debes habilitar el acceso a los modelos en Bedrock Instrucciones aqui

Requisitos:

Te recomiendo crear un entorno virtual de Python Instrucciones aqui

pip install -r requirements.txt
Enter fullscreen mode Exit fullscreen mode

Ejecución

streamlit run agent.py
Enter fullscreen mode Exit fullscreen mode

Esto comenzará a ejecutar streamlit en el puerto 8501 y puedes visitar la siguiente URL: http://localhost:8501/ para ver el frontend que invocará al agente

Demo Frontend con Streamlit

Conclusión

Si has seguido todos los pasos has:

  • Consumido la API de Amazon Bedrock desde el Playground de Bedrock y desde Python
  • Has invocado modelos fundacionales de texto y multimodales
  • Has creado un agente desde 0 que consume una API de Shopify

Algunos links para que sigas tu camino dentro de GenerativeAI

Workshop AWS generative AI
Bedrock Knowledge Bases
Anthropic Console (Para hacer debug de nuestros prompts)
Community.aws (más artículos generados por y para la comunidad)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player