<?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: felino33</title>
    <description>The latest articles on DEV Community by felino33 (@felino33).</description>
    <link>https://dev.to/felino33</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%2F1222398%2F408f556b-94b5-4ce0-9b60-2e3ab738dcab.png</url>
      <title>DEV Community: felino33</title>
      <link>https://dev.to/felino33</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/felino33"/>
    <language>en</language>
    <item>
      <title>AWS ChatBot_Lavanderia</title>
      <dc:creator>felino33</dc:creator>
      <pubDate>Fri, 17 Apr 2026 03:43:03 +0000</pubDate>
      <link>https://dev.to/felino33/aws-chatbotlavanderia-262g</link>
      <guid>https://dev.to/felino33/aws-chatbotlavanderia-262g</guid>
      <description>&lt;h1&gt;
  
  
  💧 Chatbot con Amazon Bedrock Agent + Knowledge Base RAG — Lavandería Ecológica
&lt;/h1&gt;

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




&lt;h2&gt;
  
  
  ¿Por qué Amazon Bedrock Agent?
&lt;/h2&gt;

&lt;p&gt;La mayoría de los chatbots simples solo responden con texto genérico. Un &lt;strong&gt;Bedrock Agent&lt;/strong&gt; va más allá:&lt;/p&gt;

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

&lt;p&gt;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.&lt;/p&gt;




&lt;h2&gt;
  
  
  Arquitectura completa
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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)   │  │
  │               └──────────────────────┘  │
  └─────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Servicio AWS&lt;/th&gt;
&lt;th&gt;Rol en el proyecto&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon Bedrock Agent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Orquesta la conversación, mantiene sesión, decide cuándo consultar la KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bedrock Knowledge Base&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Indexa documentos del negocio, responde con RAG (Retrieval-Augmented Generation)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon Nova-Lite v1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Modelo de lenguaje — rápido y económico para chat en producción&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Lambda&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ejecuta el backend Flask sin servidores, escala a cero cuando no hay tráfico&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;API Gateway HTTP API&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Expone el endpoint &lt;code&gt;/chat&lt;/code&gt; con baja latencia y manejo de CORS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon S3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Almacena el frontend estático y los documentos fuente de la Knowledge Base&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon CloudFront&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CDN global — sirve el frontend y enruta &lt;code&gt;/chat&lt;/code&gt; al backend desde el mismo dominio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS IAM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Controla permisos mínimos entre Lambda y Bedrock&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Cómo funciona el flujo de una pregunta
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Configuración del Bedrock Agent
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Crear la Knowledge Base
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Subir documentos fuente al bucket S3&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;documentos/ s3://tintorerias-kb-docs/ &lt;span class="nt"&gt;--recursive&lt;/span&gt;

&lt;span class="c"&gt;# 2. Crear la Knowledge Base (desde consola o CLI)&lt;/span&gt;
aws bedrock-agent create-knowledge-base &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"tintorerias-ecologicas-kb"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--description&lt;/span&gt; &lt;span class="s2"&gt;"Documentos de servicios, precios y procesos ecológicos"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role-arn&lt;/span&gt; arn:aws:iam::ACCOUNT_ID:role/AmazonBedrockExecutionRoleForKnowledgeBase &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--knowledge-base-configuration&lt;/span&gt; &lt;span class="s1"&gt;'{
    "type": "VECTOR",
    "vectorKnowledgeBaseConfiguration": {
      "embeddingModelArn": "arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-embed-text-v1"
    }
  }'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--storage-configuration&lt;/span&gt; &lt;span class="s1"&gt;'{
    "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"
      }
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Crear el Data Source y sincronizar
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Crear data source apuntando al bucket S3&lt;/span&gt;
aws bedrock-agent create-data-source &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--knowledge-base-id&lt;/span&gt; TU_KB_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"documentos-tintorerias"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-source-configuration&lt;/span&gt; &lt;span class="s1"&gt;'{
    "type": "S3",
    "s3Configuration": {
      "bucketArn": "arn:aws:s3:::tintorerias-kb-docs"
    }
  }'&lt;/span&gt;

&lt;span class="c"&gt;# Iniciar sincronización (indexación de documentos)&lt;/span&gt;
aws bedrock-agent start-ingestion-job &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--knowledge-base-id&lt;/span&gt; TU_KB_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-source-id&lt;/span&gt; TU_DATA_SOURCE_ID

&lt;span class="c"&gt;# Verificar estado de la sincronización&lt;/span&gt;
aws bedrock-agent get-ingestion-job &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--knowledge-base-id&lt;/span&gt; TU_KB_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-source-id&lt;/span&gt; TU_DATA_SOURCE_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ingestion-job-id&lt;/span&gt; TU_JOB_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Crear el Agente y asociar la Knowledge Base
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Crear el agente&lt;/span&gt;
aws bedrock-agent create-agent &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--agent-name&lt;/span&gt; &lt;span class="s2"&gt;"asistente-tintorerias"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--agent-resource-role-arn&lt;/span&gt; arn:aws:iam::ACCOUNT_ID:role/AmazonBedrockExecutionRoleForAgents &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--foundation-model&lt;/span&gt; &lt;span class="s2"&gt;"amazon.nova-lite-v1:0"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--instruction&lt;/span&gt; &lt;span class="s2"&gt;"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;/span&gt;

&lt;span class="c"&gt;# Asociar la Knowledge Base al agente&lt;/span&gt;
aws bedrock-agent associate-agent-knowledge-base &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--agent-id&lt;/span&gt; TU_AGENT_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--agent-version&lt;/span&gt; DRAFT &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--knowledge-base-id&lt;/span&gt; TU_KB_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--description&lt;/span&gt; &lt;span class="s2"&gt;"Base de conocimiento de servicios y precios"&lt;/span&gt;

&lt;span class="c"&gt;# Preparar y publicar el agente&lt;/span&gt;
aws bedrock-agent prepare-agent &lt;span class="nt"&gt;--agent-id&lt;/span&gt; TU_AGENT_ID

aws bedrock-agent create-agent-alias &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--agent-id&lt;/span&gt; TU_AGENT_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--agent-alias-name&lt;/span&gt; &lt;span class="s2"&gt;"produccion"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Código del cliente Bedrock
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Invocar el agente (con streaming)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bedrock-agent-runtime&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-east-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;chat_con_agente&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mensaje&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;agentId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PPJ6T6QBDD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;agentAliasId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;VQKXHLAVG1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;sessionId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# Bedrock mantiene el contexto por sessionId
&lt;/span&gt;        &lt;span class="n"&gt;inputText&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;mensaje&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# La respuesta llega como stream de eventos
&lt;/span&gt;    &lt;span class="n"&gt;texto_completo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;completion&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt;
        &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chunk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bytes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;texto_completo&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bytes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;texto_completo&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(sin respuesta)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Uso
&lt;/span&gt;&lt;span class="n"&gt;respuesta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;chat_con_agente&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;¿Cuánto cuesta lavar una chamarra de cuero?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sesion-123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;respuesta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Consultar la Knowledge Base directamente (sin agente)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;consultar_kb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pregunta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kb_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retrieve_and_generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pregunta&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;retrieveAndGenerateConfiguration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;KNOWLEDGE_BASE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;knowledgeBaseConfiguration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;knowledgeBaseId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kb_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;modelArn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon.nova-lite-v1:0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generationConfiguration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;promptTemplate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;textPromptTemplate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Eres un asistente de lavandería ecológica. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Responde basándote en esta información:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$search_results$&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                        &lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Soporte multi-contexto (varios clientes, un backend)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# bedrock_client.py — patrón usado en este proyecto
&lt;/span&gt;&lt;span class="n"&gt;CONFIGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;aquamax&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;agent_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PPJ6T6QBDD&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;agent_alias_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;VQKXHLAVG1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;otro_cliente&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;kb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;kb_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;KB_ID_DEL_CLIENTE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;model_arn&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;amazon.nova-lite-v1:0&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Eres el asistente de...&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;$search_results$&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mensaje&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contexto&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CONFIGS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contexto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CONFIGS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;aquamax&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;_invoke_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mensaje&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;_retrieve_and_generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mensaje&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Despliegue del backend en Lambda
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Empaquetar y crear la función
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;tintorerias-chatbot

&lt;span class="c"&gt;# Instalar dependencias en carpeta local&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;flask flask-cors boto3 python-dotenv &lt;span class="nt"&gt;-t&lt;/span&gt; package/
&lt;span class="nb"&gt;cp &lt;/span&gt;app.py bedrock_client.py config.py lambda_handler.py package/

&lt;span class="c"&gt;# Crear ZIP de despliegue&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;package &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; zip &lt;span class="nt"&gt;-r&lt;/span&gt; ../lambda_deployment.zip &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; ..

&lt;span class="c"&gt;# Obtener Account ID&lt;/span&gt;
&lt;span class="nv"&gt;ACCOUNT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws sts get-caller-identity &lt;span class="nt"&gt;--query&lt;/span&gt; Account &lt;span class="nt"&gt;--output&lt;/span&gt; text&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Crear rol IAM con permisos mínimos&lt;/span&gt;
aws iam create-role &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role-name&lt;/span&gt; tintorerias-lambda-role &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--assume-role-policy-document&lt;/span&gt; &lt;span class="s1"&gt;'{
    "Version":"2012-10-17",
    "Statement":[{
      "Effect":"Allow",
      "Principal":{"Service":"lambda.amazonaws.com"},
      "Action":"sts:AssumeRole"
    }]
  }'&lt;/span&gt;

aws iam attach-role-policy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role-name&lt;/span&gt; tintorerias-lambda-role &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--policy-arn&lt;/span&gt; arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

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

&lt;span class="c"&gt;# Crear la función Lambda&lt;/span&gt;
aws lambda create-function &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--function-name&lt;/span&gt; tintorerias-chatbot &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--runtime&lt;/span&gt; python3.11 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role&lt;/span&gt; arn:aws:iam::&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ACCOUNT_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:role/tintorerias-lambda-role &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--handler&lt;/span&gt; lambda_handler.handler &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--zip-file&lt;/span&gt; fileb://lambda_deployment.zip &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--timeout&lt;/span&gt; 30 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--memory-size&lt;/span&gt; 256 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--environment&lt;/span&gt; &lt;span class="nv"&gt;Variables&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{
    KB_ID=TU_KB_ID,
    MODEL_ARN=amazon.nova-lite-v1:0,
    AWS_REGION=us-east-1
  }"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Crear API Gateway y conectar con Lambda
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Crear HTTP API&lt;/span&gt;
&lt;span class="nv"&gt;API_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws apigatewayv2 create-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"tintorerias-chat-api"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--protocol-type&lt;/span&gt; HTTP &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'ApiId'&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; text&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Crear integración Lambda&lt;/span&gt;
&lt;span class="nv"&gt;LAMBDA_ARN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:us-east-1:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ACCOUNT_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:function:tintorerias-chatbot"&lt;/span&gt;

&lt;span class="nv"&gt;INTEGRATION_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws apigatewayv2 create-integration &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--api-id&lt;/span&gt; &lt;span class="nv"&gt;$API_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--integration-type&lt;/span&gt; AWS_PROXY &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--integration-uri&lt;/span&gt; &lt;span class="nv"&gt;$LAMBDA_ARN&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--payload-format-version&lt;/span&gt; &lt;span class="s2"&gt;"2.0"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'IntegrationId'&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; text&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Ruta POST /chat&lt;/span&gt;
aws apigatewayv2 create-route &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--api-id&lt;/span&gt; &lt;span class="nv"&gt;$API_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--route-key&lt;/span&gt; &lt;span class="s2"&gt;"POST /chat"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--target&lt;/span&gt; &lt;span class="s2"&gt;"integrations/&lt;/span&gt;&lt;span class="nv"&gt;$INTEGRATION_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Stage prod con auto-deploy&lt;/span&gt;
aws apigatewayv2 create-stage &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--api-id&lt;/span&gt; &lt;span class="nv"&gt;$API_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--stage-name&lt;/span&gt; prod &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--auto-deploy&lt;/span&gt;

&lt;span class="c"&gt;# Permiso para que API Gateway invoque Lambda&lt;/span&gt;
aws lambda add-permission &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--function-name&lt;/span&gt; tintorerias-chatbot &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--statement-id&lt;/span&gt; apigateway-invoke &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--action&lt;/span&gt; lambda:InvokeFunction &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--principal&lt;/span&gt; apigateway.amazonaws.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--source-arn&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:execute-api:us-east-1:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ACCOUNT_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;API_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/*/*/chat"&lt;/span&gt;

&lt;span class="c"&gt;# URL final del endpoint&lt;/span&gt;
aws apigatewayv2 get-api &lt;span class="nt"&gt;--api-id&lt;/span&gt; &lt;span class="nv"&gt;$API_ID&lt;/span&gt; &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'ApiEndpoint'&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  El widget de chat (frontend)
&lt;/h2&gt;

&lt;p&gt;El widget es un archivo JS autocontenido que se inyecta en cualquier página HTML con un solo &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"chatbot-wiget.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Internamente genera su propio DOM, estilos y lógica sin depender de ninguna librería:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Configuración mínima necesaria&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CONFIG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://TU_DOMINIO.cloudfront.net/chat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;requestTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aquamax&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// identifica qué agente/KB usar en el backend&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;span class="c1"&gt;// Llamada al backend&lt;/span&gt;
&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CONFIG&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CONFIG&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Probar el endpoint en producción
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Pregunta simple&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://TU_DOMINIO.cloudfront.net/chat &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"sessionId":"test-1","message":"¿Cuáles son sus servicios?","context":"aquamax"}'&lt;/span&gt;

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

&lt;span class="c"&gt;# Respuesta esperada&lt;/span&gt;
&lt;span class="c"&gt;# { "response": "Ofrecemos lavado en seco ecológico, lavado de ropa delicada..." }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Actualizar el despliegue
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Backend — reconstruir y subir Lambda&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;tintorerias-chatbot
pip &lt;span class="nb"&gt;install &lt;/span&gt;flask flask-cors boto3 python-dotenv &lt;span class="nt"&gt;-t&lt;/span&gt; package/
&lt;span class="nb"&gt;cp &lt;/span&gt;app.py bedrock_client.py config.py lambda_handler.py package/
&lt;span class="nb"&gt;cd &lt;/span&gt;package &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; zip &lt;span class="nt"&gt;-r&lt;/span&gt; ../lambda_deployment.zip &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; ..
aws lambda update-function-code &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--function-name&lt;/span&gt; tintorerias-chatbot &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--zip-file&lt;/span&gt; fileb://lambda_deployment.zip

&lt;span class="c"&gt;# Frontend — subir y limpiar caché de CloudFront&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;index.html       s3://&lt;span class="nv"&gt;$BUCKET_NAME&lt;/span&gt;/
aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;chatbot-wiget.js s3://&lt;span class="nv"&gt;$BUCKET_NAME&lt;/span&gt;/
aws cloudfront create-invalidation &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--distribution-id&lt;/span&gt; &lt;span class="nv"&gt;$DISTRIBUTION_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--paths&lt;/span&gt; &lt;span class="s2"&gt;"/*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Por qué este stack es ideal para negocios locales
&lt;/h2&gt;

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




&lt;h2&gt;
  
  
  Licencia
&lt;/h2&gt;

&lt;p&gt;Proyecto privado — todos los derechos reservados.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>aws</category>
      <category>rag</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Completely serverless architecture using AWS services. Part 1</title>
      <dc:creator>felino33</dc:creator>
      <pubDate>Tue, 20 Feb 2024 23:11:40 +0000</pubDate>
      <link>https://dev.to/felino33/completely-serverless-architecture-using-aws-services-part-1-28n4</link>
      <guid>https://dev.to/felino33/completely-serverless-architecture-using-aws-services-part-1-28n4</guid>
      <description>&lt;p&gt;Introduction:&lt;br&gt;
Despite its name, serverless does not mean a serverless existence. Rather, it indicates a &lt;br&gt;
change in responsibility: developers no longer need to manage, provision, or view the &lt;br&gt;
underlying servers. This allows them to focus on creating efficient code without the distractions &lt;br&gt;
of server complexities.&lt;/p&gt;

&lt;p&gt;By entering serverless computing services, where developers can be freed from server &lt;br&gt;
management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5hjjd5lu06v1auhcthty.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5hjjd5lu06v1auhcthty.png" alt="Image description" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Serverless means serverless, it is a solution that allows you to create and run applications &lt;br&gt;
quickly and with a lower total cost of ownership, since it is not necessary to provision and &lt;br&gt;
manage infrastructure.&lt;/p&gt;

&lt;p&gt;Of course, behind it there are servers to run the applications, but the cloud provider is &lt;br&gt;
in charge of the administration, therefore, on our side we stop worrying about managing &lt;br&gt;
servers, operating systems, software and other resources, and we only focus on the &lt;br&gt;
application code.&lt;/p&gt;

&lt;p&gt;Key Services and Features:&lt;br&gt;
Serverless means serverless, it is a solution that allows you to create and run applications &lt;br&gt;
quickly and with a lower total cost of ownership, since it is not necessary to provision and &lt;br&gt;
manage infrastructure.&lt;br&gt;
Let's explore the key services and features of this AWS architecture:&lt;/p&gt;

&lt;p&gt;1-AWS Lambda:&lt;br&gt;
AWS Lambda, a pioneer in serverless computing, introduces virtual functions that &lt;br&gt;
eliminate the need for manual server management. Focusing on&lt;br&gt;
For short executions, Lambda operates on demand, ensuring efficient resource &lt;br&gt;
utilization. Its automated scaling feature adapts perfectly to different workloads, ensuring &lt;br&gt;
optimal performance. Lambda is integrated with many programming languages &lt;br&gt;
and a full set of AWS services and can be easily monitored through AWS cloudwatch. &lt;br&gt;
AWS Lambda serves as an ideal solution to run our cloud-native API code &lt;br&gt;
efficiently while maintaining minimal costs.&lt;/p&gt;

&lt;p&gt;2-Aurora Serverless:&lt;br&gt;
A powerhouse in the cloud database space, Aurora fully supports Postgres and &lt;br&gt;
MySQL. Positioned as “optimized for the AWS cloud,” Aurora boasts a notable 5x &lt;br&gt;
performance improvement over MySQL on RDS and over 3x the performance over Postgres &lt;br&gt;
on RDS. Offering up to 15 replicas with a faster replication process than MySQL. With instant &lt;br&gt;
failover, it is inherently designed for High Availability (HA), although it has a slightly &lt;br&gt;
higher cost than RDS (20% more), its efficiency and performance make it a compelling &lt;br&gt;
option for storing our API structured data.&lt;/p&gt;

&lt;p&gt;3-Amazon Simple Storage Service (S3):&lt;br&gt;
S3 is one of the most popular offerings from AWS. S3 is a highly available, durable objectbased storage service. S3 allows objects (files) to be stored in buckets with a globally &lt;br&gt;
unique name. In this case, we use S3 to store the API binary image data (JPEG, JPG, PNG).&lt;/p&gt;

&lt;p&gt;4-API Gateway:&lt;br&gt;
AWS Lambda together with API Gateway presents a hassle-free solution with no &lt;br&gt;
infrastructure management. API Gateway not only supports HTTP and REST protocols &lt;br&gt;
but also WebSocket protocol and also skillfully handles API version control (such as v1, &lt;br&gt;
v2) and various environments (development, test, production). API Gateway also covers &lt;br&gt;
authentication and authorization, along with the ability to create API keys and manage &lt;br&gt;
request throttling. In addition, it excels in transforming and validating requests and &lt;br&gt;
responses, allowing the generation of SDKs and API specifications. With the added &lt;br&gt;
ability to cache API responses, API Gateway offers a comprehensive and efficient &lt;br&gt;
ecosystem for developing and managing APIs.&lt;/p&gt;

&lt;p&gt;5-Benefits&lt;br&gt;
AWS Serverless offers significant benefits in terms of scalability, agility, and reduced operating &lt;br&gt;
costs. However, it is essential to perform a detailed cost-benefit analysis specific to &lt;br&gt;
your particular use case and business model. This will allow you to make informed &lt;br&gt;
decisions about adopting AWS Serverless and ensure that your applications are &lt;br&gt;
economically efficient, including providing an efficient, scalable, and cost-effective way to &lt;br&gt;
develop and run applications in the cloud.&lt;/p&gt;

&lt;p&gt;These benefits can help organizations optimize their operations, accelerate application &lt;br&gt;
development, and improve the availability and security of their systems.&lt;/p&gt;

&lt;p&gt;6-Spectrum of serverless services.&lt;br&gt;
Developers using a serverless architecture don't have to worry about policies for extending their code. The &lt;br&gt;
serverless provider handles all on-demand scaling. As a result, a serverless application will be able to handle an &lt;br&gt;
unusually high number of requests as well as it can process a single request from a single user. A &lt;br&gt;
traditionally structured application with a fixed amount of server space can be overwhelmed by a sudden increase &lt;br&gt;
in usage.&lt;/p&gt;

&lt;p&gt;7-What we can do with Serverless&lt;/p&gt;

&lt;p&gt;AWS Serverless offers a wide range of services and capabilities that allow you to build &lt;br&gt;
applications without worrying about server management. Here are some of the things you can &lt;br&gt;
do with AWS Serverless:&lt;/p&gt;

&lt;p&gt;-Data Stream.&lt;br&gt;
-Chatbots and Virtual Assistants.&lt;br&gt;
-Task Automation.&lt;br&gt;
-Data Processing.&lt;br&gt;
-Automatic Scalability.&lt;/p&gt;

&lt;p&gt;Within AWS, Serverless services are highly flexible and allow you to use a combination of services to meet specific needs.&lt;br&gt;
Additionally, you only pay for the amount of resources you actually use, which can result in lower costs compared to traditional server provisioning.&lt;/p&gt;

&lt;p&gt;This is a little tour of some AWS serverless services, feel free to comment.&lt;br&gt;
Luis Enrique Aguilar.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
