Gymnasia: cómo declarar tools fiables para OpenAI, Anthropic y Google

Gymnasia: cómo declarar tools fiables para OpenAI, Anthropic y Google

Una tool es un contratolink image

Cuando un modelo decide usar una herramienta no ve la función TypeScript que acabará ejecutándose. Solo recibe tres piezas: name, description e inputSchema. Ese bloque determina si escoge la herramienta correcta y si construye argumentos que la aplicación puede aceptar.

name

Es el identificador estable que devuelve el modelo y que el ejecutor usa para localizar el handler.

description

Explica cuándo usar la tool, qué garantiza y qué pasos previos necesita. Es parte del prompt del agente.

inputSchema

Es el JSON Schema que delimita campos, tipos y argumentos obligatorios antes de ejecutar código local.

Gymnasia guarda las 13 definiciones en apps/mobile/agent/toolDefinitions.ts. Memoria personal, medidas, dieta, ejercicios, rutinas y peticiones de mejoras parten de ese único array. No existe una copia independiente por proveedor.

Esta es una definición real del catálogo:

{
  name: "read_measurement",
  description:
    "Lee las medidas corporales del usuario para una fecha específica. " +
    "Devuelve el registro de medidas de ese día si existe. " +
    "Usa esta herramienta cuando el usuario pregunte por sus medidas de un día concreto.",
  inputSchema: {
    type: "object",
    properties: {
      date: stringProperty("Fecha en formato YYYY-MM-DD")
    },
    required: ["date"]
  }
}

Los nombres actuales son save_personal_data, list_personal_data_keys, read_field_description, read_field_value, read_measurement, write_measurement, read_meal_foods, search_foods, add_meal_food, search_exercises, read_routines, create_routine y create_feature_issue.

La descripción también es promptlink image

Una descripción pobre como "Lee medidas" documenta la función para una persona, pero deja al modelo sin criterio: no dice qué fecha usar, qué devuelve ni en qué momento conviene llamarla.

La versión real explica intención, resultado y contexto. En herramientas con dependencias también impone el orden: add_meal_food indica que antes debe ejecutarse search_foods, y create_routine exige buscar los nombres exactos mediante search_exercises. Esa información mueve la precisión de elección más que cualquier comentario interno, porque es lo que el modelo sí puede leer.

Tres proveedores, una definiciónlink image

OpenAI, Anthropic y Google expresan el mismo contrato con envoltorios distintos. CHAT_TOOLS proyecta el catálogo en el momento de construir la petición:

OpenAI

type: "function" y el esquema bajo parameters.

Anthropic

Nombre y descripción directos, con el esquema bajo input_schema.

Google

Declaraciones dentro de functionDeclarations y esquema bajo parameters.

const CHAT_TOOLS = {
  openai: definitions.map(tool => ({
    type: "function", name: tool.name,
    description: tool.description, parameters: tool.inputSchema
  })),
  anthropic: definitions.map(tool => ({
    name: tool.name, description: tool.description,
    input_schema: tool.inputSchema
  })),
  google: [{ functionDeclarations: definitions.map(tool => ({
    name: tool.name, description: tool.description,
    parameters: tool.inputSchema
  })) }]
};

La sintaxis cambia; el nombre, la descripción y el esquema no. Añadir o corregir una herramienta en el catálogo actualiza los tres formatos.

Definición y ejecución locallink image

Declarar una tool no la implementa. apps/mobile/agent/toolExecutor.ts mantiene el mapa AGENT_TOOL_HANDLERS: cada nombre del catálogo debe tener exactamente un handler y ningún handler puede quedar huérfano.

Los handlers leen o modifican el estado local, AsyncStorage y los repositorios JSON empaquetados con la app. Después devuelven texto al bucle agentic para que el modelo continúe. No hay base de datos ni backend de Gymnasia entre la tool y los datos del usuario; la aplicación móvil conserva el control de la ejecución.

Tests contra la divergencialink image

El contrato se verifica en varias capas. Los tests exigen nombres únicos y válidos, descripciones significativas, esquemas de tipo objeto y campos required declarados en properties. Ajv compila los 13 JSON Schemas para detectar construcciones inválidas.

const ajv = new Ajv({ allErrors: true, strict: true });

for (const definition of AGENT_TOOL_DEFINITIONS) {
  expect(() => ajv.compile(definition.inputSchema)).not.toThrow();
}

Otras pruebas comparan el conjunto completo de definiciones con los handlers y con las proyecciones de los tres proveedores. validateToolInput se somete además a entradas arbitrarias con fast-check: nunca debe lanzar una excepción y siempre debe producir un resultado de validación estructurado.

El resultado es sencillo de mantener: una sola fuente de verdad, tres adaptadores mecánicos y pruebas que hacen visible cualquier divergencia antes de que llegue al agente.

Volver al índice de la serie sobre el agente de Gymnasia.

Seguir leyendo

Últimos posts -->

¿Has visto estos proyectos?

Gymnasia

Gymnasia Gymnasia
Expo
React Native
TypeScript
OpenAI
Anthropic

App de fitness con dos agentes que se ejecutan íntegramente en el dispositivo, sin backend, de forma que los datos del usuario nunca salen del móvil. Un coach conversacional BYOK con adaptadores para OpenAI, Anthropic y Google, 12 tools locales y system prompt remoto con fallback offline, y un subagente de visión que estima macronutrientes a partir de fotos de comida, con lectura de códigos de barras contra OpenFoodFacts.

LangGraph Deep Researcher

LangGraph Deep Researcher LangGraph Deep Researcher
Python
LangGraph
FastAPI
React
TypeScript
Docker

Sistema multiagente de investigación construido con LangGraph. Un supervisor descompone tu pregunta en temas y lanza subagentes de búsqueda en paralelo; cada uno comprime sus hallazgos antes de pasarlos a un agente redactor que escribe el informe final en markdown con sus fuentes. Streaming en vivo por WebSockets, modelo configurable por rol y claves de API propias que nunca se guardan en el servidor.

Tau

Tau Tau
Python
LangChain

Sistema multiagente de tutoría para estudiantes de secundaria, con un agente por asignatura y material de curso elaborado y validado por un equipo de profesores. Llegó a usarse con alumnos reales en un colegio privado en España y en un instituto en Colombia.

Ver todos los proyectos -->
>_ Disponible para proyectos

¿Tienes un proyecto con IA?

Hablemos.

maximofn@gmail.com

Especialista en Machine Learning e Inteligencia Artificial. Desarrollo soluciones con IA generativa, agentes inteligentes y modelos personalizados.

¿Quieres ver alguna charla?

Últimas charlas -->

¿Quieres mejorar con estos tips?

Últimos tips -->

Usa esto en local

Los espacios de Hugging Face nos permite ejecutar modelos con demos muy sencillas, pero ¿qué pasa si la demo se rompe? O si el usuario la elimina? Por ello he creado contenedores docker con algunos espacios interesantes, para poder usarlos de manera local, pase lo que pase. De hecho, es posible que si pinchas en alún botón de ver proyecto te lleve a un espacio que no funciona.

Flow edit

Flow edit Flow edit

Edita imágenes con este modelo de Flow. Basándose en SD3 o FLUX puedes editar cualquier imagen y generar nuevas

FLUX.1-RealismLora

FLUX.1-RealismLora FLUX.1-RealismLora
Ver todos los contenedores -->
>_ Disponible para proyectos

¿Tienes un proyecto con IA?

Hablemos.

maximofn@gmail.com

Especialista en Machine Learning e Inteligencia Artificial. Desarrollo soluciones con IA generativa, agentes inteligentes y modelos personalizados.

¿Quieres entrenar tu modelo con estos datasets?

short-jokes-dataset

HuggingFace

Dataset de chistes en inglés

Uso: Fine-tuning de modelos de generación de texto humorístico

231K filas 2 columnas 45 MB
Ver en HuggingFace →

opus100

HuggingFace

Dataset con traducciones de inglés a español

Uso: Entrenamiento de modelos de traducción inglés-español

1M filas 2 columnas 210 MB
Ver en HuggingFace →

netflix_titles

HuggingFace

Dataset con películas y series de Netflix

Uso: Análisis de catálogo de Netflix y sistemas de recomendación

8.8K filas 12 columnas 3.5 MB
Ver en HuggingFace →
Ver más datasets -->