<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Caleidos - Medium]]></title>
        <description><![CDATA[Nos enfocamos en la innovación a través de la tecnología, construyendo soluciones que permitan generar un impacto positivo y cambio en las organizaciones. Partners de Amazon Web Services. - Medium]]></description>
        <link>https://medium.com/caleidos?source=rss----4da51aff11a2---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Caleidos - Medium</title>
            <link>https://medium.com/caleidos?source=rss----4da51aff11a2---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 12 Nov 2026 22:52:35 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/caleidos" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[De agentes aislados a ecosistemas interoperables: MCP explicado]]></title>
            <link>https://medium.com/caleidos/de-agentes-aislados-a-ecosistemas-interoperables-mcp-explicado-15e9b2fcf212?source=rss----4da51aff11a2---4</link>
            <guid isPermaLink="false">https://medium.com/p/15e9b2fcf212</guid>
            <category><![CDATA[mcp-protocol]]></category>
            <dc:creator><![CDATA[Claudia Márquez]]></dc:creator>
            <pubDate>Wed, 01 Oct 2025 00:38:08 GMT</pubDate>
            <atom:updated>2025-10-01T00:38:05.077Z</atom:updated>
            <content:encoded><![CDATA[<p>En el último año hemos visto una evolución acelerada en la manera en que construimos aplicaciones con <strong>modelos de lenguaje (LLMs)</strong> y <strong>agentes de IA</strong>. Sin embargo, cada salto de abstracción ha traído también nuevos retos. Para entender la importancia del <strong>Model Context Protocol (MCP)</strong>, exploremos rápidamente este camino.</p><h3>Los inicios: LLMs sin acciones</h3><p>Todo comenzó con los <strong>LLMs</strong>. Estos modelos reciben un <em>input</em> (prompt) del usuario y generan una respuesta. Son muy buenos para producir contenido en base a la data con la que fueron entrenados: escribir un ensayo, resumir un documento, traducir un texto.</p><p>Pero pronto nos encontramos con un límite evidente:<br> ➡️ Los LLMs <strong>no pueden ejecutar acciones en el mundo real</strong>, solo generan texto.</p><h3>Segunda etapa: Agentes con herramientas (tools)</h3><p>La siguiente evolución fueron los <strong>agentes</strong>. Estos aprovechan la capacidad de los LLMs para razonar y generar instrucciones, pero ahora con acceso a <strong>tools</strong> (herramientas externas).</p><p>Con esto, los agentes pueden:</p><ul><li>Consultar una API (ej. <a href="https://medium.com/caleidos/creando-agentes-de-ia-con-strands-agents-6ccf36963696">tipo de cambio de la SUNAT</a>).</li><li>Buscar en la web (como hace Perplexity o ChatGPT).</li><li>Crear archivos o conectarse a sistemas de terceros.</li></ul><p>El LLM no ejecuta la acción directamente, pero decide <strong>cuándo invocar un tool</strong>, y construye la respuesta final con base en el resultado.</p><h3>El problema: acoplamiento de tools y agentes</h3><p>Esto fue un gran avance, pero trajo un reto:<br>Los agentes eran responsables de definir, mantener e integrar todos sus tools.</p><p>➡️ Cada agente terminaba acoplado a su propio set de herramientas, lo que hacía difícil la <strong>reutilización</strong>, <strong>mantenimiento</strong> y <strong>estandarización</strong>.</p><h3>El salto: llega MCP</h3><p>Para resolverlo, <strong>Anthropic </strong><a href="https://www.anthropic.com/news/model-context-protocol"><strong>introdujo el Model Context Protocol (MCP)</strong></a>.</p><p>MCP define un <strong>protocolo estándar</strong> que permite exponer herramientas (<em>capabilities</em>) a los agentes de forma desacoplada.</p><ul><li>Se construye un <strong>MCP Server</strong>, que implementa las acciones (ej. crear un repo en GitHub, consultar documentación de AWS).</li><li>Los agentes actúan como <strong>MCP Clients</strong>, conectándose a los servidores mediante: <strong>stdio</strong> (flujo estándar) o <strong>shttp</strong> (<em>streaming HTTP</em>)</li></ul><p>Los servidores MCP no solo exponen herramientas, también publican <strong>información contextual</strong> como prompts disponibles o descripciones de capabilities. De esta manera, un agente puede decidir dinámicamente qué usar para responder a la petición del usuario.</p><h3>Adopción en el ecosistema</h3><p>En poco tiempo, MCP ha sido ampliamente adoptado. Algunos ejemplos:</p><ul><li><a href="https://github.com/github/github-mcp-server"><strong>GitHub MCP Server</strong></a> → crear repositorios, issues, pull requests.</li><li><a href="https://github.com/awslabs/mcp"><strong>AWS MCP Server</strong></a> → acceder a documentación, ejecutar acciones en servicios cloud.</li></ul><p>Para empresas, MCP significa <strong>modularidad</strong>:</p><ul><li>Los equipos ya no tienen que acoplar sus agentes a tools específicos.</li><li>Pueden construir <strong>MCP Servers reutilizables</strong> y usarlos en múltiples proyectos, simplificando mantenimiento y despliegue.</li></ul><h3>MCP en acción: Amazon Q CLI + GitHub</h3><p>Veamos un ejemplo práctico: configurar el <strong>GitHub MCP Server</strong> dentro de <strong>Amazon Q CLI</strong>.</p><h4>Requisitos previos</h4><ul><li>Tener <a href="https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-installing.html">instalado el <strong>Amazon Q CLI</strong></a>.</li><li>Contar con <strong>Docker en ejecución</strong>.</li><li><a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens">Crear un <strong>GitHub Personal Access Token</strong></a> con los siguientes permisos:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-FCZvV5EwJZp7MOi_LKuRw.png" /></figure><h4>Configuración del archivo mcp.json</h4><p>Dependiendo del alcance que quieras:</p><ul><li><strong>Global (todos los proyectos):</strong> ~/.aws/amazonq/mcp.json</li><li><strong>Solo en un workspace:</strong> .amazonq/mcp.json</li></ul><p>Crea el archivo con este contenido, recuerda cambiar el github personal access token:</p><pre>{<br>  &quot;mcpServers&quot;: {<br>    &quot;github&quot;: {<br>      &quot;command&quot;: &quot;docker&quot;,<br>      &quot;args&quot;: [<br>        &quot;run&quot;,<br>        &quot;-i&quot;,<br>        &quot;--rm&quot;,<br>        &quot;-e&quot;,<br>        &quot;GITHUB_PERSONAL_ACCESS_TOKEN&quot;,<br>        &quot;ghcr.io/github/github-mcp-server&quot;<br>      ],<br>      &quot;env&quot;: {<br>        &quot;GITHUB_PERSONAL_ACCESS_TOKEN&quot;: &quot;&lt;tu-access-token&gt;&quot;<br>      }<br>    }<br>  }<br>}</pre><h4>Uso</h4><p>Ejecuta:</p><pre>q chat</pre><p>Dentro de Amazon Q puedes ver los <strong>tools configurados incluyendo el de github.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*f0XJr-3Ko_CVun3Aq5dlBA.png" /></figure><p>Ahora puedes, por ejemplo, <strong>crear un repositorio directamente desde tu consola</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2DhZwZrxbJXjTM5Y8XnAIw.png" /></figure><h3>Conclusiones</h3><p>El <strong>Model Context Protocol (MCP)</strong> representa un cambio de paradigma:</p><ul><li>Desacopla agentes y herramientas.</li><li>Establece un lenguaje común entre LLMs, agentes y sistemas externos.</li><li>Permite crear ecosistemas de herramientas reutilizables y seguros.</li></ul><p>En otras palabras, MCP nos ayuda a pasar de <em>agentes con herramientas aisladas</em> a un <strong>ecosistema interoperable de capacidades</strong>, mucho más preparado para escalar en entornos reales y empresariales.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=15e9b2fcf212" width="1" height="1" alt=""><hr><p><a href="https://medium.com/caleidos/de-agentes-aislados-a-ecosistemas-interoperables-mcp-explicado-15e9b2fcf212">De agentes aislados a ecosistemas interoperables: MCP explicado</a> was originally published in <a href="https://medium.com/caleidos">Caleidos</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Del prototipo a producción: Desplegando agentes de IA con Amazon Bedrock AgentCore]]></title>
            <link>https://medium.com/caleidos/del-prototipo-a-producci%C3%B3n-desplegando-agentes-de-ia-con-amazon-bedrock-agentcore-bf6d1c570641?source=rss----4da51aff11a2---4</link>
            <guid isPermaLink="false">https://medium.com/p/bf6d1c570641</guid>
            <category><![CDATA[amazon-bedrock-agentcore]]></category>
            <dc:creator><![CDATA[Claudia Márquez]]></dc:creator>
            <pubDate>Mon, 29 Sep 2025 22:47:33 GMT</pubDate>
            <atom:updated>2025-09-29T22:46:57.943Z</atom:updated>
            <content:encoded><![CDATA[<p>En el último año hemos visto un crecimiento acelerado en la construcción de agentes de IA: aplicaciones que no solo responden a un prompt, sino que también son capaces de razonar, planear acciones, invocar herramientas externas y aprender de sus resultados. Sin embargo, llevar un agente desde la etapa de prototipo hasta producción no es trivial: necesitas infraestructura confiable, observabilidad y controles para operar de manera segura y a escala.</p><p>Aquí es donde entra Amazon Bedrock AgentCore.</p><h3>¿Qué es Amazon Bedrock AgentCore?</h3><p>Amazon Bedrock AgentCore es un servicio que permite desplegar y operar agentes de IA altamente capaces de forma segura y escalable. Ofrece:</p><ul><li>Infraestructura optimizada para cargas dinámicas de agentes.</li><li>Integración flexible con frameworks como Strands Agents, LangGraph, LlamaIndex o CrewAI.</li><li>Compatibilidad con cualquier modelo fundacional, tanto dentro como fuera de Amazon Bedrock.</li><li>Controles de operación y observabilidad listos para producción.</li></ul><p>En pocas palabras, elimina el <em>heavy lifting</em> de crear la infraestructura de agentes desde cero, para que los equipos puedan enfocarse en la lógica de negocio y acelerar el paso a producción.</p><p>Actualmente, AgentCore se encuentra en preview, por lo que no lo recomendaría aún para despliegues críticos en producción, pero sí es un momento ideal para explorar sus capacidades y prepararse.</p><h3>Ajustando nuestro agente para AgentCore Runtime</h3><p>En un <a href="https://medium.com/caleidos/creando-agentes-de-ia-con-strands-agents-6ccf36963696">post</a> anterior construimos un agente utilizando <strong>Strands Agents</strong>. Ahora, vamos a integrarlo con <strong>AgentCore Runtime</strong> para desplegarlo.</p><p>Primero, instalamos las librerías necesarias:</p><pre>pip install bedrock-agentcore strands-agents strands-agents-tools</pre><p>Haremos tres modificaciones clave en nuestro agente existente:</p><p><strong>Importar el runtime de Bedrock</strong>:</p><pre>from bedrock_agentcore.runtime import BedrockAgentCoreApp</pre><p><strong>Inicializar la aplicación de AgentCore</strong>:</p><pre>app = BedrockAgentCoreApp()</pre><p><strong>Definir un entrypoint para procesar las solicitudes</strong>:</p><pre>@app.entrypoint<br>def invoke(payload: dict):<br>    &quot;&quot;&quot;Process user input and return a response&quot;&quot;&quot;<br>    user_message = payload.get(&quot;prompt&quot;)<br>    result = agent(user_message)<br>    return {&quot;result&quot;: result.message}<br><br><br>if __name__ == &quot;__main__&quot;:<br>    app.run()</pre><p>Con esto, nuestro agente queda listo para ejecutarse dentro de AgentCore. Este es el código completo de nuestro agente:</p><pre>from strands import Agent, tool<br>from strands_tools import calculator, current_time<br>import requests<br>from datetime import datetime<br>from bedrock_agentcore.runtime import BedrockAgentCoreApp<br><br>app = BedrockAgentCoreApp()<br><br><br>@tool<br>def tipo_cambio_sunat() -&gt; dict:<br>    &quot;&quot;&quot;<br>    Obtiene el tipo de cambio del día de hoy desde SUNAT.<br><br>    Returns:<br>        dict: Diccionario con fecha, tipo de cambio compra y venta<br>              Ejemplo: {&quot;fecha&quot;: &quot;29/09/2025&quot;, &quot;compra&quot;: 3.494, &quot;venta&quot;: 3.502}<br>    &quot;&quot;&quot;<br>    try:<br>        # Hacer request a la URL de SUNAT<br>        url = &quot;https://www.sunat.gob.pe/a/txt/tipoCambio.txt&quot;<br>        response = requests.get(url, timeout=10)<br>        response.raise_for_status()<br><br>        # Parsear la respuesta<br>        # Formato esperado: 29/09/2025|3.494|3.502|<br>        data = response.text.strip()<br>        parts = data.split(&#39;|&#39;)<br><br>        if len(parts) &lt; 3:<br>            raise ValueError(&quot;Formato de respuesta inesperado de SUNAT&quot;)<br><br>        fecha = parts[0]<br>        compra = float(parts[1])<br>        venta = float(parts[2])<br><br>        return {<br>            &quot;fecha&quot;: fecha,<br>            &quot;compra&quot;: compra,<br>            &quot;venta&quot;: venta,<br>            &quot;moneda&quot;: &quot;USD/PEN&quot;<br>        }<br><br>    except requests.RequestException as e:<br>        return {&quot;error&quot;: f&quot;Error al conectar con SUNAT: {str(e)}&quot;}<br>    except (ValueError, IndexError) as e:<br>        return {&quot;error&quot;: f&quot;Error al procesar datos de SUNAT: {str(e)}&quot;}<br>    except Exception as e:<br>        return {&quot;error&quot;: f&quot;Error inesperado: {str(e)}&quot;}<br><br><br># Crea un agente con nuestra tool y tools de la comunidad<br>agent = Agent(tools=[calculator, current_time, tipo_cambio_sunat])<br><br><br>@app.entrypoint<br>def invoke(payload: dict):<br>    &quot;&quot;&quot;Process user input and return a response&quot;&quot;&quot;<br>    user_message = payload.get(&quot;prompt&quot;)<br>    result = agent(user_message)<br>    return {&quot;result&quot;: result.message}<br><br><br>if __name__ == &quot;__main__&quot;:<br>    app.run()</pre><h3>Probando localmente</h3><p>Antes de desplegar en la nube, podemos verificarlo de forma local:</p><pre>python mi_agente.py</pre><p>El servicio se expondrá en el puerto <strong>8080</strong>. Podemos enviarle un prompt de prueba con curl:</p><pre>curl:<br>curl -X POST http://localhost:8080/invocations \<br>-H &quot;Content-Type: application/json&quot; \<br>-d &#39;{&quot;prompt&quot;: &quot;¿Cuál es el tipo de cambio de hoy según SUNAT? Y si tengo 100 dólares, ¿cuántos soles serían al tipo de cambio de venta?&quot;}&#39;</pre><p>La respuesta confirmará que el agente sigue funcionando correctamente bajo AgentCore.</p><pre>{&quot;result&quot;: {&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: [{&quot;text&quot;: &quot;Según SUNAT, el tipo de cambio de hoy **29/09/2025** es:\n- **Compra**: S/ 3.494 por dólar\n- **Venta**: S/ 3.502 por dólar\n\nSi tienes **100 dólares** y los cambias al tipo de cambio de venta, obtendrías:\n**S/ 350.20 soles**\n\nEl tipo de cambio de venta es el que se usa cuando cambias dólares por soles, ya que es el precio al cual las casas de cambio te \&quot;venden\&quot; los soles a cambio de tus dólares.&quot;}]}}</pre><h3>Realizando el despliegue</h3><p>Vamos a realizar el despliegue utilizando el starter toolkit de Amazon Bedrock AgentCore. Lo instalamos con pip:</p><pre>pip install bedrock-agentcore-starter-toolkit</pre><p>Necesitamos crear un archivo llamado requirements.txt con nuestras dependencias:</p><pre>strands-agents<br>bedrock-agentcore<br>strands-agents-tools</pre><p>Luego, realizamos la configuración de nuestro agente con el siguiente comando.</p><pre>agentcore configure -e mi_agente.py</pre><p>Puedes darle enter en todas las preguntas para usar la configuración por defecto.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LOeemVLD8dv-q5sWMBADDw.png" /></figure><p>Ahora procedemos a desplegar el agente con el siguiente comando:</p><pre>agentcore launch</pre><p>Una vez desplegado podemos probarlo con el siguiente comando:</p><pre>agentcore invoke &#39;{&quot;prompt&quot;: &quot;¿Cuál es el tipo de cambio de hoy según SUNAT? Y si tengo 100 dólares, ¿cuántos soles serían al tipo de cambio de venta?&quot;}&#39;</pre><h3>Visualizando el agente en la consola</h3><p>Podemos ingresar al servicio <strong>Amazon Bedrock AgentCore</strong>, seleccionar la opción <strong>Agent Runtime</strong> y hacer clic en nuestro agente.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zJ2to3XSPaRksAdoWJ4EWA.png" /></figure><p>En la página de detalle veremos un ejemplo de cómo invocarlo, y ahí mismo se muestra el <strong>ARN del runtime</strong> que necesitamos copiar para usar en nuestro código.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7hkG0cCLYnbyzqDWKtMXgA.png" /></figure><h3>Interactuando con el agente</h3><p>Para probar nuestro agente de forma rápida, vamos a crear una pequeña aplicación con <strong>Streamlit</strong> que nos dé una interfaz de chat.</p><p>Primero instalamos Streamlit:</p><pre>pip install streamlit</pre><p>Luego creamos un archivo llamado <strong>basic-chat-streamlit.py</strong> con el siguiente contenido:</p><pre>import json<br>import time<br>import uuid<br><br>import boto3<br>import streamlit as st<br><br># Cliente de Bedrock AgentCore<br>agent_core = boto3.client(&quot;bedrock-agentcore&quot;, region_name=&quot;us-east-1&quot;)<br><br># Generar un session_id válido (≥ 33 caracteres)<br>session_id = str(int(time.time())) + &quot;_&quot; + uuid.uuid4().hex<br><br>st.title(&quot;Chat básico con Bedrock AgentCore&quot;)<br>st.write(&quot;Ejemplo: Streamlit + AgentCore Runtime + Strands Agents&quot;)<br><br># ARN del runtime desplegado en AgentCore<br>RUNTIME_ARN = &quot;arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/mi_agente-xxxxxxxxxx&quot;<br><br># Caja de input estilo chat<br>if prompt := st.chat_input(&quot;Escribe tu mensaje...&quot;):<br>    st.chat_message(&quot;user&quot;).write(prompt)<br><br>    with st.spinner(&quot;Consultando al agente...&quot;):<br>        # Invocamos el runtime<br>        response = agent_core.invoke_agent_runtime(<br>            agentRuntimeArn=RUNTIME_ARN,<br>            runtimeSessionId=session_id,<br>            payload=json.dumps({&quot;prompt&quot;: prompt}),<br>            qualifier=&quot;DEFAULT&quot;,<br>        )<br><br>        # Parsear respuesta<br>        result = json.loads(response[&quot;response&quot;].read())<br><br>        # Mostrar respuesta del agente<br>        st.chat_message(&quot;assistant&quot;).write(result[&quot;result&quot;][&quot;content&quot;][0][&quot;text&quot;])</pre><p>👉 <strong>Importante</strong>: recuerda actualizar la <strong>región</strong> y el <strong>RUNTIME_ARN</strong> con los valores de tu propio agente.</p><p>Para ejecutar la aplicación:</p><pre>streamlit run basic-streamlit.py</pre><p>Esto abrirá una interfaz web sencilla donde podrás escribir mensajes y ver las respuestas de tu agente como un chat:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qKc1Dvczb_MsM_hoQwtoug.png" /></figure><h3>Componentes Clave de Amazon Bedrock AgentCore</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*nsBbgFfTDsgTlW1w" /></figure><p>Además del runtime que ya usamos en el ejemplo, <strong>Amazon Bedrock AgentCore trae varios componentes adicionales</strong> que facilitan la vida cuando queremos construir y operar agentes en un entorno empresarial. Aquí un repaso rápido:</p><p><strong>AgentCore Runtime<br></strong>La capa base que da un entorno de ejecución seguro y serverless para correr el código del agente o de sus herramientas. Soporta tanto interacciones en tiempo real con baja latencia como cargas asíncronas que pueden correr hasta 8 horas. Cada sesión está completamente aislada para evitar fugas de datos, y funciona con frameworks open source, modelos y cargas multimodales.</p><p><strong>AgentCore Memory<br></strong>Permite manejar memoria de corto y largo plazo para que los agentes sean <em>context aware</em>. El desarrollador decide qué recordar sin tener que construir toda la infraestructura de memoria. Así, los agentes pueden aprender de interacciones pasadas y traer el contexto adecuado a la conversación.</p><p><strong>AgentCore Identity<br></strong>Un sistema de identidad y acceso diseñado para agentes. Les permite autenticarse de forma segura y acceder a recursos o herramientas. Se integra con proveedores de identidad como Amazon Cognito, Microsoft Entra ID o Okta, y habilita acceso a recursos de AWS o servicios externos bajo consentimiento del usuario o políticas pre-aprobadas.</p><p><strong>AgentCore Gateway<br></strong>Es el puente para que los agentes descubran y usen herramientas. Convierte fácilmente APIs existentes, Lambdas o servicios en <em>tools</em> compatibles con agentes. Esto les abre la puerta a ejecutar tareas reales en entornos complejos sin fricción.</p><p><strong>AgentCore Code Interpreter<br></strong>Un entorno aislado y seguro para ejecutar código. Soporta varios lenguajes (Python, JavaScript, TypeScript) y permite que el agente haga análisis de datos o automatización de flujos sin comprometer la seguridad, gracias al aislamiento a nivel de VM.</p><p><strong>AgentCore Browser Tool<br></strong>Un navegador en la nube que los agentes pueden usar para interactuar con páginas web: desde navegar y llenar formularios hasta ejecutar flujos más complejos. Es <em>model-agnostic</em> y está pensado para escalar.</p><p><strong>AgentCore Observability<br></strong>Toda la visibilidad necesaria para producción: logs, métricas y trazas. Se apoya en Amazon CloudWatch con dashboards listos y compatibilidad con OpenTelemetry para integrarlo a tus tableros existentes.</p><h3>Conclusión</h3><p>Amazon Bedrock AgentCore es una pieza clave para pasar de un agente experimental a uno preparado para producción. Aunque todavía está en preview, ofrece una arquitectura pensada para la operación real de agentes: runtime administrado, observabilidad integrada y compatibilidad con cualquier framework o modelo.</p><p>Si ya estás experimentando con frameworks como Strands Agents, este es el momento perfecto para probar AgentCore Runtime y empezar a preparar tu stack de agentes para la nube.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bf6d1c570641" width="1" height="1" alt=""><hr><p><a href="https://medium.com/caleidos/del-prototipo-a-producci%C3%B3n-desplegando-agentes-de-ia-con-amazon-bedrock-agentcore-bf6d1c570641">Del prototipo a producción: Desplegando agentes de IA con Amazon Bedrock AgentCore</a> was originally published in <a href="https://medium.com/caleidos">Caleidos</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Creando Agentes de IA con Strands Agents]]></title>
            <link>https://medium.com/caleidos/creando-agentes-de-ia-con-strands-agents-6ccf36963696?source=rss----4da51aff11a2---4</link>
            <guid isPermaLink="false">https://medium.com/p/6ccf36963696</guid>
            <category><![CDATA[bedrock]]></category>
            <category><![CDATA[strands-agents]]></category>
            <category><![CDATA[inteligencia-artificial]]></category>
            <dc:creator><![CDATA[Claudia Márquez]]></dc:creator>
            <pubDate>Mon, 29 Sep 2025 15:36:38 GMT</pubDate>
            <atom:updated>2025-09-29T15:36:34.974Z</atom:updated>
            <content:encoded><![CDATA[<p>En los últimos años los <strong>agentes de IA</strong> han pasado a ser claves para construir aplicaciones inteligentes. Un agente no es simplemente un modelo que responde a un prompt: es un sistema capaz de <strong>razonar, planear acciones, invocar herramientas externas y aprender de sus propios resultados</strong>.</p><p>La construcción de agentes de IA tradicionalmente ha requerido <strong>definir flujos de trabajo detallados y rígidos</strong>, lo que limita su escalabilidad y capacidad de adaptación. Sin embargo, con la evolución de los modelos de lenguaje, hoy es posible dejar que el propio modelo guíe gran parte del proceso, reduciendo la complejidad para los desarrolladores y habilitando comportamientos mucho más flexibles y autónomos.</p><p>Aquí es donde entra <strong>Strands Agents</strong>, el SDK open source <a href="https://aws.amazon.com/blogs/opensource/introducing-strands-agents-an-open-source-ai-agents-sdk/">lanzado por AWS</a>. Diseñado para aprovechar las capacidades de los modelos más avanzados, Strands permite a los desarrolladores crear agentes de manera simple: basta con definir un prompt y una lista de herramientas en código. A partir de ahí, el <a href="https://strandsagents.com/latest/documentation/docs/user-guide/concepts/agents/agent-loop/"><strong>agent loop</strong></a> — un ciclo de razonamiento, uso de herramientas y generación de respuestas — se encarga de orquestar el comportamiento inteligente del agente, que puede probarse localmente y desplegarse en la nube.</p><h3>Instalación inicial</h3><p>Para empezar, instalamos las librerías necesarias:</p><pre>pip install strands-agents strands-agents-tools</pre><p>Strands Agents usa por defecto <strong>Amazon Bedrock</strong> como proveedor de modelos, específicamente <em>Claude Sonnet 4</em>. Por lo tanto, necesitamos <strong>credenciales de AWS válidas</strong> con permisos para invocar modelos en Bedrock.</p><h3>Primer agente básico</h3><p>El siguiente ejemplo crea un agente que responde usando solo el modelo LLM:</p><pre>from strands import Agent<br><br># Crear agente<br>agent = Agent()<br><br># Preguntar algo al agente<br>message = &quot;&quot;&quot;<br>¿Qué hora es en Lima, Perú?<br>&quot;&quot;&quot;<br>agent(message)</pre><p>El resultado será la respuesta generada directamente por el modelo, sin acceso a herramientas externas.</p><pre>No tengo acceso a información en tiempo real, por lo que no puedo decirte la hora exacta actual en Lima, Perú.<br><br>Sin embargo, puedo darte información útil:<br><br>- **Zona horaria**: Lima está en UTC-5 (Hora Estándar de Perú)<br>- **Diferencias horarias comunes**:<br>  - 2 horas menos que Argentina/Chile<br>  - Misma hora que Colombia/Ecuador<br>  - 1 hora más que México (centro)<br>  - 5 horas menos que España<br><br>Para conocer la hora exacta actual en Lima, te recomiendo:<br>- Buscar &quot;hora en Lima&quot; en Google<br>- Usar aplicaciones de reloj mundial<br>- Consultar sitios web como timeanddate.com<br><br>¿Te gustaría que te ayude a calcular la diferencia horaria con algún otro lugar específico?</pre><h3>Agregando herramientas</h3><p>Para hacerlo más interesante, podemos darle acceso a la herramienta current_time, incluida en el paquete strands-tools.</p><pre>from strands import Agent<br>from strands_tools import current_time<br><br># Crear agente con acceso a herramientas<br>agent = Agent(tools=[current_time])<br><br># Pregunta al agente<br>message = &quot;&quot;&quot;<br>¿Qué hora es en Lima, Perú?<br>&quot;&quot;&quot;<br><br>agent(message)</pre><p>Ahora el agente no solo depende del modelo: usa la herramienta para consultar la hora actual en Lima y responde con precisión.</p><pre>Tool #1: current_time<br>La hora actual en Lima, Perú es **10:03:24 AM** (29 de septiembre de 2025).<br><br>Lima se encuentra en la zona horaria UTC-5 (también conocida como America/Lima), y actualmente no observa el horario de verano, por lo que mantiene la misma diferencia horaria durante todo el año.</pre><h3>Creando nuestra propia herramienta</h3><p>La verdadera potencia de Strands Agents está en <strong>definir nuestras propias tools</strong>. Supongamos que queremos consultar el tipo de cambio oficial publicado por SUNAT.</p><p>Si no agregamos una herramienta, el modelo responderá con datos aproximados o dirá que no tiene acceso a esa información.</p><pre>No tengo acceso a herramientas que me permitan consultar el tipo de cambio actual de SUNAT en tiempo real. Las funciones disponibles son para cálculos matemáticos y obtener la hora actual, pero no para consultar APIs de tipo de cambio.</pre><p>Para solucionarlo, definimos una función en Python con el decorador @tool:</p><pre>from strands import Agent, tool<br>from strands_tools import calculator, current_time<br>import requests<br>from datetime import datetime<br><br>@tool<br>def tipo_cambio_sunat() -&gt; dict:<br>    &quot;&quot;&quot;<br>    Obtiene el tipo de cambio del día de hoy desde SUNAT.<br>    <br>    Returns:<br>        dict: Diccionario con fecha, tipo de cambio compra y venta<br>              Ejemplo: {&quot;fecha&quot;: &quot;29/09/2025&quot;, &quot;compra&quot;: 3.494, &quot;venta&quot;: 3.502}<br>    &quot;&quot;&quot;<br>    try:<br>        # Hacer request a la URL de SUNAT<br>        url = &quot;https://www.sunat.gob.pe/a/txt/tipoCambio.txt&quot;<br>        response = requests.get(url, timeout=10)<br>        response.raise_for_status()<br>        <br>        # Parsear la respuesta<br>        # Formato esperado: 29/09/2025|3.494|3.502|<br>        data = response.text.strip()<br>        parts = data.split(&#39;|&#39;)<br>        <br>        if len(parts) &lt; 3:<br>            raise ValueError(&quot;Formato de respuesta inesperado de SUNAT&quot;)<br>        <br>        fecha = parts[0]<br>        compra = float(parts[1])<br>        venta = float(parts[2])<br>        <br>        return {<br>            &quot;fecha&quot;: fecha,<br>            &quot;compra&quot;: compra,<br>            &quot;venta&quot;: venta,<br>            &quot;moneda&quot;: &quot;USD/PEN&quot;<br>        }<br>        <br>    except requests.RequestException as e:<br>        return {&quot;error&quot;: f&quot;Error al conectar con SUNAT: {str(e)}&quot;}<br>    except (ValueError, IndexError) as e:<br>        return {&quot;error&quot;: f&quot;Error al procesar datos de SUNAT: {str(e)}&quot;}<br>    except Exception as e:<br>        return {&quot;error&quot;: f&quot;Error inesperado: {str(e)}&quot;}<br><br># Crea un agente con nuestra tool y tools de la comunidad<br>agent = Agent(tools=[calculator, current_time, tipo_cambio_sunat])<br><br># Realiza una pregunta al agente con las herramientas disponibles<br>message = &quot;&quot;&quot;<br>¿Cuál es el tipo de cambio de hoy según SUNAT? Y si tengo 100 dólares, ¿cuántos soles serían al tipo de cambio de venta?<br>&quot;&quot;&quot;<br>agent(message)</pre><p>Con esto, el agente invoca la API de SUNAT, obtiene el tipo de cambio y lo combina con la calculadora para responder correctamente.</p><pre>Te ayudo a consultar el tipo de cambio de hoy según SUNAT y hacer el cálculo de conversión.<br>Tool #1: tipo_cambio_sunat<br>Ahora calculemos cuántos soles serían 100 dólares al tipo de cambio de venta:<br>Tool #2: calculator<br>## Tipo de cambio SUNAT - 29/09/2025<br><br>**Tipo de cambio del día:**<br>- **Compra**: S/ 3.494 por dólar<br>- **Venta**: S/ 3.502 por dólar<br><br>**Conversión de tus 100 dólares:**<br>- Al tipo de cambio de venta: **100 USD = S/ 350.20**<br><br>Esto significa que si vendes 100 dólares americanos hoy, recibirías 350.20 soles peruanos según el tipo de cambio oficial de SUNAT.</pre><h3>Conclusión</h3><p>Strands Agents facilita la construcción de agentes de IA sobre AWS al abstraer la complejidad del <em>agent loop</em> y permitir que los desarrolladores se enfoquen en lo importante: <strong>crear herramientas que conecten al LLM con datos y servicios reales</strong>.</p><ul><li>Con unas pocas líneas de código podemos pasar de un agente que responde con conocimiento general a uno que accede a información actualizada y confiable.</li><li>Gracias a la integración nativa con <strong>Amazon Bedrock</strong>, es posible crear agentes productivos sin preocuparse por la infraestructura del modelo.</li><li>Y lo más poderoso: podemos extender las capacidades del agente creando <em>tools</em> que respondan a las necesidades de cada negocio.</li></ul><p>Este es solo el inicio. El siguiente paso es explorar cómo orquestar múltiples agentes, desplegarlos en arquitecturas serverless (como AWS Lambda o Step Functions) y habilitar escenarios más avanzados de automatización con IA generativa.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6ccf36963696" width="1" height="1" alt=""><hr><p><a href="https://medium.com/caleidos/creando-agentes-de-ia-con-strands-agents-6ccf36963696">Creando Agentes de IA con Strands Agents</a> was originally published in <a href="https://medium.com/caleidos">Caleidos</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Feature Flags con AWS AppConfig: cambios seguros y confiables]]></title>
            <link>https://medium.com/caleidos/feature-flags-con-aws-appconfig-cambios-seguros-y-confiables-87fd1bdb8dc1?source=rss----4da51aff11a2---4</link>
            <guid isPermaLink="false">https://medium.com/p/87fd1bdb8dc1</guid>
            <category><![CDATA[feature-flags]]></category>
            <category><![CDATA[aws-appconfig]]></category>
            <category><![CDATA[devops]]></category>
            <dc:creator><![CDATA[Claudia Márquez]]></dc:creator>
            <pubDate>Fri, 26 Sep 2025 17:24:52 GMT</pubDate>
            <atom:updated>2025-09-26T17:24:45.405Z</atom:updated>
            <content:encoded><![CDATA[<p>Los <strong>feature flags</strong> son una técnica que permite modificar el comportamiento de una aplicación sin necesidad de desplegar una nueva versión de código. Esto significa que puedes tener código nuevo en producción, oculto detrás de un flag hasta que decidas activarlo. Si algo falla al habilitarlo, basta con desactivar el flag nuevamente, evitando revertir todo el despliegue. Esta capacidad de controlar cambios de forma segura contribuye a sistemas más confiables y por eso está recomendada dentro del pilar de <strong>Fiabilidad</strong> del<a href="https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/implement-change.html"> Well-Architected Framework de AWS</a>.</p><p><strong>Ejemplo Práctico: Creando un feature flag</strong></p><p>1. Ve a <strong>AWS AppConfig</strong> (dentro de <strong>AWS Systems Manager</strong>), entra a <strong>Applications</strong> → <strong>Create application</strong>, ingresa un nombre para la aplicación y haz clic en <strong>Create application</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8AYHwVMyJU4Pl7Fe19VKbw.png" /></figure><p>2. Dentro de la aplicación, ve a <strong>Environments</strong> → <strong>Create environment</strong>, ingresa un nombre (p. ej., prod) y haz clic en <strong>Create environment</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5OSX6NJdKiqvzv1ZDiP3ug.png" /></figure><p>3. Ve a <strong>Configuration profiles</strong> → <strong>Create configuration profile</strong>, coloca un nombre (p. ej., FraudFlags), selecciona <strong>Configuration type = Feature flags</strong> y haz clic en <strong>Next</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2sA_NnQgFnFMMDFyGOgJ2Q.png" /></figure><p>4. A continuación ingresa un <strong>Flag key</strong> (p. ej., enable-new-fraud-model), deja <strong>State = Disabled</strong>, haz clic en <strong>Next </strong>y luego en <strong>Save and continue to deploy</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fDQ7vyAxrLwilnBnQXxjOw.png" /></figure><p>5. Elige el <strong>Environment</strong> (p. ej., prod), selecciona la <strong>Deployment strategy</strong> (AllAtOnce esta bien para pruebas) y haz clic en <strong>Start deployment</strong></p><p>6. Crea una función Lambda (Python 3.12) con las siguientes características:</p><ul><li>Variables de entorno:</li><li>APPCFG_APPLICATION=BankingPlatform</li><li>APPCFG_ENVIRONMENT=prod</li><li>APPCFG_PROFILE=FraudFlags</li><li><strong>Layers → Add layer → AWS layers</strong>: agrega <strong>AWS AppConfig Lambda Extension</strong>.</li><li><strong>Role (IAM)</strong> con: appconfig:StartConfigurationSession, appconfig:GetLatestConfiguration, appconfig:GetConfiguration</li></ul><p>Este es el código de la prueba para la Lambda:</p><pre>import json<br>import logging<br>import os<br>import sys<br>import urllib.request<br><br># Logger básico<br>logger = logging.getLogger()<br>logger.setLevel(logging.INFO)<br>if not logger.handlers:<br>    h = logging.StreamHandler(sys.stdout)<br>    h.setFormatter(logging.Formatter(&quot;%(asctime)s [%(levelname)s] %(message)s&quot;))<br>    logger.addHandler(h)<br><br># Vars de entorno (defínelas en la consola)<br>APP     = os.environ[&quot;APPCFG_APPLICATION&quot;]    # AppEjemplo<br>ENV     = os.environ[&quot;APPCFG_ENVIRONMENT&quot;]    # prod<br>PROFILE = os.environ[&quot;APPCFG_PROFILE&quot;]        # FraudFlags<br><br># Endpoint del AppConfig Agent (Lambda Extension)<br>APPCFG_URL = f&quot;http://localhost:2772/applications/{APP}/environments/{ENV}/configurations/{PROFILE}&quot;<br><br>def lambda_handler(event, context):<br>    # 1) Leer feature flags nativos desde el Agent<br>    with urllib.request.urlopen(APPCFG_URL, timeout=1.5) as resp:<br>        cfg = json.loads(resp.read().decode(&quot;utf-8&quot;))<br><br>    # 2) Tomar el estado del release flag<br>    enabled = cfg[&quot;enable-new-fraud-model&quot;][&quot;enabled&quot;]<br><br>    # 3) SOLO logs (sin implementar nada de fraude)<br>    if enabled:<br>        logger.info(&quot;Nuevo modelo de fraude: **ACTIVADO** (release flag encendido)&quot;)<br>    else:<br>        logger.info(&quot;Nuevo modelo de fraude: **DESACTIVADO** (release flag apagado)&quot;)<br><br>    # 4) Respuesta mínima<br>    return {<br>        &quot;statusCode&quot;: 200,<br>        &quot;body&quot;: json.dumps({<br>            &quot;flag&quot;: &quot;enable-new-fraud-model&quot;,<br>            &quot;enabled&quot;: enabled<br>        })<br>    }</pre><p>7. Ejecuta la función <strong>Lambda</strong>; en <strong>CloudWatch Logs</strong> deberías ver un mensaje indicando que se está usando la <strong>versión antigua</strong> (flag desactivado).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QING0v0XP-Cin2OogjoRbQ.png" /></figure><p>8. En <strong>AppConfig</strong>, abre el flag <strong>enable-new-fraud-model</strong>, cambia el estado a <strong>Enabled (On)</strong> y haz clic en <strong>Save version</strong>.</p><p>9. En el <strong>Configuration profile</strong>, selecciona <strong>Start deployment</strong>, elige el <strong>Environment</strong> (p. ej., prod), define la <strong>Deployment strategy</strong> (para pruebas, <strong>AllAtOnce</strong>) y pulsa <strong>Start</strong>.</p><p>10. Vuelve a invocar la función <strong>Lambda</strong>; ahora los logs deberían indicar que se está usando la <strong>nueva versión</strong> (flag activado).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nMD61nz0ahMgOrHX0hVsFA.png" /></figure><p><strong>Buenas Practicas</strong></p><p>Al implementar feature flags en nuestros sistemas, es importante seguir ciertas <strong>buenas prácticas</strong> para obtener el máximo beneficio y evitar posibles antipatrones. A continuación, presentamos algunas recomendaciones clave, junto con formas en que <strong>AWS AppConfig</strong> soporta o automatiza cada una:</p><ul><li><strong>Desplegar funcionalidades de forma gradual:</strong> No actives un feature flag al 100% de tus usuarios de golpe. Es más seguro hacer <strong>rollout progresivo</strong>, observando métricas y feedback en cada incremento. AWS AppConfig facilita esto mediante <em>Deployment Strategies</em> configurables: puedes definir estrategias lineales (por ejemplo, aumentar 10% cada 5 minutos), exponenciales u otras, incluyendo un periodo de <em>bake time</em> para monitorear antes de continuar. En la consola de AppConfig, al iniciar un despliegue de configuración puedes escoger una estrategia predefinida (como <em>AppConfig.Linear</em>) o personalizar una estrategia a tu medida. De esta forma limitas el radio de impacto de cualquier problema potencial, tal como recomienda AWS Well-Architected.</li><li><strong>Habilitar la reversión automática (auto-rollback):</strong> Configura sistemas de <strong>monitoreo y alarmas</strong> que desencadenen la desactivación de un flag o la reversión de la configuración si algo anda mal. AWS AppConfig se integra con Amazon CloudWatch Alarms para este propósito. Puedes asociar una alarma (por ejemplo, por tasa de errores, latencia, etc.) a la implementación de un flag: si la alarma se dispara durante el rollout, AppConfig automáticamente <strong>revierte la configuración al estado anterior</strong> sin intervención humana. Esto es invaluable, pues la velocidad de reacción automática suele ser más rápida que la de un operador humano que tendría que notar el problema y apagar el flag manualmente.</li><li><strong>Validar el input de la configuración:</strong> Nunca asumas que quien cambia un valor en producción no puede cometer un error de tipeo o formato. Implementa <strong>validaciones sintácticas y semánticas</strong> para cada flag o parámetro. AWS AppConfig te permite adjuntar <em>Validators</em> a tus perfiles de configuración. Estos validadores pueden ser esquemas JSON (JSON Schema) que definen la estructura esperada y rangos válidos, o incluso funciones Lambda personalizadas para chequeos más complejos. Por ejemplo, puedes definir que un valor de porcentaje de descuento debe ser un número entre 0 y 100, o que un flag de nivel de log solo acepte “DEBUG”, “INFO”, “WARN”, “ERROR”. Si alguien introduce un valor fuera de esas reglas, AppConfig bloqueará la implementación antes de afectar a los clientes. Esto previene despliegues de configuraciones corruptas que podrían causar fallos o comportamientos inesperados en la app.</li><li><strong>Usar una capa de caché para la configuración en la aplicación:</strong> Aunque podríamos consultar el servicio de configuración en cada llamada, es más eficiente y resistente <strong>mantener una caché local</strong> de los flags en la aplicación. AWS proporciona el <strong>AppConfig Agent</strong> (y extensiones para Lambda, etc.), que actúa como intermediario entre tu aplicación y el servicio AppConfig. Este agente se encarga de obtener las configuraciones y feature flags de forma eficiente, manteniéndolas en memoria y actualizándolas en segundo plano, reduciendo la latencia y carga en tu aplicación. En producción, es considerado una <strong>mejor práctica usar el AppConfig Agent</strong> para consumir las configuraciones, ya que además maneja reconexiones y fallback si AppConfig (o la red) presenta problemas. En resumen, una caché/agent añade un <em>buffer</em> entre tu sistema y la fuente de verdad, mejorando el performance y evitando dependencia directa constante de la red para cada verificación de flag.</li><li><strong>Limpiar los feature flags obsoletos:</strong> Incorpora en tu proceso de desarrollo la eliminación de flags que ya no se necesitan. Los feature flags deberían tener un ciclo de vida: aquellos de uso temporal (como los release flags) deben ser marcados para su futura eliminación una vez que cumplen su propósito. AWS AppConfig ayuda en la gobernanza de esto: puedes etiquetar un flag como <em>Short-term</em> (corto plazo) y asignarle una fecha objetivo de deprecación. La consola de AppConfig incluso mostrará qué flags <em>han sobrepasado su fecha</em> marcándolos como “<strong>Overdue</strong>” (atrasados), facilitando al equipo identificar y eliminar esas referencias pendientes. Estas herramientas fomentan una buena higiene, evitando el temido <em>flag rot</em> donde decenas de toggles viejos complican el código. Adicionalmente, mantener documentado qué flags existen y quién es el responsable de quitarlos es una buena práctica organizativa.</li></ul><p>Los feature flags, usados con disciplina, permiten separar el despliegue de código de la liberación de funcionalidades, reduciendo riesgos y mejorando la fiabilidad. Con AWS AppConfig es posible gestionarlos de manera centralizada, validando configuraciones, habilitando rollbacks automáticos y facilitando despliegues graduales. En conjunto, estas prácticas convierten el cambio en un proceso controlado y predecible, clave para la resiliencia de cualquier sistema en producción.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=87fd1bdb8dc1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/caleidos/feature-flags-con-aws-appconfig-cambios-seguros-y-confiables-87fd1bdb8dc1">Feature Flags con AWS AppConfig: cambios seguros y confiables</a> was originally published in <a href="https://medium.com/caleidos">Caleidos</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kiro: Primeras impresiones del nuevo IDE con IA de AWS]]></title>
            <link>https://medium.com/caleidos/kiro-primeras-impresiones-del-nuevo-ide-con-ia-de-aws-78f58d45c1da?source=rss----4da51aff11a2---4</link>
            <guid isPermaLink="false">https://medium.com/p/78f58d45c1da</guid>
            <category><![CDATA[amazon-kiro]]></category>
            <category><![CDATA[kiro]]></category>
            <dc:creator><![CDATA[Claudia Márquez]]></dc:creator>
            <pubDate>Mon, 15 Sep 2025 15:42:01 GMT</pubDate>
            <atom:updated>2025-09-15T15:42:01.293Z</atom:updated>
            <content:encoded><![CDATA[<h3>Introducción</h3><p>He estado probando <a href="https://kiro.dev/"><strong>Kiro</strong></a> durante un par de semanas. Se trata del nuevo IDE potenciado con IA de Amazon Web Services (AWS) que trabaja mediante agentes inteligentes. Kiro es mucho más que una simple herramienta de autocompletado de código: su objetivo es <strong>aportar estructura al desarrollo asistido por IA</strong> mediante una filosofía llamada <em>Spec-Driven Development</em> (desarrollo dirigido por especificaciones). En otras palabras, Kiro integra de forma nativa prácticas recomendadas de ingeniería de software en el flujo de trabajo con IA, ayudándote a ir <strong>“del vibe coding al código viable”</strong> con buenas prácticas incorporadas. Este IDE <em>agéntico</em> (orientado a agentes) ofrece funciones fundamentales como especificaciones estructuradas (<em>Specs</em>), archivos de direccionamiento (<em>Steering files</em>) para contexto persistente, <em>hooks</em> inteligentes y un chat avanzado con IA, entre otras. A continuación describo mis primeras impresiones y aprendizajes al usar Kiro, desde entender el Spec-Driven Development hasta desarrollar un proyecto prototipo con su ayuda.</p><h3>Desarrollo dirigido por especificaciones (Spec-Driven Development)</h3><p><strong>Spec-Driven Development (SDD)</strong> es la piedra angular de Kiro. En este enfoque, antes de escribir una sola línea de código, colaboramos con un agente de IA para redactar las <strong>especificaciones funcionales</strong> de lo que vamos a construir. Es decir, detallamos <strong>qué</strong> debe hacer el software y <strong>cómo</strong> debería hacerlo, y lo hacemos junto con la IA en el IDE. Kiro asiste en la generación de estos artefactos de planificación: desde los requerimientos iniciales hasta el diseño técnico y la lista de tareas a ejecutar, todo queda documentado de antemano. Este proceso nos fuerza (en el buen sentido) a pensar primero en la solución de forma estructurada, antes de sumergirnos en el código.</p><p>En concreto, Kiro convierte una idea de funcionalidad en un <strong>documento de especificación</strong> que pasa por tres fases:</p><ol><li><strong>Requisitos</strong> — Historias de usuario con criterios de aceptación (usando notación <em>EARS</em>) que describen el comportamiento esperado.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8LKfGsFdo8IJzGSq-kXIPg.png" /><figcaption>Ejemplo de los requerimientos</figcaption></figure><ol><li><strong>Diseño</strong> — Una descripción de la arquitectura y las decisiones técnicas: qué componentes, APIs o módulos se necesitan y cómo interactúan.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ia0yQYerXMzBs8q9ppdxhA.png" /><figcaption>Ejemplo de diseño</figcaption></figure><ol><li><strong>Tareas</strong> — Una lista de pasos o tickets de implementación discretos, rastreables y ordenados, que cubrirán todos los elementos para cumplir con los requisitos.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Lwye41K6pkXFZySlx1G4QA.png" /><figcaption>Ejemplo de tareas</figcaption></figure><p>Al completar estas fases, obtenemos una guía paso a paso antes de comenzar a programar. Una vez acordada la especificación, <strong>los agentes de Kiro pueden proceder a implementar cada tarea</strong>, manteniéndonos siempre en control del proceso. Un aspecto poderoso es que Kiro incluso valida o complementa las tareas con pruebas automatizadas y otros artefactos de calidad. Por ejemplo, la herramienta genera casos de prueba unitarios y documentación conforme se van definiendo las tareas, asegurando que el código resultante esté respaldado por <em>tests</em> robustos desde el inicio. En resumen, el SDD en Kiro combina la <strong>velocidad de la IA</strong> con la <strong>rigurosidad de las buenas prácticas de ingeniería</strong>, antes incluso de escribir código fuente.</p><h3>Primeros pasos con Kiro y archivos Steering</h3><p>Para empezar con Kiro, lo primero es crear los <a href="https://kiro.dev/docs/steering/#getting-started-with-steering-files"><strong>Steering Files</strong></a>, que son archivos Markdown donde se guarda el contexto de tu proyecto. Gracias a ellos, la IA entiende desde el inicio de qué trata tu producto, qué tecnologías usas y cómo está organizado tu código, sin necesidad de repetirlo en cada conversación.</p><p>Con un par de clics, Kiro genera tres archivos base en la carpeta .kiro/steering:</p><ul><li><strong>product.md</strong>: explica el propósito del producto y a quién va dirigido.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_MEm7lbK6yw_m_L6yQkUBg.png" /></figure><ul><li><strong>tech.md</strong>: lista las tecnologías, frameworks y librerías que usas.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jh0BjhJ4neXgzBv2TmqwRw.png" /></figure><ul><li><strong>structure.md</strong>: describe cómo está organizado el proyecto y sus convenciones.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*L-afEhRCm3mfx5MJ_ELaWA.png" /></figure><p>Estos documentos funcionan como una “memoria” que guía a la IA y aseguran que el código sugerido se adapte a tu stack y estilo. Además, puedes añadir archivos personalizados según las necesidades de tu equipo. Lo bueno es que esto también se puede aplicar a proyectos que ya existen, no solo a los nuevos.</p><p>Con los steering en su lugar, el siguiente paso es crear tu primera especificación junto con el agente y empezar a transformar esas tareas en código real.</p><h3>MCP en Kiro</h3><p>Otro aspecto importante de Kiro son los <strong>MCP (Model Context Protocols)</strong>, que funcionan como conectores para dar a la IA acceso seguro y actualizado a herramientas externas. En lugar de trabajar solo con el contexto local, los MCP permiten que Kiro consulte directamente servicios como repositorios, bases de datos o aplicaciones de productividad.</p><p>Un ejemplo práctico: probé el <a href="https://vibe.monday.com/?path=/docs/mcp-new--docs">MCP de Vibe Design de Monday</a>. Gracias a este conector, Kiro podía acceder a la información más reciente de la herramienta sin que yo tuviera que copiarla manualmente. Esto redujo <strong>alucinaciones</strong> y evitó depender de información desfasada del modelo, ya que la IA siempre trabajaba con datos en tiempo real.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/852/1*LoUSsadMliQ4n2XnfBD5Rg.png" /><figcaption>Ejemplo de Kiro llamando MCP</figcaption></figure><h3>Mi primer proyecto con Kiro</h3><p>La mejor forma de entender una herramienta nueva es <strong>experimentar</strong>.</p><p>Para probar Kiro decidí implementar una pequeña aplicación web para ayudar a aprender japonés mediante repaso espaciado (<em>spaced repetition system</em>). Empezando desde cero, en cuestión de horas ya tenía un prototipo funcional.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/780/1*DctDAqgdgTJwPdxUULD-0w.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/780/1*sg49Q4_01klqZ33g_xIamg.png" /><figcaption>Capturas de la aplicación realizada con Kiro</figcaption></figure><p>La velocidad de desarrollo fue espectacular: Kiro se sintió como un co-desarrollador que ayudaba a pensar en arquitectura, a generar historias de usuario y a convertirlas en tareas concretas. Lo más sorprendente fue la calidad del código: pruebas unitarias, documentación básica y buenas prácticas incluidas desde el inicio.</p><p>Aunque era un proyecto sencillo, sirvió como <strong>prueba del poder de Kiro</strong>: pasar de idea a prototipo completo en pocos días, algo que normalmente tomaría semanas.</p><h3>Conclusiones</h3><p>Kiro todavía se encuentra en <strong>versión <em>Public Preview</em></strong> (vista previa pública), lo que significa que la herramienta está en pleno desarrollo y evolución. En estas pocas semanas de uso he encontrado algún que otro fallo menor y ciertas limitaciones, pero es comprensible dado que el producto aún está madurando. A pesar de ello, la dirección que marca es muy prometedora. La forma en que desarrollamos software podría <strong>cambiar radicalmente</strong> en los próximos años gracias a IDEs con IA como Kiro. Personalmente, me pregunto cómo encajará Kiro (y el enfoque de <em>Spec-Driven Development</em>) en entornos empresariales más grandes: ¿Cómo cambiará la construcción de requerimientos junto a los Product Owners? ¿Qué impacto tendrá en las prácticas ágiles actuales? ¿Se redefinirán los roles del equipo? Por ahora solo lo he usado en proyectos pequeños y personales, pero los resultados me indican que las empresas que adopten la IA de manera robusta y organizada <strong>avanzarán más rápido</strong> que las que no lo hagan. Ya empiezan a surgir metodologías y frameworks que ponen a la IA como pieza fundamental del ciclo de desarrollo, y Kiro es un ejemplo tangible de esa tendencia.</p><p>Dicho esto, no todo son fortalezas. Una <strong>limitación actual para el público de habla hispana</strong> es que el soporte de Kiro para el desarrollo dirigido por especificaciones funciona solamente en inglés por el momento. La interfaz y los agentes están optimizados para entender y generar specs en inglés, por lo que intentar usar SDD en español no brinda todavía buenos resultados. Esperemos que con el tiempo añadan compatibilidad con otros idiomas, dado que sería un gran beneficio para la comunidad global de desarrolladores.</p><p>En conclusión, mi experiencia con Kiro ha sido muy positiva: trabajar con un IDE que <strong>actúa como un desarrollador <em>senior</em></strong> acompañándote resulta tanto emocionante como productivo. Aunque Kiro apenas comienza su recorrido y quedan preguntas por responder, ya demuestra cómo la IA puede proporcionar estructura y acelerar la creación de software de calidad. Seguiré experimentando con esta herramienta y observando cómo evoluciona. Por ahora, puedo afirmar que Kiro me ha hecho replantear mi flujo de trabajo: después de probar el <em>Spec-Driven Development</em>, cuesta imaginar volver al <em>vibe coding</em> puro y desorganizado. El futuro del desarrollo de software asistido por IA luce verdaderamente interesante.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=78f58d45c1da" width="1" height="1" alt=""><hr><p><a href="https://medium.com/caleidos/kiro-primeras-impresiones-del-nuevo-ide-con-ia-de-aws-78f58d45c1da">Kiro: Primeras impresiones del nuevo IDE con IA de AWS</a> was originally published in <a href="https://medium.com/caleidos">Caleidos</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Procesamiento geoespacial en AWS Glue con Apache Sedona]]></title>
            <link>https://medium.com/caleidos/procesamiento-geoespacial-en-aws-glue-con-apache-sedona-ca8b7130f6f1?source=rss----4da51aff11a2---4</link>
            <guid isPermaLink="false">https://medium.com/p/ca8b7130f6f1</guid>
            <category><![CDATA[aws-glue]]></category>
            <category><![CDATA[geospatial]]></category>
            <category><![CDATA[apache-sedona]]></category>
            <category><![CDATA[aws]]></category>
            <dc:creator><![CDATA[Claudia Márquez]]></dc:creator>
            <pubDate>Mon, 25 Aug 2025 21:36:38 GMT</pubDate>
            <atom:updated>2025-08-25T21:36:38.063Z</atom:updated>
            <content:encoded><![CDATA[<p>En proyectos de analítica es común trabajar con datos que incluyen coordenadas: <strong>tiendas, sensores, cajeros automáticos, antenas</strong>, etc. Muchas veces necesitamos validar esas coordenadas contra mapas, asignarles distritos o generar reportes espaciales.</p><p><strong>AWS Glue</strong> no trae soporte geoespacial de fábrica, pero podemos aprovechar <a href="https://sedona.apache.org/1.7.2/setup/overview/"><strong>Apache Sedona</strong></a>, un framework distribuido sobre Spark que entiende geometrías como puntos, líneas y polígonos.</p><p>En este artículo veremos:</p><ul><li>Cómo configurar y probar Apache Sedona en AWS Glue con un ejemplo mínimo.</li><li>Un caso de uso práctico: <strong>asignar el UBIGEO a tiendas según sus coordenadas</strong>.</li></ul><h3>Configuración básica de Apache Sedona en AWS Glue</h3><p>Antes de entrar al caso de uso, veamos cómo habilitar Sedona en Glue:</p><p><strong>Sube a un bucket S3 los JARs necesarios:</strong></p><ul><li><a href="https://repo1.maven.org/maven2/org/apache/sedona/sedona-spark-shaded-3.3_2.12/1.7.1/sedona-spark-shaded-3.3_2.12-1.7.1.jar">sedona-spark-shaded-3.3_2.12–1.7.1.jar</a></li><li><a href="https://repo1.maven.org/maven2/org/datasyslab/geotools-wrapper/1.7.1-28.5/geotools-wrapper-1.7.1-28.5.jar">geotools-wrapper-1.7.1–28.5.jar</a></li></ul><h4><strong>Configura tu Job de Glue:</strong></h4><p>Entra a la pestaña <strong>Job Details</strong> y ve a la sección <strong>Advanced Properties. </strong>En el apartado Libraries ingresa lo siguiente en:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mPyX7r0omoGhgT3OHQEbYQ.png" /></figure><p><strong>Dependent JARs path:</strong></p><pre>s3://&lt;tu-bucket&gt;/geotools-wrapper-1.7.1–28.5.jar,s3://&lt;tu-bucket&gt;/sedona-spark-shaded-3.3_2.12–1.7.1.jar</pre><p><strong>Additional Python modules path</strong></p><pre>apache-sedona==1.7.1</pre><p>Con esto, tu Job ya puede ejecutar funciones espaciales como ST_Point, ST_GeomFromWKT, ST_Contains, entre otras.</p><h4>Probar la configuración con un script mínimo</h4><p>Carga el siguiente script de prueba en el Job de Glue para probar la configuración.</p><pre>from pyspark.sql import SparkSession<br>from pyspark.sql.functions import expr<br><br>from sedona.register import SedonaRegistrator<br>from sedona.utils import SedonaKryoRegistrator, KryoSerializer<br><br># ------------------------------------------------------------------------------------<br># Inicializar Spark con Sedona<br># ------------------------------------------------------------------------------------<br>spark = (<br>    SparkSession.builder<br>        .appName(&quot;SedonaDemo&quot;)<br>        .config(&quot;spark.serializer&quot;, KryoSerializer.getName)<br>        .config(&quot;spark.kryo.registrator&quot;, SedonaKryoRegistrator.getName)<br>        .getOrCreate()<br>)<br><br>SedonaRegistrator.registerAll(spark)<br><br># ------------------------------------------------------------------------------------<br># Demo: crear un DataFrame con coordenadas y un punto<br># ------------------------------------------------------------------------------------<br>data = [(1, -77.042793, -12.046374)]  # id, longitud, latitud (ejemplo: Lima, Perú)<br>columns = [&quot;id&quot;, &quot;longitud&quot;, &quot;latitud&quot;]<br><br>df = spark.createDataFrame(data, columns)<br><br>df = df.withColumn(<br>    &quot;geom&quot;,<br>    expr(&quot;ST_Point(CAST(longitud AS DECIMAL(24,20)), CAST(latitud AS DECIMAL(24,20)))&quot;)<br>)<br><br>print(&quot;=== Mostrar DataFrame con geometría ===&quot;)<br>df.show(truncate=False)<br><br><br>df.printSchema()</pre><p>Ejecuta este script: deberías ver las columnas longitud, latitud y la geometría creada con ST_Point.</p><pre>+---+----------+----------+-----------------------------+<br>|id |longitud  |latitud   |geom                         |<br>+---+----------+----------+-----------------------------+<br>|1  |-77.042793|-12.046374|POINT (-77.042793 -12.046374)|<br>+---+----------+----------+-----------------------------+</pre><h3>Caso de uso: asignar UBIGEO a tiendas</h3><p>Imagina que tienes una cadena de tiendas en todo el país y que cada una guarda sus coordenadas (latitud/longitud).</p><p>Aunque esas coordenadas bastan para mostrarlas en un mapa, para fines de <strong>analítica de negocio y reportes regulatorios</strong> necesitas enriquecer los datos con:</p><ul><li>El <strong>UBIGEO oficial</strong> del distrito donde se ubica la tienda.</li><li>El <strong>nombre del departamento, provincia y distrito</strong>.</li><li>La posibilidad de calcular métricas agrupadas por nivel administrativo (ventas por distrito, penetración por provincia, etc.).</li></ul><p>Esto lo podemos lograr uniendo las coordenadas de tiendas contra la cartografía distrital del <strong>INEI</strong> mediante Sedona en Glue.</p><h3>Preparando los datos del INEI: de GeoPackage a WKT</h3><p>El <strong>Instituto Nacional de Estadística e Informática (INEI)</strong> distribuye los <a href="https://ide.inei.gob.pe/#capas"><strong>límites distritales del Perú</strong></a> en formato <strong>GeoPackage (.gpkg)</strong>. Este archivo contiene todos los polígonos de distritos junto con los códigos UBIGEO y los nombres oficiales de departamento, provincia y distrito.</p><p>El problema es que <strong>AWS Glue no lee GeoPackage directamente</strong>. Por eso, la mejor práctica es <strong>convertirlo localmente a un formato más amigable para Spark</strong>, como <strong>Parquet</strong>, y además transformar la geometría a <strong>WKT (Well-Known Text)</strong>.</p><p>De esta forma, cuando carguemos el dataset en Glue, solo tenemos que aplicar ST_GeomFromWKT para reconstruir los polígonos.</p><h4>a) Instalar dependencias en tu máquina</h4><p>En un entorno local (puede ser un venv), instala:</p><pre>python -m pip install geopandas pyarrow</pre><p>Estas librerías te permiten leer archivos geoespaciales y exportarlos a formatos analíticos modernos.</p><h4>b) Conversión del GPKG a WKT</h4><p>Crea y ejecuta el siguiente script de python para realizar la conversión:</p><pre>import geopandas as gpd<br><br># Abre el GeoPackage y la capa correcta<br>gdf = gpd.read_file(&quot;peru_distritos.gpkg&quot;, layer=&quot;ig_distrito&quot;)<br><br># Convierte la geometría a WKT<br>gdf[&quot;geometry_wkt&quot;] = gdf.geometry.apply(lambda geom: geom.wkt)<br><br># Selecciona columnas útiles<br>df = gdf[[&quot;UBIGEO&quot;, &quot;NOMBDEP&quot;, &quot;NOMBPROV&quot;, &quot;NOMBDIST&quot;, &quot;geometry_wkt&quot;]]<br><br># Exporta a Parquet (ideal para Glue/Sedona)<br>df.to_parquet(&quot;distritos_wkt.parquet&quot;, index=False)<br><br>print(&quot;✅ Exportación lista: distritos_wkt.parquet&quot;)</pre><h4>c) Subir a S3</h4><p>Una vez ejecutado el script, sube el archivo a tu bucket:</p><pre>aws s3 cp distritos_wkt.parquet s3://&lt;bucket&gt;/distritos_wkt.parquet</pre><p>Ahora tienes un dataset rápido de consultar en Glue, con las columnas:<br> UBIGEO, NOMBDEP, NOMBPROV, NOMBDIST, geometry_wkt.</p><h3>Script de Glue: join espacial tiendas vs distritos</h3><p>Con los polígonos del INEI en S3, podemos hacer el join espacial en Glue.<br> El flujo será:</p><ol><li><strong>Crear un DataFrame de tiendas</strong> (con latitud/longitud).</li><li><strong>Leer distritos desde S3</strong> (Parquet con WKT).</li><li><strong>Convertir WKT a geometría Sedona</strong> con ST_GeomFromWKT.</li><li><strong>Hacer el join espacial</strong> con ST_Contains(polygon, point).</li></ol><p>Modifica el script del Job con el siguiente contenido:</p><pre>from pyspark.sql import SparkSession<br>from pyspark.sql.functions import expr, col<br>from pyspark.sql.types import StringType<br>from sedona.register import SedonaRegistrator<br>from sedona.utils import SedonaKryoRegistrator, KryoSerializer<br><br># ------------------------------------------------------------------------------------<br># Inicializar Spark + Sedona<br># ------------------------------------------------------------------------------------<br>spark = (<br>    SparkSession.builder<br>        .appName(&quot;SedonaTiendasUbigeo&quot;)<br>        .config(&quot;spark.serializer&quot;, KryoSerializer.getName)<br>        .config(&quot;spark.kryo.registrator&quot;, SedonaKryoRegistrator.getName)<br>        .getOrCreate()<br>)<br>SedonaRegistrator.registerAll(spark)<br><br># ------------------------------------------------------------------------------------<br># 1) Tiendas en memoria (ejemplo simple)<br># ------------------------------------------------------------------------------------<br>tiendas_data = [<br>    (&quot;T001&quot;, -77.042793, -12.046374),   # Lima<br>    (&quot;T002&quot;, -77.059714, -12.095380),   # Magdalena<br>    (&quot;T003&quot;, -71.535000, -16.398890),   # Arequipa<br>]<br>df_tiendas = spark.createDataFrame(tiendas_data, [&quot;tienda_id&quot;, &quot;longitud&quot;, &quot;latitud&quot;])<br><br># Crear POINT (X=lon, Y=lat)<br>df_tiendas_geo = df_tiendas.withColumn(<br>    &quot;point&quot;,<br>    expr(&quot;ST_Point(CAST(longitud AS DECIMAL(24,20)), CAST(latitud AS DECIMAL(24,20)))&quot;)<br>)<br><br>print(&quot;=== Tiendas ===&quot;)<br>df_tiendas_geo.show(truncate=False)<br><br># ------------------------------------------------------------------------------------<br># 2) Distritos desde S3 (Parquet con geometry_wkt del INEI)<br># ------------------------------------------------------------------------------------<br>WKT_PATH = &quot;s3://&lt;bucket&gt;/distritos_wkt.parquet&quot;<br><br>df_wkt = spark.read.parquet(WKT_PATH)<br><br># Asegurar que las columnas administrativas sean String<br>df_wkt = (<br>    df_wkt<br>    .withColumn(&quot;UBIGEO&quot;, col(&quot;UBIGEO&quot;).cast(StringType()))<br>    .withColumn(&quot;NOMBDEP&quot;, col(&quot;NOMBDEP&quot;).cast(StringType()))<br>    .withColumn(&quot;NOMBPROV&quot;, col(&quot;NOMBPROV&quot;).cast(StringType()))<br>    .withColumn(&quot;NOMBDIST&quot;, col(&quot;NOMBDIST&quot;).cast(StringType()))<br>)<br><br># Construir la geometría Sedona a partir del WKT<br>df_wkt_geo = df_wkt.withColumn(&quot;polygon&quot;, expr(&quot;ST_GeomFromWKT(geometry_wkt)&quot;))<br><br>print(&quot;=== Distritos ===&quot;)<br>df_wkt_geo.select(&quot;UBIGEO&quot;, &quot;NOMBDEP&quot;, &quot;NOMBPROV&quot;, &quot;NOMBDIST&quot;).show(5, truncate=False)<br><br># ------------------------------------------------------------------------------------<br># 3) Join espacial: ST_Contains<br># ------------------------------------------------------------------------------------<br>resultado = (<br>    df_tiendas_geo.join(<br>        df_wkt_geo.select(&quot;UBIGEO&quot;, &quot;NOMBDEP&quot;, &quot;NOMBPROV&quot;, &quot;NOMBDIST&quot;, &quot;polygon&quot;),<br>        expr(&quot;ST_Contains(polygon, point)&quot;),<br>        how=&quot;left&quot;<br>    )<br>    .withColumnRenamed(&quot;UBIGEO&quot;, &quot;ubigeo&quot;)<br>    .withColumnRenamed(&quot;NOMBDEP&quot;, &quot;departamento&quot;)<br>    .withColumnRenamed(&quot;NOMBPROV&quot;, &quot;provincia&quot;)<br>    .withColumnRenamed(&quot;NOMBDIST&quot;, &quot;distrito&quot;)<br>)<br><br>print(&quot;=== Resultado: tiendas con UBIGEO asignado ===&quot;)<br>resultado.select(&quot;tienda_id&quot;, &quot;latitud&quot;, &quot;longitud&quot;, &quot;ubigeo&quot;, &quot;departamento&quot;, &quot;provincia&quot;, &quot;distrito&quot;) \<br>         .show(truncate=False)Ejemplo de salida</pre><p>💡 <strong>Si nunca has usado Apache Sedona antes, fíjate en estos tres pasos clave dentro del script:</strong></p><ol><li><strong>Crear los puntos de las tiendas con </strong><strong>ST_Point</strong>: a partir de la longitud y latitud construimos un objeto geométrico que Sedona entiende.</li><li><strong>Convertir los polígonos del INEI desde WKT con </strong><strong>ST_GeomFromWKT</strong>: así Sedona transforma las geometrías guardadas como texto en verdaderos objetos espaciales.</li><li><strong>Hacer el join espacial con </strong><strong>ST_Contains</strong>: aquí ocurre la “magia”. Por cada tienda, Sedona evalúa en qué polígono (distrito) cae su punto y le asigna el UBIGEO y los nombres correspondientes.</li></ol><p>Ejecuta el script y deberias recibir el siguiente resultado:</p><pre>+---------+----------+----------+------+------------+---------+-----------------+<br>|tienda_id|latitud   |longitud  |ubigeo|departamento|provincia|distrito         |<br>+---------+----------+----------+------+------------+---------+-----------------+<br>|T001     |-12.046374|-77.042793|150101|LIMA        |LIMA     |LIMA             |<br>|T002     |-12.09538 |-77.059714|150120|LIMA        |LIMA     |MAGDALENA DEL MAR|<br>|T003     |-16.39889 |-71.535   |040101|AREQUIPA    |AREQUIPA |AREQUIPA         |<br>+---------+----------+----------+------+------------+---------+-----------------+</pre><p>El resultado muestra que cada tienda fue asignada correctamente a su distrito según sus coordenadas:</p><ul><li><strong>T001</strong> cayó en el distrito <strong>LIMA</strong> (UBIGEO 150101).</li><li><strong>T002</strong> se ubicó en <strong>MAGDALENA DEL MAR</strong> (UBIGEO 150120).</li><li><strong>T003</strong> corresponde a <strong>AREQUIPA</strong> (UBIGEO 040101).</li></ul><p>👉 Así comprobamos que el join espacial con Sedona funciona, enriqueciendo las coordenadas con información oficial de <strong>UBIGEO, departamento, provincia y distrito</strong>.</p><h3>Conclusiones</h3><ul><li>Con <strong>Apache Sedona en AWS Glue</strong> puedes extender tus pipelines ETL para manejar datos geoespaciales.</li><li>Convertir el <strong>GeoPackage del INEI</strong> a <strong>Parquet con geometrías en WKT</strong> facilita la integración. La misma técnica puede reutilizarse con <strong>otros mapas temáticos</strong> (provincias, regiones, áreas de cobertura, zonas de riesgo), no solo con distritos, ampliando los casos de uso en analítica geoespacial.</li><li>El join espacial permite asignar automáticamente <strong>UBIGEO y nombres administrativos</strong> a cualquier dataset con coordenadas.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ca8b7130f6f1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/caleidos/procesamiento-geoespacial-en-aws-glue-con-apache-sedona-ca8b7130f6f1">Procesamiento geoespacial en AWS Glue con Apache Sedona</a> was originally published in <a href="https://medium.com/caleidos">Caleidos</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Amazon S3 Requester Pays: qué es, cómo configurarlo y casos de uso reales]]></title>
            <link>https://medium.com/caleidos/amazon-s3-requester-pays-qu%C3%A9-es-c%C3%B3mo-configurarlo-y-casos-de-uso-reales-7f4cac5cb3b2?source=rss----4da51aff11a2---4</link>
            <guid isPermaLink="false">https://medium.com/p/7f4cac5cb3b2</guid>
            <category><![CDATA[s3]]></category>
            <category><![CDATA[aws]]></category>
            <dc:creator><![CDATA[Claudia Márquez]]></dc:creator>
            <pubDate>Mon, 18 Aug 2025 23:02:19 GMT</pubDate>
            <atom:updated>2025-08-18T23:02:19.489Z</atom:updated>
            <content:encoded><![CDATA[<p>Amazon S3 es uno de los servicios más usados para almacenar y compartir datos en la nube. Normalmente, el propietario del bucket paga tanto el almacenamiento como la transferencia. Con <strong>S3 Requester Pays</strong>, esa carga cambia: el dueño paga solo el almacenamiento y <strong>el consumidor cubre los costos de solicitudes y descargas</strong>.</p><p>Es una manera <strong>sencilla y directa</strong> de compartir datos a gran escala, sin necesidad de procesos adicionales. Para escenarios más avanzados — por ejemplo, cuando se requiere control de acceso, monetización o suscripciones — también existe <strong>AWS Data Exchange</strong>, que permite distribuir datasets de forma gestionada y con modelos comerciales más flexibles.</p><p>Esta opción resulta ideal para casos como <strong>imágenes satelitales, datasets científicos o archivos multimedia</strong>, donde cada usuario paga solo por lo que consume.</p><h3>Cómo habilitar Requester Pays en un bucket</h3><h4>1. Vía AWS Console</h4><ol><li>Abre la consola de <strong>Amazon S3</strong>.</li><li>Selecciona el bucket que quieres configurar.</li><li>Selecciona la pestaña <strong>Propiedades</strong>.</li><li>En la sección <strong>Requester Pays</strong>, activa la opción <em>“Los solicitantes pagan”</em>.</li><li>Guarda los cambios.</li></ol><h4>2. Vía AWS CLI</h4><pre>aws s3api put-bucket-request-payment \<br>  --bucket nombre-del-bucket \<br>  --request-payment-configuration &#39;{&quot;Payer&quot;:&quot;Requester&quot;}&#39;</pre><p>Confirmar la configuración:</p><pre>aws s3api get-bucket-request-payment --bucket nombre-del-bucket</pre><p>Respuesta esperada:</p><pre>{<br>    &quot;Payer&quot;: &quot;Requester&quot;<br>}</pre><h3>Accediendo a un bucket con Requester Pays</h3><p>Cuando un usuario accede al bucket, debe especificar el flag --request-payer requester. Ejemplo:</p><pre>aws s3 cp s3://nombre-del-bucket/archivo.tif ./ \<br>  --request-payer requester</pre><p>Si no incluye ese parámetro, la solicitud será rechazada.</p><h3>Ejemplo práctico: descargando imágenes satelitales públicas con Requester Pays</h3><p>Amazon mantiene el programa <a href="https://registry.opendata.aws/"><strong>AWS Open Data</strong></a>, donde muchas instituciones publican datasets abiertos. Uno de los más usados es el de <strong>imágenes satelitales Landsat</strong>, alojado en el bucket <strong>usgs-landsat</strong> (en la región us-west-2).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FZ_Y66Ql-zyw_taUTtzrHw.png" /></figure><p>Este bucket está configurado con <strong>Requester Pays</strong>: cualquiera puede acceder a las imágenes, pero el costo de descarga lo asume el solicitante.</p><h3>1. Listar objetos (con --request-payer)</h3><pre>aws s3 ls s3://usgs-landsat/collection02/ --region us-west-2 --request-payer requester</pre><h3>2. Descargar un archivo específico</h3><p>Por ejemplo, un archivo GeoTIFF de la colección Landsat 8:</p><pre>aws s3 cp \<br>  s3://usgs-landsat/collection02/level-1/standard/oli-tirs/2013/030/030/LC08_L1TP_030030_20130320_20200913_02_T1/LC08_L1TP_030030_20130320_20200913_02_T1_thumb_small.jpeg . \<br>  --region us-west-2 \<br>  --request-payer requester</pre><ul><li>--region es obligatorio porque el bucket está en <strong>us-west-2</strong>.</li><li>--request-payer requester debe ir en todas las operaciones, de lo contrario obtendrás AccessDenied.</li></ul><h3>Buenas prácticas y consideraciones</h3><ul><li><strong>No se recomienda</strong> para contenido web de acceso masivo al público general (por ejemplo, un sitio web estático), porque los visitantes no tienen manera de pasar el flag --request-payer requester.</li><li>Úsalo cuando el acceso se dé principalmente vía <strong>CLI, SDK o aplicaciones personalizadas</strong>.</li><li>Siempre documenta a tus usuarios cómo deben acceder al bucket, incluyendo el parámetro --request-payer requester.</li></ul><h3>Conclusión</h3><p>Amazon S3 Requester Pays es una solución simple pero poderosa para <strong>compartir datasets masivos</strong> de manera equitativa. Permite que investigadores, empresas y comunidades colaborativas accedan a datos como imágenes satelitales, genomics o logs sin que el costo recaiga únicamente en el propietario del bucket.</p><p>En resumen: si compartes datos a gran escala, <strong>deja que cada consumidor pague por lo que descarga</strong> y optimiza tus costos con Requester Pays.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7f4cac5cb3b2" width="1" height="1" alt=""><hr><p><a href="https://medium.com/caleidos/amazon-s3-requester-pays-qu%C3%A9-es-c%C3%B3mo-configurarlo-y-casos-de-uso-reales-7f4cac5cb3b2">Amazon S3 Requester Pays: qué es, cómo configurarlo y casos de uso reales</a> was originally published in <a href="https://medium.com/caleidos">Caleidos</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Gitlab + CodeBuild: Managed Gitlab runners]]></title>
            <link>https://medium.com/caleidos/gitlab-codebuild-managed-gitlab-runners-2cdf578e15b4?source=rss----4da51aff11a2---4</link>
            <guid isPermaLink="false">https://medium.com/p/2cdf578e15b4</guid>
            <category><![CDATA[codebuild]]></category>
            <category><![CDATA[gitlab]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[aws-developer-tools]]></category>
            <dc:creator><![CDATA[Claudia Márquez]]></dc:creator>
            <pubDate>Mon, 30 Sep 2024 21:51:23 GMT</pubDate>
            <atom:updated>2024-09-30T21:51:23.140Z</atom:updated>
            <content:encoded><![CDATA[<h3>Gitlab + AWS CodeBuild: Managed Gitlab runners</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/703/1*5bOAWkCXfODqWjySPoH-6w.png" /></figure><p>Uno de los retos que enfrentamos en la integración continua es cuando necesitamos que nuestros procesos de construcción y prueba accedan a recursos que están dentro de nuestra VPC (Virtual Private Cloud), como servicios internos o APIs que no son accesibles desde internet. Un ejemplo de esta situación es la integración con herramientas de análisis de código como SonarQube que están alojadas en redes privadas.</p><p>Tradicionalmente, para solucionar esto, muchas organizaciones optan por usar agentes de integración continua personalizados, como <a href="https://docs.gitlab.com/runner/configuration/runner_autoscale_aws/index.html"><strong>runners</strong></a> de GitLab alojados en <strong>instancias EC2</strong>. Si bien esta solución puede ser eficaz, también presenta varios inconvenientes operativos. Debes encargarte de gestionar las instancias EC2, monitorear su disponibilidad y rendimiento, así como encargarte de las actualizaciones de seguridad y la escalabilidad. Este proceso puede convertirse en una carga operativa significativa a largo plazo.</p><p>¡Pero no te preocupes! Ahora existe una mejor manera de hacer esto con <strong>AWS CodeBuild</strong> y su nueva funcionalidad que permite usarlo como un <strong>managed GitLab runner</strong> con acceso a los recursos de tu VPC. Veamos cómo esta nueva característica puede simplificar enormemente tu flujo de trabajo de integración continua.</p><h3>Crear la conexión entre Gitlab y CodeBuild</h3><p>El primer paso que tenemos que realizar es conectar la cuenta de GitLab con los servicios de Code de AWS. Para realizar eso vamos a buscar el servicio de CodeBuild en la consola.</p><p>1. En la consola de <strong>AWS CodeBuild</strong>, ve a <strong>Settings</strong> &gt; <strong>Connections</strong> y haz clic en <strong>Create Connection</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ayWm28HM_HruWekLyRS_mQ.png" /></figure><p>2. Selecciona <strong>GitLab</strong> como proveedor, ingresa un nombre para la conexión, y haz clic en <strong>Connect to GitLab</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*c8cPc5VqJaRhEHm5-js8Og.png" /></figure><p>3. Autoriza la conexión en GitLab haciendo clic en el botón <strong>Authorize AWS Connector for GitLab</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*etG3v3SVSLkGQePf0H92mQ.png" /></figure><p>4. Haz clic en el botón de <strong>Connect</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8i8CIw2iwEIhEnXz-60Bxw.png" /></figure><p>5. La conexión está lista y deberias poder visualizarla.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*z--ATm7X3LlGUdxVxgs-YA.png" /></figure><h3>Crear un proyecto de CodeBuild</h3><p>Sigue estos pasos para configurar un proyecto de <strong>CodeBuild</strong> que utilice <strong>GitLab</strong> como proveedor de código fuente:</p><p>1. En la barra de navegación despliega la opción <strong>Build</strong> &gt; <strong>Build Projects</strong> y haz clic en el botón <strong>Create build project</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*82aXx7TQ6luWm8oLgSjtUQ.png" /></figure><p>2. Ingresa un nombre para el proyecto. Yo estoy nombrandolo gitlab-runner.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NK7Jt0at6ednIfdaHeDWPw.png" /></figure><p>3. En la sección <strong>Managed default source credentials</strong> selecciona GitLab como <strong>Source Provider</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4RD7sCWjXR0ORittkntBrw.png" /></figure><p>4. La primera vez que creamos el proyecto debemos configurar la conexión, para heco debemos hacer clic en la opción <strong>Managed default source credentials</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DiGmMdwPhLsDYZCGzCp2oQ.png" /></figure><p>5. Debemos seleccionar el <strong>CodeConnection </strong>que configuramos en la sección previa y hacer clic en <strong>Save</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4RD7sCWjXR0ORittkntBrw.png" /></figure><p>6. Luego deberemos seleccionar el repositorio de GitLab con el que queramos trabajar.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cBMNAbqZgfJegwQmSXWwiA.png" /></figure><p>7. En la sección <strong>Primary source webhook events</strong>, debemos seleccionar la opción <strong>Rebuild every time a code change is pushed to this repository</strong>. En la opción <strong>Event Type</strong> debemos elegir <strong>WORKFLOW_JOB_QUEUED</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*itoclzWyYgH_fJ20w6JewQ.png" /></figure><p>8. Deja las configuraciones restantes como predeterminadas y haz clic en <strong>Create build project</strong> para finalizar la creación del proyecto.</p><h3>Crear el Pipeline en GitLab</h3><p>El siguiente paso es configurar el pipeline en <strong>GitLab</strong> para ejecutar las tareas de CI/CD utilizando <strong>AWS CodeBuild</strong>. Sigue estos pasos para crear y configurar el archivo del pipeline:</p><ol><li>En la raíz de tu repositorio de <strong>GitLab</strong>, crea un archivo llamado <strong>.gitlab-ci.yml</strong> con el siguiente contenido:</li></ol><pre>workflow:<br>  name: HelloWorld<br>stages:          # List of stages for jobs, and their order of execution<br>  - build<br><br>build-job:       # This job runs in the build stage, which runs first.<br>  stage: build<br>  script:<br>    - echo &quot;Hello World!&quot;<br>  tags:<br>    - codebuild-gitlab-runner-$CI_PROJECT_ID-$CI_PIPELINE_IID-$CI_JOB_NAME</pre><p>En el archivo, asegúrate de reemplazar la palabra <strong>“gitlab-runner”</strong> por el nombre de tu propio proyecto de CodeBuild. El resto del tag puede quedar tal como está, ya que las variables como $CI_PROJECT_ID, $CI_PIPELINE_IID y $CI_JOB_NAME serán automáticamente asignadas por GitLab.</p><p>Ejemplo:</p><pre>tags:<br>  - codebuild-mi-proyecto-$CI_PROJECT_ID-$CI_PIPELINE_IID-$CI_JOB_NAME</pre><h3><strong>Ver el Pipeline en Acción</strong></h3><p>Una vez que hayas guardado el archivo <strong>.gitlab-ci.yml</strong>, GitLab comenzará a ejecutar el pipeline. Para verificarlo:</p><ul><li>En <strong>GitLab</strong>, ve a la sección <strong>Build</strong> &gt; <strong>Job</strong> dentro de tu repositorio y selecciona el job recién creado. Podrás ver los detalles de la ejecución.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vONODr7aGELEnYkdZwljgg.png" /></figure><ul><li>También puedes verificar la ejecución en <strong>AWS CodeBuild</strong> revisando el proyecto que creaste previamente.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yygoN8O9RWgCWjd4wdpCew.png" /></figure><p>¡Eso es todo! Con esta configuración, podrás utilizar <strong>AWS CodeBuild</strong> para gestionar los trabajos de CI/CD de <strong>GitLab</strong>, aprovechando la infraestructura gestionada de AWS.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2cdf578e15b4" width="1" height="1" alt=""><hr><p><a href="https://medium.com/caleidos/gitlab-codebuild-managed-gitlab-runners-2cdf578e15b4">Gitlab + CodeBuild: Managed Gitlab runners</a> was originally published in <a href="https://medium.com/caleidos">Caleidos</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Optimizando tu Modelo de AWS DeepRacer: Una Guía para Diseñar Funciones de Recompensa]]></title>
            <link>https://medium.com/caleidos/optimizando-tu-modelo-de-aws-deepracer-una-gu%C3%ADa-para-dise%C3%B1ar-funciones-de-recompensa-ec712ffc39d1?source=rss----4da51aff11a2---4</link>
            <guid isPermaLink="false">https://medium.com/p/ec712ffc39d1</guid>
            <category><![CDATA[reinforcement-learning]]></category>
            <category><![CDATA[deepracer]]></category>
            <category><![CDATA[aws]]></category>
            <dc:creator><![CDATA[Claudia Márquez]]></dc:creator>
            <pubDate>Mon, 16 Sep 2024 23:48:57 GMT</pubDate>
            <atom:updated>2024-09-16T23:48:57.627Z</atom:updated>
            <content:encoded><![CDATA[<p>En la publicación anterior, <a href="https://medium.com/caleidos/iniciando-en-aws-deepracer-introducci%C3%B3n-a-reinforcement-learning-f467cf80c177"><strong>Iniciando en AWS DeepRacer: Introducción a Reinforcement Learning</strong></a>, cubrimos los conceptos básicos sobre cómo crear tu primer modelo de DeepRacer utilizando las configuraciones predeterminadas. Ahora que ya tienes un modelo funcionando, es hora de profundizar en un componente clave de cualquier modelo de <em>Reinforcement Learning</em>: <strong>la función de recompensa</strong>.</p><p>La función de recompensa es el corazón del aprendizaje por refuerzo en AWS DeepRacer. Define las reglas que guían al vehículo autónomo a tomar decisiones a lo largo de la pista, asignando puntos en función de qué tan bien sigue estas reglas.</p><h3>¿Qué es una Función de Recompensa?</h3><p>En DeepRacer, la función de recompensa es una pieza de código que calcula una puntuación cada vez que el coche completa un paso en la pista. Esto sucede de la siguiente manera:</p><ol><li><strong>Paso del coche</strong>: El coche se mueve una pequeña distancia basada en su velocidad y ángulo de dirección.</li><li><strong>Evaluación</strong>: Después de cada paso, DeepRacer llama a la función de recompensa y le pasa los parámetros actuales.</li><li><strong>Cálculo de la recompensa</strong>: La función de recompensa devuelve un valor que se añade a la recompensa acumulada del coche para esa carrera.</li></ol><p><strong>El objetivo del modelo es maximizar esta recompensa total. </strong>Por lo tanto, una función de recompensa bien diseñada incentiva al coche a comportarse de la manera deseada, como seguir la pista, mantener una velocidad constante o evitar salirse de la pista.</p><h3>Anatomía Básica de una Función de Recompensa</h3><p>A nivel técnico, la función de recompensa se implementa en Python. Aquí te mostramos una estructura básica:</p><pre>def reward_function(params):<br>    &#39;&#39;&#39;<br>    Ejemplo de cómo recompensar al agente por seguir la línea central<br>    &#39;&#39;&#39;<br>    <br>    # Leer los parámetros de entrada<br>    track_width = params[&#39;track_width&#39;]<br>    distance_from_center = params[&#39;distance_from_center&#39;]<br>    <br>    # Calcular 3 marcadores que están a diferentes distancias de la línea central<br>    marker_1 = 0.1 * track_width<br>    marker_2 = 0.25 * track_width<br>    marker_3 = 0.5 * track_width<br>    <br>    # Dar una recompensa mayor si el coche está más cerca de la línea central y viceversa<br>    if distance_from_center &lt;= marker_1:<br>        reward = 1.0<br>    elif distance_from_center &lt;= marker_2:<br>        reward = 0.5<br>    elif distance_from_center &lt;= marker_3:<br>        reward = 0.1<br>    else:<br>        reward = 1e-3  # probablemente se estrelló o está cerca de salirse de la pista<br>    <br>    return float(reward)</pre><p>Desglocemos los elementos importantes:</p><ol><li><strong>params</strong>: Un diccionario que contiene todas las variables que puedes usar en tu función de recompensa. Estas variables describen el estado actual del coche en la pista, como la velocidad, la posición en la pista, el ángulo de dirección, entre otros.</li><li><strong>Lógica de recompensa</strong>: Basado en las variables extraídas, puedes diseñar reglas para dar una recompensa mayor cuando el coche sigue las pautas que consideres óptimas. En este caso, hemos asignado una recompensa mayor si el coche está más cerca del centro de la pista.</li><li><strong>Retorno</strong>: La función siempre debe devolver un valor numérico de tipo flotante, que será usado por el agente para aprender y ajustar su comportamiento.</li></ol><h3>Parámetros Disponibles en la Función de Recompensa</h3><p>Existen diversas parámetros que AWS DeepRacer provee para ayudarte a crear una función de recompensa efectiva. En la <a href="https://docs.aws.amazon.com/deepracer/latest/developerguide/deepracer-reward-function-input.html#reward-function-input-closest_waypoints">documentación</a> puedes ver el listado completo.</p><p>Algunas de las más comunes son:</p><ul><li><strong>track_width</strong>: El ancho de la pista.</li><li><strong>distance_from_center</strong>: Qué tan lejos está el coche del centro de la pista.</li><li><strong>all_wheels_on_track</strong>: Un booleano que indica si todas las ruedas están dentro de los límites de la pista.</li><li><strong>speed</strong>: La velocidad actual del coche.</li><li><strong>steering_angle</strong>: El ángulo de dirección en grados.</li><li><strong>waypoints</strong>: La lista ordenada que describe el recorrido de la pista.</li><li><strong>closest_waypoints</strong>: Los dos puntos más cercanos en la pista al coche.</li></ul><p>Estas variables se pueden combinar para crear reglas más complejas. Por ejemplo, podrías incrementar la recompensa si el coche mantiene una velocidad constante y está alineado con la dirección de la pista.</p><p>En la siguiente función de recompensa podemos ver como se combinan dos parámetros para crearla. La función de recompensa premia al vehículo autónomo por mantenerse en la pista (utilizando el parámetro all_wheels_on_track) y moverse a una velocidad adecuada (con el parámetro speed). Si el coche se sale de la pista, recibe una recompensa muy baja. Si está en la pista pero va demasiado lento, la recompensa es moderada. Solo recibe la máxima recompensa si permanece en la pista y mantiene una velocidad superior al umbral definido, incentivando así un comportamiento óptimo.</p><pre>def reward_function(params):<br>    &#39;&#39;&#39;<br>    Ejemplo de uso de all_wheels_on_track y la velocidad<br>    &#39;&#39;&#39;<br><br>    # Leer las variables de entrada<br>    all_wheels_on_track = params[&#39;all_wheels_on_track&#39;]<br>    speed = params[&#39;speed&#39;]<br><br>    # Definir el umbral de velocidad basado en tu espacio de acciones<br>    SPEED_THRESHOLD = 1.0<br><br>    if not all_wheels_on_track:<br>        # Penalizar si el coche se sale de la pista<br>        reward = 1e-3<br>    elif speed &lt; SPEED_THRESHOLD:<br>        # Penalizar si el coche va demasiado lento<br>        reward = 0.5<br>    else:<br>        # Alta recompensa si el coche se mantiene en la pista y va rápido<br>        reward = 1.0<br><br>    return float(reward)</pre><h3>¿Qué son los Waypoints y cómo usarlos en la Función de Recompensa?</h3><p>Cada pista tiene una secuencia de waypoints, y cada uno está definido por un par de coordenadas (x,y). Estos puntos te permiten calcular la dirección que el coche debería seguir, así como su progreso en relación a la pista.</p><p>DeepRacer tiene muchas pistas disponibles y los waypoints son públicos dentro del repositorio <a href="https://github.com/aws-deepracer-community/deepracer-race-data/tree/main/raw_data/tracks">aws-deepracer-community/deepracer-race-data</a></p><p>Puedes descargar y visualizar estos puntos dentro de un jupyter notebook: <a href="https://github.com/claudiamp/visualize-track-deepracer/blob/main/Visualize_Track.ipynb">https://github.com/claudiamp/visualize-track-deepracer/blob/main/Visualize_Track.ipynb</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GHswCntR_5Xut4cHoEe8sA.png" /></figure><h3>Cómo Crear una Función de Recompensa Basada en Waypoints</h3><p>En la siguiente función de recompensa podemos ver como se ajusta la recompensa del vehículo según la alineación de su dirección con la dirección de la pista. Calcula la dirección de la pista entre los dos puntos de referencia más cercanos (closest_waypoints) y compara esta dirección con la dirección actual del coche (heading). Si la diferencia entre estas direcciones es mayor que un umbral definido (DIRECTION_THRESHOLD), se penaliza la recompensa reduciéndola a la mitad. Esto incentiva al coche a mantener una dirección alineada con la pista para mejorar su rendimiento.</p><pre># Coloca la declaración de importación fuera de la función (bibliotecas soportadas: math, random, numpy, scipy y shapely)<br># Ejemplos de importación de las bibliotecas disponibles<br>#<br># import math<br># import random<br># import numpy<br># import scipy<br># import shapely<br>import math<br><br>def reward_function(params):<br>    ###############################################################################<br>    &#39;&#39;&#39;<br>    Ejemplo de uso de waypoints y heading para alinear el coche en la dirección correcta<br>    &#39;&#39;&#39;<br><br>    # Leer las variables de entrada<br>    waypoints = params[&#39;waypoints&#39;]<br>    closest_waypoints = params[&#39;closest_waypoints&#39;]<br>    heading = params[&#39;heading&#39;]<br><br>    # Inicializar la recompensa con un valor típico<br>    reward = 1.0<br><br>    # Calcular la dirección de la línea central basándose en los waypoints más cercanos<br>    next_point = waypoints[closest_waypoints[1]]<br>    prev_point = waypoints[closest_waypoints[0]]<br><br>    # Calcular la dirección en radianes usando arctan2(dy, dx), el resultado está en el rango (-pi, pi)<br>    track_direction = math.atan2(next_point[1] - prev_point[1], next_point[0] - prev_point[0])<br>    # Convertir a grados<br>    track_direction = math.degrees(track_direction)<br><br>    # Calcular la diferencia entre la dirección de la pista y la dirección actual del coche<br>    direction_diff = abs(track_direction - heading)<br>    if direction_diff &gt; 180:<br>        direction_diff = 360 - direction_diff<br><br>    # Penalizar la recompensa si la diferencia es demasiado grande<br>    DIRECTION_THRESHOLD = 10.0<br>    if direction_diff &gt; DIRECTION_THRESHOLD:<br>        reward *= 0.5<br><br>    return float(reward)</pre><p><strong>Conclusión</strong></p><p>Optimizar la función de recompensa es crucial para mejorar el rendimiento de tu modelo de AWS DeepRacer. Al diseñar una función de recompensa efectiva, puedes guiar al vehículo autónomo para que tome decisiones más inteligentes y se comporte de manera óptima en la pista. Desde recompensar al coche por mantener una buena alineación con la pista hasta ajustar la recompensa según la velocidad y la proximidad al centro, cada detalle cuenta para lograr el comportamiento deseado. Aprovecha los parámetros disponibles y experimenta con diferentes estrategias para encontrar la configuración que mejor se adapte a tus objetivos. Con una función de recompensa bien afinada, estarás un paso más cerca de dominar el circuito y optimizar tu modelo de DeepRacer.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ec712ffc39d1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/caleidos/optimizando-tu-modelo-de-aws-deepracer-una-gu%C3%ADa-para-dise%C3%B1ar-funciones-de-recompensa-ec712ffc39d1">Optimizando tu Modelo de AWS DeepRacer: Una Guía para Diseñar Funciones de Recompensa</a> was originally published in <a href="https://medium.com/caleidos">Caleidos</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Conexión remota a una Raspberry Pi 5 utilizando AWS IoT Device Client]]></title>
            <link>https://medium.com/caleidos/conexi%C3%B3n-remota-a-una-raspberry-pi-5-utilizando-aws-iot-device-client-d6cec8bffc02?source=rss----4da51aff11a2---4</link>
            <guid isPermaLink="false">https://medium.com/p/d6cec8bffc02</guid>
            <dc:creator><![CDATA[Claudia Márquez]]></dc:creator>
            <pubDate>Wed, 28 Aug 2024 16:18:40 GMT</pubDate>
            <atom:updated>2024-08-28T16:18:40.563Z</atom:updated>
            <content:encoded><![CDATA[<h3>Introducción</h3><p>En muchos proyectos de IoT, la capacidad de acceder y solucionar problemas de manera remota es fundamental. Ya sea para diagnosticar fallos o realizar ajustes rápidos, contar con un acceso remoto seguro a dispositivos como la Raspberry Pi 5 es clave para mantener la continuidad del proyecto. En este tutorial, te guiaré a través del proceso de configuración y uso de AWS IoT Device Client para acceder remotamente a tu Raspberry Pi 5, asegurando que siempre puedas estar preparado para realizar troubleshooting cuando sea necesario.</p><h3>Requisitos Previos</h3><p>Antes de comenzar, asegúrate de tener lo siguiente:</p><ul><li>Una Raspberry Pi 5 con una instalación limpia de Raspberry Pi OS.</li></ul><h3>Paso 1: Crear un “thing”</h3><ol><li>En la consola de AWS IoT elegimos a <strong>Manage</strong>, <strong>All devices</strong> y <strong>Create things.</strong></li><li>En la pantalla <strong>Create Things</strong> hacemos clic en <strong>Next</strong>.</li><li>En la pantalla <strong>Specify thing properties</strong> ingresamos un nombre en <strong>Thing name</strong> para nuestro dispositivo y luego hacemos clic en <strong>Next</strong>.</li><li>En la pantalla <strong>Configure device certificate — optional</strong> dejamos seleccionada la opción <strong>Auto-generate a new certificate (recommended)</strong> y hacemos clic en <strong>Next</strong>.</li><li>En la pantalla <strong>Attach Policies to certificate — optional</strong> hacemos clic en la opción <strong>Create Policy</strong></li><li>En la pantalla <strong>Create Policy </strong>ingresamos un nombre para la política en el campo <strong>Policy Name</strong>. En la sección <strong>Policy Document</strong> seleccionamos JSON y pegamos la siguiente política.</li></ol><pre>{<br>  &quot;Version&quot;: &quot;2012-10-17&quot;,<br>  &quot;Statement&quot;: [<br>    {<br>      &quot;Effect&quot;: &quot;Allow&quot;,<br>      &quot;Action&quot;: [<br>        &quot;iot:Publish&quot;,<br>        &quot;iot:Subscribe&quot;,<br>        &quot;iot:Receive&quot;,<br>        &quot;iot:Connect&quot;<br>      ],<br>      &quot;Resource&quot;: [<br>        &quot;*&quot;<br>      ]<br>    }<br>  ]<br>}</pre><p>7. Regresamos a la pantalla de creación del objeto, seleccionamos la política creada y hacemos clic en <strong>Create thing</strong>.</p><p>8. Nos aparecerá una pantalla para descargar los certificados. Necesitamos descargar el Device Certificate, Private key file y ROOT CA Certificate.</p><p>9. Debemos copiar los 3 archivos a una carpeta dentro del Raspberry Pi y darle los permisos adecuados a los certificados</p><pre>chmod 700 ~/certs<br>chmod 600 ~/certs/pi-private.pem.key</pre><p>10. También debemos anotar el endpoint que se encuentra en la pantalla de Settings de la consola de AWS IOT para la configuración que se realizará a continuación.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*yWh8vcBek2DE2ptx" /></figure><h3>Paso 2: Instalar y Configurar AWS IoT Device Client en la Raspberry Pi</h3><ol><li>Lo primero que necesitamos hacer es asegurarnos de que la Raspberry Pi esté actualizada y tenga todas las dependencias necesarias.</li></ol><pre>sudo apt-get update &amp;&amp; sudo apt-get upgrade -y<br>sudo apt-get install cmake libssl-dev vim</pre><p>2. Clonar el repositorio de AWS IoT Device Client:</p><pre>git clone https://github.com/awslabs/aws-iot-device-client<br>cd aws-iot-device-client</pre><p>3. Compilar el cliente:</p><pre>mkdir build<br>cd build<br>cmake ../<br>cmake - build . - target aws-iot-device-client</pre><p>4. Crear un archivo de configuración en la ruta /etc/.aws-iot-device-client/aws-iot-device-client.conf con el siguiente contenido. Asegurate de cambiar los datos entre &lt;&gt; con la información de los certificados y rutas obtenidas en el paso 1.</p><pre>{<br>  &quot;endpoint&quot;: &quot;&lt;tuendpoint&gt;-ats.iot.&lt;region&gt;.amazonaws.com&quot;,<br>  &quot;cert&quot;: &quot;&lt;ruta al certificado del dispositivo (.pem.crt)&gt;&quot;,<br>  &quot;key&quot;: &quot;&lt;ruta a la llave privada (.pem.key)&gt;&quot;,<br>  &quot;root-ca&quot;: &quot;&lt;ruta a AmazonRootCA1.pem&gt;&quot;,<br>  &quot;thing-name&quot;: &quot;&lt;Nombre del thing creado en el paso 1&gt;&quot;,<br>  &quot;logging&quot;: {<br>    &quot;level&quot;: &quot;WARN&quot;,<br>    &quot;type&quot;: &quot;FILE&quot;,<br>    &quot;file&quot;: &quot;/var/log/aws-iot-device-client/aws-iot-device-client.log&quot;,<br>    &quot;enable-sdk-logging&quot;: true,<br>    &quot;sdk-log-level&quot;: &quot;WARN&quot;,<br>    &quot;sdk-log-file&quot;: &quot;/var/log/aws-iot-device-client/sdk.log&quot;<br>  },<br>  &quot;jobs&quot;: {<br>    &quot;enabled&quot;: false,<br>    &quot;handler-directory&quot;: &quot;/etc/.aws-iot-device-client/jobs&quot;<br>  },<br>  &quot;tunneling&quot;: {<br>    &quot;enabled&quot;: true<br>  },<br>  &quot;device-defender&quot;: {<br>    &quot;enabled&quot;: false,<br>    &quot;interval&quot;: 300<br>  },<br>  &quot;fleet-provisioning&quot;: {<br>    &quot;enabled&quot;: false,<br>    &quot;template-name&quot;: &quot;&quot;,<br>    &quot;template-parameters&quot;: &quot;&quot;,<br>    &quot;csr-file&quot;: &quot;&quot;,<br>    &quot;device-key&quot;: &quot;&quot;<br>  },<br>  &quot;samples&quot;: {<br>    &quot;pub-sub&quot;: {<br>      &quot;enabled&quot;: false,<br>      &quot;publish-topic&quot;: &quot;&quot;,<br>      &quot;publish-file&quot;: &quot;/etc/.aws-iot-device-client/pubsub/publish-file.txt&quot;,<br>      &quot;subscribe-topic&quot;: &quot;&quot;,<br>      &quot;subscribe-file&quot;: &quot;/etc/.aws-iot-device-client/pubsub/subscribe-file.txt&quot;<br>    }<br>  },<br>  &quot;config-shadow&quot;: {<br>    &quot;enabled&quot;: false<br>  },<br>  &quot;sample-shadow&quot;: {<br>    &quot;enabled&quot;: false,<br>    &quot;shadow-name&quot;: &quot;&quot;,<br>    &quot;shadow-input-file&quot;: &quot;&quot;,<br>    &quot;shadow-output-file&quot;: &quot;&quot;<br>  }<br>}</pre><p>4. Instalaremos el cliente y lo configuremos para que funcione como servicio.</p><pre>cd ../<br>sudo ./setup.sh</pre><p>Deberás seleccionar las siguientes opciones en la configuración del setup:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*YIJgFL0P56GAWQHU" /></figure><h3>Paso 3: Conectarse por el tunel</h3><ol><li>En la consola de AWS IoT elegimos a <strong>Manage</strong>, <strong>All devices</strong> y hacemos clic en el nombre de nuestro dispositivo.</li><li>En la pagina de nuestro dispositivo haremos clic en <strong>Create secure tunnel.</strong></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cS_v4ryJwJWd5hclZ_M06A.png" /></figure><p>3. Dejaremos las opciones por defecto y haremos clic en <strong>Next.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mrLwQzmMuUlTQXFnJbbdnQ.png" /></figure><p>4. En la siguiente pantalla seleccionaremos <strong>Confirm and create.</strong></p><p>5. Nuestro tunel ya está creado, para conectarnos debemos hacer clic en <strong>Connect </strong>e ingresar el usuario y contraseña para ingresar a nustro pi.</p><p>6. Una vez ingresado nuestra contraseña, contaremos con un shell de nuestra Raspberry PI dentro de la consola de AWS.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YQ_28J2trph3OZeQP5ilxQ.png" /></figure><p>7. En caso la conexión se pierda, se puede generar nuevos llaves de acceso haciendo clic en <strong>Generate new access tokens</strong> y volvernos a connectar haciendo clic en <strong>Connect</strong>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d6cec8bffc02" width="1" height="1" alt=""><hr><p><a href="https://medium.com/caleidos/conexi%C3%B3n-remota-a-una-raspberry-pi-5-utilizando-aws-iot-device-client-d6cec8bffc02">Conexión remota a una Raspberry Pi 5 utilizando AWS IoT Device Client</a> was originally published in <a href="https://medium.com/caleidos">Caleidos</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>