<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Blog | Pablo Sanxiao</title>
    <link>https://psanxiao.com/blog.html</link>
    <description>Artículos y reflexiones sobre tecnología, software libre, sistemas de información geográfica (GIS), deporte y proyectos personales.</description>
    <language>es-es</language>
    <atom:link href="https://psanxiao.com/feed.xml" rel="self" type="application/rss+xml" />
    
        <item>
            <title>La Guía de la IA, edición desarrollo de software</title>
            <link>https://psanxiao.com/posts/2026-05-28-la-guia-de-la-IA-version-desarrollo.html</link>
            <guid isPermaLink="true">https://psanxiao.com/posts/2026-05-28-la-guia-de-la-IA-version-desarrollo.html</guid>
            <pubDate>Thu, 28 May 2026 00:00:00 +0000</pubDate>
            <description><![CDATA[<div class="toc"><span class="toctitle">Índice de contenidos</span><ul>
<li><a href="#la-infraestructura-agentica-el-nuevo-stack">La Infraestructura Agéntica: El nuevo Stack</a><ul>
<li><a href="#el-motor-de-razonamiento-capa-de-computo">El Motor de Razonamiento (Capa de Cómputo)</a></li>
<li><a href="#el-protocolo-mcp-capa-de-conectividad">El Protocolo MCP (Capa de Conectividad)</a></li>
<li><a href="#las-skills">Las Skills</a></li>
<li><a href="#arquitectura-multi-agente-capa-de-gestion">Arquitectura Multi-Agente (Capa de Gestión)</a></li>
<li><a href="#rag-estructurado-capa-de-memoria">RAG Estructurado (Capa de Memoria)</a></li>
<li><a href="#el-bucle-pev-planificar-ejecutar-verificar">El Bucle PEV: Planificar, Ejecutar, Verificar</a></li>
</ul>
</li>
<li><a href="#las-claves-de-la-ingenieria-agentica">Las claves de la Ingeniería Agéntica</a><ul>
<li><a href="#1-el-llm-como-motor-de-razonamiento">1. El LLM como motor de razonamiento</a><ul>
<li><a href="#el-razonamiento-como-proceso-de-decision-tool-use">El Razonamiento como Proceso de Decisión (Tool Use)</a></li>
</ul>
</li>
<li><a href="#2-la-taxonomia-de-modelos-especializacion-en-2026">2. La Taxonomía de Modelos: Especialización en 2026</a><ul>
<li><a href="#modelos-de-razonamiento-profundo-los-arquitectos">Modelos de Razonamiento Profundo (Los Arquitectos)</a></li>
<li><a href="#modelos-de-codigo-y-flash-los-obreros-especializados">Modelos de Código y "Flash" (Los Obreros Especializados)</a></li>
<li><a href="#modelos-de-gran-contexto-los-bibliotecarios">Modelos de Gran Contexto (Los Bibliotecarios)</a></li>
<li><a href="#el-coste-del-razonamiento">El coste del razonamiento</a></li>
<li><a href="#como-elegirlos">Cómo elegirlos</a></li>
</ul>
</li>
<li><a href="#3-estrategia-de-orquestacion-el-patron-planificador-ejecutor">3. Estrategia de Orquestación: El Patrón Planificador-Ejecutor</a><ul>
<li><a href="#integracion-de-skills-y-evaluacion-de-mcps">Integración de Skills y Evaluación de MCPs</a></li>
<li><a href="#paralelizacion-mediante-agentes-y-subagentes">Paralelización mediante Agentes y Subagentes</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#la-conexion-con-la-ingenieria-de-software-profesional">La Conexión con la Ingeniería de Software Profesional</a><ul>
<li><a href="#spec-driven-development-desarrollo-guiado-por-especificacion">Spec-Driven Development (Desarrollo Guiado por Especificación)</a><ul>
<li><a href="#el-fundamento-tecnico-reduccion-de-entropia-en-la-prediccion-de-tokens">El Fundamento Técnico: Reducción de entropía en la predicción de tokens</a></li>
<li><a href="#anatomia-de-una-especificacion-ejecutable-por-ia">Anatomía de una Especificación Ejecutable por IA</a></li>
<li><a href="#el-ciclo-de-desarrollo-guiado-por-especificaciones">El Ciclo de Desarrollo Guiado por Especificaciones</a></li>
</ul>
</li>
<li><a href="#el-harness-el-arnes-de-pruebas-y-validacion">El Harness (El Arnés de Pruebas y Validación)</a><ul>
<li><a href="#que-es-un-harness-de-ingenieria">¿Qué es un Harness de Ingeniería?</a></li>
<li><a href="#la-arquitectura-del-bucle-de-autocorreccion">La arquitectura del bucle de autocorrección</a></li>
<li><a href="#implementacion-real-y-seguridad">Implementación real y seguridad</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#conclusiones-el-verdadero-papel-del-ingeniero">Conclusiones: El verdadero papel del ingeniero</a></li>
</ul>
</div>
<p>En 2026, el desarrollo de software, con IA, ha evolucionado más allá de la simple generación de fragmentos de código mediante prompts aislados. Estamos en plena evolución, del <em>vibe coding</em> —programar por sensaciones— a una <strong>Ingeniería Agéntica</strong> más rigurosa. La IA ya no es un asistente externo; es un componente central de la arquitectura que requiere diseño, validación y observabilidad.</p>
<p>El <strong>vibe coding</strong> consiste en utilizar la IA de forma intuitiva y no estructurada: lanzar un prompt vago, copiar el código resultante, ver si funciona y, si no, pedirle que "lo arregle". Aunque es bueno para prototipar, falla estrepitosamente al escalar por tres razones técnicas:</p>
<ul>
<li><strong>Falta de Determinismo</strong>: Al no haber un "arnés" de pruebas, dependes de la suerte estadística del modelo en ese momento.</li>
<li><strong>Context Rot (Deterioro del contexto)</strong>: En chats largos, el modelo pierde los requisitos iniciales o las restricciones arquitectónicas, introduciendo bugs sutiles que solo aparecen en runtime.</li>
<li><strong>Deuda Técnica Invisible</strong>: La IA suele priorizar la solución inmediata sobre la mantenibilidad. Sin una supervisión estructural, acabas con un "código espagueti" generado por una máquina.</li>
</ul>
<h2 id="la-infraestructura-agentica-el-nuevo-stack">La Infraestructura Agéntica: El nuevo Stack</h2>
<p>Para crear aplicaciones robustas, hemos pasado de "chatear" a implementar una infraestructura de <strong>Ingeniería Agéntica</strong>, o al menos lo estamos intentado. Esta se basa en algunas capas fundamentales, de forma resumida:</p>
<h3 id="el-motor-de-razonamiento-capa-de-computo">El Motor de Razonamiento (Capa de Cómputo)</h3>
<p>Ya no tratamos al LLM como una enciclopedia, sino como una CPU lógica.</p>
<ul>
<li><strong>Modelos de Razonamiento Profundo</strong>: En 2026, usamos modelos que ejecutan una <strong>Cadena de Pensamiento (CoT)</strong> interna para validar su lógica antes de escribir código.</li>
<li><strong>Evaluaciones Automáticas</strong>: El sistema no acepta el código porque "parezca correcto"; lo pasa por un banco de pruebas (evaluaciones) que miden su precisión técnica.</li>
</ul>
<h3 id="el-protocolo-mcp-capa-de-conectividad">El Protocolo MCP (Capa de Conectividad)</h3>
<p>El <strong>Model Context Protocol (MCP)</strong> es el estándar que permite a la IA interactuar con herramientas reales de forma segura.</p>
<ul>
<li>En lugar de que el desarrollador copie y pegue logs de error, el agente tiene una <strong>Skill</strong> conectada vía MCP que le permite leer los logs del servidor, consultar la base de datos o revisar el historial de Git por sí mismo.</li>
</ul>
<h3 id="las-skills">Las Skills</h3>
<p>Las <strong>skills</strong> (o habilidades) son las funciones deterministas y herramientas específicas que ponemos a disposición del agente para que pueda interactuar con el entorno real. Un modelo de lenguaje por sí solo es puramente predictivo, por lo que una skill actúa como su "brazo ejecutor": un fragmento de código (generalmente funciones en Python o TypeScript) diseñado para realizar una tarea concreta, como ejecutar un test unitario, consultar el esquema de una base de datos o leer los logs de un servidor.</p>
<p>Para que el agente pueda utilizarlas, no basta con programar la función lógica, sino que es imprescindible acompañarla de una descripción semántica muy clara. El modelo lee este "contrato" o definición de la skill, comprende para qué sirve y qué parámetros necesita, y decide de manera autónoma cuándo y cómo invocarla en su bucle de razonamiento según los requerimientos del software que está desarrollando.</p>
<h3 id="arquitectura-multi-agente-capa-de-gestion">Arquitectura Multi-Agente (Capa de Gestión)</h3>
<p>En lugar de un único "super-agente", dividimos el trabajo en agentes especializados.</p>
<ul>
<li><strong>Arquitecto</strong>: Define el plan y las interfaces.</li>
<li><strong>Programador</strong>: Implementa la lógica siguiendo el plan.</li>
<li><strong>QA/Tester</strong>: Intenta romper el código del programador antes de que llegue a revisión humana.</li>
</ul>
<h3 id="rag-estructurado-capa-de-memoria">RAG Estructurado (Capa de Memoria)</h3>
<p>Para que la IA "entienda" un repositorio de miles de archivos, usamos <strong>Retrieval-Augmented Generation (RAG)</strong> avanzado.</p>
<ul>
<li><strong>Embeddings de Código</strong>: El sistema fragmenta el código en vectores semánticos, permitiendo que el agente recupere exactamente el componente necesario para su tarea actual sin saturar su ventana de contexto.</li>
</ul>
<p>Para saber más sobre esto, puedes consultar la versión original de <a href="https://psanxiao.com/posts/2026-03-07-la-guia-de-la-IA.html">La Guía de la IA</a> , donde explicamos este y otros conceptos.</p>
<h3 id="el-bucle-pev-planificar-ejecutar-verificar">El Bucle PEV: Planificar, Ejecutar, Verificar</h3>
<p>La diferencia real con el <em>vibe coding</em> es el rigor en el flujo de trabajo. En la ingeniería agéntica, el proceso es circular y auto-corregido:</p>
<ol>
<li><strong>Planificación</strong>: El agente genera un <code>PLAN.md</code> que detalla los cambios. El humano lo audita.</li>
<li><strong>Ejecución</strong>: El agente aplica los cambios en un entorno aislado (sandbox).</li>
<li><strong>Verificación</strong>: Se ejecutan tests automáticos, linters y análisis de seguridad. Si falla, el agente recibe el feedback y vuelve al paso 2 sin intervención humana.</li>
</ol>
<p>En 2026, el desarrollo profesional ya no va sobre quien escribe mejor el código, sino sobre quien diseña los mejores <strong>prompts sistémicos</strong>, las <strong>herramientas MCP</strong> y los <strong>criterios de aceptación</strong> para que su infraestructura agéntica construya software de forma segura y escalable.</p>
<p>O al menos, esa es la teoría.</p>
<h2 id="las-claves-de-la-ingenieria-agentica">Las claves de la Ingeniería Agéntica</h2>
<h3 id="1-el-llm-como-motor-de-razonamiento">1. El LLM como motor de razonamiento</h3>
<p>Para construir software con IA en 2026, el primer paso es dejar de ver al LLM como una base de datos de conocimiento y empezar a verlo como un <strong>motor de razonamiento probabilístico</strong>. En esta fase de la ingeniería agéntica, el modelo no solo genera texto; actúa como el "cerebro" que evalúa el estado de un sistema, decide qué herramientas invocar y valida sus propios resultados.</p>
<h4 id="el-razonamiento-como-proceso-de-decision-tool-use">El Razonamiento como Proceso de Decisión (Tool Use)</h4>
<p>La gran diferencia entre los modelos de "chat" de años anteriores y los actuales modelos de <strong>razonamiento profundo</strong> es la capacidad de gestionar el <strong>Tool Use</strong> (o Function Calling) con criterio técnico.</p>
<p>Anteriormente, los modelos a menudo sufrían de "precipitación": intentaban responder antes de analizar las pre-condiciones. Hoy, los modelos especializados en razonamiento utilizan un <strong>monólogo interno</strong> o <strong>Cadena de Pensamiento (CoT)</strong> para:</p>
<ul>
<li><strong>Analizar la intención</strong>: ¿Qué está pidiendo realmente el desarrollador?.</li>
<li><strong>Seleccionar la herramienta</strong>: Evaluar si necesita consultar el esquema de la base de datos vía <strong>MCP</strong> o si puede resolverlo con la información en su ventana de contexto.</li>
<li><strong>Anticipar efectos</strong>: Razonar sobre cómo un cambio en un modelo de datos afectará a los controladores y a la UI antes de escribir la primera línea de código.</li>
</ul>
<h3 id="2-la-taxonomia-de-modelos-especializacion-en-2026">2. La Taxonomía de Modelos: Especialización en 2026</h3>
<p>No existe un "modelo único" para todo. La ingeniería moderna se basa en la <strong>orquestación selectiva</strong> según las capacidades y costes de cada familia de modelos:</p>
<h4 id="modelos-de-razonamiento-profundo-los-arquitectos">Modelos de Razonamiento Profundo (Los Arquitectos)</h4>
<p>Estos modelos priorizan el <strong>acierto sobre la velocidad</strong>.</p>
<ul>
<li><strong>Fortaleza</strong>: Excelente capacidad para resolver problemas de lógica pura, matemáticas y diseño de sistemas complejos.</li>
<li><strong>Uso ideal</strong>: Planificación de refactorizaciones masivas, resolución de bugs lógicos profundos y orquestación inicial de tareas agénticas.</li>
</ul>
<h4 id="modelos-de-codigo-y-flash-los-obreros-especializados">Modelos de Código y "Flash" (Los Obreros Especializados)</h4>
<p>Modelos optimizados para baja latencia y alta eficiencia en tareas sintácticas.</p>
<ul>
<li><strong>Fortaleza</strong>: Generación de <em>boilerplate</em>, escritura de tests unitarios y documentación.</li>
<li><strong>Uso ideal</strong>: Autocompletado inteligente dentro del IDE y ejecución de sub-tareas definidas previamente por un modelo arquitecto.</li>
</ul>
<h4 id="modelos-de-gran-contexto-los-bibliotecarios">Modelos de Gran Contexto (Los Bibliotecarios)</h4>
<p>Modelos capaces de ingerir millones de tokens (repositorios enteros) en una sola sesión.</p>
<ul>
<li><strong>Fortaleza</strong>: Capacidad para mantener la coherencia global en proyectos gigantescos sin depender exclusivamente de RAG externo.</li>
<li><strong>Uso ideal</strong>: Auditorías de seguridad de todo el código base o migración de versiones de frameworks en múltiples archivos simultáneamente.</li>
</ul>
<p>Los modelos especializados en desarrollo de software son entrenados específicamente, pero no todos los entrenamientos son iguales. Fruto de ello, la manera en la que se enfrentan a una tarea es diferente. Algunos intentarán realizarla de forma global, pero si es demasiado grande se pueden perder entre el contexto, olvidar cosas durante la ejecución, etc. Hay modelos que son entrenados para realizar un plan previo, a modo de TODO, descomponiendo la tarea en pasos concretos, y luego ejecutarlos. Estos suelen conseguir mejores resultados porque manejan mejor todo el contexto, incluso pueden reevaluar el resultado de la subtarea anterior si ven algún problema.</p>
<h4 id="el-coste-del-razonamiento">El coste del razonamiento</h4>
<p>Como ingenieros, debemos entender que el razonamiento no es gratuito. Los modelos que "piensan más" tienen:</p>
<ol>
<li><strong>Mayor Latencia</strong>: El tiempo de respuesta es más alto porque el modelo genera miles de tokens internos de razonamiento que tú no ves.</li>
<li><strong>Mayor Coste de Inferencia</strong>: Estamos pagando por esos tokens de pensamiento interno.</li>
</ol>
<p>Por tanto, usar un modelo de razonamiento profundo para añadir un comentario a una función es un <strong>anti-patrón de ingeniería</strong>. El criterio técnico consiste en equilibrar la complejidad del problema con la potencia del motor de razonamiento elegido.</p>
<h4 id="como-elegirlos">Cómo elegirlos</h4>
<p>Existen rankings técnicos de referencia que permiten orientar la elección del modelo según la tarea: <strong>LMSYS Arena</strong>destaca en preferencias de programación general, <strong>LiveCodeBench</strong> evalúa lógica pura frente a problemas inéditos, y <strong>SWE-bench</strong> mide la capacidad de resolver <em>issues</em> reales de GitHub, lo cual es crítico para elegir un modelo "Arquitecto". Estas herramientas, junto con el leaderboard de <strong>Aider</strong> para edición de archivos, ofrecen una visión clara de qué modelos lideran en razonamiento y ejecución sintáctica en 2026.</p>
<p>No obstante, es fundamental tomar estos datos con prudencia; los benchmarks son entornos controlados que no siempre reflejan las fricciones de una infraestructura agéntica privada. Para una implementación profesional, los rankings deben servir solo como punto de partida, debiendo ser validados con métricas propias de observabilidad que analicen la latencia, el coste por millón de tokens y la precisión específica dentro de tu propio código base.</p>
<p>En el argot ciclista solemos decir que lo importante es el indio, no la flecha. Un buen ciclista con peor material (la bicicleta) siempre será mejor que uno mediocre aunque este lleve lo mejor de lo mejor. El cómo construyamos herramientas alrededor de un modelo, el cómo le demos contexto, instrucciones, etc. puede hacer que un modelo en teoría más modesto nos consiga mejores resultados.</p>
<h3 id="3-estrategia-de-orquestacion-el-patron-planificador-ejecutor">3. Estrategia de Orquestación: El Patrón Planificador-Ejecutor</h3>
<p>La efectividad de un modelo no depende solo de cuántos miles de millones de parámetros tiene, sino de cómo ha sido entrenado para enfrentarse a una tarea. Mientras que los modelos generalistas intentan resolver peticiones de forma global —lo que a menudo provoca que se "pierdan" en el contexto o ignoren restricciones críticas al final de una respuesta larga—, los modelos de razonamiento profundo actúan bajo una lógica de <strong>planificación previa</strong>. Este entrenamiento les permite generar un "monólogo interno" o un mapa de tareas (TODO) donde descomponen el problema en pasos atómicos antes de escribir la primera línea de código.</p>
<p>Esta capacidad de descomposición es lo que permite manejar proyectos complejos sin que la calidad del código se degrade. Al centrarse en subtareas específicas —como definir primero la interfaz, luego la lógica del repositorio y finalmente los tests—, el modelo mantiene una atención mucho más cerrada sobre las reglas de negocio de cada fragmento. Además, este enfoque permite la <strong>reevaluación dinámica</strong>: si el modelo detecta un error en el paso tres, tiene la capacidad de retroceder y ajustar el paso uno, algo que un modelo de generación directa simplemente no puede hacer porque su proceso es puramente predictivo y hacia adelante.</p>
<p>Por eso, en una infraestructura agéntica profesional, el éxito reside en saber qué "cerebro" asignar a cada fase del desarrollo. Utilizamos modelos de razonamiento profundo, como <strong>OpenAI o1</strong> o <strong>DeepSeek-R1</strong>, para la fase de arquitectura y planificación, donde el acierto y la lógica son innegociables. Una vez que el plan es sólido y las subtareas están definidas, podemos delegar la ejecución mecánica en modelos más rápidos y económicos como <strong>Claude 3.5 Haiku</strong> o <strong>GPT-4o-mini</strong>, que destacan por su precisión sintáctica y velocidad. Esta orquestación no solo optimiza el coste y el tiempo de entrega, sino que garantiza que el resultado final sea fruto de una arquitectura pensada y no de una simple probabilidad estadística.</p>
<h4 id="integracion-de-skills-y-evaluacion-de-mcps">Integración de Skills y Evaluación de MCPs</h4>
<p>Un modelo de lenguaje, por muy especializado que esté en código, vive aislado en un entorno puramente conceptual. Para que pueda operar de forma autónoma en el mundo real, necesita herramientas de interacción directa que actúen como sus manos y sus ojos. Estas herramientas se dividen en dos conceptos clave: las <em>skills</em> y los conectores de contexto.</p>
<p>Con el plan trazado, el sistema debe activar las herramientas necesarias para interactuar con el entorno. Aquí es donde integramos las <strong>skills</strong>: las funciones deterministas escritas en código (Python o TypeScript) que permiten al agente ejecutar acciones concretas como correr un linter o empaquetar un binario.</p>
<p>En paralelo, el ingeniero debe evaluar si la tarea requiere conectar con fuentes de información externas o bases de datos locales; de ser así, se despliegan servidores basados en el protocolo <strong>MCP (Model Context Protocol)</strong>. El MCP actúa como el sistema nervioso del agente, permitiéndole consultar de forma estructurada el esquema de una base de datos PostgreSQL, leer archivos locales o comunicarse con APIs de terceros sin saturar la ventana de contexto con volcados masivos de texto.</p>
<p>Cuando te enfrentas a un problema que puede resolverse tanto con una skill como con un servidor MCP —el acceso a una base de datos es el ejemplo de manual—, la elección debe basarse en un criterio de eficiencia y seguridad. Los servidores MCP son excelentes como conectores universales y exploratorios, pero tienden a consumir mucha más ventana de contexto porque vuelcan metadatos estructurados y relaciones complejas para que el modelo decida de forma abierta. Una skill, en cambio, ofrece un control ultra-específico: tú defines la consulta exacta, ahorrando tokens y forzando al modelo a recibir una respuesta atómica. Sin embargo, hay un factor crítico: el riesgo de ejecución. Mientras que un servidor MCP suele estar limitado por diseño a la lectura del contexto, una skill basada en un script local suele ejecutarse con permisos completos de escritura por defecto. Si vas a usar una skill para interactuar con tus datos, es una buena práctica obligatoria crear usuarios del sistema o de la base de datos con permisos capados exclusivamente a nivel de lectura, impidiendo que una mala interpretación del agente altere accidentalmente los datos de tu entorno.</p>
<h4 id="paralelizacion-mediante-agentes-y-subagentes">Paralelización mediante Agentes y Subagentes</h4>
<p>Para evitar cuellos de botella en proyectos de gran envergadura, la arquitectura debe estructurarse mediante una jerarquía de agentes y subagentes. Un agente supervisor recibe el plan general y distribuye las subtareas de manera síncrona o asíncrona entre subagentes especializados que corren en paralelo. Mientras un subagente desarrolla el componente de autenticación, otro puede estar generando de forma simultánea la lógica de la API de pagos. Esta paralelización no solo acelera el ciclo de desarrollo, sino que compartimenta el contexto, asegurando que un error en un módulo no contamine el razonamiento del resto del sistema.</p>
<h2 id="la-conexion-con-la-ingenieria-de-software-profesional">La Conexión con la Ingeniería de Software Profesional</h2>
<p>Toda esta orquestación agéntica cobra sentido real cuando se conecta con dos metodologías críticas que garantizan que el código generado sea predecible, seguro y mantenible.</p>
<h3 id="spec-driven-development-desarrollo-guiado-por-especificacion">Spec-Driven Development (Desarrollo Guiado por Especificación)</h3>
<p>El mayor error que cometen los desarrolladores al integrar agentes de IA en sus flujos de trabajo es asumir que el modelo "entiende" la arquitectura solo porque puede leer el código. Cuando delegamos tareas complejas a un sistema agéntico basándonos en instrucciones abiertas en lenguaje natural ("implementa el módulo de pasarela de pagos"), exponemos al sistema a la deriva semántica. El resultado suele ser un bucle infinito de correcciones, dependencias rotas y código que funciona de forma aislada pero destruye la consistencia del repositorio.</p>
<p>Para construir software profesional con modelos probabilísticos, necesitamos un marco determinista: el <strong>Spec-Driven Development (SDD)</strong> o Desarrollo Guiado por Especificación.</p>
<h4 id="el-fundamento-tecnico-reduccion-de-entropia-en-la-prediccion-de-tokens">El Fundamento Técnico: Reducción de entropía en la predicción de tokens</h4>
<p>Para entender por qué el SDD es imprescindible, debemos recordar cómo funciona un LLM por debajo. Un modelo de lenguaje no compila lógica; calcula la probabilidad estadística de la siguiente unidad de información o token.</p>
<p>Cuando lanzas una petición abierta en lenguaje natural, el espacio semántico de respuestas válidas tiende al infinito. El modelo se ve obligado a elegir entre miles de formas posibles de estructurar una función, nombrar variables o manejar errores. Cuanto mayor es la libertad del modelo, mayor es la <strong>entropía</strong> (el desorden del sistema) y, por tanto, mayor es la probabilidad de que ocurra una alucinación técnica o una inconsistencia arquitectónica.</p>
<p>El Spec-Driven Development mitiga este problema convirtiendo el lenguaje natural vago en un conjunto de restricciones rígidas e innegociables antes de que el agente escriba una sola línea de código de producción. Al alimentar al agente con una especificación técnica estricta (como un esquema JSON o un contrato OpenAPI), acotamos el espacio matemático de soluciones. El modelo ya no tiene que inventar la estructura; solo tiene que calcular los tokens que mejor se ajustan al contrato predefinido. La indeterminación de la IA se reduce al mínimo porque el margen de error probabilístico queda encajonado por la regla de negocio.</p>
<h4 id="anatomia-de-una-especificacion-ejecutable-por-ia">Anatomía de una Especificación Ejecutable por IA</h4>
<p>Una especificación para consumo agéntico no es un documento de requerimientos tradicional lleno de prosa. Debe ser una <strong>fuente de verdad estructurada y procesable</strong> que sirva como contrato tanto para el programador humano como para la flota de subagentes.</p>
<p>Una <em>spec</em> efectiva debe contener tres capas de aislamiento:</p>
<ul>
<li><strong>El Contrato de Interfaz (Sintaxis Estricta)</strong>: Define las firmas exactas de las funciones, los endpoints de las APIs, los tipos de datos de entrada y salida, y los códigos de respuesta esperados. Utilizar formatos estandarizados como OpenAPI (Swagger) o esquemas de TypeScript TypeScript-first asegura que el modelo no improvise nombres de parámetros o tipos de variables.</li>
<li><strong>Las Reglas de Dominio (Semántica de Negocio)</strong>: Describe el comportamiento lógico esperado bajo condiciones específicas. En lugar de explicarlo con ambigüedad, se define mediante lógica booleana o pseudocódigo declarativo (ej: <code>si el estado del usuario es INACTIVO, la API debe retornar 403 inmediatamente</code>).</li>
<li><strong>Restricciones de Infraestructura y Estilo</strong>: Establece qué librerías específicas están permitidas y cuáles están explícitamente prohibidas (ej: <code>usar Leaflet para mapas, prohibido usar OpenLayers</code>), el patrón arquitectónico obligatorio (ej: clean architecture, inyección de dependencias) y las directrices de manejo de excepciones.</li>
</ul>
<h4 id="el-ciclo-de-desarrollo-guiado-por-especificaciones">El Ciclo de Desarrollo Guiado por Especificaciones</h4>
<p>En un entorno de ingeniería real, el flujo de trabajo sigue una secuencia rígida dividida entre la toma de decisiones estratégicas (humano) y la ejecución sintáctica (IA).</p>
<ul>
<li><strong>Diseño de la Spec</strong>: El desarrollador humano colabora con un modelo de razonamiento profundo para redactar la especificación técnica (<code>SPEC.md</code> u OpenAPI).</li>
<li><strong>Auditoría y Bloqueo</strong>: El humano audita la especificación, asegura que cubre las reglas de negocio y los casos límite, y bloquea el archivo. A partir de este momento, la <em>spec</em> es inmutable para los agentes</li>
<li><strong>Inyección y Ejecución</strong>: La <em>spec</em> se inyecta en el contexto de los subagentes ejecutores. Los subagentes programan las funciones ciñéndose estrictamente a las interfaces definidas.</li>
<li><strong>Validación en el Harness</strong>: El código generado se envía directamente al <strong>harness</strong> (el arnés de pruebas automatizadas). El arnés compila el código, corre linters, ejecuta tests unitarios y estresa la aplicación contra los criterios definidos en la especificación. Si un test falla, los logs se devuelven al agente que autocorrige su código hasta cumplir el contrato.</li>
</ul>
<h3 id="el-harness-el-arnes-de-pruebas-y-validacion">El Harness (El Arnés de Pruebas y Validación)</h3>
<p>Una vez que los subagentes generan el código basándose en la especificación, el sistema no puede dar la tarea por buena sin una validación automática: aquí entra el <strong>harness</strong> (o arnés de ingeniería). El <em>harness</em> es el entorno aislado (sandbox o contenedor) provisto de un banco de pruebas automáticas (tests unitarios, de integración, linters y analizadores estáticos de seguridad) diseñados específicamente para validar el código producido. El agente no interactúa directamente con producción; entrega su código al arnés. Si el código pasa todas las pruebas del <em>harness</em>, se considera válido; si falla, los logs de error se inyectan automáticamente en la ventana de contexto del agente como retroalimentación para que inicie su bucle de autocorrección sin intervención humana. El <em>harness</em> es, en definitiva, la red de seguridad técnica que transforma la probabilidad del LLM en el determinismo que exige el software profesional.</p>
<h4 id="que-es-un-harness-de-ingenieria">¿Qué es un Harness de Ingeniería?</h4>
<p>En el desarrollo de software AI-First, el <strong>harness</strong> (o arnés de validación) es un entorno aislado de ejecución —generalmente implementado mediante sandboxes o contenedores seguros— diseñado para interceptar, ejecutar y evaluar de forma determinista el código producido por un agente antes de que este pueda ser integrado en el repositorio principal.</p>
<p>El arnés actúa como un árbitro neutral. Su filosofía es simple: no importa lo seguro que el modelo afirme estar sobre su propuesta; el código no tiene valor hasta que demuestra su validez en runtime bajo pruebas controladas. El agente no interactúa de forma directa con las ramas productivas ni realiza commits automáticos; su único canal de entrega es el propio arnés.</p>
<h4 id="la-arquitectura-del-bucle-de-autocorreccion">La arquitectura del bucle de autocorrección</h4>
<p>La principal virtud del <em>harness</em> no es solo detener el código defectuoso, sino cerrar el bucle de retroalimentación (<em>feedback loop</em>) para que el sistema se repare a sí mismo sin consumir tiempo del desarrollador humano. Esta infraestructura opera en cuatro etapas secuenciales:</p>
<ul>
<li><strong>Intercepción y Aislamiento</strong>: El agente finaliza la edición de un componente y envía los archivos modificados al arnés. Esta ejecución ocurre dentro de un contenedor efímero (ej. Docker) totalmente aislado de la máquina local y de los servidores de producción para mitigar riesgos de seguridad.</li>
<li><strong>Análisis Estático y Estilo</strong>: El arnés somete los archivos a herramientas automáticas de formateo y estilo (linters como ESLint o Black) y a analizadores estáticos de seguridad. Si el modelo ha inventado una dependencia, ha dejado una credencial expuesta en el código o viola las reglas de tipado estricto, el arnés detiene el proceso.</li>
<li><strong>Ejecución de la Suite de Pruebas</strong>: El arnés lanza de forma automatizada las pruebas unitarias y de integración vinculadas al módulo modificado. Estas pruebas han sido predefinidas por el equipo de ingeniería o generadas a partir de una especificación técnica rígida (<em>Spec-Driven Development</em>).</li>
<li><strong>Enrutamiento del Output (Paso o Corrección)</strong>: Si el código supera todas las pruebas del pipeline de forma determinista, el arnés valida la tarea y genera automáticamente una solicitud de extracción (Pull Request) para la revisión final del ingeniero humano. Si se detecta un fallo, el arnés intercepta la salida estándar de error (<code>stderr</code>), captura los logs detallados del compilador o del framework de pruebas, y los inyecta estructuradamente de vuelta en el contexto del agente.</li>
</ul>
<h4 id="implementacion-real-y-seguridad">Implementación real y seguridad</h4>
<p>Desplegar un arnés profesional requiere tomar decisiones estrictas de infraestructura, poniendo especial atención en dos factores críticos:</p>
<ul>
<li>
<p><strong>Sandboxing estricto:</strong> Permitir que un LLM ejecute código de forma dinámica significa darle la capacidad de correr comandos en el terminal. El arnés debe estar completamente capado a nivel de red (sin acceso a internet a menos que sea estrictamente necesario para descargar dependencias controladas) y con acceso restringido al sistema de archivos para evitar que un bucle defectuoso o una inyección de prompt comprometa la infraestructura de la empresa.</p>
</li>
<li>
<p><strong>Condición de parada y control de costes:</strong> Un agente atrapado en un error lógico complejo puede intentar corregirse a sí mismo infinitamente, consumiendo miles de tokens en el proceso. El arnés debe configurar límites estrictos de ejecución (ej: un máximo de 3 a 5 intentos de autocorrección). Si el agente no logra superar los tests tras el límite fijado, el arnés aborta la operación, congela el estado y alerta al desarrollador humano proporcionando la traza completa para su intervención.</p>
</li>
</ul>
<h2 id="conclusiones-el-verdadero-papel-del-ingeniero">Conclusiones: El verdadero papel del ingeniero</h2>
<p>En esta era de la IA —y ya veremos lo que viene después—, la ingeniería del software seguirá siendo ingeniería del software. No estamos presenciando el fin de nuestra profesión, sino una evolución directa de nuestras responsabilidades. Los ingenieros seguiremos exactamente en nuestro papel de siempre, enfrentados ahora a un nuevo reto arquitectónico: intentar hacer que un modelo probabilístico se comporte de forma determinista.</p>
<p>El tablero se ha movido y el valor ya no está en el acto mecánico de escribir código, sino en crear los sistemas, las especificaciones y los arneses de validación necesarios para garantizar que lo que escriban las máquinas sea bueno, seguro y mantenible. Nuestra función es domar la estadística subyacente de los modelos y transformarla en software predecible de producción.</p>
<p>Seguiremos haciendo lo que sabemos hacer, ingeniería.</p>]]></description>
        </item>
    
        <item>
            <title>Gemma 4 en local: Del chat a la automatización con OpenCode y LM Studio</title>
            <link>https://psanxiao.com/posts/2026-04-22-gemma4-local-con-lmstudio-opencode.html</link>
            <guid isPermaLink="true">https://psanxiao.com/posts/2026-04-22-gemma4-local-con-lmstudio-opencode.html</guid>
            <pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate>
            <description><![CDATA[<p>Hasta hace muy poco, los modelos locales eran poco más que una curiosidad técnica o juguetes para tareas extremadamente simples. El lanzamiento reciente de Gemma 4 se presenta como un paso adelante: un modelo que promete capacidades de razonamiento serias en un tamaño lo suficientemente contenido como para correr en un portátil convencional.</p>
<p>Esto no significa necesariamente que vayamos a cancelar nuestras suscripciones hoy mismo. La propuesta de valor de Gemma 4 es, sobre el papel, ayudarnos a ahorrar tokens de nuestras cuentas de pago y ganar privacidad en tareas mecánicas o procesamiento de datos locales. En este post, vamos a comprobar si realmente es capaz de actuar como un agente operativo configurándolo con LM Studio y OpenCode.</p>
<h2 id="el-fundamento-que-significan-los-numeros">El Fundamento: ¿Qué significan los números?</h2>
<p>Al buscar Gemma 4, verás nomenclaturas como "26B A4B". Descifrarlas es vital para no bloquear tu máquina:</p>
<ul>
<li>
<p>Los Parámetros (B): La "B" significa Billions (miles de millones). Son las variables que el modelo ajustó durante su entrenamiento. A más parámetros, mayor capacidad de razonamiento.</p>
</li>
<li>
<p>Arquitectura MoE (Mixture of Experts): El modelo 26B A4B tiene 26 mil millones de parámetros totales, pero solo activa 4 mil millones (Active) por cada token generado. Obtienes la inteligencia de un modelo grande con la velocidad de uno pequeño, aunque necesitas RAM para alojar los 26B enteros.</p>
</li>
</ul>
<h2 id="el-formato-gguf-vs-mlx">El Formato: GGUF vs MLX</h2>
<ul>
<li>
<p><strong>GGUF: El estándar universal</strong>. Es el formato más común para Windows o Linux. Su gran ventaja es el GPU Offloading: si el modelo no cabe entero en tu tarjeta gráfica (VRAM), GGUF permite que la CPU ayude con el trabajo sobrante de forma transparente.</p>
</li>
<li>
<p><strong>MLX: El "traje a medida" para Apple Silicon</strong>. Si tienes un Mac (M1 a M4), el formato MLX es superior. Está diseñado por Apple para aprovechar la memoria unificada, permitiendo que la CPU y la GPU compartan datos instantáneamente sin cuellos de botella. Es más rápido y eficiente que cualquier otro formato en esta arquitectura.</p>
</li>
</ul>
<h2 id="cuantizacion-por-que-hablamos-de-bits">Cuantización: ¿Por qué hablamos de "Bits"?</h2>
<p>Los pesos originales de un modelo ocupan mucha memoria (16 bits). Cuantizar es reducir esos bits para que el modelo quepa en hardware doméstico:</p>
<ul>
<li>
<p><em>8 bits</em>: Casi sin pérdida de inteligencia, pero pesado.</p>
</li>
<li>
<p><em>4 bits (Q4_K_M)</em>: El estándar de oro. El modelo ocupa una cuarta parte del original con una pérdida mínima de razonamiento. Siempre que puedas, apunta a este nivel.</p>
</li>
<li>
<p><em>2 bits</em>: El modelo se vuelve "torpe" y pierde coherencia lógica. Solo como último recurso.</p>
</li>
</ul>
<h2 id="licencia-apache-20-un-cambio-de-paradigma">Licencia Apache 2.0: Un cambio de paradigma</h2>
<p>Uno de los aspectos más disruptivos de Gemma 4 no es técnico, sino legal. Históricamente, modelos como Llama o las versiones previas de Gemma utilizaban licencias personalizadas de "pesos abiertos" que imponían restricciones de uso comercial o límites de usuarios.</p>
<p>Gemma 4 rompe con esto al adoptar la licencia Apache 2.0. A diferencia de los modelos anteriores que eran "abiertos pero con condiciones", Apache 2.0 es una licencia permisiva de software libre real. Esto permite a cualquier desarrollador o empresa modificar, distribuir y usar el modelo con mayor libertad.</p>
<h2 id="mas-alla-del-chat-gemma-4-en-modo-agente">Más allá del chat: Gemma 4 en Modo Agente</h2>
<p>Aquí es donde Gemma 4 brilla frente a sus predecesores. Ha sido diseñada con soporte nativo para function-calling y flujos de trabajo agénticos. Mientras que en LM Studio solo tienes un chat, herramientas como OpenCode permiten que Gemma 4 actúe como un agente de codificación.</p>
<h3 id="que-es-opencode">¿Qué es OpenCode?</h3>
<p>OpenCode es un agente de código abierto para tu terminal o IDE que puede leer tus archivos, ejecutar comandos de shell y aplicar correcciones automáticamente. No solo te da el código; crea el archivo, lo prueba y lo itera hasta que funciona.</p>
<h3 id="configuracion-del-entorno-paso-a-paso">Configuración del entorno (paso a paso)</h3>
<p>Para tener este flujo de trabajo, necesitamos conectar ambas herramientas:</p>
<p><strong>En LM Studio</strong>:</p>
<ul>
<li>
<p>Descarga Gemma 4 26B A4B (o la versión E4B si tienes poca RAM).</p>
</li>
<li>
<p>Ve a la pestaña de Local Server y actívalo en el puerto 1234.</p>
</li>
<li>
<p>Asegúrate de subir el GPU Offload al máximo y ajustar el contexto a un mínimo de 32K.</p>
</li>
</ul>
<p><strong>En OpenCode</strong>:</p>
<p>Configura el archivo opencode.json para que apunte a tu servidor local:</p>
<div class="codehilite"><pre><span></span><code><span class="nt">&quot;lmstudio&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w">  </span><span class="nt">&quot;name&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;LM Studio&quot;</span><span class="p">,</span>
<span class="w">  </span><span class="nt">&quot;npm&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;@ai-sdk/openai-compatible&quot;</span><span class="p">,</span>
<span class="w">  </span><span class="nt">&quot;options&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="nt">&quot;baseURL&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;http://localhost:1234/v1&quot;</span><span class="p">,</span>
<span class="w">    </span><span class="nt">&quot;apiKey&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;lm-studio&quot;</span>
<span class="w">  </span><span class="p">},</span>
<span class="w">  </span><span class="nt">&quot;models&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="nt">&quot;gemma-4-e2b&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w">      </span><span class="nt">&quot;name&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Gemma 4 Local (LM Studio)&quot;</span>
<span class="w">    </span><span class="p">}</span>
<span class="w">  </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>

<p>Ahora, desde tu terminal, puedes lanzar comandos como: opencode "refactoriza este componente usando hooks de React" y el agente usará a Gemma 4 para realizar la tarea directamente en tu sistema de archivos.</p>
<p>Aunque sobre el papel todo parece sencillo, suele haber un problema con estas configuraciones. Le pides a opencode que haga algo usando gemma 4 y en lugar de esa acción te entrega un mensaje diciendo como se hace. Las herramientas no se terminan de entender entre sí. Raro en informática verdad?.</p>
<h2 id="que-es-la-paralisis-del-modelo">¿Qué es la parálisis del modelo?</h2>
<p>Aunque Gemma 4 está entrenada para actuar como agente, su entrenamiento de refuerzo (RLHF) a menudo prioriza ser un "asistente servicial de chat". Ante una orden como "lista los archivos", el modelo puede caer en la parálisis de explicar en lugar de ejecutar. Te dirá "Para ver los archivos deberías usar ls" en lugar de emitir el comando técnico que OpenCode necesita procesar.</p>
<h3 id="el-system-prompt-como-protocolo-operativo">El System Prompt como Protocolo Operativo</h3>
<p>Para romper esta inercia, debemos configurar un System Prompt en LM Studio que actúe como un "contrato de ejecución". No le estamos enseñando capacidades nuevas; le estamos indicando qué rol operativo debe asumir en este flujo de trabajo, por ejemplo:</p>
<p>"Eres un asistente de programación integrado en el terminal mediante OpenCode. Obligatorio: Para cualquier acción que requiera el sistema (leer archivos, listar directorios, ejecutar comandos), utiliza siempre el formato de herramientas de OpenCode. No te limites a escribir el comando, ejecútalo."</p>
<p>Este prompt garantiza que el modelo pase del modo "consultor" al modo "ejecutor", emitiendo las señales JSON correctas para que OpenCode actúe sobre tu sistema de archivos.</p>
<h2 id="conclusion">Conclusión</h2>
<p>Gemma 4 es el primer modelo abierto que realmente permite un desarrollo local-first con capacidades agénticas algo serias. Pero seamos realistas, no se puede comparar con los servicios por API de los big players. Es una buena alternativa para no gastar tokens en tareas sencillas. Y Evidentemente, si tienes que trabajar con datos sensibles o necesitas privacidad y trabajar en local, aunque sea limitado, puede ser una gran ayuda.</p>
<p>Esto abre posibilidades interesantes, además, para explorar técnicas de trabajo con IA sin quemar el presupuesto de tokens. Eso sí, no esperes que te permita olvidarte de tus suscripciones actuales, porque las tareas que vas a poder delegar todavía están limitadas. Toca probarla a fondo y ver hasta dónde llega.</p>]]></description>
        </item>
    
        <item>
            <title>Optimización de flujos de trabajo con OpenCode y Ollama: IA local para tareas sencillas</title>
            <link>https://psanxiao.com/posts/2026-03-28-optimiza-flujo-trabajo-ia-local-opencode-ollama.html</link>
            <guid isPermaLink="true">https://psanxiao.com/posts/2026-03-28-optimiza-flujo-trabajo-ia-local-opencode-ollama.html</guid>
            <pubDate>Sat, 28 Mar 2026 00:00:00 +0000</pubDate>
            <description><![CDATA[<p>En el desarrollo de software, a menudo nos enfrentamos a tareas que, aunque sencillas, resultan tediosas: escribir scripts de automatización, comparar estructuras de archivos en diferentes directorios o realizar transformaciones de datos repetitivas. Aunque herramientas en la nube como Claude o GPT-4 son excelentes para tareas complejas, utilizarlas para estos procesos menores implica un consumo innecesario de tokens y una dependencia constante de servicios de pago.</p>
<p>La alternativa más eficiente hoy en día es el uso de <strong>modelos de lenguaje locales</strong>. Gracias a la integración entre <strong>Ollama</strong> y el proyecto CLI <strong>OpenCode</strong>, es posible ejecutar un asistente potente directamente en tu máquina, sin costes de suscripción y con total privacidad.</p>
<h2 id="1-verificacion-de-hardware-que-puedes-ejecutar">1. Verificación de hardware: ¿Qué puedes ejecutar?</h2>
<p>El primer paso para trabajar en local es conocer la capacidad real de tu equipo. No necesitas una estación de trabajo de última generación para tareas de código básicas, pero sí un mínimo de recursos para que la experiencia sea fluida.</p>
<p>Una herramienta muy recomendable para esto es <a href="https://canirun.ai">canirun.ai</a>. Este sitio analiza tus especificaciones técnicas (especialmente la memoria RAM y la VRAM de tu tarjeta gráfica) y te indica qué modelos podrás ejecutar.</p>
<h2 id="2-el-equilibrio-entre-potencia-y-ligereza">2. El equilibrio entre potencia y ligereza</h2>
<p>Para tareas de automatización y ayuda en el código, la regla general es que un modelo a partir de <strong>7 mil millones de parámetros (7B)</strong> suele ser el punto de equilibrio ideal. Son lo suficientemente inteligentes para entender lógica de programación y lo bastante ligeros para correr rápido en hardware doméstico moderno.</p>
<p>En mi caso personal, estoy utilizando actualmente <strong>Qwen 2.5 Coder 7B</strong>. Para generar pequeños scripts de Python o comparar ficheros JSON de gran tamaño, su respuesta es casi instantánea y la precisión es sorprendente. No obstante, dependiendo de tu hardware (si tienes más de 32GB de RAM o una GPU potente), podrías escalar a modelos de 14B o 32B si buscas un razonamiento más profundo.</p>
<h2 id="3-configuracion-simplificada-el-comando-magico">3. Configuración simplificada: El comando "mágico"</h2>
<p>Aunque OpenCode permite una configuración manual detallada, la forma más rápida y limpia de conectar tus modelos locales con el asistente es utilizar el puente directo que ofrece Ollama.</p>
<p>Una vez tengas instalado Ollama y hayas descargado tu modelo preferido (por ejemplo, con <code>ollama pull qwen2.5-coder</code>), solo tienes que ejecutar:</p>
<div class="codehilite"><pre><span></span><code>ollama<span class="w"> </span>launch<span class="w"> </span>opencode
</code></pre></div>

<p>Este comando es clave porque automatiza toda la configuración: detecta tu instancia local, establece las variables de entorno necesarias y lanza la interfaz de OpenCode lista para trabajar. Evitas así tener que configurar manualmente proveedores externos o servicios en la nube, manteniendo todo el flujo 100% local.</p>
<h2 id="4-casos-de-uso-ideales">4. Casos de uso ideales</h2>
<p>¿Cuándo merece la pena usar este setup en lugar de una IA comercial? Principalmente en tareas de "baja complejidad pero alta fricción":</p>
<ul>
<li><strong>Manipulación de archivos</strong>: "Crea un script que renombre todos los .txt de esta carpeta a .md y les añada la fecha actual".</li>
<li><strong>Comparación lógica</strong>: "Analiza estos dos directorios y dime qué funciones faltan por sincronizar".</li>
<li><strong>Limpieza de datos</strong>: "Tengo este CSV mal formateado, genera un script para normalizar las columnas".</li>
</ul>
<h2 id="conclusion">Conclusión</h2>
<p>La combinación de OpenCode y Ollama no solo es una cuestión de ahorro de costes (que también), sino de agilidad y privacidad. Al delegar las tareas más pesadas y repetitivas a un modelo local de 7B, liberas tu presupuesto de tokens para problemas realmente complejos y mantienes un flujo de trabajo en la terminal mucho más dinámico.</p>]]></description>
        </item>
    
        <item>
            <title>La guía de la IA</title>
            <link>https://psanxiao.com/posts/2026-03-07-la-guia-de-la-IA.html</link>
            <guid isPermaLink="true">https://psanxiao.com/posts/2026-03-07-la-guia-de-la-IA.html</guid>
            <pubDate>Sat, 07 Mar 2026 00:00:00 +0000</pubDate>
            <description><![CDATA[<p>Dedicándome a la tecnología, trabajando con software y manteniendo un blog donde me gusta escribir y lo hago menos de lo que me gustaría, resulta casi imposible no hablar de la Inteligencia Artificial. Durante el último año, la IA ha pasado de ser casi ciencia ficción a inundarlo todo.</p>
<p>Este post, más largo de lo habitual, nace de una necesidad personal: la de poner en orden mis propias notas, investigaciones y aprendizajes. Al final, escribir es la mejor forma que conozco de estructurar las ideas y separar el grano de la paja. Mi intención con esta serie no es venderte la última herramienta de moda, sino bajar a tierra lo que está pasando y cómo podemos entender esta tecnología sin que nos explote la cabeza.</p>
<div class="toc"><span class="toctitle">Índice de contenidos</span><ul>
<li><a href="#ni-magia-ni-robots-solo-computacion-y-patrones">Ni magia, ni robots: Solo computación y patrones</a></li>
<li><a href="#por-que-ahora">¿Por qué ahora?</a></li>
<li><a href="#que-es-un-llm-en-realidad">¿Qué es un LLM en realidad?</a><ul>
<li><a href="#los-tres-pilares-de-lo-que-puede-generar">Los tres pilares de lo que puede generar:</a></li>
</ul>
</li>
<li><a href="#que-no-es-la-ia">¿Qué NO es la IA?</a><ul>
<li><a href="#como-aprende-una-maquina">Cómo aprende una máquina?</a></li>
</ul>
</li>
<li><a href="#el-espejo-humano-el-sesgo-que-nos-complica-la-vida">El espejo humano: El sesgo que nos complica la vida</a></li>
<li><a href="#capitulo-2-el-diccionario-de-supervivencia">Capítulo 2. El Diccionario de Supervivencia</a><ul>
<li><a href="#1-el-token-la-unidad-de-medida">1. El Token: La unidad de medida</a></li>
<li><a href="#2-la-ventana-de-contexto-no-es-un-pozo-sin-fondo">2. La Ventana de Contexto: No es un pozo sin fondo</a></li>
<li><a href="#3-embeddings-el-carnet-de-identidad-de-tus-datos">3. Embeddings: El carnet de identidad de tus datos</a></li>
<li><a href="#4-alucinaciones-cuando-la-probabilidad-falla">4. Alucinaciones: Cuando la probabilidad falla</a></li>
<li><a href="#5-parametros-el-tamano-del-cerebro">5. Parámetros: El tamaño del "cerebro"</a></li>
<li><a href="#6-temperatura-robot-o-artista">6. Temperatura: ¿Robot o Artista?</a></li>
<li><a href="#7-el-rag-como-aprende-la-ia-sobre-tus-datos">7. El RAG: ¿Cómo aprende la IA sobre tus datos?</a><ul>
<li><a href="#como-funciona-el-rag-por-dentro">¿Cómo funciona el RAG por dentro?</a></li>
<li><a href="#por-que-herramientas-como-notebooklm-parecen-acotarse-tanto">¿Por qué herramientas como NotebookLM parecen "acotarse" tanto?</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#capitulo-3-el-traductor-universal">Capítulo 3. El Traductor Universal</a><ul>
<li><a href="#1-el-codigo-como-arquitectura-logica">1. El código como arquitectura lógica</a></li>
<li><a href="#2-por-que-algunos-modelos-programan-mejor-que-otros">2. ¿Por qué algunos modelos programan mejor que otros?</a></li>
<li><a href="#3-imagenes-y-video-traduciendo-palabras-a-pixeles">3. Imágenes y Vídeo: Traduciendo palabras a píxeles</a></li>
<li><a href="#4-la-trampa-del-dibujo-por-que-la-ia-no-sabe-cuantos-dedos-tiene-una-mano">4. La trampa del dibujo: ¿Por qué la IA no sabe cuántos dedos tiene una mano?</a></li>
<li><a href="#5-por-que-unos-modelos-son-mas-rapidos-que-otros">5. ¿Por qué unos modelos son más rápidos que otros?</a></li>
</ul>
</li>
<li><a href="#capitulo-4-instrucciones-operativas-prompting">Capítulo 4. Instrucciones operativas (Prompting)</a><ul>
<li><a href="#1-rompe-el-espejo-de-la-conversacion-a-la-instruccion">1. Rompe el espejo: De la conversación a la instrucción</a></li>
<li><a href="#2-la-anatomia-de-un-prompt-profesional">2. La anatomía de un prompt profesional</a></li>
<li><a href="#3-la-tecnica-de-la-cadena-de-pensamiento">3. La técnica de la "Cadena de Pensamiento"</a></li>
<li><a href="#4-el-few-shot-ensenar-con-ejemplos">4. El "Few-Shot": Enseñar con ejemplos</a></li>
<li><a href="#5-itera-el-prompt-perfecto-no-existe-a-la-primera">5. Itera: El prompt perfecto no existe a la primera</a></li>
</ul>
</li>
<li><a href="#capitulo-5-las-herramientas-de-desarrollo-de-software">Capítulo 5. Las Herramientas de Desarrollo de Software</a><ul>
<li><a href="#el-agente-el-cerebro-con-iniciativa">El Agente: El "Cerebro" con iniciativa</a></li>
<li><a href="#mcp-el-protocolo-que-lo-cambia-todo">MCP: El protocolo que lo cambia todo</a></li>
<li><a href="#las-skills-herramientas-las-manos-del-agente">Las Skills (Herramientas): Las "Manos" del agente</a><ul>
<li><a href="#1-skills-nativas-las-que-ya-vienen-instaladas">1. Skills Nativas (Las que ya vienen "instaladas")</a></li>
<li><a href="#2-skills-de-ecosistema-marketplace-de-conectores">2. Skills de Ecosistema (Marketplace de conectores)</a></li>
<li><a href="#3-skills-a-medida-las-que-tu-programas">3. Skills a medida (Las que tú programas)</a></li>
</ul>
</li>
<li><a href="#como-encaja-todo-esto-ejemplo-practico">¿Cómo encaja todo esto? (Ejemplo práctico)</a></li>
<li><a href="#instrucciones-persistentes-los-archivos-md-y-ficheros-de-configuracion">Instrucciones persistentes: Los archivos .md y ficheros de configuración</a></li>
</ul>
</li>
<li><a href="#capitulo-6-estrategia-de-modelos-a-quien-le-pides-cada-tarea">Capítulo 6. Estrategia de modelos: ¿A quién le pides cada tarea?</a><ul>
<li><a href="#1-modelos-de-razonamiento-o-series-deep-thinking">1. Modelos de Razonamiento (O-series / "Deep Thinking")</a></li>
<li><a href="#2-modelos-de-desarrollo-coding-assistants">2. Modelos de Desarrollo (Coding Assistants)</a></li>
<li><a href="#3-modelos-flash-o-ligeros-velocidad-y-eficiencia">3. Modelos "Flash" o Ligeros (Velocidad y Eficiencia)</a></li>
<li><a href="#4-modelos-de-gran-contexto-la-memoria-infinita">4. Modelos de Gran Contexto (La memoria infinita)</a></li>
</ul>
</li>
<li><a href="#capitulo-7-conclusiones-y-el-camino-a-seguir">Capítulo 7. Conclusiones y el camino a seguir</a><ul>
<li><a href="#1-la-comprension-es-tu-mejor-herramienta">1. La comprensión es tu mejor herramienta</a></li>
<li><a href="#2-solo-estamos-rascando-la-superficie">2. Solo estamos rascando la superficie</a></li>
<li><a href="#3-orquestacion-frente-a-monopolio">3. Orquestación frente a monopolio</a></li>
<li><a href="#reflexion-final">Reflexión final</a></li>
</ul>
</li>
</ul>
</div>
<h2 id="ni-magia-ni-robots-solo-computacion-y-patrones">Ni magia, ni robots: Solo computación y patrones</h2>
<p>A veces parece que hay una especie de "niebla" mental sobre la IA. Parece que estamos ante un oráculo o un cerebro consciente. Lo que veíamos en las películas se ha hecho realidad, y tenemos entre nosotros un <em>Skynet</em> o <em><a href="https://es.wikipedia.org/wiki/HAL_9000">HAL</a></em> de verdad. Pero si abrimos el capó y miramos los engranajes, la realidad es mucho más terrenal.</p>
<p>En esencia, la IA es software diseñado para imitar capacidades humanas, pero con una diferencia fundamental respecto al desarrollo tradicional. Si un programa clásico es una receta rígida donde yo, como programador, defino que <em>"si pasa A, haz B"</em>, la IA es un <strong>aprendiz de patrones</strong>. No necesita que le dé todas las reglas por escrito; ella misma encuentra las regularidades en los datos. Pero ojo, no "piensa". Es pura estadística aplicada a una escala masiva.</p>
<h2 id="por-que-ahora">¿Por qué ahora?</h2>
<p>Algo que solemos ignorar es que las <strong><a href="https://es.wikipedia.org/wiki/Red_neuronal_artificial">redes neuronales</a></strong> no son una novedad de hace dos años. La idea de imitar las conexiones sinápticas para procesar datos es una teoría que ya se manejaba en los años 50. Entonces, ¿por qué no tuvimos este "boom" hace décadas?</p>
<p>Para que estas redes neuronales "despertaran", han necesitado dos ingredientes que solo coinciden ahora:</p>
<ul>
<li><strong>Datos masivos:</strong> Internet se ha convertido en el campo de entrenamiento más grande de la historia.</li>
<li><strong>Hardware (GPUs):</strong> Necesitábamos chips capaces de hacer billones de operaciones por segundo. La receta ya estaba escrita, pero hasta hace poco no teníamos el horno lo bastante potente para cocinarla.</li>
</ul>
<h2 id="que-es-un-llm-en-realidad">¿Qué es un LLM en realidad?</h2>
<p>Los modelos de lenguaje que usamos hoy son redes neuronales gigantescas entrenadas para una sola tarea: <strong>adivinar la siguiente palabra.</strong></p>
<ul>
<li>Si escribes "El cielo está...", la red neuronal ha procesado tanta información que sabe que la palabra más probable es "azul".</li>
<li>No es que "entienda" el concepto de cielo, es que es un maestro de la probabilidad estadística gracias a esa capacidad de computación masiva.</li>
</ul>
<p>Hasta hace nada, la IA se dedicaba a clasificar: te decía si un correo era spam o si en una foto aparecía un gato. Era IA discriminativa. Lo que ha cambiado las reglas del juego es la <strong>IA Generativa</strong>.</p>
<p>Como su nombre indica, su superpoder es crear contenido nuevo. Ha pasado de organizar carpetas a ser capaz de redactar un texto, generar una imagen desde cero o, lo que a muchos nos interesa, escribir una función de código que funciona a la primera. No es que "sepa" lo que hace, es que sabe qué palabra o píxel tiene más probabilidades de ir después del anterior.</p>
<h3 id="los-tres-pilares-de-lo-que-puede-generar">Los tres pilares de lo que puede generar:</h3>
<ol>
<li><strong>Texto (LLMs):</strong> Como ya vimos, son redes neuronales maestras en la probabilidad. No solo escriben poemas; pueden programar software, resumir libros o traducir idiomas captando los matices culturales, no solo palabra por palabra.</li>
<li><strong>Imagen y Arte Visual:</strong> Modelos como Midjourney o DALL-E han aprendido la relación entre las palabras y los píxeles. Saben qué aspecto tiene la "luz de atardecer" o el "estilo cyberpunk" y pueden construir una imagen desde cero (píxel a píxel) a partir de una frase.</li>
<li><strong>Multimodalidad (El presente):</strong> Esto es lo más nuevo y potente. Es la capacidad de la IA para saltar entre formatos. Por ejemplo, una IA que puede "ver" una foto de tu nevera y "escribir" una receta con lo que hay dentro, o una IA que "escucha" un audio y lo convierte en un vídeo.</li>
</ol>
<h2 id="que-no-es-la-ia">¿Qué NO es la IA?</h2>
<ul>
<li><strong>No es un buscador como Google:</strong> Un buscador te lleva a una web; una IA genera una respuesta nueva combinando lo que sabe.</li>
<li><strong>No tiene sentimientos:</strong> Si te pide perdón por un error, no es porque esté arrepentida, es porque ha aprendido que "lo siento" es la respuesta socialmente correcta en esa situación.</li>
<li><strong>No es infalible:</strong> Puede equivocarse (y mucho). Es una herramienta de apoyo, no una verdad absoluta.</li>
</ul>
<h3 id="como-aprende-una-maquina">Cómo aprende una máquina?</h3>
<p>Imagina que quieres enseñarle a un niño a distinguir entre un perro y un gato. No le das un manual de 500 páginas sobre anatomía felina; simplemente ve un perro y le dices: "Esto es un perro", ve un gato y le dices "Esto es un gato". Aprende por repetición y asociación.</p>
<p>Con la IA pasa exactamente lo mismo:</p>
<ol>
<li><strong>Entrenamiento:</strong> Le "alimentamos" con millones de ejemplos (textos, fotos, códigos).</li>
<li><strong>Patrones:</strong> La máquina nota que los gatos suelen tener orejas puntiagudas y los perros hocicos más largos.</li>
<li><strong>Predicción:</strong> Cuando le enseñas una foto nueva, no "sabe" qué es, pero dice: "Hay un <strong>98%</strong> de probabilidades de que esto sea un gato".</li>
</ol>
<h2 id="el-espejo-humano-el-sesgo-que-nos-complica-la-vida">El espejo humano: El sesgo que nos complica la vida</h2>
<p>Aquí entra un tema que me parece clave para entender por qué a veces nos frustramos con estas herramientas. En los años 60, Joseph Weizenbaum creó <strong><a href="https://es.wikipedia.org/wiki/ELIZA">ELIZA</a></strong>, un chatbot básico que imitaba a un terapeuta. Weizenbaum lo programó para imitar a un <strong>terapeuta rogeriano</strong> (una técnica de psicología que consiste en devolverle al paciente sus propias palabras).</p>
<ul>
<li><strong>Si tú decías:</strong> "Me duele la cabeza".</li>
<li><strong>ELIZA buscaba las palabras clave y respondía:</strong> "¿Por qué dices que te duele la cabeza?".</li>
</ul>
<p>Se quedó horrorizado al ver que la gente se abría emocionalmente con la máquina, creyendo que los entendía.</p>
<p>Tenemos una tendencia innata a humanizar la tecnología (<strong><a href="https://es.wikipedia.org/wiki/Antropomorfismo">antropomorfismo</a></strong>). Si algo nos responde con lenguaje fluido, nuestro cerebro asume que "hay alguien ahí". Nos enfadamos con el chat o le hablamos con rodeos. El problema es que, al tratarla como a un humano, perdemos la <strong>especificidad operativa</strong>. Olvidamos que estamos ante una herramienta de cálculo y no ante un oráculo.</p>
<p>Para sacarle partido de verdad a la IA, el primer paso es romper ese espejo: menos charla y más instrucciones precisas. No pienses que "entiende" tu problema, cuando en realidad sólo está haciendo estadística avanzada para darte la respuesta más probable. Entender esto es la clave para saber como sacarle partido, tratándola como lo que es: una herramienta.</p>
<h1 id="capitulo-2-el-diccionario-de-supervivencia">Capítulo 2. El Diccionario de Supervivencia</h1>
<p>En el post anterior hablábamos de que la IA no es magia, sino computación y patrones. Pero para movernos con soltura en este ecosistema y, sobre todo, para no frustrarnos cuando las cosas no salen como esperamos, necesitamos hablar el mismo idioma que la máquina.</p>
<p>Para manejar la IA con criterio, no basta con saber qué botones pulsar. Necesitas entender los mecanismos que definen su comportamiento. Si ignoras estos conceptos, estarás usando la herramienta a ciegas.</p>
<h3 id="1-el-token-la-unidad-de-medida">1. El Token: La unidad de medida</h3>
<p>La IA no procesa palabras completas como nosotros; <a href="https://platform.openai.com/tokenizer">trocea el texto en <strong>tokens</strong></a>. Un token puede ser una palabra corta, una sílaba o incluso un signo de puntuación.</p>
<p><strong>¿Por qué te importa?</strong> Porque todo en este mundo se mide en tokens: desde la capacidad de respuesta hasta lo que te cobran por las APIs. Si entiendes que la IA "trocea" la información, entenderás por qué a veces le cuesta tanto contar letras de una palabra o hacer rimas perfectas: ella no ve letras individuales, ve bloques de datos.</p>
<h3 id="2-la-ventana-de-contexto-no-es-un-pozo-sin-fondo">2. La Ventana de Contexto: No es un pozo sin fondo</h3>
<p>Este es, probablemente, el concepto más crítico. La <strong>Ventana de Contexto</strong> es la "memoria de trabajo" o la capacidad de atención de la IA en una sola sesión. Imagina que es una mesa de escritorio: cuando la mesa se llena, para poner un papel nuevo tienes que tirar uno de los que ya estaban.</p>
<ul>
<li>
<p><strong>El peligro del truncamiento:</strong> Si le pasas un PDF de 200 páginas a una IA que solo tiene capacidad para 50, la IA no te avisará de que no llega. Simplemente <strong>cortará el texto sobrante</strong>. Tú creerás que ha analizado todo el archivo, pero la información del final (donde quizás estaba la conclusión o la cláusula clave) será invisible para ella.</p>
</li>
<li>
<p><strong>La pérdida en el medio:</strong> Incluso si el texto cabe, se ha demostrado que la IA recuerda mejor el principio y el final de lo que lee. Los detalles que quedan enterrados en el centro del documento suelen diluirse.</p>
</li>
</ul>
<h3 id="3-embeddings-el-carnet-de-identidad-de-tus-datos">3. Embeddings: El carnet de identidad de tus datos</h3>
<p>Si la Ventana de Contexto es nuestra "mesa de trabajo", los <strong><a href="https://en.wikipedia.org/wiki/Word_embedding">Embeddings</a></strong> son el sistema de archivado inteligente que nos permite no saturarla.</p>
<p>Para que una IA entienda la relación entre las ideas, utiliza estos "embeddings": una lista de números (vectores) que sitúa cada frase en un mapa gigante de miles de dimensiones. Para entenderlo como desarrolladores, bajémoslo a un ejemplo de solo 3 coordenadas: <strong>[¿Es software?, ¿Es una base de datos?, ¿Es un animal?]</strong></p>
<ul>
<li><strong>"PostgreSQL"</strong> → <code>[0.9, 0.9, 0.0]</code> (Mucho software, mucha DB, nada animal).</li>
<li><strong>"MySQL"</strong> → <code>[0.9, 0.8, 0.0]</code> (Coordenadas casi idénticas; están "pegados" en el mapa).</li>
<li><strong>"Delfín"</strong> → <code>[0.0, 0.0, 0.9]</code> (Vive en un barrio matemático totalmente distinto).</li>
</ul>
<p><strong>¿Por qué te importa esto en la práctica?</strong> Piensa en cuando subes un PDF a una IA. La IA no "lee" las 200 páginas cada vez que le preguntas algo. Lo que hace es:</p>
<ol>
<li><strong>Trocear</strong> el PDF en párrafos.</li>
<li>Generar el <strong>embedding</strong> (las coordenadas) de cada párrafo.</li>
<li>Cuando preguntas algo, busca qué trozos del PDF tienen las coordenadas más parecidas a tu duda y <strong>solo le pasa esos trozos</strong> a la Ventana de Contexto.</li>
</ol>
<p>Es la base de lo que llamamos <strong>RAG</strong>: buscar por "sentido común" matemático para ahorrar tokens y ganar precisión.</p>
<h3 id="4-alucinaciones-cuando-la-probabilidad-falla">4. Alucinaciones: Cuando la probabilidad falla</h3>
<p>La IA Generativa es una máquina de predecir la siguiente palabra más probable. No tiene una base de datos de "verdades".</p>
<ul>
<li>
<p><strong>El riesgo:</strong> Como está diseñada para ser coherente y elocuente, cuando no sabe algo, "rellena" el vacío con información que suena muy profesional pero que es <strong>falsa</strong>. No te miente por maldad; simplemente está cumpliendo su función de completar texto basándose en patrones.</p>
</li>
<li>
<p><strong>Mi consejo:</strong> Nunca la uses como fuente primaria para datos biográficos, leyes o fechas. Úsala para procesar datos que tú le entregues, no para que ella te los traiga de fuera.</p>
</li>
</ul>
<h3 id="5-parametros-el-tamano-del-cerebro">5. Parámetros: El tamaño del "cerebro"</h3>
<p>Seguro que has oído que X modelo tiene "billones de parámetros". Un parámetro es, básicamente, una conexión ajustable en la red neuronal (como los cables en un cuadro de conexiones).</p>
<ul>
<li>
<p><strong>Más parámetros</strong> suelen significar más matices, mejor comprensión de la ironía y más "sabiduría" generalista.</p>
</li>
<li>
<p>Sin embargo, un modelo con menos parámetros pero <strong>mejor entrenado</strong> (con datos de mayor calidad) puede ser mucho más eficaz para tareas específicas, como programar, y además será mucho más rápido y barato.</p>
</li>
</ul>
<h3 id="6-temperatura-robot-o-artista">6. Temperatura: ¿Robot o Artista?</h3>
<p>Aunque a veces está oculto en la interfaz, la mayoría de los modelos tienen un ajuste de <strong>Temperatura</strong>.</p>
<ul>
<li>
<p><strong>Temperatura baja (Cercana a 0):</strong> La IA es conservadora y previsible. Es el modo "ingeniero": ideal para código, resúmenes técnicos o datos.</p>
</li>
<li>
<p><strong>Temperatura alta (Cercana a 1):</strong> La IA se arriesga más, elige palabras menos probables. Es el modo "creativo": ideal para lluvia de ideas o escribir ficción.</p>
</li>
</ul>
<h3 id="7-el-rag-como-aprende-la-ia-sobre-tus-datos">7. El RAG: ¿Cómo aprende la IA sobre tus datos?</h3>
<p>Seguramente has probado herramientas como <strong>NotebookLM</strong> o le has subido un PDF a ChatGPT y te has sorprendido: de repente, la IA sabe todo sobre ese documento técnico de 50 páginas y sus respuestas se "acotan" estrictamente a lo que pone ahí. No se inventa cosas de internet, se centra en <strong>tus</strong> datos.</p>
<p>¿Cómo es posible? ¿Ha "estudiado" la IA tu documento y se lo ha aprendido para siempre? <strong>No.</strong> Lo que estás viendo en acción es una técnica llamada **<a href="https://es.wikipedia.org/wiki/Generación_aumentada_por_recuperación">RAG (Retrieval-Augmented Generation</a></p>
<p>Para entender el RAG, olvida la idea de que la IA "aprende". Imagina que la IA es un <strong>profesor superdotado</strong> que sabe de todo, pero al que le pides que haga un examen sobre un proyecto tuyo que él nunca ha visto.</p>
<ol>
<li>
<p><strong>Sin RAG (Entrenamiento):</strong> Sería como obligar al profesor a memorizar tu proyecto antes del examen. Es costoso, lento y, si mañana cambias una frase del proyecto, el profesor ya tiene información obsoleta en su cabeza.</p>
</li>
<li>
<p><strong>Con RAG:</strong> Es como si el profesor fuera al examen con <strong>tus apuntes en la mano</strong>. No necesita memorizarlos; simplemente, cuando le haces una pregunta, él busca rápidamente en los apuntes, lee el párrafo relevante y te responde usando su inteligencia pero basándose <strong>solo</strong> en lo que pone el papel.</p>
</li>
</ol>
<h4 id="como-funciona-el-rag-por-dentro">¿Cómo funciona el RAG por dentro?</h4>
<p>Cuando subes ese PDF, el sistema hace tres cosas en milisegundos:</p>
<ul>
<li>
<p><strong>Recuperación (Retrieval):</strong> Gracias a los <strong>Embeddings</strong> (los "carnets de identidad numéricos" que vimos antes), el sistema sabe qué párrafos de tu PDF están matemáticamente cerca de tu pregunta. Si preguntas por el "presupuesto", el sistema localiza instantáneamente la página donde están las cifras.</p>
</li>
<li>
<p><strong>Aumento (Augmentation):</strong> El sistema coge esos párrafos y los "pega" en un prompt invisible para ti que dice: <em>"Aquí tienes estos fragmentos de texto. Úsalos como única fuente de verdad"</em>.</p>
</li>
<li>
<p><strong>Generación (Generation):</strong> La IA redacta la respuesta. Sigue usando su "cerebro" (su entrenamiento previo) para entender el lenguaje y redactar bien, pero los datos los saca exclusivamente de los fragmentos que le acabas de pasar.</p>
</li>
</ul>
<h4 id="por-que-herramientas-como-notebooklm-parecen-acotarse-tanto">¿Por qué herramientas como NotebookLM parecen "acotarse" tanto?</h4>
<p>Te habrás fijado en que si le preguntas a <a href="https://notebooklm.google.com/">NotebookLM</a> algo que no está en tus archivos, a veces te dice: <em>"No puedo responder porque esa información no aparece en los documentos"</em>.</p>
<p>Esto no es porque la IA se haya vuelto "tonta" o haya olvidado lo que sabía. Es porque el sistema RAG tiene una <strong>instrucción de seguridad</strong> muy estricta: priorizar siempre el libro que tiene abierto. Esto es lo que nos da la seguridad de que la IA no va a "alucinar" o inventarse datos basándose en información genérica de internet.</p>
<h1 id="capitulo-3-el-traductor-universal">Capítulo 3. El Traductor Universal</h1>
<p>Si has seguido los posts anteriores, ya tienes claro que la IA no es un oráculo, sino un procesador de patrones. Pero aquí es donde la cosa se pone interesante: ¿Cómo es posible que un "Modelo de Lenguaje" (LLM) sea capaz de escribir una función en Python, <a href="https://psanxiao.com/posts/2025-08-15-introduccion-a-leaflet.html">diseñar un mapa web en Leaflet</a> o generar una imagen de un astronauta a caballo?</p>
<p>La respuesta corta es que, para una IA, <strong>todo es lenguaje</strong>. Pero vamos a desglosarlo un poco mejor, porque entender esto es lo que te permite pasar de "jugar" con la IA a usarla como una herramienta de ingeniería real.</p>
<h3 id="1-el-codigo-como-arquitectura-logica">1. El código como arquitectura lógica</h3>
<p>Para nosotros, programar es crear lógica. Para un LLM, aprender a programar no ha sido muy distinto a aprender inglés o gallego. El código tiene una sintaxis, una gramática y, sobre todo, una estructura previsible.</p>
<p>La IA ha sido entrenada con casi todo el código público que existe (pensemos en el volumen de datos de GitHub). Lo que hace no es "entender" informática, sino entender la <strong>secuencia lógica</strong>. Sabe que después de un <code>if</code> suele venir una condición y, tras ella, una indentación con una instrucción. Al ser un entorno tan rígido y con reglas tan claras, a la IA le resulta más fácil ser precisa programando que escribiendo poesía.</p>
<h3 id="2-por-que-algunos-modelos-programan-mejor-que-otros">2. ¿Por qué algunos modelos programan mejor que otros?</h3>
<p>No es que unos sean "más listos" que otros, es una cuestión de <strong>dieta de datos</strong>.</p>
<ul>
<li>
<p><strong>Los generalistas:</strong> Han leído de todo, incluyendo tutoriales obsoletos y código basura de foros olvidados. Por eso a veces te sugieren soluciones que "huelen" a 2010.</p>
</li>
<li>
<p><strong>Los especialistas (Fine-tuning):</strong> Son modelos que han pasado por un "posgrado". Se les ha entrenado específicamente con repositorios de alta calidad y se les ha refinado mediante humanos que les dicen: <em>"Esta solución funciona, pero esta otra es más eficiente y segura"</em>. Es la diferencia entre un aprendiz y un senior.</p>
</li>
</ul>
<h3 id="3-imagenes-y-video-traduciendo-palabras-a-pixeles">3. Imágenes y Vídeo: Traduciendo palabras a píxeles</h3>
<p>Aquí es donde ocurre lo que llamamos <strong>multimodalidad</strong>. Al principio, esto era como un juego de teléfonos descompuestos: tenías un modelo que entendía el texto y le pasaba la orden a otro que generaba la imagen.</p>
<p>Hoy, los modelos más potentes son <strong>nativos multimodales</strong>. Desde el minuto uno de su entrenamiento, han visto imágenes y han leído sus descripciones simultáneamente. Han aprendido que el concepto lingüístico "atardecer" está vinculado a ciertos patrones de color y degradados de píxeles. Ya no "traducen" de un idioma a otro; entienden el mundo en ambos formatos de forma nativa.</p>
<h3 id="4-la-trampa-del-dibujo-por-que-la-ia-no-sabe-cuantos-dedos-tiene-una-mano">4. La trampa del dibujo: ¿Por qué la IA no sabe cuántos dedos tiene una mano?</h3>
<p>Seguro que has visto esas imágenes con manos de seis dedos. Esto explica perfectamente por qué la IA no tiene un modelo mental de la realidad. Ella no sabe qué es una "mano" ni para qué sirve; solo sabe que en las fotos etiquetadas como "mano" suele haber formas alargadas de color carne. Si estadísticamente el patrón es confuso, el resultado visual también lo será.</p>
<h3 id="5-por-que-unos-modelos-son-mas-rapidos-que-otros">5. ¿Por qué unos modelos son más rápidos que otros?</h3>
<p>A veces te encuentras con modelos que parecen un rayo y otros que escriben a paso de tortuga. Esto depende del <strong>número de parámetros</strong> (el tamaño del "cerebro") y del <strong>hardware</strong> que tengan detrás.</p>
<ul>
<li>
<p><strong>Modelos Flash/Mini:</strong> Pocos parámetros, muy rápidos, ideales para tareas sencillas.</p>
</li>
<li>
<p><strong>Modelos de razonamiento:</strong> Son deliberadamente más lentos porque están programados para "pensar antes de hablar", verificando sus propios pasos lógicos internamente.</p>
</li>
</ul>
<p>Entender que la IA es un <strong>motor de razonamiento estadístico</strong> cambia la forma en la que le pides las cosas. Si le pides código, dale la estructura. Si le pides una imagen, describe los patrones. No estás hablando con un artista ni con un colega senior; estás interactuando con un traductor universal de patrones que es tan bueno como la información con la que lo alimentas.</p>
<h1 id="capitulo-4-instrucciones-operativas-prompting">Capítulo 4. Instrucciones operativas (Prompting)</h1>
<p>Si has llegado hasta aquí, ya sabes que la IA no te "entiende" en el sentido humano de la palabra; lo que hace es procesar una instrucción y calcular la respuesta más probable basándose en su entrenamiento. Por eso, el "arte" de dar instrucciones (que algunos llaman pomposamente <em><a href="https://developers.openai.com/api/docs/guides/prompt-engineering">Prompt Engineering</a></em>) no consiste en ser educado, sino en ser <strong>meticuloso</strong>.</p>
<p>En mi día a día con el código o los mapas, si una consulta SQL no devuelve lo que quiero, no me enfado con la base de datos; reviso la sintaxis. Con la IA hay que aplicar la misma mentalidad.</p>
<h3 id="1-rompe-el-espejo-de-la-conversacion-a-la-instruccion">1. Rompe el espejo: De la conversación a la instrucción</h3>
<p>El mayor error es tratar el chat como una charla de café. Escribir <em>"Oye, ¿sería posible que quizás me ayudaras a resumir esto si no es mucha molestia?"</em> solo añade ruido innecesario a la <strong>ventana de contexto</strong>.</p>
<p>La IA no necesita cortesía, necesita <strong>parámetros</strong>. Pasa de la "charla" a la <strong>instrucción operativa</strong>. Sé directo. Usa verbos de acción: "Resume", "Analiza", "Escribe", "Extrae".</p>
<h3 id="2-la-anatomia-de-un-prompt-profesional">2. La anatomía de un prompt profesional</h3>
<p>Para que una instrucción sea robusta, yo suelo usar una estructura de tres capas:</p>
<ul>
<li>
<p><strong>Rol (¿Quién eres?):</strong> Dile a la IA cómo debe comportarse. No es lo mismo pedirle algo a un "asistente genérico" que a un "ingeniero senior experto en PostgreSQL". Definir el rol acota el "espacio" de donde la IA sacará la información.</p>
</li>
<li>
<p><strong>Contexto y Tarea (¿Qué hacemos?):</strong> Sé específico. En lugar de "haz un resumen", usa "resume los 3 puntos clave de este texto técnico para un cliente que no sabe de tecnología".</p>
</li>
<li>
<p><strong>Formato de salida (¿Cómo lo quiero?):</strong> Define el <em>output</em>. ¿Quieres un JSON? ¿Una tabla Markdown? ¿Un párrafo de 50 palabras? Si no lo defines, la IA elegirá por ti, y probablemente no sea lo que necesitas.</p>
</li>
</ul>
<h3 id="3-la-tecnica-de-la-cadena-de-pensamiento">3. La técnica de la "Cadena de Pensamiento"</h3>
<p>Como vimos en el post anterior, algunos modelos programan mejor porque "piensan" antes de hablar. Tú puedes forzar ese comportamiento en cualquier modelo usando una técnica sencilla: <strong><a href="https://www.ibm.com/think/topics/chain-of-thoughts">pídele que razone paso a paso</a></strong>.</p>
<p>Si le lanzas un problema complejo de golpe, es más fácil que alucine. Si le dices: <em>"Analiza el problema, desglósalo en pasos lógicos y, finalmente, dame la solución"</em>, la probabilidad de éxito aumenta drásticamente. Estás obligando a la red neuronal a seguir un camino lógico trazable.</p>
<h3 id="4-el-few-shot-ensenar-con-ejemplos">4. El "Few-Shot": Enseñar con ejemplos</h3>
<p>A veces, una descripción no basta. Si quieres que la IA escriba con un estilo concreto o clasifique datos de una forma específica, <strong>dale ejemplos</strong>.</p>
<ul>
<li><strong>Ejemplo 1:</strong> Entrada -&gt; Salida.</li>
<li><strong>Ejemplo 2:</strong> Entrada -&gt; Salida.</li>
<li><strong>Ahora tú:</strong> Entrada -&gt; ...</li>
</ul>
<p>Es la forma más rápida de que la IA capte el patrón que buscas sin tener que escribir un manual de instrucciones infinito que sature los <strong>tokens</strong> de la sesión.</p>
<h3 id="5-itera-el-prompt-perfecto-no-existe-a-la-primera">5. Itera: El prompt perfecto no existe a la primera</h3>
<p>En el desarrollo de software, raramente algo funciona a la primera versión. Con el prompting es igual.</p>
<ul>
<li>Si el resultado es demasiado largo, pide que lo recorte.</li>
<li>Si es muy técnico, pide que baje el nivel.</li>
<li>Si ha olvidado una parte, es posible que hayas superado la <strong>ventana de contexto</strong> o que la instrucción fuera ambigua.</li>
</ul>
<p>Dominar el prompting no es aprenderse "fórmulas mágicas", es aprender a comunicarte con una máquina de forma estructurada. Es, en esencia, volver a ser un poco <strong>artesano de la palabra</strong> para obtener resultados de <strong>ingeniería.</strong></p>
<h1 id="capitulo-5-las-herramientas-de-desarrollo-de-software">Capítulo 5. Las Herramientas de Desarrollo de Software</h1>
<p>Si eres de los que, como yo, empezó usando la IA solo para preguntarle cómo centrar un <code>div</code> o para que te explicara una función compleja de PostgreSQL, tengo que decirte que te estás quedando en la superficie. En los últimos meses, el ecosistema ha dado un salto gigante: hemos pasado de "hablar con la IA" a "integrar la IA en nuestro entorno de desarrollo".</p>
<p>Como ingeniero, siempre busco soluciones que resuelvan problemas reales. Y aquí el problema real es la fricción: copiar código del chat, pegarlo en el editor, ver que falla porque la IA no conoce mi base de datos, y volver a empezar. Para resolver esto, han aparecido tres conceptos clave: <strong>Agentes, Skills y el protocolo MCP</strong>.</p>
<h3 id="el-agente-el-cerebro-con-iniciativa">El Agente: El "Cerebro" con iniciativa</h3>
<p>Un chat normal es pasivo: tú preguntas, él responde. Un <strong>Agente</strong> es un modelo de lenguaje al que le hemos dado un objetivo y autonomía para usar herramientas.</p>
<ul>
<li>
<p><strong>Diferencia clave:</strong> Si le pides a un chat "arregla este bug", te dará el código. Si se lo pides a un <strong>Agente</strong>, él leerá el archivo, ejecutará el código para ver el error, buscará una solución y aplicará el parche.</p>
</li>
<li>
<p><strong>En resumen:</strong> Es un LLM que puede ejecutar un ciclo de: <em>Pensar -&gt; Actuar -&gt; Observar el resultado</em>.</p>
</li>
</ul>
<h3 id="mcp-el-protocolo-que-lo-cambia-todo">MCP: El protocolo que lo cambia todo</h3>
<p>Hace poco escribí en el blog sobre <a href="https://psanxiao.com/posts/2026-01-14-conectar-postgres-ia-mediante-mcp.html">cómo conectar PostgreSQL a un agente de IA</a> mediante <strong><a href="https://modelcontextprotocol.io/">MCP (Model Context Protocol)</a></strong>. </p>
<ul>
<li>
<p><strong>¿Qué es?</strong> Es un estándar abierto que permite que cualquier IA se conecte de forma segura a tus datos locales.</p>
</li>
<li>
<p><strong>¿Para qué sirve?</strong> En lugar de copiar y pegar el esquema de tu base de datos en el chat (con el riesgo de seguridad y el gasto de <strong>tokens</strong> que eso supone), el agente "habla" directamente con tu base de datos a través de MCP.</p>
</li>
<li><strong>Utilidad real:</strong> Puedes decirle: <em>"Busca en mi tabla de usuarios cuáles no han verificado el email y genera un script para enviarles un recordatorio"</em>. La IA consulta la estructura real, no se la inventa.</li>
</ul>
<p>Los MCP son, en esencia, canales de comunicación entre los modelos de IA y herramientas externas.</p>
<h3 id="las-skills-herramientas-las-manos-del-agente">Las Skills (Herramientas): Las "Manos" del agente</h3>
<p>Una de las dudas más comunes es cómo "aprende" la IA a hacer cosas nuevas. Las Skills (o herramientas) no son algo que la IA traiga de serie (aunque algunas sí) por "saber mucho", sino funciones que tú, como desarrollador, tienes que habilitar o programar.</p>
<p>Podemos dividirlas en tres niveles según su origen:</p>
<h4 id="1-skills-nativas-las-que-ya-vienen-instaladas">1. Skills Nativas (Las que ya vienen "instaladas")</h4>
<p>Muchas herramientas de IA (como ChatGPT, Claude o Gemini) ya traen herramientas de serie. Por ejemplo, el acceso a internet, la ejecución de código Python en un entorno seguro (Code Interpreter) o la generación de imágenes.</p>
<ul>
<li><strong>Cómo se usan:</strong> No tienes que hacer nada. La IA decide usarlas cuando tu petición lo requiere.</li>
</ul>
<h4 id="2-skills-de-ecosistema-marketplace-de-conectores">2. Skills de Ecosistema (Marketplace de conectores)</h4>
<p>Aquí es donde entra lo que comentábamos del <strong>MCP</strong>. Existe ya un ecosistema de servidores MCP creados por la comunidad.</p>
<ul>
<li>
<p><strong>Cómo se instalan:</strong> Es muy parecido a instalar una dependencia en un proyecto. Te descargas un servidor MCP ya hecho (por ejemplo, uno para Google Drive, otro para Slack o el de PostgreSQL que mencioné en mi post ).</p>
</li>
<li>
<p><strong>Configuración:</strong> Simplemente editas un archivo de configuración en tu entorno (como el <code>claude_desktop_config.json</code>) y le dices dónde está ese servidor. A partir de ese momento, la IA "ve" esa nueva habilidad.</p>
</li>
</ul>
<p>Los MCP dotan a los modelos de IA de nuevas Skills.</p>
<h4 id="3-skills-a-medida-las-que-tu-programas">3. Skills a medida (Las que tú programas)</h4>
<p>Si necesitas que la IA haga algo muy específico de tu flujo de trabajo (por ejemplo, "publicar este borrador en mi blog de Hugo"), tienes que crear la Skill tú mismo.</p>
<ul>
<li>
<p><strong>Cómo se hacen:</strong> No es más que una función en Python o TypeScript.</p>
</li>
<li>
<p><strong>El "Contrato":</strong> Lo más importante no es solo el código, sino la <strong>descripción</strong>. Tienes que escribir un pequeño texto explicando a la IA para qué sirve esa función y qué parámetros necesita. La IA lee esa descripción y, cuando ve que tu petición encaja, "llama" a tu función.</p>
</li>
</ul>
<h3 id="como-encaja-todo-esto-ejemplo-practico">¿Cómo encaja todo esto? (Ejemplo práctico)</h3>
<p>Imagina que estás trabajando en un mapa con Leaflet. Quieres añadir marcadores desde una base de datos:</p>
<ol>
<li>El <strong>Agente</strong> es tu interlocutor.</li>
<li>El <strong>MCP</strong> es el puente que le permite leer tu base de datos PostgreSQL local.</li>
<li>La <strong>Skill</strong> es la capacidad que le has dado para "escribir en el archivo <code>mapa.js</code>".</li>
</ol>
<p>Tú solo dices: <em>"Añade al mapa los puntos de la tabla 'eventos' de mi base de datos"</em>. El Agente usa el <strong>MCP</strong> para consultar la tabla, procesa los datos y usa su <strong>Skill</strong> de escritura para actualizar tu código.</p>
<h3 id="instrucciones-persistentes-los-archivos-md-y-ficheros-de-configuracion">Instrucciones persistentes: Los archivos <code>.md</code> y ficheros de configuración</h3>
<p>Si estamos tratando de ser meticulosos y evitar la "charla" innecesaria, no tiene sentido repetirle nuestras preferencias a la IA en cada nuevo chat. Aquí es donde entran los archivos de configuración de contexto, como los <code>ai.md</code>, <code>agents.md</code> o los <code>.cursorrules</code>.</p>
<ul>
<li>
<p><strong>¿Qué son?</strong> Son archivos de texto plano que colocas en la raíz de tu proyecto. En ellos defines las reglas del juego: qué librerías prefieres (por ejemplo, Leaflet sobre OpenLayers ), cómo quieres que se estructure el código o qué estándares de seguridad debe seguir.</p>
</li>
<li>
<p><strong>Instrucciones del modelo (System Prompts):</strong> Muchos modelos permiten ahora adjuntar un archivo de "instrucciones personalizadas". En lugar de un prompt efímero, es un contrato permanente. Si en mi blog hablo de usar PostgreSQL con MCP, en mi archivo de agente definiré que siempre que consulte la base de datos, use ese protocolo específico.</p>
</li>
<li>
<p><strong>La ventaja técnica:</strong> Al tener estas instrucciones en un fichero <code>.md</code>, puedes versionarlas con Git. Si cambias tu forma de trabajar o añades una nueva <strong>Skill</strong> a tu flujo, el Agente se actualiza automáticamente al leer el archivo.</p>
</li>
</ul>
<h1 id="capitulo-6-estrategia-de-modelos-a-quien-le-pides-cada-tarea">Capítulo 6. Estrategia de modelos: ¿A quién le pides cada tarea?</h1>
<p>A estas alturas de la guía, ya tienes el entorno configurado y sabes cómo dar instrucciones. Pero te falta lo más importante para el día a día: saber qué modelo elegir. Hoy en día no hay una sola "IA"; hay un catálogo creciente de modelos con especialidades muy distintas.</p>
<p>Si intentas resolver un problema de lógica compleja con un modelo rápido, te dará una respuesta errónea con mucha seguridad. Si usas un modelo pesado para corregir una falta de ortografía, estás matando moscas a cañonazos. Vamos a poner orden en este ecosistema.</p>
<h3 id="1-modelos-de-razonamiento-o-series-deep-thinking">1. Modelos de Razonamiento (O-series / "Deep Thinking")</h3>
<p>Estos son los modelos "lentos" por diseño (como la serie o1 o los nuevos modelos de pensamiento profundo). Su característica principal es que utilizan una <strong>cadena de pensamiento interna</strong> antes de escribir la primera palabra.</p>
<ul>
<li>
<p><strong>Cuándo usarlos:</strong> Problemas de lógica pura, matemáticas, arquitectura de software compleja o cuando necesitas que la IA verifique su propia respuesta varias veces.</p>
</li>
<li>
<p><strong>La clave:</strong> Úsalos cuando el "qué" es difícil de resolver y requiere un plan previo. No esperes velocidad; espera acierto.</p>
</li>
</ul>
<h3 id="2-modelos-de-desarrollo-coding-assistants">2. Modelos de Desarrollo (Coding Assistants)</h3>
<p>Aunque los generalistas programan bien, existen versiones optimizadas para el código (como los que alimentan a Cursor o versiones específicas "Coder"). Estos modelos han tenido una dieta de entrenamiento basada en repositorios de alta calidad y entienden mejor la <strong>jerarquía de un proyecto</strong>.</p>
<ul>
<li>
<p><strong>Cuándo usarlos:</strong> Para refactorizar código, crear tests unitarios o entender cómo una función en <code>db.py</code> afecta a tu mapa en <code>index.html</code>.</p>
</li>
<li>
<p><strong>El consejo:</strong> Úsalos dentro de tu IDE. Son modelos que brillan cuando tienen acceso a tu sistema de archivos.</p>
</li>
</ul>
<h3 id="3-modelos-flash-o-ligeros-velocidad-y-eficiencia">3. Modelos "Flash" o Ligeros (Velocidad y Eficiencia)</h3>
<p>Son los modelos pequeños (como GPT-4o-mini, Claude Haiku o Gemini Flash). Tienen menos parámetros, lo que los hace increíblemente rápidos y económicos en términos de <strong>tokens</strong>.</p>
<ul>
<li>
<p><strong>Cuándo usarlos:</strong> Tareas mecánicas o de bajo razonamiento. Traducir un texto, resumir un hilo de emails, formatear un JSON o cambiar el tono de un párrafo.</p>
</li>
<li>
<p><strong>La ventaja:</strong> Su latencia es mínima. En el tiempo que un modelo de razonamiento empieza a "pensar", este ya ha terminado la tarea.</p>
</li>
</ul>
<h3 id="4-modelos-de-gran-contexto-la-memoria-infinita">4. Modelos de Gran Contexto (La memoria infinita)</h3>
<p>Hay modelos específicos que destacan por tener una <strong>Ventana de Contexto</strong> gigantesca (capaces de leer libros enteros o repositorios completos de una vez).</p>
<ul>
<li>
<p><strong>Cuándo usarlos:</strong> Cuando tienes que analizar una documentación técnica de 500 páginas, buscar un bug en un proyecto antiguo con cientos de archivos o cruzar datos de múltiples fuentes.</p>
</li>
<li>
<p><strong>Ojo con:</strong> "Lost in the middle". Aunque puedan leer mucho, recuerda lo que vimos en el Capítulo 2: si el dato importante está en la mitad del texto, es mejor usar un modelo de razonamiento para asegurar que no se le pase por alto.</p>
</li>
</ul>
<h1 id="capitulo-7-conclusiones-y-el-camino-a-seguir">Capítulo 7. Conclusiones y el camino a seguir</h1>
<p>Después de haber desgranado desde qué es un token hasta cómo orquestar agentes con MCP, toca hacer una pausa y mirar el mapa completo. Escribir esta serie me ha servido para poner orden a mis investigaciones, pero sobre todo para reafirmar algunas convicciones sobre cómo debemos afrontar este cambio quienes nos dedicamos a la tecnología.</p>
<p>Estas son mis conclusiones tras meses de "cacharrreo", pruebas y algún que otro error de concepto:</p>
<h3 id="1-la-comprension-es-tu-mejor-herramienta">1. La comprensión es tu mejor herramienta</h3>
<p>No basta con saber qué botones pulsar. <strong>Entender cómo funciona la IA por dentro</strong>, su naturaleza estadística, sus límites de contexto y por qué alucina, es lo que marca la diferencia entre quien se frustra y quien sabe trabajar con ella. Como en cualquier otra rama de la ingeniería, conocer los cimientos te permite construir estructuras mucho más sólidas. Si sabes por qué la IA se equivoca, sabrás cómo corregir la instrucción para que no vuelva a suceder.</p>
<h3 id="2-solo-estamos-rascando-la-superficie">2. Solo estamos rascando la superficie</h3>
<p>Lo que hoy nos parece revolucionario, como el Model Context Protocol (MCP) que os comentaba hace unos días, probablemente sea solo el estándar básico de mañana. Estamos en una fase muy temprana de esta tecnología.</p>
<ul>
<li>Mi consejo: mantén la curiosidad activa.</li>
<li>No te conformes con lo que aprendiste el mes pasado.</li>
<li>Investiga, prueba modelos locales, experimenta con nuevos flujos de trabajo y, sobre todo, no te cases con una sola herramienta. La flexibilidad va a ser nuestra mayor ventaja competitiva.</li>
</ul>
<h3 id="3-orquestacion-frente-a-monopolio">3. Orquestación frente a monopolio</h3>
<p>Si algo me preocupa de este "boom" es la tendencia a quedarnos atrapados en un solo ecosistema. Ahora más que nunca, es vital <strong>huir del <em>vendor lock-in</em></strong>.</p>
<ul>
<li>
<p>Usa modelos diferentes según la tarea: razonamiento para la lógica, modelos <em>flash</em> para la velocidad y modelos de código para el desarrollo.</p>
</li>
<li>
<p>Prioriza opciones que te permitan saltar entre proveedores. Herramientas como OpenRouter u OpenCode Zen, o incluso el uso de modelos <em>Open Source</em> en local no son solo una cuestión de preferencia técnica; son una cuestión de <strong><a href="https://es.wikipedia.org/wiki/Soberanía_tecnológica">soberanía tecnológica</a></strong>. En un mundo donde los modelos cambian de la noche a la mañana, tener el control de tus fuentes de inteligencia es fundamental.</p>
</li>
</ul>
<h3 id="reflexion-final">Reflexión final</h3>
<p>La IA no ha venido a sustituir nuestra capacidad de pensar, sino a amplificar nuestra capacidad de hacer. Seguimos siendo artesanos e ingenieros de la tecnología , y nuestra labor sigue siendo la misma: resolver problemas reales con las mejores herramientas a nuestro alcance. La IA es solo un nuevo martillo, muy potente, pero que requiere una mano experta que sepa dónde golpear.</p>
<p>Espero que esta guía te haya servido para despejar un poco la niebla y empezar a usar estas herramientas con más criterio y menos miedo. Nos vemos en los próximos posts, seguramente probando alguna nueva "skill" o integrando mapas en algún flujo de trabajo que hoy ni siquiera imaginamos.</p>]]></description>
        </item>
    
        <item>
            <title>Conectar PostgreSQL a un agente IA mediante MCP. Háblale a tu base de datos.</title>
            <link>https://psanxiao.com/posts/2026-01-14-conectar-postgres-ia-mediante-mcp.html</link>
            <guid isPermaLink="true">https://psanxiao.com/posts/2026-01-14-conectar-postgres-ia-mediante-mcp.html</guid>
            <pubDate>Wed, 14 Jan 2026 00:00:00 +0000</pubDate>
            <description><![CDATA[<h1 id="conectar-postgresql-a-un-agente-ia-mediante-mcp-hablale-a-tu-base-de-datos">Conectar PostgreSQL a un agente IA mediante MCP. Háblale a tu base de datos.</h1>
<p>Me encontraba en una situación que probablemente te suene familiar. Tenía un proyecto antiguo, una aplicación web funcional que lleva años funcionando, alimentada por una base de datos PostgreSQL que... bueno, digamos que ha vivido su propia vida.</p>
<p>Cada cierto tiempo, el cliente pedía información que no se podía ver en la aplicación web, por lo que era necesario consultar directamente la base de datos. Y cada vez, me enfrentaba al mismo ritual:</p>
<ol>
<li>Abrir el cliente de base de datos</li>
<li>Recordar qué tabla almacena qué información (la documentación estaba, sabes, "actualizada")</li>
<li>Escribir consultas SQL que parecían novelas de misterio con múltiples JOINs</li>
<li>Esperar varios minutos mientras la base de datos trabajaba</li>
<li>Formatear los resultados para que fueran comprensibles</li>
</ol>
<p>No era técnicamente difícil, pero sí increíblemente lento y repetitivo. Y no nos engañemos, hacer consultas SQL no es divertido.</p>
<h2 id="primer-intento-de-solucion-ia-ayudame-a-escribir-sql">Primer Intento de solución: "IA, Ayúdame a Escribir SQL"</h2>
<p>Como buen desarrollador del siglo XXI, mi primer pensamiento fue: "¿Puede la IA ayudarme con esto?". Empecé a usar chats con modelos de IA para generar las consultas SQL.</p>
<p>El proceso era algo así:</p>
<p><strong>Yo:</strong> <em>Necesito una consulta que me muestre estos datos.</em></p>
<p><strong>IA:</strong> <em>Aquí tienes la consulta SQL:</em></p>
<p>Funcionaba... hasta que no funcionaba. El problema fundamental: la IA no conocía mi base de datos. Tenía que explicarle constantemente:</p>
<p>"La tabla <code>usuarios</code> se llama realmente <code>clientes</code>"
"Los campos de fecha están en formato timestamp"
"La relación entre clientes y pedidos es a través de <code>cliente_id</code>, no <code>usuario_id</code>"
"Ten cuidado que hay clientes inactivos en la tabla <code>clientes_baja</code>"</p>
<p>Cada consulta me llevaba más tiempo explicando el contexto que escribiendo SQL yo mismo. Era como tener que entrenar a alguien cada vez que quería hacer una pregunta, bueno, de hecho era literalmente así.</p>
<h2 id="el-momento-mcp-cuando-todo-cambio">El Momento MCP: Cuando Todo Cambió</h2>
<p>Investigando sobre cómo las IAs podrían conectarse directamente a bases de datos, apareció <strong>MCP (Model Context Protocol)</strong>. Y fue como si se encendiera una bombilla.</p>
<p>MCP no es un modelo ni una IA nueva, es un protocolo que permite a los modelos interactuar con herramientas externas (bases de datos, APIs, sistemas locales) de forma estructurada.</p>
<p><strong>¿Y si en lugar de explicarle a la IA cómo es mi base de datos, pudiera simplemente dejarla hablar con ella directamente?</strong></p>
<p>Dejé de pensar en "cómo genero mejores consultas SQL" y empecé a pensar en "cómo conecto la IA directamente a mis datos".</p>
<p>La diferencia es sutil pero fundamental:</p>
<ul>
<li><strong>Antes:</strong> yo → IA → texto SQL → yo → base de datos → yo → IA</li>
<li><strong>Ahora:</strong> yo → IA → base de datos → IA</li>
</ul>
<p>Eliminaba el intermediario (yo) y con ello, toda la fricción.</p>
<h2 id="experimento-1-gemini-cli-y-la-via-facil">Experimento #1: Gemini-cli y la Vía Fácil</h2>
<p>Empecé con Gemini-cli porque descubrí que tenía un sistema de extensiones ya maduro. Entre ellas, una extensión oficial para PostgreSQL. </p>
<p><strong>La instalación fue ridiculamente sencilla:</strong></p>
<div class="codehilite"><pre><span></span><code>gemini<span class="w"> </span>extensions<span class="w"> </span>install<span class="w"> </span>https://github.com/gemini-cli-extensions/postgres
</code></pre></div>

<p>Configuré las variables de entorno, y en minutos, tenía una IA que podía consultar mi base de datos real. El momento mágico fue cuando pregunté (ejemplo figurado):</p>
<p><strong>Yo:</strong> <em>"Muéstrame todos los clientes de Madrid"</em></p>
<p><strong>Gemini:</strong> <em>"Tengo 3 clientes en Madrid: Ana García, Carlos López y María Pérez. Ana se registró hace 2 semanas y ya ha hecho un pedido."</em></p>
<p>No me devolvió una consulta SQL, me devolvió una respuesta basada en los datos. La IA había ejecutado la consulta, interpretado los resultados, y me los presentó de forma natural.</p>
<p><strong>Ventajas de este enfoque:</strong> </p>
<ul>
<li>Super rápido de configurar</li>
<li>Extensión oficial y bien mantenida</li>
<li>Integración perfecta con PostgreSQL</li>
<li>Resultados conversacionales inmediatos</li>
</ul>
<h2 id="experimento-2-opencode-y-el-camino-manual">🚀 Experimento #2: Opencode y el Camino Manual</h2>
<p>Como últimamente estoy experimentando bastante con Opencode (una herramienta que me está encantando), quise ver cómo podía lograr lo mismo con ellos. Aquí la historia fue diferente.</p>
<p>Opencode no tiene un sistema de extensiones predefinido como Gemini-cli. En su lugar, utiliza MCP de forma más nativa, pero requiere que configuremos los servicios MCP manualmente.</p>
<p><strong>El proceso fue:</strong></p>
<ol>
<li>Instalar <code>postgres-mcp</code> como paquete npm</li>
<li>Configurar <code>opencode.json</code> para que usara este MCP local</li>
<li>Ajustar las variables de entorno para que coincidieran</li>
</ol>
<p>Aunque fue más manual que el enfoque de Gemini-cli, una vez funcionó, la experiencia fue igual de impresionante. La diferencia principal está en la filosofía:</p>
<ul>
<li><strong>Gemini-cli:</strong> Tiene extensiones prefabricadas para todo</li>
<li><strong>Opencode:</strong> Te da las herramientas para construir tus propias conexiones</li>
</ul>
<h2 id="este-repositorio-no-es-el-proyecto-es-mi-guia">Este Repositorio No Es el Proyecto, Es Mi Guía</h2>
<p>He creado un pequeño <a href="https://github.com/psanxiao/ia-postgresql-mcp-template">repositorio en mi cuenta de GitHub</a> con la configuración y una base de datos de ejemplo para probarlo. Es principalmente una <strong>documentación para mi yo del futuro</strong>. Pero como compartir es vivir, ahí queda, por si a alguien le es útil o quiere hacer pruebas.</p>
<ul>
<li><strong>Tiene una configuración para arrancar un PostgreSQL con Docker</strong></li>
<li><strong>Tiene una base de datos de ejemplo</strong> (una tienda online con datos realistas)</li>
<li><strong>Está todo documentado paso a paso</strong> (para no perder horas configurándolo de nuevo)</li>
<li><strong>Incluye la configuración para ambas soluciones</strong> (Gemini-cli y Opencode)</li>
<li><strong>Funciona out-of-the-box</strong> (para que mi yo del futuro no sufra)</li>
</ul>
<h2 id="conclusiones">Conclusiones</h2>
<p>Si no te gustan, tengo otras. Pero:</p>
<ul>
<li>
<p>La IA es el mayor avance en interfaces de usuario desde que se inventó el ratón. Los modelos pueden ser mejores o peores, acertar más o menos según su entrenamiento y sus capaciades, pero lo que es innegable es que la IA está cambiando la forma de relacionarnos con la tecnología. Ahora podemos hablarle a todo, incluído a una base de datos.</p>
</li>
<li>
<p><strong>"Me fío de todo el mundo pero desconfío del diablo que llevan dentro"</strong>. Esta frase es de la película <em>The Italian Job</em>. Viene que ni al pelo. Los modelos de IA son lo que son, se basan en probabilidad, no hacen magia, recuérdalo siempre. En este ejemplo concreto, si conoces el dominio que estás consultando y algo te huele raro, revisa, es muy probable que la IA haya hecho mal. Coteja la información, revisa la SQL que ha usado, etc. sobre todo si la información es importante.</p>
</li>
</ul>]]></description>
        </item>
    
        <item>
            <title>Leaflet.js avanzado: GeoJSON, WMS y selector de capas</title>
            <link>https://psanxiao.com/posts/2025-08-24-leaflet-avanzado-geojson.html</link>
            <guid isPermaLink="true">https://psanxiao.com/posts/2025-08-24-leaflet-avanzado-geojson.html</guid>
            <pubDate>Sun, 24 Aug 2025 00:00:00 +0000</pubDate>
            <description><![CDATA[<p>En el <a href="/posts/2025-08-15-introduccion-a-leaflet.html">post anterior</a> vimos cómo crear un mapa web básico. Ahora vamos a dar un salto cualitativo añadiendo funcionalidades avanzadas: marcadores personalizados desde GeoJSON, capas WMS y un control para que el usuario pueda elegir qué mapa base visualizar.</p>
<h3 id="definiendo-nuestros-datos-geojson">Definiendo nuestros datos GeoJSON</h3>
<p>Para este ejemplo, definiremos los datos directamente en una variable de JavaScript. En una aplicación real, estos datos vendrían normalmente de una API o un fichero <code>.geojson</code>.</p>
<h3 id="anadiendo-capas-wms">Añadiendo capas WMS</h3>
<p>Además de las capas de teselas habituales (llamadas capas TMS o XYZ), Leaflet puede consumir servicios WMS (Web Map Service). Estos servicios son un estándar muy común en el mundo de los SIG. Para este ejemplo, usaremos el servicio de ortofotos del Plan Nacional de Ortofotografía Aérea (PNOA) de España. Se hace a través de <code>L.tileLayer.wms</code>:</p>
<div class="codehilite"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">pnoa</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">L</span><span class="p">.</span><span class="nx">tileLayer</span><span class="p">.</span><span class="nx">wms</span><span class="p">(</span><span class="s1">&#39;http://www.ign.es/wms-inspire/pnoa-ma&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="nx">layers</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;OI.OrthoimageCoverage&#39;</span><span class="p">,</span>
<span class="w">    </span><span class="nx">format</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;image/jpeg&#39;</span><span class="p">,</span>
<span class="w">    </span><span class="nx">transparent</span><span class="o">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
<span class="w">    </span><span class="nx">attribution</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;PNOA cedido por © &lt;a href=&quot;http://www.ign.es/ign/main/index.do&quot;&gt;Instituto Geográfico Nacional&lt;/a&gt;&#39;</span>
<span class="p">});</span>
</code></pre></div>

<h3 id="marcadores-personalizados-con-html-css-y-font-awesome">Marcadores personalizados con HTML, CSS y Font Awesome</h3>
<p>Una de las formas más potentes de personalizar los marcadores es usando <code>L.divIcon</code>. A diferencia de <code>L.icon</code> que usa una imagen, <code>divIcon</code> nos permite usar código HTML y CSS, lo que abre la puerta a usar librerías de iconos como <a href="https://fontawesome.com/">Font Awesome</a>.</p>
<p>El proceso combina la lógica de JavaScript con los estilos de CSS.</p>
<p><strong>En la parte de JavaScript</strong>, dentro de la función <code>pointToLayer</code>, decidimos qué icono y qué estilo aplicar a cada punto. Usamos un <code>switch</code> para elegir una clase de Font Awesome (ej: <code>fa-tree</code>) y una clase CSS propia (ej: <code>parque</code>) basándonos en las propiedades de los datos. Luego, pasamos estas clases al <code>divIcon</code>:</p>
<div class="codehilite"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">customIcon</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">L</span><span class="p">.</span><span class="nx">divIcon</span><span class="p">({</span>
<span class="w">    </span><span class="nx">className</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;custom-marker &#39;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">markerColorClass</span><span class="p">,</span><span class="w"> </span><span class="c1">// Clases para el CSS</span>
<span class="w">    </span><span class="nx">html</span><span class="o">:</span><span class="w"> </span><span class="sb">`&lt;i class=&quot;fas </span><span class="si">${</span><span class="nx">iconClass</span><span class="si">}</span><span class="sb">&quot;&gt;&lt;/i&gt;`</span><span class="p">,</span><span class="w">      </span><span class="c1">// HTML con el icono de Font Awesome</span>
<span class="w">    </span><span class="nx">iconSize</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="mf">30</span><span class="p">,</span><span class="w"> </span><span class="mf">30</span><span class="p">]</span>
<span class="p">});</span>
</code></pre></div>

<p><strong>A continuación, en el CSS</strong>, definimos los estilos. Tenemos una clase base, <code>.custom-marker</code>, que crea el círculo contenedor del icono. Luego, las clases específicas (<code>.playa</code>, <code>.parque</code>, <code>.faro</code>) establecen el color tanto del borde del círculo como del propio icono de Font Awesome que contiene.</p>
<div class="codehilite"><pre><span></span><code><span class="p">.</span><span class="nc">custom-marker</span><span class="w"> </span><span class="p">{</span><span class="w"> </span>
<span class="w">    </span><span class="k">background-color</span><span class="p">:</span><span class="w"> </span><span class="nb">rgba</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span><span class="w"> </span><span class="mi">255</span><span class="p">,</span><span class="w"> </span><span class="mi">255</span><span class="p">,</span><span class="w"> </span><span class="mf">0.9</span><span class="p">);</span><span class="w"> </span>
<span class="w">    </span><span class="k">border</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="kt">px</span><span class="w"> </span><span class="kc">solid</span><span class="w"> </span><span class="mh">#333</span><span class="p">;</span><span class="w"> </span>
<span class="w">    </span><span class="k">border-radius</span><span class="p">:</span><span class="w"> </span><span class="mi">50</span><span class="kt">%</span><span class="p">;</span>
<span class="w">    </span><span class="c">/* ... más estilos ... */</span>
<span class="p">}</span>
<span class="p">.</span><span class="nc">custom-marker</span><span class="p">.</span><span class="nc">playa</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">border-color</span><span class="p">:</span><span class="w"> </span><span class="mh">#00aaff</span><span class="p">;</span><span class="w"> </span><span class="k">color</span><span class="p">:</span><span class="w"> </span><span class="mh">#00aaff</span><span class="p">;</span><span class="w"> </span><span class="p">}</span>
<span class="p">.</span><span class="nc">custom-marker</span><span class="p">.</span><span class="nc">parque</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">border-color</span><span class="p">:</span><span class="w"> </span><span class="mh">#28a745</span><span class="p">;</span><span class="w"> </span><span class="k">color</span><span class="p">:</span><span class="w"> </span><span class="mh">#28a745</span><span class="p">;</span><span class="w"> </span><span class="p">}</span>
</code></pre></div>

<p>De esta forma, el HTML y el CSS trabajan juntos para crear un marcador totalmente personalizado.</p>
<h3 id="creando-un-selector-de-capas">Creando un selector de capas</h3>
<p>Para permitir al usuario cambiar entre diferentes mapas base y activar o desactivar capas de datos, usamos <code>L.control.layers</code>.</p>
<div class="codehilite"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">baseMaps</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="s2">&quot;Mapa&quot;</span><span class="o">:</span><span class="w"> </span><span class="nx">carto</span><span class="p">,</span>
<span class="w">    </span><span class="s2">&quot;Ortofoto&quot;</span><span class="o">:</span><span class="w"> </span><span class="nx">pnoa</span>
<span class="p">};</span>
<span class="kd">var</span><span class="w"> </span><span class="nx">overlayMaps</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="s2">&quot;Puntos de interés&quot;</span><span class="o">:</span><span class="w"> </span><span class="nx">markers</span>
<span class="p">};</span>
<span class="nx">L</span><span class="p">.</span><span class="nx">control</span><span class="p">.</span><span class="nx">layers</span><span class="p">(</span><span class="nx">baseMaps</span><span class="p">,</span><span class="w"> </span><span class="nx">overlayMaps</span><span class="p">).</span><span class="nx">addTo</span><span class="p">(</span><span class="nx">map</span><span class="p">);</span>
</code></pre></div>

<h3 id="ejemplo-completo">Ejemplo completo</h3>
<p>El siguiente código HTML es un ejemplo completo y autocontenido.</p>
<div class="codehilite"><pre><span></span><code><span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
    <span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>Leaflet Avanzado: WMS y Control de Capas<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&quot;utf-8&quot;</span> <span class="p">/&gt;</span>
    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">&quot;viewport&quot;</span> <span class="na">content</span><span class="o">=</span><span class="s">&quot;width=device-width, initial-scale=1.0&quot;</span><span class="p">&gt;</span>
    <span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&quot;stylesheet&quot;</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;https://unpkg.com/leaflet/dist/leaflet.css&quot;</span> <span class="p">/&gt;</span>
    <span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&quot;stylesheet&quot;</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css&quot;</span><span class="p">&gt;</span>
    <span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;</span>
<span class="w">        </span><span class="nt">html</span><span class="o">,</span><span class="w"> </span><span class="nt">body</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">height</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="kt">%</span><span class="p">;</span><span class="w"> </span><span class="k">margin</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="k">padding</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="k">display</span><span class="p">:</span><span class="w"> </span><span class="kc">flex</span><span class="p">;</span><span class="w"> </span><span class="k">flex-direction</span><span class="p">:</span><span class="w"> </span><span class="kc">column</span><span class="p">;</span><span class="w"> </span><span class="p">}</span>
<span class="w">        </span><span class="nt">h1</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">text-align</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span><span class="w"> </span><span class="k">padding</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="kt">px</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="k">margin</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="p">}</span>
<span class="w">        </span><span class="p">#</span><span class="nn">map</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">flex-grow</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="p">}</span>
<span class="w">        </span><span class="p">.</span><span class="nc">custom-marker</span><span class="w"> </span><span class="p">{</span><span class="w"> </span>
<span class="w">            </span><span class="k">background-color</span><span class="p">:</span><span class="w"> </span><span class="nb">rgba</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span><span class="w"> </span><span class="mi">255</span><span class="p">,</span><span class="w"> </span><span class="mi">255</span><span class="p">,</span><span class="w"> </span><span class="mf">0.9</span><span class="p">);</span><span class="w"> </span>
<span class="w">            </span><span class="k">border</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="kt">px</span><span class="w"> </span><span class="kc">solid</span><span class="w"> </span><span class="mh">#333</span><span class="p">;</span><span class="w"> </span>
<span class="w">            </span><span class="k">border-radius</span><span class="p">:</span><span class="w"> </span><span class="mi">50</span><span class="kt">%</span><span class="p">;</span><span class="w"> </span>
<span class="w">            </span><span class="k">width</span><span class="p">:</span><span class="w"> </span><span class="mi">30</span><span class="kt">px</span><span class="p">;</span><span class="w"> </span>
<span class="w">            </span><span class="k">height</span><span class="p">:</span><span class="w"> </span><span class="mi">30</span><span class="kt">px</span><span class="p">;</span><span class="w"> </span>
<span class="w">            </span><span class="k">display</span><span class="p">:</span><span class="w"> </span><span class="kc">flex</span><span class="p">;</span><span class="w"> </span>
<span class="w">            </span><span class="k">justify-content</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span><span class="w"> </span>
<span class="w">            </span><span class="k">align-items</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span><span class="w"> </span>
<span class="w">            </span><span class="k">box-shadow</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="mi">2</span><span class="kt">px</span><span class="w"> </span><span class="mi">5</span><span class="kt">px</span><span class="w"> </span><span class="nb">rgba</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mf">0.3</span><span class="p">);</span><span class="w"> </span>
<span class="w">            </span><span class="k">font-size</span><span class="p">:</span><span class="w"> </span><span class="mi">16</span><span class="kt">px</span><span class="p">;</span><span class="w"> </span>
<span class="w">        </span><span class="p">}</span>
<span class="w">        </span><span class="p">.</span><span class="nc">custom-marker</span><span class="p">.</span><span class="nc">playa</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">border-color</span><span class="p">:</span><span class="w"> </span><span class="mh">#00aaff</span><span class="p">;</span><span class="w"> </span><span class="k">color</span><span class="p">:</span><span class="w"> </span><span class="mh">#00aaff</span><span class="p">;</span><span class="w"> </span><span class="p">}</span>
<span class="w">        </span><span class="p">.</span><span class="nc">custom-marker</span><span class="p">.</span><span class="nc">parque</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">border-color</span><span class="p">:</span><span class="w"> </span><span class="mh">#28a745</span><span class="p">;</span><span class="w"> </span><span class="k">color</span><span class="p">:</span><span class="w"> </span><span class="mh">#28a745</span><span class="p">;</span><span class="w"> </span><span class="p">}</span>
<span class="w">        </span><span class="p">.</span><span class="nc">custom-marker</span><span class="p">.</span><span class="nc">faro</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">border-color</span><span class="p">:</span><span class="w"> </span><span class="mh">#ffc107</span><span class="p">;</span><span class="w"> </span><span class="k">color</span><span class="p">:</span><span class="w"> </span><span class="mh">#ffc107</span><span class="p">;</span><span class="w"> </span><span class="p">}</span>
<span class="w">    </span><span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>

<span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>Leaflet Avanzado: WMS y Control de Capas<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&quot;map&quot;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>

<span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&quot;https://unpkg.com/leaflet/dist/leaflet.js&quot;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
<span class="w">    </span><span class="c1">// 1. Definir capas base</span>
<span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">carto</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">L</span><span class="p">.</span><span class="nx">tileLayer</span><span class="p">(</span>
<span class="w">        </span><span class="s1">&#39;https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png&#39;</span><span class="p">,</span><span class="w"> </span>
<span class="w">        </span><span class="p">{</span>
<span class="w">            </span><span class="nx">attribution</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;&amp;copy; &lt;a href=&quot;https://www.openstreetmap.org/copyright&quot;&gt;OpenStreetMap&lt;/a&gt; contributors &amp;copy; &lt;a href=&quot;https://carto.com/attributions&quot;&gt;CARTO&lt;/a&gt;&#39;</span>
<span class="w">        </span><span class="p">}</span>
<span class="w">    </span><span class="p">);</span>

<span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">pnoa</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">L</span><span class="p">.</span><span class="nx">tileLayer</span><span class="p">.</span><span class="nx">wms</span><span class="p">(</span><span class="s1">&#39;http://www.ign.es/wms-inspire/pnoa-ma&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="nx">layers</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;OI.OrthoimageCoverage&#39;</span><span class="p">,</span>
<span class="w">        </span><span class="nx">format</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;image/jpeg&#39;</span><span class="p">,</span>
<span class="w">        </span><span class="nx">transparent</span><span class="o">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
<span class="w">        </span><span class="nx">attribution</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;PNOA cedido por © &lt;a href=&quot;http://www.ign.es/ign/main/index.do&quot;&gt;IGN&lt;/a&gt;&#39;</span>
<span class="w">    </span><span class="p">});</span>

<span class="w">    </span><span class="c1">// 2. Inicializar el mapa</span>
<span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">map</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">L</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="s1">&#39;map&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="nx">center</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="mf">43.35</span><span class="p">,</span><span class="w"> </span><span class="o">-</span><span class="mf">8.36</span><span class="p">],</span>
<span class="w">        </span><span class="nx">zoom</span><span class="o">:</span><span class="w"> </span><span class="mf">13</span><span class="p">,</span>
<span class="w">        </span><span class="nx">layers</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="nx">carto</span><span class="p">]</span>
<span class="w">    </span><span class="p">});</span>

<span class="w">    </span><span class="c1">// 3. Datos GeoJSON</span>
<span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">geojsonData</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w">      </span><span class="s2">&quot;type&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;FeatureCollection&quot;</span><span class="p">,</span>
<span class="w">      </span><span class="s2">&quot;name&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;oleiros_puntos&quot;</span><span class="p">,</span>
<span class="w">      </span><span class="s2">&quot;features&quot;</span><span class="o">:</span><span class="w"> </span><span class="p">[</span>
<span class="w">        </span><span class="p">{</span>
<span class="w">          </span><span class="s2">&quot;type&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Feature&quot;</span><span class="p">,</span>
<span class="w">          </span><span class="s2">&quot;properties&quot;</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">&quot;name&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Playa de Santa Cristina&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;tipo&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Playa&quot;</span><span class="w"> </span><span class="p">},</span>
<span class="w">          </span><span class="s2">&quot;geometry&quot;</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">&quot;type&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Point&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;coordinates&quot;</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="o">-</span><span class="mf">8.378631</span><span class="p">,</span><span class="w"> </span><span class="mf">43.339596</span><span class="p">]</span><span class="w"> </span><span class="p">}</span>
<span class="w">        </span><span class="p">},</span>
<span class="w">        </span><span class="p">{</span>
<span class="w">          </span><span class="s2">&quot;type&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Feature&quot;</span><span class="p">,</span>
<span class="w">          </span><span class="s2">&quot;properties&quot;</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">&quot;name&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Parque de José Martí&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;tipo&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Parque&quot;</span><span class="w"> </span><span class="p">},</span>
<span class="w">          </span><span class="s2">&quot;geometry&quot;</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">&quot;type&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Point&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;coordinates&quot;</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="o">-</span><span class="mf">8.378567</span><span class="p">,</span><span class="w"> </span><span class="mf">43.336728</span><span class="p">]</span><span class="w"> </span><span class="p">}</span>
<span class="w">        </span><span class="p">},</span>
<span class="w">        </span><span class="p">{</span>
<span class="w">          </span><span class="s2">&quot;type&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Feature&quot;</span><span class="p">,</span>
<span class="w">          </span><span class="s2">&quot;properties&quot;</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">&quot;name&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Faro de Mera&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;tipo&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Faro&quot;</span><span class="w"> </span><span class="p">},</span>
<span class="w">          </span><span class="s2">&quot;geometry&quot;</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">&quot;type&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Point&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;coordinates&quot;</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="o">-</span><span class="mf">8.354416</span><span class="p">,</span><span class="w"> </span><span class="mf">43.383347</span><span class="p">]</span><span class="w"> </span><span class="p">}</span>
<span class="w">        </span><span class="p">},</span>
<span class="w">        </span><span class="p">{</span>
<span class="w">          </span><span class="s2">&quot;type&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Feature&quot;</span><span class="p">,</span>
<span class="w">          </span><span class="s2">&quot;properties&quot;</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">&quot;name&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Playa de Bastiagueiro&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;tipo&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Playa&quot;</span><span class="w"> </span><span class="p">},</span>
<span class="w">          </span><span class="s2">&quot;geometry&quot;</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">&quot;type&quot;</span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;Point&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;coordinates&quot;</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="o">-</span><span class="mf">8.362489</span><span class="p">,</span><span class="w"> </span><span class="mf">43.340981</span><span class="p">]</span><span class="w"> </span><span class="p">}</span>
<span class="w">        </span><span class="p">}</span>
<span class="w">      </span><span class="p">]</span>
<span class="w">    </span><span class="p">};</span>

<span class="w">    </span><span class="c1">// 4. Capa de marcadores personalizados</span>
<span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">markers</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">L</span><span class="p">.</span><span class="nx">geoJSON</span><span class="p">(</span><span class="nx">geojsonData</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="nx">pointToLayer</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="w"> </span><span class="p">(</span><span class="nx">feature</span><span class="p">,</span><span class="w"> </span><span class="nx">latlng</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="kd">var</span><span class="w"> </span><span class="nx">iconClass</span><span class="p">,</span><span class="w"> </span><span class="nx">markerColorClass</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;&#39;</span><span class="p">;</span>
<span class="w">            </span><span class="k">switch</span><span class="w"> </span><span class="p">(</span><span class="nx">feature</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="nx">tipo</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w">                </span><span class="k">case</span><span class="w"> </span><span class="s1">&#39;Playa&#39;</span><span class="o">:</span><span class="w"> </span>
<span class="w">                    </span><span class="nx">iconClass</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;fa-umbrella-beach&#39;</span><span class="p">;</span><span class="w"> </span>
<span class="w">                    </span><span class="nx">markerColorClass</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;playa&#39;</span><span class="p">;</span><span class="w"> </span>
<span class="w">                    </span><span class="k">break</span><span class="p">;</span>
<span class="w">                </span><span class="k">case</span><span class="w"> </span><span class="s1">&#39;Parque&#39;</span><span class="o">:</span><span class="w"> </span>
<span class="w">                    </span><span class="nx">iconClass</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;fa-tree&#39;</span><span class="p">;</span><span class="w"> </span>
<span class="w">                    </span><span class="nx">markerColorClass</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;parque&#39;</span><span class="p">;</span><span class="w"> </span>
<span class="w">                    </span><span class="k">break</span><span class="p">;</span>
<span class="w">                </span><span class="k">case</span><span class="w"> </span><span class="s1">&#39;Faro&#39;</span><span class="o">:</span><span class="w"> </span>
<span class="w">                    </span><span class="nx">iconClass</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;fa-lightbulb&#39;</span><span class="p">;</span><span class="w"> </span>
<span class="w">                    </span><span class="nx">markerColorClass</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;faro&#39;</span><span class="p">;</span><span class="w"> </span>
<span class="w">                    </span><span class="k">break</span><span class="p">;</span>
<span class="w">                </span><span class="k">default</span><span class="o">:</span><span class="w"> </span>
<span class="w">                    </span><span class="nx">iconClass</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;fa-map-marker-alt&#39;</span><span class="p">;</span><span class="w"> </span>
<span class="w">                    </span><span class="k">break</span><span class="p">;</span>
<span class="w">            </span><span class="p">}</span>
<span class="w">            </span><span class="kd">var</span><span class="w"> </span><span class="nx">customIcon</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">L</span><span class="p">.</span><span class="nx">divIcon</span><span class="p">({</span>
<span class="w">                </span><span class="nx">className</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;custom-marker &#39;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">markerColorClass</span><span class="p">,</span>
<span class="w">                </span><span class="nx">html</span><span class="o">:</span><span class="w"> </span><span class="sb">`&lt;i class=&quot;fas </span><span class="si">${</span><span class="nx">iconClass</span><span class="si">}</span><span class="sb">&quot;&gt;&lt;/i&gt;`</span><span class="p">,</span>
<span class="w">                </span><span class="nx">iconSize</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="mf">30</span><span class="p">,</span><span class="w"> </span><span class="mf">30</span><span class="p">]</span>
<span class="w">            </span><span class="p">});</span>
<span class="w">            </span><span class="kd">var</span><span class="w"> </span><span class="nx">popupText</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;&lt;strong&gt;&#39;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">feature</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="nx">name</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">&#39;&lt;/strong&gt;&#39;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span>
<span class="w">                            </span><span class="s1">&#39;&lt;br&gt;Tipo: &#39;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">feature</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="nx">tipo</span><span class="p">;</span>

<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">L</span><span class="p">.</span><span class="nx">marker</span><span class="p">(</span><span class="nx">latlng</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">icon</span><span class="o">:</span><span class="w"> </span><span class="nx">customIcon</span><span class="w"> </span><span class="p">}).</span><span class="nx">bindPopup</span><span class="p">(</span><span class="nx">popupText</span><span class="p">);</span>
<span class="w">        </span><span class="p">}</span>
<span class="w">    </span><span class="p">}).</span><span class="nx">addTo</span><span class="p">(</span><span class="nx">map</span><span class="p">);</span>

<span class="w">    </span><span class="c1">// 5. Configurar el control de capas</span>
<span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">baseMaps</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="s2">&quot;Mapa&quot;</span><span class="o">:</span><span class="w"> </span><span class="nx">carto</span><span class="p">,</span>
<span class="w">        </span><span class="s2">&quot;Ortofoto&quot;</span><span class="o">:</span><span class="w"> </span><span class="nx">pnoa</span>
<span class="w">    </span><span class="p">};</span>

<span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">overlayMaps</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="s2">&quot;Puntos de interés&quot;</span><span class="o">:</span><span class="w"> </span><span class="nx">markers</span>
<span class="w">    </span><span class="p">};</span>

<span class="w">    </span><span class="nx">L</span><span class="p">.</span><span class="nx">control</span><span class="p">.</span><span class="nx">layers</span><span class="p">(</span><span class="nx">baseMaps</span><span class="p">,</span><span class="w"> </span><span class="nx">overlayMaps</span><span class="p">).</span><span class="nx">addTo</span><span class="p">(</span><span class="nx">map</span><span class="p">);</span>

<span class="w">    </span><span class="c1">// 6. Ajustar el zoom a los marcadores</span>
<span class="w">    </span><span class="nx">map</span><span class="p">.</span><span class="nx">fitBounds</span><span class="p">(</span><span class="nx">markers</span><span class="p">.</span><span class="nx">getBounds</span><span class="p">());</span>

<span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>

<span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</code></pre></div>

<h3 id="bonus-final-latitud-y-longitud-el-eterno-debate">Bonus final: Latitud y Longitud, el eterno debate</h3>
<p>Un detalle importante a tener en cuenta es el orden de las coordenadas. Si te has dado cuenta el orden de las coordenadas es diferente cuando definimos el centro del mapa en leaflet, respecto de como se definen en el geojson. No existe un estándar único en el mundo de la información geográfica, lo que a menudo causa errores inesperados.</p>
<ul>
<li><strong>Leaflet</strong>, en sus funciones principales como <code>L.mapsetView()</code> o <code>L.marker()</code>, generalmente espera el formato <code>[latitud, longitud]</code>.</li>
<li><strong>El estándar GeoJSON</strong>, sin embargo, especifica el orden inverso: <code>[longitud, latitud]</code>.</li>
</ul>
<p>Esta inconsistencia es habitual entre diferentes herramientas, formatos y estándares del mundo SIG. Afortunadamente, en este caso, la función <code>L.geoJSON()</code> de Leaflet es lo suficientemente inteligente como para leer correctamente las coordenadas en el formato estándar de GeoJSON sin que tengamos que hacer ninguna conversión manual. Para quien quiera profundizar más en este curioso problema, el artículo <a href="https://macwright.com/lonlat/">Lon, lat is the right way</a> de Tom MacWright lo explica de maravilla.</p>]]></description>
        </item>
    
        <item>
            <title>Introducción a Leaflet: mapas interactivos sencillos y potentes</title>
            <link>https://psanxiao.com/posts/2025-08-15-introduccion-a-leaflet.html</link>
            <guid isPermaLink="true">https://psanxiao.com/posts/2025-08-15-introduccion-a-leaflet.html</guid>
            <pubDate>Fri, 15 Aug 2025 00:00:00 +0000</pubDate>
            <description><![CDATA[<p>En el mundo del desarrollo web, <strong><a href="https://leafletjs.com/">Leaflet</a></strong> se ha convertido en una de las librerías JavaScript más populares para crear mapas interactivos. Su diseño está pensado para ser <strong>ligero</strong>, con un núcleo (<em>core</em>) pequeño que ofrece las funciones esenciales para mostrar mapas y elementos básicos de interacción.  </p>
<p>Esta filosofía tiene una ventaja importante: <strong>puedes empezar de forma simple y rápida</strong>, sin tener que aprender una API enorme o cargar funcionalidades que no necesitas. Y si tu proyecto crece, puedes ir ampliándolo con una extensa colección de <a href="https://leafletjs.com/plugins.html">plugins</a> oficiales y de la comunidad que añaden todo tipo de capacidades: desde dibujar polígonos y medir distancias, hasta mostrar datos en 3D o integrar servicios de geocodificación.</p>
<p>En resumen: <strong>Leaflet es pequeño y fácil al principio, pero no se queda corto</strong>. Es como una navaja suiza a la que le puedes ir añadiendo herramientas a medida que las necesitas.</p>
<h2 id="por-que-usar-leaflet">¿Por qué usar Leaflet?</h2>
<ul>
<li><strong>Ligera:</strong> el núcleo pesa menos de 50 KB.</li>
<li><strong>Compatible:</strong> funciona en la mayoría de navegadores y dispositivos móviles.</li>
<li><strong>Extensible:</strong> cuenta con multitud de <a href="https://leafletjs.com/plugins.html">plugins</a> para añadir funcionalidades avanzadas.</li>
<li><strong>Fácil de aprender:</strong> ideal para principiantes y proyectos rápidos.</li>
</ul>
<h2 id="ejemplo-basico-de-mapa-con-leaflet">Ejemplo básico de mapa con Leaflet</h2>
<p>El siguiente ejemplo muestra cómo crear un mapa centrado en unas coordenadas concretas, añadir un marcador y mostrar un popup. Solo necesitas incluir la librería Leaflet y un contenedor para el mapa.</p>
<div class="codehilite"><pre><span></span><code><span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&quot;utf-8&quot;</span> <span class="p">/&gt;</span>
    <span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>Mapa con Leaflet<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">&quot;viewport&quot;</span> <span class="na">content</span><span class="o">=</span><span class="s">&quot;width=device-width, initial-scale=1.0&quot;</span><span class="p">&gt;</span>

    <span class="cm">&lt;!-- CSS de Leaflet --&gt;</span>
    <span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&quot;stylesheet&quot;</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;https://unpkg.com/leaflet/dist/leaflet.css&quot;</span> <span class="p">/&gt;</span>

    <span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;</span>
<span class="w">        </span><span class="p">#</span><span class="nn">map</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="k">height</span><span class="p">:</span><span class="w"> </span><span class="mi">500</span><span class="kt">px</span><span class="p">;</span>
<span class="w">        </span><span class="p">}</span>
<span class="w">    </span><span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>

<span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>Mi primer mapa con Leaflet<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&quot;map&quot;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>

<span class="cm">&lt;!-- JS de Leaflet --&gt;</span>
<span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&quot;https://unpkg.com/leaflet/dist/leaflet.js&quot;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
<span class="w">    </span><span class="c1">// Inicializar el mapa</span>
<span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">map</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">L</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="s1">&#39;map&#39;</span><span class="p">).</span><span class="nx">setView</span><span class="p">([</span><span class="mf">43.3336</span><span class="p">,</span><span class="w"> </span><span class="o">-</span><span class="mf">8.3174</span><span class="p">],</span><span class="w"> </span><span class="mf">14</span><span class="p">);</span>

<span class="w">    </span><span class="c1">// Añadir capa base de OpenStreetMap</span>
<span class="w">    </span><span class="nx">L</span><span class="p">.</span><span class="nx">tileLayer</span><span class="p">(</span><span class="s1">&#39;https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="nx">attribution</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;&amp;copy; &lt;a href=&quot;https://www.openstreetmap.org/&quot;&gt;OpenStreetMap&lt;/a&gt; contributors&#39;</span>
<span class="w">    </span><span class="p">}).</span><span class="nx">addTo</span><span class="p">(</span><span class="nx">map</span><span class="p">);</span>

<span class="w">    </span><span class="c1">// Añadir un marcador</span>
<span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">marker</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">L</span><span class="p">.</span><span class="nx">marker</span><span class="p">([</span><span class="mf">43.3336</span><span class="p">,</span><span class="w"> </span><span class="o">-</span><span class="mf">8.3174</span><span class="p">]).</span><span class="nx">addTo</span><span class="p">(</span><span class="nx">map</span><span class="p">);</span>

<span class="w">    </span><span class="c1">// Popup en el marcador</span>
<span class="w">    </span><span class="nx">marker</span><span class="p">.</span><span class="nx">bindPopup</span><span class="p">(</span><span class="s2">&quot;&lt;b&gt;Hola!&lt;/b&gt;&lt;br&gt;Este es un mapa de Leaflet centrado en Oleiros.&quot;</span><span class="p">).</span><span class="nx">openPopup</span><span class="p">();</span>
<span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>

<span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</code></pre></div>

<h2 id="como-funciona-el-codigo">Cómo funciona el código</h2>
<ul>
<li>Importamos Leaflet: a través de sus archivos CSS y JS desde un CDN.</li>
<li>Creamos un contenedor #map: donde se dibujará el mapa.</li>
<li>Inicializamos el mapa: con L.map() y lo centramos en un punto.</li>
<li>Añadimos una capa base: usando L.tileLayer() con teselas de OpenStreetMap.</li>
<li>Colocamos un marcador: y le añadimos un popup.</li>
</ul>]]></description>
        </item>
    
        <item>
            <title>De la Tierra al navegador: entendiendo la base de los mapas web</title>
            <link>https://psanxiao.com/posts/2025-08-14-de-la-tierra-al-navegador.html</link>
            <guid isPermaLink="true">https://psanxiao.com/posts/2025-08-14-de-la-tierra-al-navegador.html</guid>
            <pubDate>Thu, 14 Aug 2025 00:00:00 +0000</pubDate>
            <description><![CDATA[<p>Si estás empezando a trabajar con <strong>mapas en la web</strong>, probablemente tu primer impulso será abrir una librería como <a href="https://openlayers.org/">OpenLayers</a>, <a href="https://leafletjs.com/">Leaflet</a> o <a href="https://maplibre.org/">MapLibre</a> y cargar tus datos. Y está bien. Pero antes de ver nada en pantalla, puede que aparezcan palabras que suenan algo misteriosas: <em>proyección</em>, <em>WGS84</em>, <em>EPSG:3857</em>, <em>coordenadas geográficas</em>, <em>sistema de referencia</em>…</p>
<p>Entender qué significan estos conceptos te ahorrará muchos quebraderos de cabeza. Porque antes de representar datos geográficos en la web, hay que entender una idea clave: <strong>el planeta en el que vivimos no es fácil de convertir en un plano</strong>.</p>
<p>La Tierra no es una esfera perfecta. De hecho, se parece más a una patata: está achatada por los polos, algo abultada por el ecuador y llena de irregularidades causadas por la gravedad, las montañas y los océanos. Esa forma tan real pero complicada se llama <a href="https://es.wikipedia.org/wiki/Geoide"><strong>geoide</strong></a>, y aunque describe bien cómo es el planeta, resulta imposible de usar directamente en los cálculos de un mapa.</p>
<p>Para simplificar las cosas, se utiliza una superficie más regular llamada <a href="https://es.wikipedia.org/wiki/Elipsoide_de_referencia"><strong>elipsoide de referencia</strong></a>. Es una figura matemática que se ajusta al geoide, pero lo bastante sencilla para trabajar con ella. Existen varios elipsoides, pero hoy el más usado es el <strong>WGS84</strong>, el mismo que emplea el GPS y la mayoría de servicios de mapas en línea.</p>
<p>Con el elipsoide definido, necesitamos una forma de localizar puntos sobre él. Para eso se usan las <a href="https://es.wikipedia.org/wiki/Coordenadas_geogr%C3%A1ficas"><strong>coordenadas geográficas</strong></a>, que indican la <strong>latitud</strong> (posición norte-sur) y la <strong>longitud</strong> (posición este-oeste). Por ejemplo, <code>43.333°N, -8.317°O</code> nos lleva a Oleiros, en Galicia. Es un sistema perfecto para referirse a lugares sobre el globo, pero poco práctico para dibujarlos en una pantalla, porque los ordenadores trabajan con coordenadas <strong>planas (x, y)</strong>.</p>
<p>Y aquí llega el paso más importante: <strong>convertir una superficie curva en un plano</strong>. Este proceso se llama <a href="https://es.wikipedia.org/wiki/Proyecci%C3%B3n_cartogr%C3%A1fica"><strong>proyección cartográfica</strong></a>.Imagina intentar aplanar la piel de una naranja sobre una hoja de papel: tendrás que estirar, cortar o deformar algo. Con la Tierra pasa lo mismo. Cada proyección elige qué quiere conservar (las distancias, las áreas, los ángulos…) y qué está dispuesta a deformar. No hay una proyección perfecta, solo la más adecuada según el uso.</p>
<h2 id="la-proyeccion-web-mercator">La proyección Web Mercator</h2>
<p>En el mundo del webmapping, la proyección más común es la <a href="https://es.wikipedia.org/wiki/Pseudo-Mercator"><strong>Web Mercator</strong></a>, una adaptación moderna de la proyección creada por <strong>Gerardus Mercator</strong> en el siglo XVI. Es la que utilizan <strong>Google Maps</strong>, <strong>OpenStreetMap</strong>, <strong>Bing Maps</strong>, y casi todos los visores actuales.  </p>
<p>Su gran ventaja es que permite mostrar todo el planeta como una cuadrícula continua y realizar <strong>zoom progresivo</strong> sin interrupciones, lo que resulta ideal para aplicaciones interactivas. Internamente, Web Mercator transforma las coordenadas de latitud y longitud en metros usando el elipsoide <strong>WGS84</strong>, y “recorta” la Tierra a una latitud máxima de ±85°. Esto evita que las zonas cercanas a los polos se estiren infinitamente.</p>
<p>El inconveniente, claro, es la <strong>distorsión</strong>: los objetos cercanos a los polos se ven mucho más grandes de lo que son. Groenlandia parece casi tan grande como África, cuando en realidad África es unas 14 veces mayor. Por eso, aunque Web Mercator es práctica, no es la proyección adecuada para hacer cálculos de superficie o distancia.</p>
<p>Aun así, su sencillez y compatibilidad la han convertido en el estándar de facto en los mapas web. Cuando ves un mapa en línea, lo más probable es que esté en <strong>EPSG:3857</strong>, el código oficial de esta proyección.</p>
<h2 id="sistemas-de-referencia-el-idioma-de-los-mapas">Sistemas de referencia: el idioma de los mapas</h2>
<p>Cada combinación de elipsoide, proyección y unidad de medida forma lo que se conoce como un <a href="https://es.wikipedia.org/wiki/Sistema_de_referencia_geod%C3%A9sico"><strong>sistema de referencia espacial</strong></a>. Podemos imaginarlo como el “idioma” que usan los datos geográficos para decirle al mapa <strong>dónde</strong> se encuentra cada punto.</p>
<p>Un sistema de referencia se compone, generalmente, de tres partes:</p>
<ol>
<li><strong>Datum o marco de referencia</strong>: define la forma y posición del elipsoide respecto a la Tierra real. Por ejemplo, el <strong>WGS84</strong> es un datum global.  </li>
<li><strong>Proyección cartográfica</strong>: establece cómo se transforma la superficie curva del elipsoide en un plano (por ejemplo, <strong>Mercator</strong>, <strong>UTM</strong>, <strong>Lambert</strong>, etc.).  </li>
<li><strong>Unidades de medida</strong>: indican en qué se expresan las coordenadas (grados, metros, pies…).</li>
</ol>
<p>Estas tres piezas juntas determinan cómo deben interpretarse las coordenadas de un archivo o servicio geográfico. Por ejemplo:</p>
<ul>
<li><strong>EPSG:4326</strong> → usa el datum WGS84, sin proyección (coordenadas en grados de latitud y longitud).  </li>
<li><strong>EPSG:3857</strong> → usa el mismo datum WGS84, pero proyectado con Web Mercator, y las coordenadas se expresan en metros.  </li>
<li><strong>EPSG:25831</strong> → corresponde al sistema UTM huso 31N sobre el datum ETRS89, habitual en España peninsular.</li>
</ul>
<p>Saber en qué sistema están tus datos, y cuál usa tu mapa, es esencial para que todo encaje. Si no coinciden, los puntos aparecerán desplazados, a veces cientos de kilómetros fuera de lugar. Por suerte, la mayoría de librerías modernas permiten gestionar estos sistemas de forma automática.</p>
<h2 id="que-hacen-las-librerias-web-con-todo-esto">¿Qué hacen las librerías web con todo esto?</h2>
<p>Una buena noticia: no necesitas preocuparte demasiado por las transformaciones.<br />
Librerías como <strong>Leaflet</strong>, <strong>OpenLayers</strong> o <strong>MapLibre</strong> están pensadas para que los datos “simplemente funcionen”.</p>
<p>La mayoría de los mapas en la web utilizan <strong>Web Mercator (EPSG:3857)</strong>, pero muchos conjuntos de datos, APIs o servicios de datos abiertos vienen en <strong>EPSG:4326</strong>, es decir, con latitudes y longitudes en grados. ¿Cómo es posible que ambos se entiendan?</p>
<p>La clave está en que <strong>los dos sistemas comparten el mismo elipsoide, WGS84</strong>.<br />
Eso significa que la relación entre coordenadas geográficas (grados) y proyectadas (metros) es directa y fácil de calcular matemáticamente. Cuando una librería como OpenLayers recibe datos en 4326, <strong>no necesita hacer una transformación geodésica compleja</strong>, sino una simple conversión de grados a metros en la proyección Web Mercator.  </p>
<p>En la práctica, es como si el mapa y tus datos hablaran el mismo idioma con distinto acento: basta una pequeña traducción. Por eso puedes pasar coordenadas en 4326 y ver cómo se dibujan correctamente sobre un mapa base en 3857, sin que aparezcan desplazadas ni deformadas.</p>
<p>Ahora bien, cada librería gestiona esto de forma un poco diferente:</p>
<ul>
<li>
<p><strong>Leaflet</strong> trabaja de forma nativa en Web Mercator y no incluye soporte interno para transformar entre sistemas distintos. Si tus datos están en otra proyección, tendrás que convertirlos antes o usar un plugin como <a href="https://github.com/kartena/Proj4Leaflet">Proj4Leaflet</a>.</p>
</li>
<li>
<p><strong>OpenLayers</strong> integra el motor <a href="https://proj4js.org/">Proj4js</a> y puede <strong>transformar coordenadas directamente</strong> entre sistemas definidos por su código EPSG. Esto la hace más flexible para trabajar con datos en diferentes proyecciones sin necesidad de preprocesarlos.</p>
</li>
<li>
<p><strong>MapLibre GL JS</strong> trabaja también en <strong>Web Mercator</strong>, pero con una particularidad: está pensada principalmente para <strong>mapas vectoriales</strong>. Su motor de renderizado asume que las coordenadas de los datos están en EPSG:4326 (grados) y las proyecta internamente a 3857 en tiempo real, aprovechando la GPU del navegador. Es decir, hace la conversión sobre la marcha de forma eficiente y transparente para ti. No incluye herramientas de reproyección entre otros sistemas, pero en la mayoría de los casos no las necesita.</p>
</li>
</ul>
<p>En resumen, las tres librerías coinciden en que <strong>Web Mercator es su lenguaje común</strong>, y todas pueden mostrar datos en 4326 sin problemas. La diferencia está en cuánta ayuda ofrecen si trabajas fuera de ese “idioma estándar”.</p>
<h2 id="en-resumen">En resumen</h2>
<p>Cuando trabajas con mapas web, tus datos siguen un camino que va desde la forma real del planeta hasta el plano del navegador:</p>
<blockquote>
<p><strong>Tierra → Geoide → Elipsoide → Coordenadas → Proyección → Mapa</strong></p>
</blockquote>
<p>Comprender esta secuencia te ayudará a evitar errores y, sobre todo, a entender qué está ocurriendo “debajo del mapa”. </p>
<p>En siguientes artículos veremos cómo llevar estos conceptos a la práctica: cómo cargar datos, elegir proyecciones y crear tus propios mapas interactivos.</p>]]></description>
        </item>
    
        <item>
            <title>Leaflet, OpenLayers y MapLibre en 2025: ¿Cuál librería elegir para iniciarte en la visualización de datos geográficos web?</title>
            <link>https://psanxiao.com/posts/2025-08-12-leaflet-openlayers-y-maplibre-en-2025.html</link>
            <guid isPermaLink="true">https://psanxiao.com/posts/2025-08-12-leaflet-openlayers-y-maplibre-en-2025.html</guid>
            <pubDate>Tue, 12 Aug 2025 00:00:00 +0000</pubDate>
            <description><![CDATA[<p>Si estás dando tus primeros pasos en el mundo de la visualización de datos geográficos en la web, es normal que te preguntes qué herramienta utilizar para crear mapas interactivos. En este artículo voy a hablar de tres librerías muy populares y con mucha comunidad detrás: <em>Leaflet, OpenLayers y MapLibre</em>. Analizaremos sus características, su comunidad de usuarios y desarrolladores, su ritmo de desarrollo y también sus licencias de software libre. Así tendrás toda la información para decidir cuál se ajusta mejor a tu proyecto y nivel.</p>
<h2 id="que-son-leaflet-openlayers-y-maplibre">¿Qué son Leaflet, OpenLayers y MapLibre?</h2>
<p>Para empezar, un poco de contexto. <a href="https://leafletjs.com">Leaflet</a> es una librería nacida en 2011 que se ha ganado la fama por ser ligera, fácil de aprender y con una curva de aprendizaje muy amigable para principiantes. Su foco principal es facilitar la creación de mapas web sencillos, con funcionalidades básicas pero muy bien diseñadas, y una amplia variedad de plugins para ampliar sus capacidades.</p>
<p>Por otro lado, <a href="https://openlayers.org">OpenLayers</a> es un proyecto más antiguo (desde 2006) y mucho más completo y robusto. Está pensado para quienes necesitan hacer proyectos GIS avanzados con análisis espacial, soporte para múltiples formatos, proyecciones y operaciones complejas sobre datos geográficos. Su curva de aprendizaje es más pronunciada, pero a cambio ofrece una potencia y flexibilidad que pocas librerías pueden igualar.</p>
<p>Finalmente, <a href="https://maplibre.org">MapLibre</a> es relativamente más nuevo y nace como un fork abierto de Mapbox GL JS. Su especialidad son los mapas vectoriales renderizados con WebGL, lo que permite crear visualizaciones muy modernas, estilizadas y con gran rendimiento para datos complejos y dinámicos. MapLibre está ganando mucha popularidad especialmente para aplicaciones que buscan estética y rendimiento en mapas web.</p>
<h2 id="comunidad-y-desarrollo-que-libreria-esta-mas-activa">Comunidad y desarrollo: ¿qué librería está más activa?</h2>
<p>Al elegir una librería para tus proyectos, es fundamental conocer qué tan activa y saludable es su comunidad de desarrolladores, así como la frecuencia con la que se actualiza el proyecto. Esto afecta la calidad del software, la rapidez en corregir errores y la disponibilidad de nuevas funcionalidades.</p>
<p>Una métrica comúnmente citada son las estrellas en GitHub, que indican popularidad, pero no siempre reflejan la actividad real de desarrollo. Por eso, también es útil mirar otros datos como el número de contribuidores activos, la frecuencia de lanzamientos y el nivel de interacción en los issues y pull requests.</p>
<p>Leaflet tiene aproximadamente 43,000 estrellas en GitHub, lo que indica una comunidad muy amplia y extendida. El número de contribuidores totales es de más de 800 en total, aunque a lo largo del tiempo no se ha mantenido constante. La frecuencia de actualizaciones es moderada, con la última versión estable importante lanzada hace más de dos años. Aunque la comunidad es grande, el ritmo de desarrollo es algo pausado en la actualidad. Hay que tener en cuenta que el modelo de Leaflet es tener un núcleo pequeño, que es el repositorio del que se muestra la gráfica, y un ecosistema grande de plugins, a través de los cuales se dota de más funcionalidad.</p>
<p><img src="./img/Leaflet-Commits-over-time.png" alt="Leaflet commits from github" style="max-width: 100%;"></p>
<p>OpenLayers cuenta con unas 13,000 estrellas en GitHub y alrededor de 400 contribuidores en total. A diferencia de Leaflet, el equipo de desarrollo lanza actualizaciones regularmente, con versiones nuevas casi cada mes. Además, la comunidad es muy técnica, lo que favorece un desarrollo continuado y la incorporación de funcionalidades complejas, muy valoradas en proyectos GIS profesionales.</p>
<p><img src="./img/Openlayers-Commits-over-time.png" alt="Openlayers commits from github" style="max-width: 100%;"></p>
<p>MapLibre, con cerca de 8,500 estrellas, es la más joven de las tres pero destaca por su crecimiento rápido. Cuenta ya con más de 500 contribuidores en total y una actividad intensa en issues y pull requests, lo que refleja una comunidad vibrante y muy involucrada en mantener la librería actualizada con las últimas tecnologías, especialmente para mapas vectoriales con WebGL.</p>
<p><img src="./img/Maplibre-Commits-over-time.png" alt="Maplibre commits from github" style="max-width: 100%;"></p>
<p>En resumen, si bien Leaflet sigue siendo la librería más popular, OpenLayers y MapLibre tienen comunidades muy activas y desarrollo frecuente, cada una con su enfoque particular.</p>
<h2 id="licencias-la-tranquilidad-de-trabajar-con-software-libre">Licencias: la tranquilidad de trabajar con software libre</h2>
<p>Otro punto que siempre preocupa a quienes empiezan y también a quienes trabajan en proyectos profesionales es la licencia del software. Las tres librerías usan licencias permisivas BSD de 2 cláusulas, lo que significa que puedes usarlas, modificarlas y distribuirlas sin muchas restricciones, incluso en proyectos comerciales. Esto ofrece una gran tranquilidad y flexibilidad para tu trabajo.</p>
<h2 id="cual-libreria-elegir">¿Cuál librería elegir?</h2>
<p>Si estás buscando algo sencillo, que te permita crear mapas rápidamente sin tener que lidiar con complejidades técnicas, Leaflet es sin duda la mejor opción para empezar. Su comunidad enorme y su ecosistema de plugins te facilitarán mucho el aprendizaje y la implementación.</p>
<p>Si tu objetivo es ir más allá y trabajar en proyectos GIS con análisis espaciales, múltiples capas y datos complejos, OpenLayers es la herramienta ideal. Su potencia y flexibilidad se reflejan en el nivel de detalle que puedes manejar en tus mapas.</p>
<p>Por último, si quieres crear mapas modernos, vectoriales y estilizados, que aprovechen WebGL para un rendimiento y estética superior, MapLibre es una opción muy interesante y actualizada, ideal para aplicaciones que buscan impactar visualmente sin perder rendimiento.</p>
<h2 id="conclusion">Conclusión</h2>
<p>En resumen, las tres librerías tienen sus puntos fuertes y la elección depende mucho del tipo de proyecto que quieras hacer y tu nivel de experiencia. Leaflet es ideal para empezar rápido y sencillo, OpenLayers para proyectos GIS más avanzados y MapLibre para quienes buscan mapas vectoriales modernos y estilizados.</p>
<p>Este artículo ofrece una visión general basada en el estado actual de las herramientas y sus comunidades, pero no debe tomarse al pie de la letra. La mejor manera de aprender y decidir es explorando y probando por ti mismo cada una de ellas, ya que cada proyecto tiene necesidades y matices únicos.</p>]]></description>
        </item>
    
        <item>
            <title>El software ya es libre</title>
            <link>https://psanxiao.com/posts/2024-10-07-el-software-ya-es-libre.html</link>
            <guid isPermaLink="true">https://psanxiao.com/posts/2024-10-07-el-software-ya-es-libre.html</guid>
            <pubDate>Mon, 07 Oct 2024 00:00:00 +0000</pubDate>
            <description><![CDATA[<p>Hoy se celebra el día mundial del software libre. Pero por si acaso no lo sabes, ya te lo digo yo, el software es libre.</p>
<p>Cuando comenzó a desarrollarse el mundo de la informática, los ordenadores eran aparatos muy caros que casi no cabían en una habitación. Un par de fabricantes se repartían el mercado de ese hardware, porque en aquel momento el software no valía nada por sí mismo. En ese momento el software era libre.</p>
<p>La cosa siguió avanzando, los ordenadores empezaron a cambiar de tamaño, cada vez eran más pequeños y su capacidad de procesamiento más grande. Llegamos a la década de los 70, aparece el PC, el personal computer, la posibilidad de llevar los ordenadores a los hogares. Al mercado del hardware empiezan a llegar más fabricantes, el software poco a poco empieza a ser compatible entre equipos y entonces se vuelve importante.</p>
<p>De repente alguien piensa que el negocio ya no está tanto en el hardware sino en el software, así que decide cogerlo y meterlo en cajas para venderlo. Junto con unos textos amplios y de tamaño de letra muy pequeña que establecen las condiciones bajo las que, una vez comprado, puedes hacer uso del mismo. Porque lo compraste, pero no es tuyo. Solo tienes una licencia de uso.</p>
<p>Desde ese momento llega una época oscura, en la que el software ya no es libre. Pero igual que en los cómics de Astérix, hay una aldea de irreductibles galos que no están dispuestos a dejarse conquistar por el imperio. Son el movimiento del Software Libre.</p>
<p>Gracias a ellos el software resistió y no todo se volvió privativo. Pero fueron tiempos difíciles, porque el imperio intentó acabar con estos valientes galos de muchas formas.</p>
<p>Finalmente, y como bien sabemos por la historia, todos los grandes imperios acaban cayendo, o cambiando. Hoy en día, esas grandes corporaciones que querían acabar con el software libre, son las que más contribuyen a su desarrollo. <em>Cosas veredes</em>.</p>
<p>Vivimos ahora en un tiempo donde el hardware está en la nube y el software se utiliza para crear servicios, que es donde está el negocio. El software dejó de ser un fin para ser un medio y, por tanto, ya puede ser libre de nuevo. No hay mal que por bien no venga.</p>
<p>Pero si otra cosa nos enseñó la historia es que, de una forma u otra, todo se repite. Cuando un imperio cae, otro ya está empezando a crecer. Por eso ahora que el software vuelve a ser libre, no podemos bajar la guardia. En nuestras manos está lograr que esta situación perdure. No venció la filosofía, sino la conveniencia, y por lo tanto este <em>statu quo</em> es aún frágil.</p>
<p>En nuestras manos está hacer ver que este modelo funciona, que se puede hacer negocio liberando el software, que puede ser igual o incluso más seguro a pesar de que el código fuente sea público, que facilita y potencia mucho más la innovación. En definitiva, que es el modelo que nunca se debió abandonar.</p>
<p>Porque el software siempre fue libre.</p>
<p>-- <br />
<em><a href="https://mancomun.gal/es/novas/el-software-ya-es-libre/">Editorial publicada en el portal Mancomún</a>.</em></p>]]></description>
        </item>
    
  </channel>
</rss>