<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: YUVARAJ. R</title>
    <description>The latest articles on DEV Community by YUVARAJ. R (@yuvaraj_r_25388937f9607d).</description>
    <link>https://dev.to/yuvaraj_r_25388937f9607d</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3885661%2F0120d4ae-3217-4e41-97d4-dd5132641a1b.png</url>
      <title>DEV Community: YUVARAJ. R</title>
      <link>https://dev.to/yuvaraj_r_25388937f9607d</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yuvaraj_r_25388937f9607d"/>
    <language>en</language>
    <item>
      <title>AWS ChatBot</title>
      <dc:creator>YUVARAJ. R</dc:creator>
      <pubDate>Sat, 18 Apr 2026 07:26:27 +0000</pubDate>
      <link>https://dev.to/yuvaraj_r_25388937f9607d/aws-chatbot-2nfi</link>
      <guid>https://dev.to/yuvaraj_r_25388937f9607d/aws-chatbot-2nfi</guid>
      <description>&lt;p&gt;Chatbot with Amazon Bedrock Agent + Knowledge Base RAG — Ecological Laundry&lt;br&gt;
How we built a conversational AI assistant for an eco-friendly laundry using Amazon Bedrock Agent, Knowledge Base RAG, AWS Lambda and a 100% static landing page — without servers, without heavy frameworks, without complications.&lt;/p&gt;

&lt;p&gt;Why Amazon Bedrock Agent?&lt;br&gt;
Most simple chatbots only respond with generic text. A Bedrock Agent it goes further:&lt;/p&gt;

&lt;p&gt;Native session memory — the agent remembers the context of the conversation without you having to implement anything&lt;br&gt;
Integrated RAG Knowledge Base — connect the agent to your own documents (PDFs, FAQs, manuals) and respond with real business information, not hallucinations&lt;br&gt;
Automatic orchestration — the agent decides when to query the KB, when to respond directly, and how to combine sources&lt;br&gt;
Nova-lite model — fast, economical and powerful enough for conversational use cases in production&lt;br&gt;
No ML infrastructure — no models to maintain, no GPUs, no training pipelines&lt;br&gt;
For a local business like a laundromat, this means having an assistant who knows your prices, schedules, green processes, and policies — all automatically pulled from your own documents.&lt;/p&gt;

&lt;p&gt;Complete architecture&lt;br&gt;
Cliente (navegador)&lt;br&gt;
        │&lt;br&gt;
        ▼&lt;br&gt;
  CloudFront CDN&lt;br&gt;
  ┌─────────────────────────────────────────┐&lt;br&gt;
  │  /          → S3 Bucket                 │&lt;br&gt;
  │             (index.html + widget JS)    │&lt;br&gt;
  │                                         │&lt;br&gt;
  │  /chat      → API Gateway HTTP API      │&lt;br&gt;
  │             → Lambda (Flask)            │&lt;br&gt;
  │             → Bedrock Agent Runtime     │&lt;br&gt;
  │               ┌──────────────────────┐  │&lt;br&gt;
  │               │  Bedrock Agent       │  │&lt;br&gt;
  │               │  (Nova-Lite v1)      │  │&lt;br&gt;
  │               │       │              │  │&lt;br&gt;
  │               │  Knowledge Base RAG  │  │&lt;br&gt;
  │               │  (OpenSearch + S3)   │  │&lt;br&gt;
  │               └──────────────────────┘  │&lt;br&gt;
  └─────────────────────────────────────────┘&lt;br&gt;
AWS Service Role in the project&lt;br&gt;
Amazon Bedrock Agent    Orchestra the conversation, hold session, decide when to consult the KB&lt;br&gt;
Bedrock Knowledge Base  Indexes business documents, responds with RAG (Retrieval-Augmented Generation)&lt;br&gt;
Amazon Nova-Lite v1 Fast and economical — language model for chat in production&lt;br&gt;
AWS Lambda  Runs the Flask backend without servers, scales to zero when there is no traffic&lt;br&gt;
HTTP API Gateway API    Exposes the endpoint /chat with low latency and CORS handling&lt;br&gt;
Amazon S3   Stores the static frontend and source documents of the Knowledge Base&lt;br&gt;
Amazon CloudFront   global — CDN serves the frontend and routes /chat to the backend from the same domain&lt;br&gt;
AWS IAM Control minimum permissions between Lambda and Bedrock&lt;br&gt;
How the flow of a question works&lt;br&gt;
Usuario escribe: "¿Cuánto cuesta lavar un traje?"&lt;br&gt;
        │&lt;br&gt;
        ▼&lt;br&gt;
chatbot-wiget.js  →  POST /chat  { sessionId, message, context }&lt;br&gt;
        │&lt;br&gt;
        ▼&lt;br&gt;
Lambda (Flask)  →  bedrock_client.py&lt;br&gt;
        │&lt;br&gt;
        ▼&lt;br&gt;
invoke_agent(agentId, agentAliasId, sessionId, inputText)&lt;br&gt;
        │&lt;br&gt;
        ▼&lt;br&gt;
Bedrock Agent evalúa:&lt;br&gt;
  ¿Tengo esta info en la KB?  →  Sí&lt;br&gt;
        │&lt;br&gt;
        ▼&lt;br&gt;
Knowledge Base RAG:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Embedding de la pregunta&lt;/li&gt;
&lt;li&gt;Búsqueda semántica en OpenSearch&lt;/li&gt;
&lt;li&gt;Recupera fragmentos relevantes del PDF de precios&lt;/li&gt;
&lt;li&gt;Nova-Lite genera respuesta contextualizada
    │
    ▼
Stream de respuesta  →  Lambda  →  API Gateway  →  Widget
Bedrock Agent configuration
Create the Knowledge Base
# 1. Subir documentos fuente al bucket S3
aws s3 cp documentos/ s3://tintorerias-kb-docs/ --recursive&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  2. Crear la Knowledge Base (desde consola o CLI)
&lt;/h1&gt;

&lt;p&gt;aws bedrock-agent create-knowledge-base \&lt;br&gt;
  --name "tintorerias-ecologicas-kb" \&lt;br&gt;
  --description "Documentos de servicios, precios y procesos ecológicos" \&lt;br&gt;
  --role-arn arn:aws:iam::ACCOUNT_ID:role/AmazonBedrockExecutionRoleForKnowledgeBase \&lt;br&gt;
  --knowledge-base-configuration '{&lt;br&gt;
    "type": "VECTOR",&lt;br&gt;
    "vectorKnowledgeBaseConfiguration": {&lt;br&gt;
      "embeddingModelArn": "arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-embed-text-v1"&lt;br&gt;
    }&lt;br&gt;
  }' \&lt;br&gt;
  --storage-configuration '{&lt;br&gt;
    "type": "OPENSEARCH_SERVERLESS",&lt;br&gt;
    "opensearchServerlessConfiguration": {&lt;br&gt;
      "collectionArn": "arn:aws:aoss:us-east-1:ACCOUNT_ID:collection/COLLECTION_ID",&lt;br&gt;
      "vectorIndexName": "tintorerias-index",&lt;br&gt;
      "fieldMapping": {&lt;br&gt;
        "vectorField": "embedding",&lt;br&gt;
        "textField": "text",&lt;br&gt;
        "metadataField": "metadata"&lt;br&gt;
      }&lt;br&gt;
    }&lt;br&gt;
  }'&lt;br&gt;
Create the Data Source and synchronize&lt;/p&gt;

&lt;h1&gt;
  
  
  Crear data source apuntando al bucket S3
&lt;/h1&gt;

&lt;p&gt;aws bedrock-agent create-data-source \&lt;br&gt;
  --knowledge-base-id TU_KB_ID \&lt;br&gt;
  --name "documentos-tintorerias" \&lt;br&gt;
  --data-source-configuration '{&lt;br&gt;
    "type": "S3",&lt;br&gt;
    "s3Configuration": {&lt;br&gt;
      "bucketArn": "arn:aws:s3:::tintorerias-kb-docs"&lt;br&gt;
    }&lt;br&gt;
  }'&lt;/p&gt;

&lt;h1&gt;
  
  
  Iniciar sincronización (indexación de documentos)
&lt;/h1&gt;

&lt;p&gt;aws bedrock-agent start-ingestion-job \&lt;br&gt;
  --knowledge-base-id TU_KB_ID \&lt;br&gt;
  --data-source-id TU_DATA_SOURCE_ID&lt;/p&gt;

&lt;h1&gt;
  
  
  Verificar estado de la sincronización
&lt;/h1&gt;

&lt;p&gt;aws bedrock-agent get-ingestion-job \&lt;br&gt;
  --knowledge-base-id TU_KB_ID \&lt;br&gt;
  --data-source-id TU_DATA_SOURCE_ID \&lt;br&gt;
  --ingestion-job-id TU_JOB_ID&lt;br&gt;
Create the Agent and associate the Knowledge Base&lt;/p&gt;

&lt;h1&gt;
  
  
  Crear el agente
&lt;/h1&gt;

&lt;p&gt;aws bedrock-agent create-agent \&lt;br&gt;
  --agent-name "asistente-tintorerias" \&lt;br&gt;
  --agent-resource-role-arn arn:aws:iam::ACCOUNT_ID:role/AmazonBedrockExecutionRoleForAgents \&lt;br&gt;
  --foundation-model "amazon.nova-lite-v1:0" \&lt;br&gt;
  --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."&lt;/p&gt;

&lt;h1&gt;
  
  
  Asociar la Knowledge Base al agente
&lt;/h1&gt;

&lt;p&gt;aws bedrock-agent associate-agent-knowledge-base \&lt;br&gt;
  --agent-id TU_AGENT_ID \&lt;br&gt;
  --agent-version DRAFT \&lt;br&gt;
  --knowledge-base-id TU_KB_ID \&lt;br&gt;
  --description "Base de conocimiento de servicios y precios"&lt;/p&gt;

&lt;h1&gt;
  
  
  Preparar y publicar el agente
&lt;/h1&gt;

&lt;p&gt;aws bedrock-agent prepare-agent --agent-id TU_AGENT_ID&lt;/p&gt;

&lt;p&gt;aws bedrock-agent create-agent-alias \&lt;br&gt;
  --agent-id TU_AGENT_ID \&lt;br&gt;
  --agent-alias-name "produccion"&lt;br&gt;
Bedrock Customer Code&lt;br&gt;
Invoke the agent (with streaming)&lt;br&gt;
import boto3&lt;/p&gt;

&lt;p&gt;client = boto3.client("bedrock-agent-runtime", region_name="us-east-1")&lt;/p&gt;

&lt;p&gt;def chat_con_agente(mensaje: str, session_id: str) -&amp;gt; str:&lt;br&gt;
    response = client.invoke_agent(&lt;br&gt;
        agentId="PPJ6T6QBDD",&lt;br&gt;
        agentAliasId="VQKXHLAVG1",&lt;br&gt;
        sessionId=session_id,       # Bedrock mantiene el contexto por sessionId&lt;br&gt;
        inputText=mensaje,&lt;br&gt;
    )&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# La respuesta llega como stream de eventos&lt;br&gt;
texto_completo = ""&lt;br&gt;
for event in response.get("completion", []):&lt;br&gt;
    chunk = event.get("chunk", {})&lt;br&gt;
    if "bytes" in chunk:&lt;br&gt;
        texto_completo += chunk["bytes"].decode("utf-8")

&lt;p&gt;return texto_completo or "(sin respuesta)"&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Uso&lt;br&gt;
&lt;/h1&gt;

&lt;p&gt;respuesta = chat_con_agente("¿Cuánto cuesta lavar una chamarra de cuero?", "sesion-123")&lt;br&gt;
print(respuesta)&lt;br&gt;
Consult the Knowledge Base directly (without agent)&lt;br&gt;
def consultar_kb(pregunta: str, kb_id: str) -&amp;gt; str:&lt;br&gt;
    response = client.retrieve_and_generate(&lt;br&gt;
        input={"text": pregunta},&lt;br&gt;
        retrieveAndGenerateConfiguration={&lt;br&gt;
            "type": "KNOWLEDGE_BASE",&lt;br&gt;
            "knowledgeBaseConfiguration": {&lt;br&gt;
                "knowledgeBaseId": kb_id,&lt;br&gt;
                "modelArn": "amazon.nova-lite-v1:0",&lt;br&gt;
                "generationConfiguration": {&lt;br&gt;
                    "promptTemplate": {&lt;br&gt;
                        "textPromptTemplate": (&lt;br&gt;
                            "Eres un asistente de lavandería ecológica. "&lt;br&gt;
                            "Responde basándote en esta información:\n\n"&lt;br&gt;
                            "$search_results$"&lt;br&gt;
                        )&lt;br&gt;
                    }&lt;br&gt;
                },&lt;br&gt;
            },&lt;br&gt;
        },&lt;br&gt;
    )&lt;br&gt;
    return response["output"]["text"]&lt;br&gt;
Multi-context support (multiple clients, one backend)&lt;/p&gt;

&lt;h1&gt;
  
  
  bedrock_client.py — patrón usado en este proyecto
&lt;/h1&gt;

&lt;p&gt;CONFIGS = {&lt;br&gt;
    'aquamax': {&lt;br&gt;
        'type': 'agent',&lt;br&gt;
        'agent_id': 'PPJ6T6QBDD',&lt;br&gt;
        'agent_alias_id': 'VQKXHLAVG1',&lt;br&gt;
    },&lt;br&gt;
    'otro_cliente': {&lt;br&gt;
        'type': 'kb',&lt;br&gt;
        'kb_id': 'KB_ID_DEL_CLIENTE',&lt;br&gt;
        'model_arn': 'amazon.nova-lite-v1:0',&lt;br&gt;
        'prompt': "Eres el asistente de...\n\n$search_results$",&lt;br&gt;
    },&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;def chat(mensaje: str, session_id: str, contexto: str) -&amp;gt; str:&lt;br&gt;
    cfg = CONFIGS.get(contexto, CONFIGS['aquamax'])&lt;br&gt;
    if cfg['type'] == 'agent':&lt;br&gt;
        return _invoke_agent(mensaje, session_id, cfg)&lt;br&gt;
    return _retrieve_and_generate(mensaje, cfg)&lt;br&gt;
Deployment of the backend in Lambda&lt;br&gt;
Package and create the function&lt;br&gt;
cd tintorerias-chatbot&lt;/p&gt;

&lt;h1&gt;
  
  
  Instalar dependencias en carpeta local
&lt;/h1&gt;

&lt;p&gt;pip install flask flask-cors boto3 python-dotenv -t package/&lt;br&gt;
cp app.py bedrock_client.py config.py lambda_handler.py package/&lt;/p&gt;

&lt;h1&gt;
  
  
  Crear ZIP de despliegue
&lt;/h1&gt;

&lt;p&gt;cd package &amp;amp;&amp;amp; zip -r ../lambda_deployment.zip . &amp;amp;&amp;amp; cd ..&lt;/p&gt;

&lt;h1&gt;
  
  
  Obtener Account ID
&lt;/h1&gt;

&lt;p&gt;ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)&lt;/p&gt;

&lt;h1&gt;
  
  
  Crear rol IAM con permisos mínimos
&lt;/h1&gt;

&lt;p&gt;aws iam create-role \&lt;br&gt;
  --role-name tintorerias-lambda-role \&lt;br&gt;
  --assume-role-policy-document '{&lt;br&gt;
    "Version":"2012-10-17",&lt;br&gt;
    "Statement":[{&lt;br&gt;
      "Effect":"Allow",&lt;br&gt;
      "Principal":{"Service":"lambda.amazonaws.com"},&lt;br&gt;
      "Action":"sts:AssumeRole"&lt;br&gt;
    }]&lt;br&gt;
  }'&lt;/p&gt;

&lt;p&gt;aws iam attach-role-policy \&lt;br&gt;
  --role-name tintorerias-lambda-role \&lt;br&gt;
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole&lt;/p&gt;

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

&lt;h1&gt;
  
  
  Crear la función Lambda
&lt;/h1&gt;

&lt;p&gt;aws lambda create-function \&lt;br&gt;
  --function-name tintorerias-chatbot \&lt;br&gt;
  --runtime python3.11 \&lt;br&gt;
  --role arn:aws:iam::${ACCOUNT_ID}:role/tintorerias-lambda-role \&lt;br&gt;
  --handler lambda_handler.handler \&lt;br&gt;
  --zip-file fileb://lambda_deployment.zip \&lt;br&gt;
  --timeout 30 \&lt;br&gt;
  --memory-size 256 \&lt;br&gt;
  --environment Variables="{&lt;br&gt;
    KB_ID=TU_KB_ID,&lt;br&gt;
    MODEL_ARN=amazon.nova-lite-v1:0,&lt;br&gt;
    AWS_REGION=us-east-1&lt;br&gt;
  }"&lt;br&gt;
Create API Gateway and connect with Lambda&lt;/p&gt;

&lt;h1&gt;
  
  
  Crear HTTP API
&lt;/h1&gt;

&lt;p&gt;API_ID=$(aws apigatewayv2 create-api \&lt;br&gt;
  --name "tintorerias-chat-api" \&lt;br&gt;
  --protocol-type HTTP \&lt;br&gt;
  --query 'ApiId' --output text)&lt;/p&gt;

&lt;h1&gt;
  
  
  Crear integración Lambda
&lt;/h1&gt;

&lt;p&gt;LAMBDA_ARN="arn:aws:lambda:us-east-1:${ACCOUNT_ID}:function:tintorerias-chatbot"&lt;/p&gt;

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

&lt;h1&gt;
  
  
  Ruta POST /chat
&lt;/h1&gt;

&lt;p&gt;aws apigatewayv2 create-route \&lt;br&gt;
  --api-id $API_ID \&lt;br&gt;
  --route-key "POST /chat" \&lt;br&gt;
  --target "integrations/$INTEGRATION_ID"&lt;/p&gt;

&lt;h1&gt;
  
  
  Stage prod con auto-deploy
&lt;/h1&gt;

&lt;p&gt;aws apigatewayv2 create-stage \&lt;br&gt;
  --api-id $API_ID \&lt;br&gt;
  --stage-name prod \&lt;br&gt;
  --auto-deploy&lt;/p&gt;

&lt;h1&gt;
  
  
  Permiso para que API Gateway invoque Lambda
&lt;/h1&gt;

&lt;p&gt;aws lambda add-permission \&lt;br&gt;
  --function-name tintorerias-chatbot \&lt;br&gt;
  --statement-id apigateway-invoke \&lt;br&gt;
  --action lambda:InvokeFunction \&lt;br&gt;
  --principal apigateway.amazonaws.com \&lt;br&gt;
  --source-arn "arn:aws:execute-api:us-east-1:${ACCOUNT_ID}:${API_ID}/&lt;em&gt;/&lt;/em&gt;/chat"&lt;/p&gt;

&lt;h1&gt;
  
  
  URL final del endpoint
&lt;/h1&gt;

&lt;p&gt;aws apigatewayv2 get-api --api-id $API_ID --query 'ApiEndpoint' --output text&lt;br&gt;
The chat widget (frontend)&lt;br&gt;
The widget is a self-contained JS file that is injected into any HTML page with a single :&amp;lt;/p&amp;gt;

&amp;lt;script src="chatbot-wiget.js"&amp;gt;

&lt;/p&gt;
&lt;p&gt;Internally it generates its own DOM, styles and logic without depending on any library:&lt;/p&gt;

&lt;p&gt;// Configuración mínima necesaria&lt;br&gt;
const CONFIG = {&lt;br&gt;
  apiUrl: '&lt;a href="https://TU_DOMINIO.cloudfront.net/chat" rel="noopener noreferrer"&gt;https://TU_DOMINIO.cloudfront.net/chat&lt;/a&gt;',&lt;br&gt;
  requestTimeout: 30000,&lt;br&gt;
  context: 'aquamax',   // identifica qué agente/KB usar en el backend&lt;br&gt;
};&lt;/p&gt;

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

&lt;p&gt;// Llamada al backend&lt;br&gt;
fetch(CONFIG.apiUrl, {&lt;br&gt;
  method: 'POST',&lt;br&gt;
  headers: { 'Content-Type': 'application/json' },&lt;br&gt;
  body: JSON.stringify({&lt;br&gt;
    sessionId: state.sessionId,&lt;br&gt;
    message: texto,&lt;br&gt;
    context: CONFIG.context,&lt;br&gt;
  }),&lt;br&gt;
});&lt;br&gt;
Test the endpoint in production&lt;/p&gt;

&lt;h1&gt;
  
  
  Pregunta simple
&lt;/h1&gt;

&lt;p&gt;curl -X POST &lt;a href="https://TU_DOMINIO.cloudfront.net/chat" rel="noopener noreferrer"&gt;https://TU_DOMINIO.cloudfront.net/chat&lt;/a&gt; \&lt;br&gt;
  -H "Content-Type: application/json" \&lt;br&gt;
  -d '{"sessionId":"test-1","message":"¿Cuáles son sus servicios?","context":"aquamax"}'&lt;/p&gt;

&lt;h1&gt;
  
  
  Pregunta de seguimiento (mismo sessionId — el agente recuerda el contexto)
&lt;/h1&gt;

&lt;p&gt;curl -X POST &lt;a href="https://TU_DOMINIO.cloudfront.net/chat" rel="noopener noreferrer"&gt;https://TU_DOMINIO.cloudfront.net/chat&lt;/a&gt; \&lt;br&gt;
  -H "Content-Type: application/json" \&lt;br&gt;
  -d '{"sessionId":"test-1","message":"¿Y cuánto tiempo tarda?","context":"aquamax"}'&lt;/p&gt;

&lt;h1&gt;
  
  
  Respuesta esperada
&lt;/h1&gt;

&lt;h1&gt;
  
  
  { "response": "Ofrecemos lavado en seco ecológico, lavado de ropa delicada..." }
&lt;/h1&gt;

&lt;p&gt;Update the deployment&lt;/p&gt;

&lt;h1&gt;
  
  
  Backend — reconstruir y subir Lambda
&lt;/h1&gt;

&lt;p&gt;cd tintorerias-chatbot&lt;br&gt;
pip install flask flask-cors boto3 python-dotenv -t package/&lt;br&gt;
cp app.py bedrock_client.py config.py lambda_handler.py package/&lt;br&gt;
cd package &amp;amp;&amp;amp; zip -r ../lambda_deployment.zip . &amp;amp;&amp;amp; cd ..&lt;br&gt;
aws lambda update-function-code \&lt;br&gt;
  --function-name tintorerias-chatbot \&lt;br&gt;
  --zip-file fileb://lambda_deployment.zip&lt;/p&gt;

&lt;h1&gt;
  
  
  Frontend — subir y limpiar caché de CloudFront
&lt;/h1&gt;

&lt;p&gt;aws s3 cp index.html       s3://$BUCKET_NAME/&lt;br&gt;
aws s3 cp chatbot-wiget.js s3://$BUCKET_NAME/&lt;br&gt;
aws cloudfront create-invalidation \&lt;br&gt;
  --distribution-id $DISTRIBUTION_ID \&lt;br&gt;
  --paths "/*"&lt;/p&gt;

&lt;p&gt;Why this stack is ideal for local businesses&lt;br&gt;
Almost zero cost at rest — Lambda and API Gateway charge per invocation, not per hour. A chatbot with moderate traffic costs pennies a month.&lt;br&gt;
No server maintenance — no EC2 to patch, no containers to monitor.&lt;br&gt;
Automatic scale — from 0 to thousands of simultaneous users without additional configuration.&lt;br&gt;
Knowledge of real business — the RAG Knowledge Base ensures that the assistant responds with up-to-date business information, not generic model data.&lt;br&gt;
Reusable — the same backend supports multiple clients by changing only the field context in the petition.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>aws</category>
      <category>devops</category>
    </item>
    <item>
      <title>AWS Observability vs OpenTelemetry</title>
      <dc:creator>YUVARAJ. R</dc:creator>
      <pubDate>Sat, 18 Apr 2026 07:23:02 +0000</pubDate>
      <link>https://dev.to/yuvaraj_r_25388937f9607d/aws-observability-vs-opentelemetry-devops-10oo</link>
      <guid>https://dev.to/yuvaraj_r_25388937f9607d/aws-observability-vs-opentelemetry-devops-10oo</guid>
      <description>&lt;p&gt;observability&lt;br&gt;
After using AWS-native observability (CloudWatch/X-Ray) as my default choice for nearly a decade, I recently implemented an open-source observability stack for a greenfield project. Here's what I learned about when to use each approach.&lt;/p&gt;

&lt;p&gt;Why I Explored OpenTelemetry&lt;br&gt;
For the past 9 years, every AWS project I worked on used CloudWatch and X-Ray. It was automatic — spin up services, observability comes built-in. No complaints.&lt;/p&gt;

&lt;p&gt;Then came a project with a twist: the application needed to run across multiple clouds. AWS-native observability simply wasn't an option.&lt;/p&gt;

&lt;p&gt;That led me to explore alternatives — both paid and open-source. After analyzing several options, we landed on OpenTelemetry. The paid tools were impressive, but we didn't want to trade one vendor lock-in for another.&lt;/p&gt;

&lt;p&gt;What I Still Like About CloudWatch/X-Ray&lt;br&gt;
Let me be clear: CloudWatch and X-Ray are excellent tools. Here's where they shine:&lt;/p&gt;

&lt;p&gt;Zero setup friction. You can get up and running in no time. Almost no code required — everything works out of the box.&lt;/p&gt;

&lt;p&gt;Native integration. CloudWatch talks to Lambda, API Gateway, DynamoDB, and every other AWS service without configuration. It just works.&lt;/p&gt;

&lt;p&gt;Perfect for getting started. When you're building an MVP or early-stage product, you don't need a complex observability pipeline. You need to ship. CloudWatch lets you do that.&lt;/p&gt;

&lt;p&gt;Where CloudWatch Falls Short&lt;br&gt;
After years of using it, I've hit some consistent pain points:&lt;/p&gt;

&lt;p&gt;Customization is hard. The visualization is rigid. Widget limitations and cross-account/cross-region constraints get frustrating as your system grows.&lt;/p&gt;

&lt;p&gt;Connecting the dots is painful. Correlating metrics, logs, and traces in a single view requires significant configuration and code. It's possible, but not seamless.&lt;/p&gt;

&lt;p&gt;These aren't deal-breakers for simple architectures. But when you're running distributed systems across environments, they start to compound.&lt;/p&gt;

&lt;p&gt;Setting Up OpenTelemetry&lt;br&gt;
For our stack, we chose:&lt;/p&gt;

&lt;p&gt;Prometheus for metrics&lt;br&gt;
Jaeger for traces&lt;br&gt;
OpenSearch for logs&lt;br&gt;
Grafana for visualization&lt;br&gt;
OpenTelemetry has become an industry standard with strong community support and integrations with virtually every observability tool on the market.&lt;/p&gt;

&lt;p&gt;What surprised me: The configuration is simple yet powerful. It covers not just the application layer but the underlying system as well. OpenTelemetry exports data to specialized tools (Prometheus, Jaeger, OpenSearch), and Grafana ties it all together with end-to-end request lifecycle visualization.&lt;/p&gt;

&lt;p&gt;Setup time: A few hours to get a working proof-of-concept. We've since automated the entire setup with Ansible, making it repeatable across environments.&lt;/p&gt;

&lt;p&gt;To be clear: a few hours gets you a PoC. Production-ready deployment — handling high-cardinality metrics, tuning collectors, configuring retention, setting up alerting — is a multi-week effort. Don't underestimate it.&lt;/p&gt;

&lt;p&gt;The Hybrid Approach: Managed OTel on AWS&lt;br&gt;
There's a middle ground worth mentioning: AWS now heavily supports OpenTelemetry.&lt;/p&gt;

&lt;p&gt;AWS Distro for OpenTelemetry (ADOT) lets you instrument with vendor-neutral OTel code, but route telemetry to Amazon Managed Prometheus (AMP) and Amazon Managed Grafana (AMG).&lt;/p&gt;

&lt;p&gt;This gives you:&lt;/p&gt;

&lt;p&gt;→ Vendor-neutral instrumentation (no code lock-in)&lt;br&gt;
→ Managed infrastructure (no self-hosting headaches)&lt;br&gt;
→ AWS-native billing and support&lt;/p&gt;

&lt;p&gt;For teams who want portability at the application layer but don't want to manage Prometheus/OpenSearch clusters, this is the smart middle path.&lt;/p&gt;

&lt;p&gt;We chose full self-hosting because our multi-cloud requirement included non-AWS environments. But if you're AWS-primary with future portability concerns, ADOT + AMP + AMG is worth evaluating.&lt;/p&gt;

&lt;p&gt;The Real Comparison&lt;br&gt;
Here's how the two approaches stack up in practice:&lt;/p&gt;

&lt;p&gt;Dimension   CloudWatch/X-Ray    OpenTelemetry&lt;br&gt;
Setup time  Almost none Few hours (PoC) / weeks (production)&lt;br&gt;
Customization   Hard    Easy&lt;br&gt;
SaaS invoice    $$$ $&lt;br&gt;
Total Cost of Ownership $$  $$ (shifts to compute + engineering)&lt;br&gt;
Multi-cloud support No  Yes&lt;br&gt;
Debugging experience    Easy    Easy&lt;br&gt;
Team learning curve Easy    Easy&lt;br&gt;
A note on cost: OpenTelemetry software is free, but self-hosting isn't. Running OpenSearch clusters, Prometheus instances, and EBS volumes for retention can get expensive at scale — not to mention engineering hours for index management, patching, and scaling. OTel lowers your SaaS invoice, but shifts the cost to compute and engineering time. It's a strategic reinvestment, not a simple cost-saving.&lt;/p&gt;

&lt;p&gt;Where OpenTelemetry wins: Cloud-agnostic solutions without vendor lock-in. Same monitoring capabilities for on-premises and internal applications. When we needed identical observability for internal applications running on on-prem servers, the OTel stack worked flawlessly.&lt;/p&gt;

&lt;p&gt;Where CloudWatch wins: Quick deployment on AWS when you want an efficient, no-code monitoring solution.&lt;/p&gt;

&lt;p&gt;The Operational Reality&lt;br&gt;
Running your own observability stack isn't free. Here's what I've learned:&lt;/p&gt;

&lt;p&gt;Index management is painful. Managing indices for logs and traces in OpenSearch requires ongoing attention. It's not set-and-forget.&lt;/p&gt;

&lt;p&gt;Reliability requires planning. Early on, Prometheus stopped accepting requests due to high call volume. Once we started batching requests, it stabilized. But it was a reminder: you're now responsible for your monitoring infrastructure.&lt;/p&gt;

&lt;p&gt;Monitoring the monitor. We use Grafana alerts to notify us of any downtime in the observability pipeline itself. Yes, you need to monitor your monitoring.&lt;/p&gt;

&lt;p&gt;Cost comparison: OpenTelemetry is cheaper than most paid solutions in terms of licensing. But factor in compute, storage, and engineering time. There are no restrictions on application count, call volume, or data retention — retention depends entirely on your needs and infrastructure budget. Maintenance has its overhead, but so does running any production system.&lt;/p&gt;

&lt;p&gt;Team Adaptation&lt;br&gt;
The team was happy. Using the same tooling everywhere meant consistent knowledge across environments. Same dashboards, same queries, same debugging workflows — whether troubleshooting AWS, another cloud, or on-prem.&lt;/p&gt;

&lt;p&gt;Skills required: Prometheus and Grafana experience was important for our team. Jaeger and OpenSearch were easier to pick up.&lt;/p&gt;

&lt;p&gt;Small teams: It depends entirely on the application's architecture and roadmap. A distributed, multi-cloud application in maintenance mode can actually be managed by a small team if the automation is solid. However, for a 2-3 person team building a fresh AWS-only MVP, the overhead of OTel might be a distraction.&lt;/p&gt;

&lt;p&gt;My Decision Framework&lt;br&gt;
When a CTO asks me "CloudWatch or OpenTelemetry?", I ask three questions:&lt;/p&gt;

&lt;p&gt;Where will your applications run? AWS only, or multiple environments?&lt;br&gt;
Is AWS the only cloud you're targeting? Now and in the future?&lt;br&gt;
Are you willing to invest in monitoring infrastructure right now?&lt;br&gt;
My rule of thumb:&lt;/p&gt;

&lt;p&gt;If you're targeting AWS only and it's a new product, the AWS observability stack gets you up and running in no time.&lt;br&gt;
If you want future portability without self-hosting, consider the hybrid approach (ADOT + AMP + AMG).&lt;br&gt;
If you have a mature product with multiple microservices, multi-cloud requirements, and don't want vendor lock-in, choose full OTel.&lt;br&gt;
For my next greenfield project: It depends. For serverless development, AWS observability still suits perfectly. But if I'm building a distributed system with multi-cloud support, OpenTelemetry will be my default choice.&lt;/p&gt;

&lt;p&gt;The Future of Observability&lt;br&gt;
Every major paid monitoring tool now supports OpenTelemetry. That tells you where the industry is heading. The community support is massive and growing.&lt;/p&gt;

&lt;p&gt;OpenTelemetry is becoming the standard — not because it's free, but because it solves real problems around portability and vendor independence.&lt;/p&gt;

&lt;p&gt;The Unbeatable Value of Traces&lt;br&gt;
If I could only have one observability signal — logs, metrics, or traces — I'd choose traces without hesitation.&lt;/p&gt;

&lt;p&gt;Here's why: as systems evolve from simple APIs into distributed orchestration layers (Kubernetes, event-driven pipelines, multi-service workflows), logs lose context rapidly. A log line tells you something happened. A trace tells you why, where, and how long it took across every hop.&lt;/p&gt;

&lt;p&gt;For debugging distributed systems, tracing is irreplaceable.&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;br&gt;
Use CloudWatch/X-Ray when you need to hit the ground running on AWS with zero setup friction. Use OpenTelemetry when you need a mature, cloud-agnostic standard that grows with your multi-cloud or on-prem architecture without vendor lock-in.&lt;/p&gt;

&lt;p&gt;One thing most people get wrong about observability: it's not a silver bullet. It gives you insight, but at the end of the day, it's still a developer's responsibility to write performant code.&lt;/p&gt;

&lt;p&gt;Any regrets going the OpenTelemetry route? None so far.&lt;/p&gt;

&lt;p&gt;What drove your observability strategy? Running OpenTelemetry in production — how are you managing collector infrastructure and reliability? I'd love to hear your experience.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
