<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Roi Gomez</title>
  <subtitle>Claude API, Claude Code, MCP y productividad con IA</subtitle>
  <link href="https://roigomez.com/feed.xml" rel="self"/>
  <link href="https://roigomez.com/"/>
  <updated>2025-05-11</updated>
  <id>https://roigomez.com/</id>
  <author><name>Roi Gomez</name><email>roi.gomez@gmail.com</email></author>
  <language>es</language>

  
  <entry>
    <title>Cómo construí un agente de IA con Claude Code en 20 minutos</title>
    <link href="https://roigomez.com/blog/agente-ia-claude-code-20-minutos/"/>
    <id>https://roigomez.com/blog/agente-ia-claude-code-20-minutos/</id>
    <updated>2025-05-11</updated>
    <summary>Un walkthrough completo: desde cero hasta un agente funcional usando solo el CLI de Claude Code. Sin frameworks, sin magia.</summary>
    <content type="html"><![CDATA[<p>Claude Code no es solo un autocomplete glorificado. Es un runtime de agentes con acceso completo a tu filesystem, terminal y capacidad de ejecutar cualquier comando. Cuando entiendes eso, las posibilidades cambian.</p>
<h2 id="el-punto-de-partida" tabindex="-1">El punto de partida</h2>
<p>Quería un agente simple: monitorizar un directorio <code>src/</code>, detectar cambios en archivos <code>.ts</code>, ejecutar los tests afectados y reportar el resultado. Sin configurar watchers externos. Sin CI. Solo Claude haciendo el trabajo.</p>
<p>El prompt inicial fue así de directo:</p>
<pre class="language-bash"><code class="language-bash">claude <span class="token string">"Monitoriza el directorio src/. Cuando detectes cambios en archivos .ts,
ejecuta los tests relacionados con npx jest y reporta el resultado con un resumen
de qué pasó y qué falló."</span></code></pre>
<p>Claude Code tiene acceso a <code>Bash</code> y <code>Read</code> tools de serie. Sabe ejecutar comandos y leer archivos. El agente funcionó en el primer intento — no porque el prompt fuera perfecto, sino porque la tarea encajaba con las herramientas disponibles.</p>
<h2 id="a%C3%B1adiendo-persistencia-con-un-claude.md" tabindex="-1">Añadiendo persistencia con un <a href="http://CLAUDE.md">CLAUDE.md</a></h2>
<p>El problema con el agente anterior es que pierde contexto entre sesiones. La solución es un <code>CLAUDE.md</code> en la raíz del proyecto — Claude Code lo lee automáticamente al iniciar.</p>
<pre class="language-markdown"><code class="language-markdown"><span class="token title important"><span class="token punctuation">#</span> Proyecto: API de usuarios</span>

<span class="token title important"><span class="token punctuation">##</span> Stack</span>
<span class="token list punctuation">-</span> TypeScript + Node.js
<span class="token list punctuation">-</span> Jest para tests
<span class="token list punctuation">-</span> PostgreSQL con Drizzle ORM

<span class="token title important"><span class="token punctuation">##</span> Convenciones de tests</span>
<span class="token list punctuation">-</span> Los tests viven en <span class="token code-snippet code keyword">`src/__tests__/`</span>
<span class="token list punctuation">-</span> Nombre del archivo: <span class="token code-snippet code keyword">`[feature].test.ts`</span>
<span class="token list punctuation">-</span> Ejecutar solo los tests del módulo afectado: <span class="token code-snippet code keyword">`npx jest [filename]`</span>

<span class="token title important"><span class="token punctuation">##</span> Reglas del agente</span>
<span class="token list punctuation">-</span> Si un test falla, busca primero el error en los logs antes de editar código
<span class="token list punctuation">-</span> No modifiques archivos fuera de <span class="token code-snippet code keyword">`src/`</span></code></pre>
<p>Con este contexto persistente, el agente tiene las instrucciones necesarias para operar correctamente incluso en sesiones nuevas.</p>
<h2 id="el-resultado" tabindex="-1">El resultado</h2>
<p>El agente tardó unos 3 minutos en configurarse y funcionó de forma fiable durante semanas. La clave no fue la complejidad del prompt sino la claridad: tarea concreta, herramientas conocidas, restricciones explícitas.</p>
<p>Lo que me sorprendió fue la capacidad de Claude para encadenar acciones: detectar el archivo cambiado → identificar qué tests ejecutar → correr los tests → parsear el output → reportar solo los fallos con contexto. Todo eso sin código adicional de mi parte.</p>
<p>Si tienes una tarea que se puede describir en lenguaje natural y ejecutar con comandos de terminal, probablemente puedas automatizarla con Claude Code en menos tiempo del que crees.</p>
]]></content>
  </entry>
  
  <entry>
    <title>CLAUDE.md: las mejores prácticas para configurar tu agente</title>
    <link href="https://roigomez.com/blog/mejores-practicas-claude-md/"/>
    <id>https://roigomez.com/blog/mejores-practicas-claude-md/</id>
    <updated>2025-05-06</updated>
    <summary>Cómo escribir un CLAUDE.md efectivo que haga a Claude Code más útil y predecible en tu proyecto. Estructura, ejemplos y errores comunes.</summary>
    <content type="html"><![CDATA[<p><a href="http://CLAUDE.md">CLAUDE.md</a> es el archivo de configuración que Claude Code lee automáticamente al iniciar en un proyecto. Es tu forma de decirle al agente cómo debe comportarse, qué convenciones seguir y qué contexto necesita para ser útil desde el primer mensaje.</p>
<h2 id="qu%C3%A9-va-en-claude.md-y-qu%C3%A9-no" tabindex="-1">Qué va en <a href="http://CLAUDE.md">CLAUDE.md</a> y qué no</h2>
<p><a href="http://CLAUDE.md">CLAUDE.md</a> no es documentación técnica del proyecto. Es un briefing para el agente. Incluye información que Claude necesita para operar bien pero que no puede inferir leyendo el código.</p>
<p><strong>Sí incluir:</strong></p>
<ul>
<li>Stack tecnológico y versiones específicas</li>
<li>Convenciones de código del proyecto</li>
<li>Comandos de desarrollo, test y deploy</li>
<li>Restricciones y archivos que no debe tocar</li>
<li>Contexto del negocio o dominio no obvio</li>
</ul>
<p><strong>No incluir:</strong></p>
<ul>
<li>Documentación de funciones (eso va en el código)</li>
<li>Historiales de cambios</li>
<li>Documentación para usuarios humanos</li>
<li>Cosas que Claude puede inferir leyendo el código</li>
</ul>
<h2 id="estructura-recomendada" tabindex="-1">Estructura recomendada</h2>
<pre class="language-markdown"><code class="language-markdown"><span class="token title important"><span class="token punctuation">#</span> Proyecto</span>

[2-3 frases describiendo qué hace el proyecto y para quién]

<span class="token title important"><span class="token punctuation">##</span> Stack</span>

<span class="token list punctuation">-</span> Runtime: Node.js 20
<span class="token list punctuation">-</span> Framework: Next.js 14 App Router
<span class="token list punctuation">-</span> Base de datos: PostgreSQL vía Drizzle ORM
<span class="token list punctuation">-</span> Tests: Vitest + Testing Library

<span class="token title important"><span class="token punctuation">##</span> Comandos</span>

```bash
npm run dev          # servidor desarrollo en :3000
npm run test         # tests en modo watch
npm run test:ci      # tests sin watch (para CI)
npm run db:push      # sincronizar schema con BD</code></pre>
<h2 id="convenciones" tabindex="-1">Convenciones</h2>
<ul>
<li>Componentes en PascalCase, hooks con prefijo <code>use</code></li>
<li>Imports absolutos desde <code>@/</code> (alias configurado en tsconfig)</li>
<li>No usar <code>any</code> en TypeScript — usa <code>unknown</code> si necesitas</li>
<li>Tests junto al archivo que testean, no en carpeta separada</li>
</ul>
<h2 id="restricciones" tabindex="-1">Restricciones</h2>
<ul>
<li>No modificar <code>src/migrations/</code> — las migraciones se generan automáticamente</li>
<li>No instalar dependencias sin confirmar primero</li>
<li>El directorio <code>src/lib/vendor/</code> es código de terceros, no tocarlo</li>
</ul>
<pre><code>
## El error más común: instrucciones vagas

Las instrucciones vagas no ayudan. &quot;Escribe código limpio&quot; o &quot;sigue las mejores prácticas&quot; no le dice nada útil al agente. Sé específico sobre qué significa limpio en tu proyecto.

En lugar de:
</code></pre>
<p>Usa buenas prácticas de seguridad.</p>
<pre><code>
Escribe:
</code></pre>
<p>Validación de inputs: usa Zod en todos los endpoints de API.
Nunca construyas queries SQL con concatenación de strings — usa siempre parámetros preparados.
Las claves de API van en variables de entorno, nunca hardcodeadas.</p>
<pre><code>
## CLAUDE.md en subdirectorios

Claude Code lee todos los CLAUDE.md en la jerarquía de directorios. Puedes tener uno raíz con configuración global y archivos adicionales en subdirectorios para contexto específico:

</code></pre>
<p>proyecto/
├── <a href="http://CLAUDE.md">CLAUDE.md</a>              # config global
├── frontend/
│   └── <a href="http://CLAUDE.md">CLAUDE.md</a>          # convenciones específicas del frontend
└── backend/
└── <a href="http://CLAUDE.md">CLAUDE.md</a>          # convenciones del backend</p>
<pre><code>
El agente combina todos los contextos relevantes según el directorio donde esté trabajando.

## Actualiza CLAUDE.md cuando el proyecto cambia

CLAUDE.md es un documento vivo. Si cambias el stack, añades una nueva convención o descubres que el agente hace algo que no quieres consistentemente, actualiza el archivo. Es más eficiente que corregirle en cada sesión.

Un CLAUDE.md bien mantenido es la diferencia entre un agente que necesita orientación constante y uno que opera bien desde el inicio.
</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title>Prompt caching: cómo reducir costes de Claude API un 80%</title>
    <link href="https://roigomez.com/blog/prompt-caching-reducir-costes/"/>
    <id>https://roigomez.com/blog/prompt-caching-reducir-costes/</id>
    <updated>2025-05-05</updated>
    <summary>La feature más infrautilizada de la API de Anthropic. Te explico cómo funciona, cuándo usarla, y cuánto ahorré yo.</summary>
    <content type="html"><![CDATA[<p>Hay una línea de código que redució mi factura de Claude API en un 78% de un mes para otro. Se llama <code>cache_control</code>. La mayoría de la gente que usa la API de Anthropic no la está usando. Esto es un error.</p>
<h2 id="qu%C3%A9-es-el-prompt-caching" tabindex="-1">Qué es el prompt caching</h2>
<p>Cuando haces una llamada a Claude API, pagas por cada token que procesa el modelo — tanto los del prompt como los de la respuesta. Si tienes un system prompt de 2000 tokens que envías en cada request, estás pagando esos 2000 tokens cada vez.</p>
<p>El prompt caching cambia eso. Marcas partes del prompt como cacheables, y Anthropic las almacena en su infraestructura durante 5 minutos. Las peticiones posteriores que usen esa parte cacheada cuestan aproximadamente un 90% menos por ese segmento.</p>
<pre class="language-python"><code class="language-python"><span class="token keyword">import</span> anthropic

client <span class="token operator">=</span> anthropic<span class="token punctuation">.</span>Anthropic<span class="token punctuation">(</span><span class="token punctuation">)</span>

response <span class="token operator">=</span> client<span class="token punctuation">.</span>messages<span class="token punctuation">.</span>create<span class="token punctuation">(</span>
    model<span class="token operator">=</span><span class="token string">"claude-sonnet-4-6"</span><span class="token punctuation">,</span>
    max_tokens<span class="token operator">=</span><span class="token number">1024</span><span class="token punctuation">,</span>
    system<span class="token operator">=</span><span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
            <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"text"</span><span class="token punctuation">,</span>
            <span class="token string">"text"</span><span class="token punctuation">:</span> <span class="token string">"Eres un asistente experto en código TypeScript..."</span><span class="token punctuation">,</span>
            <span class="token string">"cache_control"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"ephemeral"</span><span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    messages<span class="token operator">=</span><span class="token punctuation">[</span><span class="token punctuation">{</span><span class="token string">"role"</span><span class="token punctuation">:</span> <span class="token string">"user"</span><span class="token punctuation">,</span> <span class="token string">"content"</span><span class="token punctuation">:</span> <span class="token string">"Explica los generics"</span><span class="token punctuation">}</span><span class="token punctuation">]</span>
<span class="token punctuation">)</span></code></pre>
<p>El campo <code>cache_control</code> con <code>type: &quot;ephemeral&quot;</code> le dice a Anthropic: “cachea todo lo que va antes de este punto”.</p>
<h2 id="cu%C3%A1ndo-tiene-sentido-usarlo" tabindex="-1">Cuándo tiene sentido usarlo</h2>
<p>El caching es más efectivo cuando tienes:</p>
<p><strong>System prompts largos y estables.</strong> Un system prompt que define el comportamiento del agente, incluye documentación, o proporciona contexto extenso. Si tu system prompt tiene más de 500 tokens y no cambia entre requests, cachealo.</p>
<p><strong>Documentos o código de referencia.</strong> Si estás haciendo Q&amp;A sobre un documento, análisis de código, o cualquier tarea que requiera contexto fijo, ese contexto debería estar cacheado.</p>
<p><strong>Conversaciones largas.</strong> Los mensajes anteriores de una conversación pueden cachearse para ahorrar en el re-procesamiento del historial.</p>
<p>El caching NO ayuda si tus prompts cambian constantemente o son cortos (menos de 1024 tokens para Sonnet — ese es el mínimo de tokens para que el cache tenga efecto).</p>
<h2 id="los-n%C3%BAmeros-reales" tabindex="-1">Los números reales</h2>
<p>En un proyecto donde usaba Claude para analizar código en un repo, tenía un system prompt de ~3000 tokens que incluía convenciones del proyecto. Sin cache: ~$0.18 por request (solo el system prompt). Con cache: $0.018 en el primer request, $0.003 en los siguientes.</p>
<p>Para 500 requests al día, eso pasa de $90/día a $1.50/día en el coste del system prompt. El ahorro se paga solo en horas.</p>
<h2 id="un-detalle-importante" tabindex="-1">Un detalle importante</h2>
<p>El cache dura 5 minutos. Si hay un gap de más de 5 minutos entre requests que usen el mismo cache, el siguiente request pagará el precio completo y refrescará el cache. Esto importa si tienes workloads intermitentes.</p>
<p>Para verificar si el cache está funcionando, mira la respuesta de la API — el campo <code>usage</code> incluye <code>cache_creation_input_tokens</code> y <code>cache_read_input_tokens</code>. Si <code>cache_read_input_tokens &gt; 0</code>, el cache está activo.</p>
<p>Implementarlo tarda menos de 10 minutos. No hay razón para no hacerlo.</p>
]]></content>
  </entry>
  
  <entry>
    <title>Construye tu primer servidor MCP en TypeScript</title>
    <link href="https://roigomez.com/blog/primer-servidor-mcp-typescript/"/>
    <id>https://roigomez.com/blog/primer-servidor-mcp-typescript/</id>
    <updated>2025-04-28</updated>
    <summary>Model Context Protocol explicado con código real. De zero a servidor funcional en TypeScript con las herramientas que necesitas.</summary>
    <content type="html"><![CDATA[<p>MCP (Model Context Protocol) es el mecanismo que permite a Claude Code conectarse con herramientas externas. Un servidor MCP expone funciones que Claude puede invocar, igual que un LLM invoca function calls en la OpenAI API, pero con un protocolo estandarizado que funciona con cualquier cliente MCP.</p>
<h2 id="qu%C3%A9-es-exactamente-un-servidor-mcp" tabindex="-1">Qué es exactamente un servidor MCP</h2>
<p>Un servidor MCP es un proceso que expone un conjunto de herramientas (tools) a través de un protocolo JSON-RPC. Claude Code se conecta a él en el arranque y puede invocar esas herramientas durante la sesión.</p>
<p>Los casos de uso más útiles: conectar Claude con tu base de datos, exponerle APIs internas, darle acceso a servicios que no tiene de serie (Slack, Jira, tu propio CMS).</p>
<h2 id="setup-inicial" tabindex="-1">Setup inicial</h2>
<pre class="language-bash"><code class="language-bash"><span class="token function">mkdir</span> my-mcp-server <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">cd</span> my-mcp-server
<span class="token function">npm</span> init <span class="token parameter variable">-y</span>
<span class="token function">npm</span> <span class="token function">install</span> @modelcontextprotocol/sdk
<span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">-D</span> typescript @types/node ts-node</code></pre>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"compilerOptions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"target"</span><span class="token operator">:</span> <span class="token string">"ES2022"</span><span class="token punctuation">,</span>
    <span class="token property">"module"</span><span class="token operator">:</span> <span class="token string">"CommonJS"</span><span class="token punctuation">,</span>
    <span class="token property">"outDir"</span><span class="token operator">:</span> <span class="token string">"dist"</span><span class="token punctuation">,</span>
    <span class="token property">"strict"</span><span class="token operator">:</span> <span class="token boolean">true</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="el-servidor-m%C3%ADnimo" tabindex="-1">El servidor mínimo</h2>
<pre class="language-typescript"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Server <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@modelcontextprotocol/sdk/server/index.js"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> StdioServerTransport <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@modelcontextprotocol/sdk/server/stdio.js"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> CallToolRequestSchema<span class="token punctuation">,</span> ListToolsRequestSchema <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@modelcontextprotocol/sdk/types.js"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> server <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Server</span><span class="token punctuation">(</span>
  <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">"my-tools"</span><span class="token punctuation">,</span> version<span class="token operator">:</span> <span class="token string">"1.0.0"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> capabilities<span class="token operator">:</span> <span class="token punctuation">{</span> tools<span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>

server<span class="token punctuation">.</span><span class="token function">setRequestHandler</span><span class="token punctuation">(</span>ListToolsRequestSchema<span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
  tools<span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      name<span class="token operator">:</span> <span class="token string">"get_timestamp"</span><span class="token punctuation">,</span>
      description<span class="token operator">:</span> <span class="token string">"Devuelve el timestamp actual en formato ISO"</span><span class="token punctuation">,</span>
      inputSchema<span class="token operator">:</span> <span class="token punctuation">{</span> type<span class="token operator">:</span> <span class="token string">"object"</span><span class="token punctuation">,</span> properties<span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> required<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

server<span class="token punctuation">.</span><span class="token function">setRequestHandler</span><span class="token punctuation">(</span>CallToolRequestSchema<span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>request<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>request<span class="token punctuation">.</span>params<span class="token punctuation">.</span>name <span class="token operator">===</span> <span class="token string">"get_timestamp"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span>
      content<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> type<span class="token operator">:</span> <span class="token string">"text"</span><span class="token punctuation">,</span> text<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toISOString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Tool not found: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>request<span class="token punctuation">.</span>params<span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> transport <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StdioServerTransport</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">await</span> server<span class="token punctuation">.</span><span class="token function">connect</span><span class="token punctuation">(</span>transport<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2 id="conectarlo-a-claude-code" tabindex="-1">Conectarlo a Claude Code</h2>
<p>En tu <code>.claude/settings.json</code>:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"mcpServers"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"my-tools"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"command"</span><span class="token operator">:</span> <span class="token string">"node"</span><span class="token punctuation">,</span>
      <span class="token property">"args"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"./dist/index.js"</span><span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Después de <code>npx tsc &amp;&amp; claude</code>, Claude Code tiene acceso a tu herramienta <code>get_timestamp</code>. Desde ahí, puedes añadir las herramientas que necesites: queries a base de datos, llamadas a APIs, lectura de archivos de configuración.</p>
<p>El SDK de MCP maneja todo el protocolo. Tu trabajo es solo definir las herramientas y su lógica.</p>
]]></content>
  </entry>
  
  <entry>
    <title>Extended thinking en Claude: cuándo y cómo usar el razonamiento profundo</title>
    <link href="https://roigomez.com/blog/extended-thinking-claude/"/>
    <id>https://roigomez.com/blog/extended-thinking-claude/</id>
    <updated>2025-04-22</updated>
    <summary>Extended thinking permite a Claude mostrar su proceso de razonamiento antes de responder. Guía práctica para activarlo y sacarle partido en tareas complejas.</summary>
    <content type="html"><![CDATA[<p>Extended thinking es el modo en que Claude “piensa en voz alta” antes de dar una respuesta. En lugar de saltar directamente a la contestación, Claude trabaja el problema internamente y puedes ver ese proceso. Para tareas complejas, la diferencia en calidad es significativa.</p>
<h2 id="c%C3%B3mo-funciona-internamente" tabindex="-1">Cómo funciona internamente</h2>
<p>Cuando activas extended thinking, Claude genera un bloque <code>thinking</code> antes del bloque <code>text</code> de la respuesta. Este bloque contiene el razonamiento interno: hipótesis, verificaciones, correcciones de errores. No es un adorno — es el proceso real que mejora la respuesta final.</p>
<p>El thinking consume tokens de salida pero Anthropic lo factura diferente: los tokens de thinking cuestan lo mismo que los de salida normales pero no cuentan para el límite de contexto de la misma forma.</p>
<h2 id="activar-extended-thinking-en-la-api" tabindex="-1">Activar extended thinking en la API</h2>
<pre class="language-python"><code class="language-python"><span class="token keyword">import</span> anthropic

client <span class="token operator">=</span> anthropic<span class="token punctuation">.</span>Anthropic<span class="token punctuation">(</span><span class="token punctuation">)</span>

response <span class="token operator">=</span> client<span class="token punctuation">.</span>messages<span class="token punctuation">.</span>create<span class="token punctuation">(</span>
    model<span class="token operator">=</span><span class="token string">"claude-sonnet-4-6"</span><span class="token punctuation">,</span>
    max_tokens<span class="token operator">=</span><span class="token number">16000</span><span class="token punctuation">,</span>
    thinking<span class="token operator">=</span><span class="token punctuation">{</span>
        <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"enabled"</span><span class="token punctuation">,</span>
        <span class="token string">"budget_tokens"</span><span class="token punctuation">:</span> <span class="token number">10000</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    messages<span class="token operator">=</span><span class="token punctuation">[</span><span class="token punctuation">{</span>
        <span class="token string">"role"</span><span class="token punctuation">:</span> <span class="token string">"user"</span><span class="token punctuation">,</span>
        <span class="token string">"content"</span><span class="token punctuation">:</span> <span class="token string">"Diseña una arquitectura de microservicios para un e-commerce con 50k usuarios concurrentes."</span>
    <span class="token punctuation">}</span><span class="token punctuation">]</span>
<span class="token punctuation">)</span>

<span class="token keyword">for</span> block <span class="token keyword">in</span> response<span class="token punctuation">.</span>content<span class="token punctuation">:</span>
    <span class="token keyword">if</span> block<span class="token punctuation">.</span><span class="token builtin">type</span> <span class="token operator">==</span> <span class="token string">"thinking"</span><span class="token punctuation">:</span>
        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"RAZONAMIENTO:"</span><span class="token punctuation">,</span> block<span class="token punctuation">.</span>thinking<span class="token punctuation">)</span>
    <span class="token keyword">elif</span> block<span class="token punctuation">.</span><span class="token builtin">type</span> <span class="token operator">==</span> <span class="token string">"text"</span><span class="token punctuation">:</span>
        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"RESPUESTA:"</span><span class="token punctuation">,</span> block<span class="token punctuation">.</span>text<span class="token punctuation">)</span></code></pre>
<p>El parámetro <code>budget_tokens</code> controla cuántos tokens puede usar el thinking. Más presupuesto = más razonamiento = mejor respuesta (con mayor coste y latencia).</p>
<h2 id="cu%C3%A1ndo-usar-extended-thinking" tabindex="-1">Cuándo usar extended thinking</h2>
<p><strong>Vale la pena activarlo para:</strong></p>
<ul>
<li>Problemas de arquitectura de software complejos</li>
<li>Análisis de código con múltiples dependencias</li>
<li>Razonamiento matemático o lógico</li>
<li>Decisiones con muchos trade-offs</li>
<li>Tareas donde el primer intento suele ser incorrecto</li>
</ul>
<p><strong>No hace falta para:</strong></p>
<ul>
<li>Generación de texto creativo</li>
<li>Traducciones</li>
<li>Extracción de datos estructurados</li>
<li>Preguntas con respuesta directa</li>
</ul>
<h2 id="budget-tokens-recomendado-por-caso" tabindex="-1">Budget tokens recomendado por caso</h2>
<table>
<thead>
<tr>
<th>Tarea</th>
<th>Budget sugerido</th>
</tr>
</thead>
<tbody>
<tr>
<td>Análisis de código simple</td>
<td>2.000</td>
</tr>
<tr>
<td>Diseño de arquitectura</td>
<td>8.000</td>
</tr>
<tr>
<td>Problemas matemáticos difíciles</td>
<td>10.000</td>
</tr>
<tr>
<td>Análisis de sistemas complejos</td>
<td>15.000+</td>
</tr>
</tbody>
</table>
<p>El modelo para solo cuando ha llegado a una respuesta satisfactoria, no cuando agota el budget. Si ves que el thinking se corta antes de concluir, sube el budget.</p>
<h2 id="streaming-con-extended-thinking" tabindex="-1">Streaming con extended thinking</h2>
<p>Para producción, usa streaming para no bloquear mientras Claude piensa:</p>
<pre class="language-python"><code class="language-python"><span class="token keyword">with</span> client<span class="token punctuation">.</span>messages<span class="token punctuation">.</span>stream<span class="token punctuation">(</span>
    model<span class="token operator">=</span><span class="token string">"claude-sonnet-4-6"</span><span class="token punctuation">,</span>
    max_tokens<span class="token operator">=</span><span class="token number">16000</span><span class="token punctuation">,</span>
    thinking<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"enabled"</span><span class="token punctuation">,</span> <span class="token string">"budget_tokens"</span><span class="token punctuation">:</span> <span class="token number">8000</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
    messages<span class="token operator">=</span><span class="token punctuation">[</span><span class="token punctuation">{</span><span class="token string">"role"</span><span class="token punctuation">:</span> <span class="token string">"user"</span><span class="token punctuation">,</span> <span class="token string">"content"</span><span class="token punctuation">:</span> <span class="token string">"..."</span><span class="token punctuation">}</span><span class="token punctuation">]</span>
<span class="token punctuation">)</span> <span class="token keyword">as</span> stream<span class="token punctuation">:</span>
    <span class="token keyword">for</span> event <span class="token keyword">in</span> stream<span class="token punctuation">:</span>
        <span class="token keyword">if</span> <span class="token builtin">hasattr</span><span class="token punctuation">(</span>event<span class="token punctuation">,</span> <span class="token string">'type'</span><span class="token punctuation">)</span> <span class="token keyword">and</span> event<span class="token punctuation">.</span><span class="token builtin">type</span> <span class="token operator">==</span> <span class="token string">'content_block_delta'</span><span class="token punctuation">:</span>
            <span class="token comment"># Procesar thinking o text según block_index</span>
            <span class="token keyword">pass</span></code></pre>
<p>Extended thinking es una de las capacidades más infrautilizadas de Claude. Para los problemas donde la primera respuesta no basta, es el cambio que más impacto tiene en la calidad.</p>
]]></content>
  </entry>
  
  <entry>
    <title>Orquestación de agentes: patrones que escalan</title>
    <link href="https://roigomez.com/blog/orquestacion-agentes-patrones/"/>
    <id>https://roigomez.com/blog/orquestacion-agentes-patrones/</id>
    <updated>2025-04-20</updated>
    <summary>Cómo diseñar sistemas multi-agente con Claude que no se descontrolan. Patrones reales de coordinación y handoffs.</summary>
    <content type="html"><![CDATA[<p>Un agente que funciona solo es fácil. Un sistema donde varios agentes coordinan trabajo es donde la mayoría de la gente se pierde. Hay tres patrones que resuelven el 90% de los casos.</p>
<h2 id="el-problema-de-escalar-agentes" tabindex="-1">El problema de escalar agentes</h2>
<p>Un solo agente con acceso a todas las herramientas y todo el contexto colapsa rápido. El contexto window se llena, las instrucciones se mezclan, y los errores se propagan sin control. La solución no es prompts más grandes, sino sistemas más pequeños bien coordinados.</p>
<h2 id="patr%C3%B3n-1%3A-orchestrator-%2B-workers" tabindex="-1">Patrón 1: Orchestrator + Workers</h2>
<p>El orchestrator recibe la tarea de alto nivel, la descompone y delega a workers especializados. Cada worker tiene un scope limitado y herramientas específicas.</p>
<pre><code>Orchestrator: &quot;Analiza este PR y escribe el reporte&quot;
  → Worker A: revisa cambios de código (tools: Read, Bash/git)
  → Worker B: verifica tests (tools: Bash/npm test)
  → Worker C: redacta reporte (tools: Write)
</code></pre>
<p>El orchestrator recibe los outputs y los ensambla. Ningún worker necesita saber qué hacen los demás.</p>
<h2 id="patr%C3%B3n-2%3A-pipeline-secuencial" tabindex="-1">Patrón 2: Pipeline secuencial</h2>
<p>Para procesos donde cada paso depende del anterior. Los datos fluyen de agente en agente, cada uno transformando el output del anterior.</p>
<p>Este patrón es simple pero poderoso para procesos ETL, pipelines de contenido, o cualquier workflow donde el orden importa. El riesgo es que un error en un paso bloquea todo el pipeline — hay que diseñar los handoffs con validación explícita.</p>
<h2 id="patr%C3%B3n-3%3A-parallel-fan-out" tabindex="-1">Patrón 3: Parallel fan-out</h2>
<p>Cuando tienes tareas independientes que se pueden ejecutar a la vez. El orchestrator las lanza en paralelo y espera todos los resultados antes de continuar.</p>
<p>La implementación con la API de Claude es directa: múltiples llamadas asíncronas con <code>asyncio.gather()</code> en Python o <code>Promise.all()</code> en JS. El contexto de cada agente es independiente, así que no hay riesgo de interferencia.</p>
<h2 id="la-regla-pr%C3%A1ctica" tabindex="-1">La regla práctica</h2>
<p>Empieza con un agente. Cuando notes que el contexto window se llena o que el agente está mezclando preocupaciones distintas, es el momento de separar. Cada split debería tener una razón concreta — no abstracciones prematuras.</p>
]]></content>
  </entry>
  
  <entry>
    <title>Las 5 técnicas de prompting que realmente importan</title>
    <link href="https://roigomez.com/blog/5-tecnicas-prompting-importan/"/>
    <id>https://roigomez.com/blog/5-tecnicas-prompting-importan/</id>
    <updated>2025-04-14</updated>
    <summary>Sin teoría vacía. Estas son las técnicas que cambio los resultados en proyectos reales con Claude.</summary>
    <content type="html"><![CDATA[<p>Hay decenas de “técnicas de prompting” flotando por internet. La mayoría son ruido. Estas cinco son las que uso en producción y que tienen impacto medible.</p>
<h2 id="1.-rol-%2B-contexto-espec%C3%ADfico%2C-no-gen%C3%A9rico" tabindex="-1">1. Rol + contexto específico, no genérico</h2>
<p>“Eres un experto en X” es demasiado vago. El rol útil incluye contexto específico del dominio y las restricciones que aplican.</p>
<p>En lugar de: <code>&quot;Eres un experto en TypeScript&quot;</code>, prueba: <code>&quot;Eres un senior engineer revisando código TypeScript para producción. El codebase usa Node.js 20, strict mode, y Drizzle ORM. Priorizas la seguridad sobre la brevedad.&quot;</code> La diferencia en calidad de output es notable.</p>
<h2 id="2.-output-format-expl%C3%ADcito" tabindex="-1">2. Output format explícito</h2>
<p>Si no dices cómo quieres el output, Claude elegirá. A veces elige bien; a menudo no. Especifica: tipo (lista, JSON, código, markdown), longitud aproximada, y qué incluir/excluir.</p>
<p><code>&quot;Responde con un JSON array. Cada objeto tiene: { error: string, severity: 'low'|'medium'|'high', fix: string }. Sin explicaciones adicionales.&quot;</code></p>
<h2 id="3.-chain-of-thought-para-tareas-complejas" tabindex="-1">3. Chain-of-thought para tareas complejas</h2>
<p>Para razonamiento complejo, pedir el proceso explícitamente mejora la calidad del resultado. <code>&quot;Piensa paso a paso antes de responder&quot;</code> activa un modo de razonamiento más cuidadoso. Es especialmente útil en debugging y análisis de código donde el primer impulso suele ser incorrecto.</p>
<h2 id="4.-ejemplos-few-shot-para-formato-exacto" tabindex="-1">4. Ejemplos few-shot para formato exacto</h2>
<p>Cuando el formato importa (y casi siempre importa), un ejemplo vale más que mil palabras de descripción. Muestra input → output esperado antes de dar la tarea real. Con dos o tres ejemplos, Claude replica el patrón con alta fidelidad.</p>
<h2 id="5.-restricciones-negativas-expl%C3%ADcitas" tabindex="-1">5. Restricciones negativas explícitas</h2>
<p>“No hagas X” es tan importante como “haz Y”. Las restricciones negativas evitan comportamientos por defecto que no quieres: <code>&quot;No expliques el código que generes&quot;</code>, <code>&quot;No uses comentarios&quot;</code>, <code>&quot;No añadas error handling innecesario&quot;</code>.</p>
<p>Sin restricciones explícitas, Claude tiende a ser “helpful” añadiendo cosas que no pediste. En un pipeline automatizado eso es ruido, no valor.</p>
]]></content>
  </entry>
  
  <entry>
    <title>Hooks en Claude Code: automatiza guardarraíles con shell commands</title>
    <link href="https://roigomez.com/blog/hooks-claude-code/"/>
    <id>https://roigomez.com/blog/hooks-claude-code/</id>
    <updated>2025-04-08</updated>
    <summary>Cómo usar hooks en Claude Code para ejecutar comandos antes o después de cada acción del agente. Control total sobre lo que hace Claude en tu proyecto.</summary>
    <content type="html"><![CDATA[<p>Los hooks son uno de los features menos conocidos de Claude Code y uno de los más poderosos. Te permiten ejecutar comandos de shell automáticamente antes o después de que Claude use cualquier herramienta. Guardarraíles sin fricción.</p>
<h2 id="qu%C3%A9-son-los-hooks-y-para-qu%C3%A9-sirven" tabindex="-1">Qué son los hooks y para qué sirven</h2>
<p>Un hook es un comando shell que Claude Code ejecuta en respuesta a eventos del agente. Eventos disponibles:</p>
<ul>
<li><code>PreToolUse</code> — antes de que Claude use una herramienta</li>
<li><code>PostToolUse</code> — después de que Claude use una herramienta</li>
<li><code>Notification</code> — cuando Claude quiere notificarte algo</li>
<li><code>Stop</code> — cuando Claude termina una tarea</li>
</ul>
<p>Casos de uso reales: ejecutar el linter después de cada edición, hacer un snapshot de git antes de cambios destructivos, bloquear ediciones en archivos protegidos, enviar notificaciones a Slack cuando el agente termina.</p>
<h2 id="configurar-hooks-en-settings.json" tabindex="-1">Configurar hooks en settings.json</h2>
<p>Los hooks se configuran en <code>~/.claude/settings.json</code> (global) o <code>.claude/settings.json</code> (proyecto):</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"hooks"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"PostToolUse"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span>
        <span class="token property">"matcher"</span><span class="token operator">:</span> <span class="token string">"Write|Edit"</span><span class="token punctuation">,</span>
        <span class="token property">"hooks"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
          <span class="token punctuation">{</span>
            <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"command"</span><span class="token punctuation">,</span>
            <span class="token property">"command"</span><span class="token operator">:</span> <span class="token string">"cd $CLAUDE_PROJECT_DIR &amp;&amp; npx eslint --fix $CLAUDE_FILE_PATHS 2>/dev/null || true"</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">]</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">]</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>El <code>matcher</code> es una regex que coincide con el nombre de la herramienta. <code>Write|Edit</code> captura ambas herramientas de edición.</p>
<h2 id="variables-de-entorno-disponibles" tabindex="-1">Variables de entorno disponibles</h2>
<p>Claude Code expone variables útiles en cada hook:</p>
<ul>
<li><code>$CLAUDE_PROJECT_DIR</code> — directorio raíz del proyecto</li>
<li><code>$CLAUDE_FILE_PATHS</code> — archivos afectados por la herramienta (separados por espacio)</li>
<li><code>$CLAUDE_TOOL_NAME</code> — nombre de la herramienta que se ejecutó</li>
<li><code>$CLAUDE_SESSION_ID</code> — ID de la sesión actual</li>
</ul>
<h2 id="bloquear-archivos-protegidos" tabindex="-1">Bloquear archivos protegidos</h2>
<p>Puedes usar el exit code para bloquear acciones. Si el hook retorna exit code 2, Claude Code cancela la acción y muestra el stderr como mensaje de error:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"hooks"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"PreToolUse"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span>
        <span class="token property">"matcher"</span><span class="token operator">:</span> <span class="token string">"Write|Edit"</span><span class="token punctuation">,</span>
        <span class="token property">"hooks"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
          <span class="token punctuation">{</span>
            <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"command"</span><span class="token punctuation">,</span>
            <span class="token property">"command"</span><span class="token operator">:</span> <span class="token string">"if echo \"$CLAUDE_FILE_PATHS\" | grep -q 'production.env\\|\\.secrets'; then echo 'Archivo protegido: edición bloqueada' >&amp;2; exit 2; fi"</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">]</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">]</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="hook-para-auto-commit-tras-cada-tarea" tabindex="-1">Hook para auto-commit tras cada tarea</h2>
<p>Un pattern útil: hacer commit automático cuando Claude termina, para tener un historial granular de cada cambio del agente:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"hooks"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"Stop"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span>
        <span class="token property">"matcher"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
        <span class="token property">"hooks"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
          <span class="token punctuation">{</span>
            <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"command"</span><span class="token punctuation">,</span>
            <span class="token property">"command"</span><span class="token operator">:</span> <span class="token string">"cd $CLAUDE_PROJECT_DIR &amp;&amp; git diff --quiet || git add -A &amp;&amp; git commit -m 'chore: claude agent checkpoint'"</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">]</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">]</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Los hooks convierten a Claude Code en un agente auditable y controlado. Con unos pocos comandos shell defines exactamente qué puede y no puede hacer en tu proyecto.</p>
]]></content>
  </entry>
  
  <entry>
    <title>Mi workflow con Claude Code después de 3 meses</title>
    <link href="https://roigomez.com/blog/workflow-claude-code-3-meses/"/>
    <id>https://roigomez.com/blog/workflow-claude-code-3-meses/</id>
    <updated>2025-04-08</updated>
    <summary>Lo que cambié, lo que mantuve, y lo que aprendí usando Claude Code como herramienta principal de desarrollo.</summary>
    <content type="html"><![CDATA[<p>Llevo tres meses usando Claude Code como herramienta principal. No como asistente ocasional — como parte del flujo de trabajo diario. Esto es lo que aprendí.</p>
<h2 id="lo-que-cambi%C3%B3-desde-el-primer-mes" tabindex="-1">Lo que cambió desde el primer mes</h2>
<p>El primer mes lo usé como un autocomplete potente. Pedía código, lo revisaba, lo ajustaba. Productividad razonable pero no espectacular.</p>
<p>El cambio llegó cuando empecé a trabajar con tareas, no con preguntas. En lugar de “escribe una función que haga X”, empecé a describir el objetivo completo: “implementa el endpoint <code>/users/:id</code> con validación de permisos, manejo de errores estándar, y tests”. La diferencia es sustancial — Claude puede mantener el contexto de una tarea completa mejor que de preguntas fragmentadas.</p>
<h2 id="lo-que-mantuve%3A-el-claude.md-como-memoria" tabindex="-1">Lo que mantuve: el <a href="http://CLAUDE.md">CLAUDE.md</a> como memoria</h2>
<p>El archivo <code>CLAUDE.md</code> en la raíz del proyecto es lo más valioso que adopté. Incluye:</p>
<ul>
<li>Stack exacto del proyecto (versiones, librerías)</li>
<li>Convenciones de código (naming, estructura de carpetas)</li>
<li>Reglas específicas del dominio (“no usar <code>any</code> en TypeScript”, “los errores van en formato <code>{ code, message }</code>”)</li>
<li>Contexto de negocio que Claude no puede inferir del código</li>
</ul>
<p>Sin esto, cada sesión empezaba desde cero. Con esto, Claude tiene el contexto necesario para tomar decisiones correctas sin preguntarme cada vez.</p>
<h2 id="lo-que-descubr%C3%AD%3A-los-hooks-son-poderosos" tabindex="-1">Lo que descubrí: los hooks son poderosos</h2>
<p>Los hooks de Claude Code (pre-tool, post-tool) permiten automatizar acciones alrededor de las herramientas. Lo uso para: loggear qué archivos modifica, ejecutar el linter automáticamente después de cada Write, y alertar si intenta modificar archivos fuera del scope permitido.</p>
<p>Esto convierte Claude Code de “agente que ejecuta lo que le pides” a “agente con guardarraíles automáticos”.</p>
<h2 id="el-l%C3%ADmite-real%3A-el-contexto-window" tabindex="-1">El límite real: el contexto window</h2>
<p>Después de tres meses, el límite principal no es la calidad de las respuestas — es el contexto window. En proyectos grandes, el contexto se llena y la calidad baja. La solución no es forzar más contexto, es trabajar en sesiones más cortas con tareas más específicas. Una sesión = una tarea bien definida.</p>
]]></content>
  </entry>
  
  <entry>
    <title>Tool use en Claude API: guía práctica con ejemplos reales</title>
    <link href="https://roigomez.com/blog/tool-use-claude-api-guia/"/>
    <id>https://roigomez.com/blog/tool-use-claude-api-guia/</id>
    <updated>2025-03-25</updated>
    <summary>Cómo implementar function calling en Claude API. Desde la definición de herramientas hasta el manejo de respuestas en producción.</summary>
    <content type="html"><![CDATA[<p>Tool use (function calling) es la capacidad que convierte a Claude de un generador de texto en un agente que puede interactuar con el mundo real. Con herramientas, Claude puede consultar APIs, leer bases de datos, ejecutar cálculos o llamar a cualquier función que le definas.</p>
<h2 id="c%C3%B3mo-funciona-el-ciclo-tool-use" tabindex="-1">Cómo funciona el ciclo tool use</h2>
<p>El flujo es un ciclo de 3 pasos:</p>
<ol>
<li>Envías a Claude una lista de herramientas disponibles con su descripción y schema</li>
<li>Claude decide si necesita usar una herramienta y devuelve un <code>tool_use</code> block con los parámetros</li>
<li>Ejecutas la herramienta, devuelves el resultado y Claude genera la respuesta final</li>
</ol>
<pre class="language-python"><code class="language-python"><span class="token keyword">import</span> anthropic

client <span class="token operator">=</span> anthropic<span class="token punctuation">.</span>Anthropic<span class="token punctuation">(</span><span class="token punctuation">)</span>

tools <span class="token operator">=</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
        <span class="token string">"name"</span><span class="token punctuation">:</span> <span class="token string">"get_weather"</span><span class="token punctuation">,</span>
        <span class="token string">"description"</span><span class="token punctuation">:</span> <span class="token string">"Obtiene el tiempo actual para una ciudad"</span><span class="token punctuation">,</span>
        <span class="token string">"input_schema"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
            <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"object"</span><span class="token punctuation">,</span>
            <span class="token string">"properties"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
                <span class="token string">"city"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"string"</span><span class="token punctuation">,</span> <span class="token string">"description"</span><span class="token punctuation">:</span> <span class="token string">"Nombre de la ciudad"</span><span class="token punctuation">}</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token string">"required"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"city"</span><span class="token punctuation">]</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">]</span>

response <span class="token operator">=</span> client<span class="token punctuation">.</span>messages<span class="token punctuation">.</span>create<span class="token punctuation">(</span>
    model<span class="token operator">=</span><span class="token string">"claude-sonnet-4-6"</span><span class="token punctuation">,</span>
    max_tokens<span class="token operator">=</span><span class="token number">1024</span><span class="token punctuation">,</span>
    tools<span class="token operator">=</span>tools<span class="token punctuation">,</span>
    messages<span class="token operator">=</span><span class="token punctuation">[</span><span class="token punctuation">{</span><span class="token string">"role"</span><span class="token punctuation">:</span> <span class="token string">"user"</span><span class="token punctuation">,</span> <span class="token string">"content"</span><span class="token punctuation">:</span> <span class="token string">"¿Qué tiempo hace en Madrid?"</span><span class="token punctuation">}</span><span class="token punctuation">]</span>
<span class="token punctuation">)</span></code></pre>
<h2 id="procesando-la-respuesta-de-tool-use" tabindex="-1">Procesando la respuesta de tool use</h2>
<p>Claude puede devolver <code>tool_use</code> en el <code>stop_reason</code>. Tienes que manejar este caso:</p>
<pre class="language-python"><code class="language-python"><span class="token keyword">if</span> response<span class="token punctuation">.</span>stop_reason <span class="token operator">==</span> <span class="token string">"tool_use"</span><span class="token punctuation">:</span>
    tool_block <span class="token operator">=</span> <span class="token builtin">next</span><span class="token punctuation">(</span>b <span class="token keyword">for</span> b <span class="token keyword">in</span> response<span class="token punctuation">.</span>content <span class="token keyword">if</span> b<span class="token punctuation">.</span><span class="token builtin">type</span> <span class="token operator">==</span> <span class="token string">"tool_use"</span><span class="token punctuation">)</span>
    tool_name <span class="token operator">=</span> tool_block<span class="token punctuation">.</span>name
    tool_input <span class="token operator">=</span> tool_block<span class="token punctuation">.</span><span class="token builtin">input</span>

    <span class="token comment"># Ejecuta tu función real aquí</span>
    result <span class="token operator">=</span> call_your_function<span class="token punctuation">(</span>tool_name<span class="token punctuation">,</span> tool_input<span class="token punctuation">)</span>

    <span class="token comment"># Devuelve el resultado a Claude</span>
    final_response <span class="token operator">=</span> client<span class="token punctuation">.</span>messages<span class="token punctuation">.</span>create<span class="token punctuation">(</span>
        model<span class="token operator">=</span><span class="token string">"claude-sonnet-4-6"</span><span class="token punctuation">,</span>
        max_tokens<span class="token operator">=</span><span class="token number">1024</span><span class="token punctuation">,</span>
        tools<span class="token operator">=</span>tools<span class="token punctuation">,</span>
        messages<span class="token operator">=</span><span class="token punctuation">[</span>
            <span class="token punctuation">{</span><span class="token string">"role"</span><span class="token punctuation">:</span> <span class="token string">"user"</span><span class="token punctuation">,</span> <span class="token string">"content"</span><span class="token punctuation">:</span> <span class="token string">"¿Qué tiempo hace en Madrid?"</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">{</span><span class="token string">"role"</span><span class="token punctuation">:</span> <span class="token string">"assistant"</span><span class="token punctuation">,</span> <span class="token string">"content"</span><span class="token punctuation">:</span> response<span class="token punctuation">.</span>content<span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">{</span><span class="token string">"role"</span><span class="token punctuation">:</span> <span class="token string">"user"</span><span class="token punctuation">,</span> <span class="token string">"content"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>
                <span class="token punctuation">{</span><span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"tool_result"</span><span class="token punctuation">,</span> <span class="token string">"tool_use_id"</span><span class="token punctuation">:</span> tool_block<span class="token punctuation">.</span><span class="token builtin">id</span><span class="token punctuation">,</span> <span class="token string">"content"</span><span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">}</span>
            <span class="token punctuation">]</span><span class="token punctuation">}</span>
        <span class="token punctuation">]</span>
    <span class="token punctuation">)</span></code></pre>
<h2 id="m%C3%BAltiples-herramientas-y-tool-choice" tabindex="-1">Múltiples herramientas y tool choice</h2>
<p>Puedes definir varias herramientas y Claude elegirá la apropiada. Con <code>tool_choice</code> puedes forzar el uso de una herramienta específica o desactivar la selección automática.</p>
<pre class="language-python"><code class="language-python"><span class="token comment"># Forzar una herramienta específica</span>
response <span class="token operator">=</span> client<span class="token punctuation">.</span>messages<span class="token punctuation">.</span>create<span class="token punctuation">(</span>
    model<span class="token operator">=</span><span class="token string">"claude-sonnet-4-6"</span><span class="token punctuation">,</span>
    max_tokens<span class="token operator">=</span><span class="token number">1024</span><span class="token punctuation">,</span>
    tools<span class="token operator">=</span>tools<span class="token punctuation">,</span>
    tool_choice<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"tool"</span><span class="token punctuation">,</span> <span class="token string">"name"</span><span class="token punctuation">:</span> <span class="token string">"get_weather"</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
    messages<span class="token operator">=</span><span class="token punctuation">[</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">]</span>
<span class="token punctuation">)</span></code></pre>
<h2 id="cu%C3%A1ndo-usar-tool-use-vs-prompt-simple" tabindex="-1">Cuándo usar tool use vs prompt simple</h2>
<p>Tool use añade latencia y complejidad. Úsalo cuando necesites datos externos en tiempo real, ejecutar acciones con efectos secundarios, o cuando el resultado depende de información que no está en el contexto. Para razonamiento puro o generación de texto, un prompt directo es más rápido y barato.</p>
]]></content>
  </entry>
  
</feed>
