MIKEB.MD
EN
AI

Qué significa usar una tool de verdad

Mike Bermeo ⏱ 7 min de lectura Read in English

En el post anterior dejamos una pregunta muy específica abierta: qué pasa exactamente cuando el agente decide usar una herramienta. Ya sabemos que hay un loop. Ya sabemos que en cada vuelta el sistema elige una acción. Pero no abrimos la acción en sí.

Eso es lo que toca ahora.

Y la respuesta tiene una parte contraintuitiva que vale la pena decir desde el principio:

cuando Claude Code “usa una tool”, el modelo no ejecuta nada.

Lo pide.

Esa distinción parece pequeña. No lo es.

El modelo no ejecuta. Emite una solicitud.

Cuando el modelo decide que necesita leer un archivo, no abre el archivo.

Lo que hace es producir una salida estructurada que dice, en esencia: quiero usar esta herramienta, con estos parámetros. Así se ve una solicitud real de Claude Code:

1. El modelo emite — tool_use
{
"type": "tool_use",
"id": "toolu_01Hy3k9mX2pL8vRqN4wTzA",
"name": "read_file",
"input": {
"path": "src/auth/handleAuth.ts"
}
}

Eso es todo lo que sale del modelo. No una acción. Una intención estructurada con un id para rastrear la respuesta.

El runtime recibe eso, abre el archivo, y devuelve el resultado vinculado al mismo id:

2. El runtime responde — tool_result
{
"type": "tool_result",
"tool_use_id": "toolu_01Hy3k9mX2pL8vRqN4wTzA",
"content": "export async function handleAuth(\n userId: string,\n token: string\n): Promise<Session> {\n const user = await db.users.findById(userId);\n if (!user) throw new AuthError('User not found');\n return createSession(user, token);\n}"
}

El tool_use_id es el hilo que conecta la solicitud con su resultado. El modelo no tiene que saber cómo se ejecutó — solo recibe el contenido y continúa.

Lo que viene después ocurre fuera del modelo. Hay otro componente del sistema — el runtime — que recibe esa solicitud y se encarga de convertirla en algo real.

flowchart LR
  M(["🧠 Modelo"]):::model --> E(["📤 Emite solicitud"]):::model
  E --> RV(["✔ Runtime valida"]):::runtime
  RV --> RX(["⚙ Runtime ejecuta"]):::runtime
  RX --> RR(["📥 Devuelve resultado"]):::runtime
  RR --> MI(["🧠 Modelo interpreta"]):::model
  MI --> O(["💬 Decide qué sigue"]):::output

  classDef model   fill:#312e81,stroke:#818cf8,color:#e2e2f0,stroke-width:2px
  classDef runtime fill:#164e63,stroke:#22d3ee,color:#e2e2f0
  classDef output  fill:#14532d,stroke:#4ade80,color:#e2e2f0

  linkStyle 1,2,3 stroke:#22d3ee,stroke-width:2px
  linkStyle 4,5 stroke:#818cf8,stroke-width:2px

El modelo aparece dos veces: primero emitiendo la solicitud, después interpretando el resultado. En el medio, el runtime hace el trabajo físico. Esa estructura no es un detalle de implementación. Es la arquitectura central del sistema.

La capa que traduce

Entre el lenguaje del modelo y la acción real existe una brecha. El modelo habla en intenciones. El sistema operativo habla en llamadas de sistema. El runtime es lo que cruza esa brecha en ambas direcciones.

Hacia afuera: toma la intención estructurada del modelo, la valida, la convierte en una operación real y la ejecuta.

Hacia adentro: toma el resultado crudo de esa operación y lo convierte en algo que el modelo pueda leer y usar en la siguiente vuelta.

flowchart LR
  MI(["🧠 Intención"]):::model
  RV(["✔ Valida"]):::runtime
  RE(["⚙ Ejecuta"]):::runtime
  W(["🌍 Filesystem / Shell"]):::world
  RF(["📋 Formatea"]):::runtime
  MR(["🧠 Interpreta"]):::model

  MI --> RV --> RE --> W --> RF --> MR

  classDef model   fill:#312e81,stroke:#818cf8,color:#e2e2f0,stroke-width:2px
  classDef runtime fill:#164e63,stroke:#22d3ee,color:#e2e2f0
  classDef world   fill:#1c1917,stroke:#78716c,color:#a8a29e

  linkStyle 0,1 stroke:#22d3ee,stroke-width:2px
  linkStyle 2 stroke:#78716c,stroke-width:2px
  linkStyle 3,4 stroke:#818cf8,stroke-width:2px

La palabra clave aquí es traducción.

El modelo produce una intención. El runtime la traduce en una acción. El resultado de esa acción lo traduce de vuelta a algo que el modelo pueda leer. Ese ciclo de traducción es lo que convierte una tool de una idea dentro de un prompt en una capacidad real del sistema.

Chat vs. agente: dónde termina el lenguaje

Esta separación es también la diferencia más profunda entre un chat y un agente.

Un chat clásico vive enteramente dentro del lenguaje. Puede describir lo que haría si leyera un archivo. Puede imaginar el resultado de un comando. Puede producir texto que suena como si hubiera verificado algo.

Pero no verificó nada.

En un agente con tools reales, el sistema puede cruzar esa frontera. Ya no se queda imaginando. Puede decir: no voy a adivinar; voy a revisar.

ChatAgente
Qué produceTexto sobre el mundoSolicitudes al runtime
Fuente del resultadoEntrenamiento + inferenciaEjecución real
Puede equivocarse sobre hechosSí, sin saberloSolo sobre interpretación
Toca archivos, shell, APIsNoSí, a través del runtime
Verifica o imaginaImaginaVerifica

El modelo todavía decide todo lo que importa

Hasta aquí podría parecer que el modelo es pasivo — que solo emite JSON y el runtime hace el trabajo real.

No es así.

El runtime ejecuta. Pero el modelo decide:

  • qué tool usar
  • con qué parámetros llamarla
  • qué significa el resultado que vuelve
  • si eso es suficiente para responder o si necesita otra vuelta
flowchart LR
  D1{{"¿Qué tool?"}}:::decision --> D2{{"¿Qué parámetros?"}}:::decision
  D2 --> RT(["⚙ Runtime"]):::runtime
  RT --> D3{{"¿Qué significa?"}}:::decision
  D3 --> D4{{"¿Respondo o sigo?"}}:::decision
  D4 -->|"Sigo"| D1
  D4 -->|"Respondo"| R(["💬 Respuesta"]):::output

  classDef decision fill:#1c1917,stroke:#f59e0b,color:#fbbf24
  classDef runtime  fill:#164e63,stroke:#22d3ee,color:#e2e2f0
  classDef output   fill:#14532d,stroke:#4ade80,color:#e2e2f0

  linkStyle 4 stroke:#818cf8,stroke-width:2px,stroke-dasharray:5
  linkStyle 5 stroke:#4ade80,stroke-width:2px

El runtime es una caja dentro de ese ciclo. Ejecuta lo que el modelo le pide. Pero las decisiones antes y después de esa caja pertenecen al modelo.

La relación no es modelo contra runtime. Es modelo para decidir, runtime para ejecutar.

Por qué esta separación importa

La división entre modelo y runtime podría parecer un detalle de ingeniería. Pero tiene consecuencias directas en tres cosas importantes.

Seguridad. El modelo puede solicitar leer un archivo fuera del directorio permitido. El runtime lo rechaza. Esa capa de permisos no existe dentro del modelo — vive en el runtime. El modelo no puede darse acceso a sí mismo.

Confiabilidad. El runtime puede validar el formato de los parámetros antes de ejecutar, reintentar si algo falla y limitar el alcance de una operación. El modelo no tiene que manejar esos casos — el runtime los absorbe.

Extensibilidad. Agregar una nueva tool al sistema no requiere re-entrenar el modelo. Basta con registrarla en el runtime y describirla correctamente. El modelo aprende a usarla a partir de la descripción, no de un nuevo ciclo de entrenamiento.

Lo que viene después

Ahora ya tenemos las tres piezas base de la arquitectura.

El primer post explicó que Claude Code no es un chat — es un sistema que trabaja. El segundo abrió el loop. Este abrió la acción dentro de ese loop.

Lo que todavía no miramos de cerca son las tools más concretas que tiene el sistema: el filesystem y la shell.

Esas dos tools definen la mayor parte de lo que un agente puede hacer dentro de un proyecto real. No como conceptos — como operaciones físicas sobre tu máquina.

Eso es lo que toca abrir después.