DEV Community

felino33
felino33

Posted on

AWS ChatBot_Lavanderia

💧 Chatbot con Amazon Bedrock Agent + Knowledge Base RAG — Lavandería Ecológica

Cómo construimos un asistente de IA conversacional para una lavandería ecológica usando Amazon Bedrock Agent, Knowledge Base RAG, AWS Lambda y una landing page 100% estática — sin servidores, sin frameworks pesados, sin complicaciones.


¿Por qué Amazon Bedrock Agent?

La mayoría de los chatbots simples solo responden con texto genérico. Un Bedrock Agent va más allá:

  • Memoria de sesión nativa — el agente recuerda el contexto de la conversación sin que tengas que implementar nada
  • Knowledge Base RAG integrada — conecta el agente a documentos propios (PDFs, FAQs, manuales) y responde con información real del negocio, no alucinaciones
  • Orquestación automática — el agente decide cuándo consultar la KB, cuándo responder directamente y cómo combinar fuentes
  • Modelo Nova-Lite — rápido, económico y suficientemente potente para casos de uso conversacionales en producción
  • Sin infraestructura de ML — no hay modelos que mantener, no hay GPUs, no hay pipelines de entrenamiento

Para un negocio local como una lavandería, esto significa tener un asistente que conoce sus precios, horarios, procesos ecológicos y políticas — todo extraído automáticamente de sus propios documentos.


Arquitectura completa

Cliente (navegador)
        │
        ▼
  CloudFront CDN
  ┌─────────────────────────────────────────┐
  │  /          → S3 Bucket                 │
  │             (index.html + widget JS)    │
  │                                         │
  │  /chat      → API Gateway HTTP API      │
  │             → Lambda (Flask)            │
  │             → Bedrock Agent Runtime     │
  │               ┌──────────────────────┐  │
  │               │  Bedrock Agent       │  │
  │               │  (Nova-Lite v1)      │  │
  │               │       │              │  │
  │               │  Knowledge Base RAG  │  │
  │               │  (OpenSearch + S3)   │  │
  │               └──────────────────────┘  │
  └─────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode
Servicio AWS Rol en el proyecto
Amazon Bedrock Agent Orquesta la conversación, mantiene sesión, decide cuándo consultar la KB
Bedrock Knowledge Base Indexa documentos del negocio, responde con RAG (Retrieval-Augmented Generation)
Amazon Nova-Lite v1 Modelo de lenguaje — rápido y económico para chat en producción
AWS Lambda Ejecuta el backend Flask sin servidores, escala a cero cuando no hay tráfico
API Gateway HTTP API Expone el endpoint /chat con baja latencia y manejo de CORS
Amazon S3 Almacena el frontend estático y los documentos fuente de la Knowledge Base
Amazon CloudFront CDN global — sirve el frontend y enruta /chat al backend desde el mismo dominio
AWS IAM Controla permisos mínimos entre Lambda y Bedrock

Cómo funciona el flujo de una pregunta

Usuario escribe: "¿Cuánto cuesta lavar un traje?"
        │
        ▼
chatbot-wiget.js  →  POST /chat  { sessionId, message, context }
        │
        ▼
Lambda (Flask)  →  bedrock_client.py
        │
        ▼
invoke_agent(agentId, agentAliasId, sessionId, inputText)
        │
        ▼
Bedrock Agent evalúa:
  ¿Tengo esta info en la KB?  →  Sí
        │
        ▼
Knowledge Base RAG:
  1. Embedding de la pregunta
  2. Búsqueda semántica en OpenSearch
  3. Recupera fragmentos relevantes del PDF de precios
  4. Nova-Lite genera respuesta contextualizada
        │
        ▼
Stream de respuesta  →  Lambda  →  API Gateway  →  Widget
Enter fullscreen mode Exit fullscreen mode

Configuración del Bedrock Agent

Crear la Knowledge Base

# 1. Subir documentos fuente al bucket S3
aws s3 cp documentos/ s3://tintorerias-kb-docs/ --recursive

# 2. Crear la Knowledge Base (desde consola o CLI)
aws bedrock-agent create-knowledge-base \
  --name "tintorerias-ecologicas-kb" \
  --description "Documentos de servicios, precios y procesos ecológicos" \
  --role-arn arn:aws:iam::ACCOUNT_ID:role/AmazonBedrockExecutionRoleForKnowledgeBase \
  --knowledge-base-configuration '{
    "type": "VECTOR",
    "vectorKnowledgeBaseConfiguration": {
      "embeddingModelArn": "arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-embed-text-v1"
    }
  }' \
  --storage-configuration '{
    "type": "OPENSEARCH_SERVERLESS",
    "opensearchServerlessConfiguration": {
      "collectionArn": "arn:aws:aoss:us-east-1:ACCOUNT_ID:collection/COLLECTION_ID",
      "vectorIndexName": "tintorerias-index",
      "fieldMapping": {
        "vectorField": "embedding",
        "textField": "text",
        "metadataField": "metadata"
      }
    }
  }'
Enter fullscreen mode Exit fullscreen mode

Crear el Data Source y sincronizar

# Crear data source apuntando al bucket S3
aws bedrock-agent create-data-source \
  --knowledge-base-id TU_KB_ID \
  --name "documentos-tintorerias" \
  --data-source-configuration '{
    "type": "S3",
    "s3Configuration": {
      "bucketArn": "arn:aws:s3:::tintorerias-kb-docs"
    }
  }'

# Iniciar sincronización (indexación de documentos)
aws bedrock-agent start-ingestion-job \
  --knowledge-base-id TU_KB_ID \
  --data-source-id TU_DATA_SOURCE_ID

# Verificar estado de la sincronización
aws bedrock-agent get-ingestion-job \
  --knowledge-base-id TU_KB_ID \
  --data-source-id TU_DATA_SOURCE_ID \
  --ingestion-job-id TU_JOB_ID
Enter fullscreen mode Exit fullscreen mode

Crear el Agente y asociar la Knowledge Base

# Crear el agente
aws bedrock-agent create-agent \
  --agent-name "asistente-tintorerias" \
  --agent-resource-role-arn arn:aws:iam::ACCOUNT_ID:role/AmazonBedrockExecutionRoleForAgents \
  --foundation-model "amazon.nova-lite-v1:0" \
  --instruction "Eres el asistente virtual de una lavandería ecológica. Responde preguntas sobre servicios, precios, horarios y procesos de limpieza ecológica de manera amable y concisa. Usa la información de los documentos para dar respuestas precisas."

# Asociar la Knowledge Base al agente
aws bedrock-agent associate-agent-knowledge-base \
  --agent-id TU_AGENT_ID \
  --agent-version DRAFT \
  --knowledge-base-id TU_KB_ID \
  --description "Base de conocimiento de servicios y precios"

# Preparar y publicar el agente
aws bedrock-agent prepare-agent --agent-id TU_AGENT_ID

aws bedrock-agent create-agent-alias \
  --agent-id TU_AGENT_ID \
  --agent-alias-name "produccion"
Enter fullscreen mode Exit fullscreen mode

Código del cliente Bedrock

Invocar el agente (con streaming)

import boto3

client = boto3.client("bedrock-agent-runtime", region_name="us-east-1")

def chat_con_agente(mensaje: str, session_id: str) -> str:
    response = client.invoke_agent(
        agentId="PPJ6T6QBDD",
        agentAliasId="VQKXHLAVG1",
        sessionId=session_id,       # Bedrock mantiene el contexto por sessionId
        inputText=mensaje,
    )

    # La respuesta llega como stream de eventos
    texto_completo = ""
    for event in response.get("completion", []):
        chunk = event.get("chunk", {})
        if "bytes" in chunk:
            texto_completo += chunk["bytes"].decode("utf-8")

    return texto_completo or "(sin respuesta)"

# Uso
respuesta = chat_con_agente("¿Cuánto cuesta lavar una chamarra de cuero?", "sesion-123")
print(respuesta)
Enter fullscreen mode Exit fullscreen mode

Consultar la Knowledge Base directamente (sin agente)

def consultar_kb(pregunta: str, kb_id: str) -> str:
    response = client.retrieve_and_generate(
        input={"text": pregunta},
        retrieveAndGenerateConfiguration={
            "type": "KNOWLEDGE_BASE",
            "knowledgeBaseConfiguration": {
                "knowledgeBaseId": kb_id,
                "modelArn": "amazon.nova-lite-v1:0",
                "generationConfiguration": {
                    "promptTemplate": {
                        "textPromptTemplate": (
                            "Eres un asistente de lavandería ecológica. "
                            "Responde basándote en esta información:\n\n"
                            "$search_results$"
                        )
                    }
                },
            },
        },
    )
    return response["output"]["text"]
Enter fullscreen mode Exit fullscreen mode

Soporte multi-contexto (varios clientes, un backend)

# bedrock_client.py — patrón usado en este proyecto
CONFIGS = {
    'aquamax': {
        'type': 'agent',
        'agent_id': 'PPJ6T6QBDD',
        'agent_alias_id': 'VQKXHLAVG1',
    },
    'otro_cliente': {
        'type': 'kb',
        'kb_id': 'KB_ID_DEL_CLIENTE',
        'model_arn': 'amazon.nova-lite-v1:0',
        'prompt': "Eres el asistente de...\n\n$search_results$",
    },
}

def chat(mensaje: str, session_id: str, contexto: str) -> str:
    cfg = CONFIGS.get(contexto, CONFIGS['aquamax'])
    if cfg['type'] == 'agent':
        return _invoke_agent(mensaje, session_id, cfg)
    return _retrieve_and_generate(mensaje, cfg)
Enter fullscreen mode Exit fullscreen mode

Despliegue del backend en Lambda

Empaquetar y crear la función

cd tintorerias-chatbot

# Instalar dependencias en carpeta local
pip install flask flask-cors boto3 python-dotenv -t package/
cp app.py bedrock_client.py config.py lambda_handler.py package/

# Crear ZIP de despliegue
cd package && zip -r ../lambda_deployment.zip . && cd ..

# Obtener Account ID
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

# Crear rol IAM con permisos mínimos
aws iam create-role \
  --role-name tintorerias-lambda-role \
  --assume-role-policy-document '{
    "Version":"2012-10-17",
    "Statement":[{
      "Effect":"Allow",
      "Principal":{"Service":"lambda.amazonaws.com"},
      "Action":"sts:AssumeRole"
    }]
  }'

aws iam attach-role-policy \
  --role-name tintorerias-lambda-role \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

aws iam put-role-policy \
  --role-name tintorerias-lambda-role \
  --policy-name BedrockAccess \
  --policy-document '{
    "Version":"2012-10-17",
    "Statement":[{
      "Effect":"Allow",
      "Action":[
        "bedrock:InvokeAgent",
        "bedrock:RetrieveAndGenerate",
        "bedrock:Retrieve",
        "bedrock:InvokeModel"
      ],
      "Resource":"*"
    }]
  }'

# Crear la función Lambda
aws lambda create-function \
  --function-name tintorerias-chatbot \
  --runtime python3.11 \
  --role arn:aws:iam::${ACCOUNT_ID}:role/tintorerias-lambda-role \
  --handler lambda_handler.handler \
  --zip-file fileb://lambda_deployment.zip \
  --timeout 30 \
  --memory-size 256 \
  --environment Variables="{
    KB_ID=TU_KB_ID,
    MODEL_ARN=amazon.nova-lite-v1:0,
    AWS_REGION=us-east-1
  }"
Enter fullscreen mode Exit fullscreen mode

Crear API Gateway y conectar con Lambda

# Crear HTTP API
API_ID=$(aws apigatewayv2 create-api \
  --name "tintorerias-chat-api" \
  --protocol-type HTTP \
  --query 'ApiId' --output text)

# Crear integración Lambda
LAMBDA_ARN="arn:aws:lambda:us-east-1:${ACCOUNT_ID}:function:tintorerias-chatbot"

INTEGRATION_ID=$(aws apigatewayv2 create-integration \
  --api-id $API_ID \
  --integration-type AWS_PROXY \
  --integration-uri $LAMBDA_ARN \
  --payload-format-version "2.0" \
  --query 'IntegrationId' --output text)

# Ruta POST /chat
aws apigatewayv2 create-route \
  --api-id $API_ID \
  --route-key "POST /chat" \
  --target "integrations/$INTEGRATION_ID"

# Stage prod con auto-deploy
aws apigatewayv2 create-stage \
  --api-id $API_ID \
  --stage-name prod \
  --auto-deploy

# Permiso para que API Gateway invoque Lambda
aws lambda add-permission \
  --function-name tintorerias-chatbot \
  --statement-id apigateway-invoke \
  --action lambda:InvokeFunction \
  --principal apigateway.amazonaws.com \
  --source-arn "arn:aws:execute-api:us-east-1:${ACCOUNT_ID}:${API_ID}/*/*/chat"

# URL final del endpoint
aws apigatewayv2 get-api --api-id $API_ID --query 'ApiEndpoint' --output text
Enter fullscreen mode Exit fullscreen mode

El widget de chat (frontend)

El widget es un archivo JS autocontenido que se inyecta en cualquier página HTML con un solo <script>:

<script src="chatbot-wiget.js"></script>
Enter fullscreen mode Exit fullscreen mode

Internamente genera su propio DOM, estilos y lógica sin depender de ninguna librería:

// Configuración mínima necesaria
const CONFIG = {
  apiUrl: 'https://TU_DOMINIO.cloudfront.net/chat',
  requestTimeout: 30000,
  context: 'aquamax',   // identifica qué agente/KB usar en el backend
};

// Cada sesión de navegador tiene su propio UUID
// Bedrock Agent usa este ID para mantener el contexto de conversación
state.sessionId = crypto.randomUUID();

// Llamada al backend
fetch(CONFIG.apiUrl, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    sessionId: state.sessionId,
    message: texto,
    context: CONFIG.context,
  }),
});
Enter fullscreen mode Exit fullscreen mode

Probar el endpoint en producción

# Pregunta simple
curl -X POST https://TU_DOMINIO.cloudfront.net/chat \
  -H "Content-Type: application/json" \
  -d '{"sessionId":"test-1","message":"¿Cuáles son sus servicios?","context":"aquamax"}'

# Pregunta de seguimiento (mismo sessionId — el agente recuerda el contexto)
curl -X POST https://TU_DOMINIO.cloudfront.net/chat \
  -H "Content-Type: application/json" \
  -d '{"sessionId":"test-1","message":"¿Y cuánto tiempo tarda?","context":"aquamax"}'

# Respuesta esperada
# { "response": "Ofrecemos lavado en seco ecológico, lavado de ropa delicada..." }
Enter fullscreen mode Exit fullscreen mode

Actualizar el despliegue

# Backend — reconstruir y subir Lambda
cd tintorerias-chatbot
pip install flask flask-cors boto3 python-dotenv -t package/
cp app.py bedrock_client.py config.py lambda_handler.py package/
cd package && zip -r ../lambda_deployment.zip . && cd ..
aws lambda update-function-code \
  --function-name tintorerias-chatbot \
  --zip-file fileb://lambda_deployment.zip

# Frontend — subir y limpiar caché de CloudFront
aws s3 cp index.html       s3://$BUCKET_NAME/
aws s3 cp chatbot-wiget.js s3://$BUCKET_NAME/
aws cloudfront create-invalidation \
  --distribution-id $DISTRIBUTION_ID \
  --paths "/*"
Enter fullscreen mode Exit fullscreen mode

Por qué este stack es ideal para negocios locales

  • Costo casi cero en reposo — Lambda y API Gateway cobran por invocación, no por hora. Un chatbot con tráfico moderado cuesta centavos al mes.
  • Sin mantenimiento de servidores — no hay EC2 que parchear, no hay contenedores que monitorear.
  • Escala automática — de 0 a miles de usuarios simultáneos sin configuración adicional.
  • Conocimiento del negocio real — la Knowledge Base RAG garantiza que el asistente responda con información actualizada del negocio, no con datos genéricos del modelo.
  • Reutilizable — el mismo backend soporta múltiples clientes cambiando solo el campo context en la petición.

Licencia

Proyecto privado — todos los derechos reservados.

Top comments (0)