Back to blog
    Pydantic AI en Dispositivo: Ajusta Qwen3-4B para Agentes Móviles con Seguridad de Tipos
    pydantic-aifine-tuningtool-callingqwen3on-devicemobileai-agents

    Pydantic AI en Dispositivo: Ajusta Qwen3-4B para Agentes Móviles con Seguridad de Tipos

    Pydantic AI aporta seguridad de tipos y ergonomía de FastAPI a los agentes LLM. Combínalo con un modelo de 4B ajustado ejecutándose en el dispositivo vía llama.cpp y obtienes agentes de calidad de producción en aplicaciones móviles con cero costes de API y salidas validadas por construcción.

    EErtas Team·

    Actualizado 2026-05-10 — Refleja los lanzamientos puntuales de Pydantic AI v1.90.x y v1.93.x de principios de mayo, que añadieron una configuración explícita de tool_choice en Agent (para que puedas fijar el modelo a una llamada de función específica cuando el flujo de trabajo lo demande) más eventos de streaming dedicados OutputToolCallEvent y OutputToolResultEvent para una observabilidad de grano más fino. Ambos son útiles cuando el agente se ejecuta contra un modelo local ajustado y quieres poder afirmar exactamente qué herramienta se seleccionó en cada paso.

    Pydantic AI es el framework de agentes que los desarrolladores Python han estado esperando. Las anotaciones de tipo se convierten en contratos. Las definiciones de herramientas se convierten en funciones validadas. Los esquemas de salida se convierten en garantías, no sugerencias. Es FastAPI para agentes LLM — y se combina inusualmente bien con un modelo local ajustado.

    La combinación importa porque el diseño de Pydantic AI asume que el modelo puede producir salidas estructuradas de forma confiable. Contra una API frontier como Claude o GPT-5, esa suposición usualmente se cumple. Contra un modelo open-weight 7B genérico, no se cumple — las violaciones de esquema son comunes, los reintentos son rutinarios, y la seguridad de tipos que el framework promete empieza a sentirse como un envoltorio alrededor de inferencia frágil.

    Un modelo de 4B ajustado arregla esto. Entrenado en los esquemas de herramientas y formatos de salida exactos que tu agente utiliza, el modelo produce salidas validadas casi siempre. El validador de Pydantic AI se convierte en una baranda en lugar de una fuente recurrente de excepciones. Y como el modelo es lo suficientemente pequeño para ejecutarse en el dispositivo a través de llama.cpp, obtienes la seguridad de tipos que Pydantic AI promete sin ninguno de los costes de API por token que rompen la economía unitaria de las aplicaciones móviles entre 500 y 5,000 usuarios.

    Esta guía recorre el pipeline completo: ajusta Qwen3-4B en Ertas Studio para un agente de aplicación móvil de muestra, despliégalo en el dispositivo a través del Ertas Deployment CLI, y conéctalo a un agente Pydantic AI que se ejecuta enteramente en el teléfono del usuario.

    La configuración: un agente asistente de calendario

    Construiremos un asistente de calendario que lee solicitudes en lenguaje natural y emite acciones de reserva validadas. El agente tiene tres herramientas:

    • find_availability(start: datetime, end: datetime, duration_min: int) devuelve los huecos abiertos
    • book_meeting(slot: TimeSlot, attendees: list[str], title: str) crea una reserva
    • cancel_meeting(meeting_id: str) cancela una reserva existente

    La salida del agente es un modelo Pydantic BookingDecision con campos estructurados. Pydantic AI valida cada salida contra este esquema. Si el modelo emite una salida inválida, Pydantic AI lanza un ValidationError que la aplicación host puede capturar y reintentar.

    Este es el tipo de agente que es caro cuando se ejecuta contra una API frontier y lento cuando se ejecuta contra un modelo local genérico. Ajustado y en el dispositivo, es tanto rápido como gratis.

    Paso 1: cura un dataset de fine-tuning en Studio

    Abre Ertas Studio y crea un nuevo proyecto. Usa Data Craft para definir tus esquemas de herramientas — pega las firmas de las funciones en el panel de esquemas, y Studio las usa como objetivo estructural para los datos de entrenamiento.

    Para un asistente de calendario típicamente quieres 300–800 ejemplos de entrenamiento que cubran:

    • Llamadas de una sola herramienta: "reserva una reunión de 30 minutos mañana a las 14h con john@" → una llamada book_meeting
    • Llamadas multi-paso: "encuentra 30 minutos mañana por la tarde y resérvalo con el equipo de diseño" → find_availability luego book_meeting
    • Casos límite de validación: "cancela esa reunión que acabamos de reservar" (requiere meeting_id del contexto previo)
    • Rechazos: "envía un correo de seguimiento a todos los asistentes" — fuera de alcance, devolver un rechazo estructurado

    Data Craft tiene dos modos para esto. El modo manual te permite escribir cada ejemplo en una tabla estructurada. El modo bulk emite una plantilla de prompt estructurada que pegas en Claude o ChatGPT para generar cientos de ejemplos conversacionalmente — Studio ingiere la salida y valida cada ejemplo contra tus esquemas de herramientas antes de añadirlo al conjunto de entrenamiento.

    Apunta a 500 ejemplos. Más allá de 500, la calidad del dataset importa mucho más que la cantidad. Dedica tiempo a los casos límite de validación y los rechazos — ahí es donde los modelos de propósito general alucinan parámetros y donde el fine-tuning produce las mayores ganancias de confiabilidad.

    Paso 2: ajusta Qwen3-4B

    Elige Qwen3-4B-Instruct como el modelo base en Studio. El tamaño 4B es el equilibrio adecuado para despliegue en el dispositivo — lo suficientemente pequeño para caber cómodamente en teléfonos modernos (unos 2,5 GB en Q4_K_M), lo suficientemente grande para manejar conversaciones multi-turno y llamadas paralelas a herramientas de forma confiable.

    La configuración de entrenamiento por defecto de Studio para fine-tunes de tool-calling es QLoRA en rango 32 sobre 3 épocas. La curva de pérdida de validación típicamente se aplana alrededor de la época 2,5; la auto-evaluación de Studio marca el sobreajuste si aparece. En el nivel estándar de GPU, una ejecución de entrenamiento de 500 ejemplos se completa en menos de una hora.

    Cuando termina el entrenamiento, ejecuta la suite de evaluación de Studio contra tu conjunto de validación reservado. Para fine-tunes de tool-calling, observa tres métricas: precisión del nombre de herramienta (¿el modelo eligió la función correcta?), precisión del nombre de parámetro (¿rellenó los parámetros correctos?) y precisión del valor de parámetro (¿usó los valores correctos?). Los modelos listos para producción puntúan por encima del 95% en las tres.

    Si alguna métrica está por debajo del 95%, la causa habitual son lagunas en el dataset — encuentra los ejemplos fallidos en el informe de evaluación, añade datos de entrenamiento representativos para los casos faltantes, y ejecuta fine-tuning incremental. Studio admite entrenamiento continuado desde un checkpoint sin reiniciar desde cero.

    Paso 3: exporta a GGUF y envíalo al móvil

    El flujo de exportación de Studio produce un binario GGUF en el nivel de cuantización que elijas. Para Qwen3-4B en móvil, Q4_K_M es el predeterminado — unos 2,5 GB en disco, ~3 GB de memoria de trabajo, y dentro del presupuesto de cualquier teléfono moderno.

    Ejecuta el Ertas Deployment CLI contra tu proyecto existente de iOS, Android, Flutter o React Native:

    ertas deploy mobile \\
      --project ./my-app \\
      --model ertas-calendar-agent-4b.gguf \\
      --framework react-native
    

    El CLI instala los enlaces FFI móviles de llama.cpp, deja caer el modelo GGUF en la ubicación correcta del proyecto, y conecta una llamada de inferencia funcional. Para React Native específicamente, el CLI expone un hook useErtasModel que devuelve una función de inferencia tipada. Tiempo total transcurrido desde ejecutar el CLI hasta una llamada de inferencia funcional en el dispositivo: típicamente menos de 5 minutos.

    Paso 4: conecta Pydantic AI al modelo en el dispositivo

    Pydantic AI no se ejecuta en el dispositivo — es un framework Python. Así que la arquitectura es un patrón de backend: Pydantic AI se ejecuta en tu backend (servicio Python o función serverless), pero el modelo al que llama es el servidor de inferencia en el dispositivo que el Ertas Deployment CLI expone desde la aplicación móvil a través de un endpoint HTTP local.

    Para desarrollo, ejecuta el modelo en tu portátil vía Ollama y apunta Pydantic AI al endpoint local:

    from datetime import datetime
    from typing import Literal
    from pydantic import BaseModel
    from pydantic_ai import Agent
    from pydantic_ai.models.openai import OpenAIModel
    
    # Apunta Pydantic AI al Qwen3-4B entrenado con Ertas servido vía Ollama
    model = OpenAIModel(
        "ertas-calendar-agent-4b",
        base_url="http://localhost:11434/v1",
        api_key="not-needed",
    )
    
    class TimeSlot(BaseModel):
        start: datetime
        end: datetime
    
    class BookingDecision(BaseModel):
        action: Literal["book", "find", "cancel", "reject"]
        slot: TimeSlot | None = None
        meeting_id: str | None = None
        rejection_reason: str | None = None
    
    agent = Agent(
        model,
        result_type=BookingDecision,
        system_prompt="You schedule meetings. Use the available tools to find slots and book.",
    )
    
    @agent.tool
    async def find_availability(ctx, start: datetime, end: datetime, duration_min: int) -> list[TimeSlot]:
        """Find open calendar slots between start and end of at least duration_min."""
        return await calendar_api.search(start, end, duration_min)
    
    @agent.tool
    async def book_meeting(ctx, slot: TimeSlot, attendees: list[str], title: str) -> dict:
        """Create a calendar booking."""
        return await calendar_api.book(slot, attendees, title)
    
    @agent.tool
    async def cancel_meeting(ctx, meeting_id: str) -> dict:
        """Cancel a calendar booking by ID."""
        return await calendar_api.cancel(meeting_id)
    
    # Ejecuta el agente con una solicitud en lenguaje natural
    result = agent.run_sync(
        "Find me 30 minutes tomorrow afternoon and book it with the design team."
    )
    print(result.data)
    # BookingDecision(action='book', slot=TimeSlot(start=..., end=...), meeting_id='m-abc', ...)
    

    Hay dos cosas que están pasando que no ves en el código. Primero, el validador de Pydantic AI ha confirmado que la salida del modelo coincide con BookingDecision exactamente — sin campos faltantes, sin extras alucinados. Si el modelo hubiera emitido una salida inválida, Pydantic AI habría lanzado un ValidationError y lo habrías capturado. Segundo, la entrada de cada llamada a herramienta fue validada contra la firma de la herramienta. Si el modelo hubiera pasado tipos incorrectos, Pydantic AI habría rechazado la llamada antes de que tocara tu CRM.

    Para producción, cambia el base_url de http://localhost:11434/v1 al endpoint que sirva tu modelo. Si el modelo se está ejecutando en el teléfono del usuario a través del Ertas Deployment CLI, el endpoint es el servidor de inferencia local del dispositivo (típicamente http://localhost:8080/v1 desde la propia perspectiva del dispositivo, o enrutado a través de tu backend dependiendo de tu arquitectura).

    Por qué funciona esta arquitectura

    Tres fuerzas se alinean.

    Pydantic AI te da seguridad de tipos. La capa de validación del framework convierte cada salida del modelo en un objeto Python verificado. Las violaciones de esquema se convierten en excepciones, no en bugs silenciosos. Para agentes que impulsan acciones reales — reservas, pagos, cambios de infraestructura — esto es esencial.

    El fine-tuning hace que esa seguridad de tipos sea estable. Sin fine-tuning, el modelo es un productor poco confiable de salidas estructuradas y el validador de Pydantic AI se dispara constantemente. Con fine-tuning sobre los esquemas exactos que el agente usa, el modelo se convierte en un productor confiable y el validador es principalmente una baranda en lugar de un punto de falla recurrente. Las dos capas se complementan: el entrenamiento enseña al modelo a producir salidas estructuradas, la validación impone el contrato en tiempo de ejecución.

    La inferencia en el dispositivo hace que la economía funcione. Una llamada a una API frontier para un flujo de reserva multi-paso cuesta $0,01–$0,05 dependiendo del contexto. A 1,000 usuarios activos diarios ejecutando 5 flujos de reserva cada uno, eso son $50–$250 por día, o $1,500–$7,500 por mes. En el dispositivo, el coste es el tamaño del modelo en el almacenamiento del usuario y unos pocos cientos de milisegundos de tiempo de CPU/GPU por inferencia. La factura no crece con tu base de usuarios.

    La combinación produce algo raro en 2026: un sistema de agentes que está tanto bien diseñado como es económico a escala. Pydantic AI maneja la ingeniería. Los modelos entrenados con Ertas manejan la especialización. El Ertas Deployment CLI te lleva al móvil.

    Yendo de prototipo a producción

    Un pipeline típico para enviar este tipo de agente se ve así:

    1. Prototipo contra una API (1–2 días). Construye el agente Pydantic AI contra OpenAI o Claude. Acierta con los esquemas, acierta con el flujo de herramientas, demuestra el valor.
    2. Cura un dataset (1–2 días). Usa Data Craft y unas pocas cientos de conversaciones de tu prototipo. Valida ejemplos contra los esquemas.
    3. Ajusta en Studio (menos de una hora de tiempo de entrenamiento, más evaluación). Itera sobre el dataset hasta que las métricas de evaluación superen el 95%.
    4. Envía al móvil (menos de una hora con el Deployment CLI). Ejecuta el CLI contra tu proyecto de iOS, Android, Flutter o React Native. Reemplaza la llamada a la API en tu agente Pydantic AI con el endpoint local.
    5. Itera sobre trazas de producción. Las trazas de Pydantic AI (especialmente a través de Logfire) se convierten en la siguiente ronda de datos de entrenamiento. Studio admite fine-tuning incremental desde trazas de producción, así que el modelo mejora con el tiempo sin nunca enviar datos de usuario fuera del dispositivo.

    Los primeros tres pasos solían ser la parte difícil. Pydantic AI redujo la brecha de prototipo-a-producción de "semanas de ingeniería de prompts" a "una tarde de curación de dataset." Studio reduce la brecha de dataset-a-fine-tune de "un mes-MLE de trabajo" a "un par de horas." El Ertas Deployment CLI cierra la última y más obstinada brecha: entrenar un modelo es una cosa, enviarlo a una aplicación real de iOS o Android es otra, y ese paso ha sido históricamente 20–40 horas de configuración de build de llama.cpp que la mayoría de los desarrolladores de aplicaciones nunca terminan.

    Juntas, las cuatro piezas — Pydantic AI para ingeniería, Studio para fine-tuning, Data Craft para datasets, el Deployment CLI para envío — colapsan la línea de tiempo de prototipo a producción-en-móvil de "un trimestre de trabajo" a "una semana de trabajo." Para los desarrolladores de aplicaciones móviles que sienten el precipicio de costes de API morder entre 500 y 5,000 usuarios, esa es la diferencia entre permanecer en el precipicio y bajarse de él.

    Ship AI that runs on your users' devices.

    Early bird pricing starts at $14.50/mo — locked in for life. Plans for builders and agencies.

    Keep reading