DEV Community

Cover image for Total.js AIModel: una base práctica para flujos de trabajo impulsados por IA
Spanish Total.js
Spanish Total.js

Posted on

Total.js AIModel: una base práctica para flujos de trabajo impulsados por IA

La IA se está convirtiendo en una parte habitual del software empresarial. No como un chatbot aislado, sino como una funcionalidad integrada dentro de flujos de trabajo reales:

  • generación de código
  • traducciones
  • automatización del soporte
  • resúmenes
  • asistentes internos
  • análisis de monitorización
  • revisión de contenidos
  • procesamiento de documentos
  • asistentes basados en bases de conocimiento
  • flujos de trabajo controlados por herramientas

Lo importante no es únicamente llamar a un proveedor de IA. Lo importante es conectar el proveedor correctamente con la aplicación.

Total.js AIModel proporciona a los desarrolladores una base sencilla para crear flujos de trabajo impulsados por IA directamente dentro de aplicaciones Total.js. Permite utilizar modelos de IA con nombre, construir mensajes mediante una API fluida, trabajar con streaming, realizar parsing, obtener información del proceso de razonamiento, utilizar herramientas basadas en contexto y controlar la ejecución mediante acciones de Total.js.

El resultado es sencillo: puedes crear funcionalidades de IA sin distribuir llamadas HTTP específicas de cada proveedor por todo tu código.

Una única capa de IA para tu aplicación

Con AIModel, la implementación del proveedor se registra una sola vez mediante NEWAIMODEL().

NEWAIMODEL('qwen3-coder:480b-cloud', function($, next) {
    // Implementación específica del proveedor
});
Enter fullscreen mode Exit fullscreen mode

Después, la aplicación utiliza el modelo mediante su nombre:

let response = await AIMODEL('qwen3-coder:480b-cloud')
    .system('Eres un desarrollador. Devuelve siempre únicamente código.')
    .user('Crea un ejemplo sencillo de "Hello world" en Node.js.')
    .promise();
Enter fullscreen mode Exit fullscreen mode

Esta es la idea principal: la aplicación no necesita conocer qué endpoint HTTP, token, formato de payload o formato de streaming se utiliza. Ese conocimiento permanece dentro del registro del modelo.

Esto hace que la integración de IA sea más sencilla de mantener, más fácil de desplegar y más sencilla de cambiar posteriormente.

Registra una vez, utiliza en cualquier lugar

NEWAIMODEL() puede registrar uno o varios nombres de modelos y mantener la configuración personalizada en un único lugar.

NEWAIMODEL('qwen3-totaljs:8b', {
    url: 'http://localhost:11434/api/chat',
    temperature: 0
}, function($, next) {

    let opt = {};
    let parser = AIPARSER('ollama');

    $.payload.options = { temperature: $.config.temperature };
    $.payload.stream = true;
    $.payload.think = true;

    parser.on('content', function(event) {
        $.options.stream && $.options.stream(event.delta);
    });

    opt.method = 'POST';
    opt.url = $.config.url;
    opt.timeout = 100000;
    opt.custom = true;
    opt.type = 'json';
    opt.body = JSON.stringify($.payload);
    opt.callback = function(_, response) {
        response.stream.on('data', chunk => parser.write(chunk));
        response.stream.on('end', function() {
            let output = parser.end();
            next(null, output.content);
        });
    };

    REQUEST(opt);

});
Enter fullscreen mode Exit fullscreen mode

Después, cualquier parte de la aplicación puede utilizarlo:

let response = await AIMODEL('qwen3-totaljs:8b')
    .system('Eres un experto en Total.js.')
    .user('Crea una acción sencilla para guardar un contacto.')
    .promise();
Enter fullscreen mode Exit fullscreen mode

El proveedor puede ser local, privado, alojado en la nube o compatible con OpenAI. La aplicación Total.js llama a un modelo por su nombre y continúa trabajando.

Una API fluida para flujos de trabajo de IA

AIModel proporciona una API fluida y práctica para construir conversaciones:

AIMODEL('qwen3-totaljs:8b')
    .system('Eres un asistente de soporte.')
    .user('El usuario no puede restablecer su contraseña.')
    .assistant('Solicita más detalles y mantén la respuesta breve.')
    .user('El usuario dice que el correo de restablecimiento nunca llega.')
    .promise();
Enter fullscreen mode Exit fullscreen mode

Esto hace que las tareas habituales de IA sean fáciles de leer:

  • generar código
  • explicar una entrada de log
  • resumir un ticket
  • traducir texto
  • clasificar contenido
  • preparar una respuesta
  • extraer campos útiles de una solicitud de un cliente

AIModel se convierte en un componente normal de la aplicación.

Streaming y razonamiento

Muchas funcionalidades de IA ofrecen una mejor experiencia cuando la respuesta se transmite progresivamente. AIModel permite utilizar streaming mediante .stream().

AIMODEL('qwen3-totaljs:8b')
    .system('Eres un desarrollador.')
    .user('Crea un componente de Total.js Flow que ejecute Hello World.')
    .stream(function(line) {
        console.log(line);
    });
Enter fullscreen mode Exit fullscreen mode

Para integraciones de streaming de nivel más bajo, Total.js también proporciona AIPARSER(). Puede analizar los streams de los proveedores y exponer eventos útiles como contenido, razonamiento y llamadas a herramientas.

let parser = AIPARSER('ollama');

parser.on('thinking', function(event) {
    console.log('THINKING:', event.delta);
});

response.stream.on('data', chunk => parser.write(chunk));
response.stream.on('end', function() {
    let output = parser.end();
    console.log(output);
});
Enter fullscreen mode Exit fullscreen mode

Esto resulta útil cuando un proveedor devuelve fragmentos mediante streaming, información de razonamiento o instrucciones para llamar a herramientas. En lugar de escribir un parser personalizado para cada flujo de trabajo, el parser se convierte en parte de la capa de IA de Total.js.

Asistentes conscientes del contexto

El verdadero valor de la IA aparece cuando comprende el contexto propio de la aplicación.

El ejemplo de Peter muestra un patrón sencillo y potente: almacenar contextos en Markdown, analizarlos y exponerlos al modelo como archivos legibles. De esta forma, el asistente puede solicitar exactamente el contexto que necesita.

let context = (await Total.readfile('context.txt', 'utf8')).parseContext();
let items = [];

for (let m of context) {
    items.push('- ' + m.name + ': ' + m.summary);
    AICONTEXT.push(m);
}

Total.actions['AI|Ask'].config.system += '\n\nLos posibles contextos de archivos que se pueden utilizar son:\n\n' + items.join('\n');
Enter fullscreen mode Exit fullscreen mode

Un archivo de contexto puede contener reglas para generar componentes de Flow, scripts de PostgreSQL, convenciones de programación de Total.js o reglas de negocio específicas de una aplicación.

Esto convierte un modelo genérico en un asistente especializado para tu producto.

Herramientas conectadas a las acciones de Total.js

La parte más potente de AIModel es la ejecución de herramientas. En Total.js, las herramientas pueden ser manejadores normales de NEWACTION().

El modelo de IA no ejecuta directamente el código de la aplicación. Solicita una llamada a una herramienta. Total.js genera el esquema de la herramienta a partir de la entrada de la acción, ejecuta la acción y envía el resultado de vuelta al modelo.

Aquí tienes un ejemplo completo:

require('total5');

const TOOLS = {};

NEWACTION('AI', {
    input: '*user,system,tools,model,think:Boolean',
    config: {
        ollama: 'http://127.0.0.1:11434/api/chat',
        model: 'qwen3-totaljs:8b'
    },
    action: function($, model) {

        let history = { messages: [], tools: [], limits: {} };

        model.system && history.messages.push({ role: 'system', content: model.system });

        if (model.tools) {
            let tools = model.tools.split(',').trim();
            for (let tool of tools) {

                let action = Total.actions[tool];

                if (!TOOLS[tool]) {
                    let schema = action.jsinput ? action.jsinput.aitool(tool) : {
                        type: 'function',
                        function: {
                            name: tool,
                            parameters: { properties: {}, required: [] }
                        }
                    };

                    schema.function.description = action.summary || action.name || tool;
                    TOOLS[tool] = schema;
                }

                history.limits[tool] = action.config?.limit == null ? 1000 : action.config.limit;

                if (action.config?.end)
                    history.end = tool;

                history.tools.push(TOOLS[tool]);
            }
        }

        history.messages.push({ role: 'user', content: model.user });

        let opt = {};
        let payload = {};
        let parser = AIPARSER('ollama');

        payload.model = model.model || $.config.model;
        payload.stream = true;
        payload.think = model.think;
        payload.messages = history.messages;
        payload.tools = history.tools;

        opt.method = 'POST';
        opt.url = $.config.ollama;
        opt.timeout = 100000;
        opt.custom = true;
        opt.type = 'json';

        opt.callback = function(_, response) {

            response.stream.on('data', chunk => parser.write(chunk));
            response.stream.on('end', function() {

                let output = parser.end();

                if (output.reasoning === 'tool') {

                    payload.messages.push({
                        role: 'assistant',
                        content: '',
                        tool_calls: output.tools.map(tool => ({
                            function: {
                                name: tool.name,
                                arguments: tool.arguments
                            }
                        }))
                    });

                    output.tools.wait(function(tool, next) {

                        history.limits[tool.name] -= 1;

                        ACTION(tool.name, tool.arguments).callback(function(_, response) {

                            if (tool.name === history.end)
                                output.END = response;

                            payload.messages.push({
                                role: 'tool',
                                name: tool.name,
                                content: JSON.stringify(response)
                            });

                            next();
                        });

                    }, function() {
                        if (output.END) {
                            $.callback(output.END);
                        } else {
                            parser.reset();
                            opt.body = JSON.stringify(payload);
                            REQUEST(opt);
                        }
                    });

                } else
                    $.callback(output);
            });
        };

        opt.body = JSON.stringify(payload);
        REQUEST(opt);

    }
});
Enter fullscreen mode Exit fullscreen mode

Esto crea un flujo completo de IA:

  1. El usuario realiza una pregunta.
  2. El modelo determina que necesita una herramienta.
  3. Total.js valida y ejecuta la acción.
  4. El resultado de la herramienta se envía de vuelta al modelo.
  5. El modelo genera la respuesta final.

Así es como la IA pasa de ser un simple "chat" a convertirse en automatización real dentro de una aplicación.

Prueba completa

Las siguientes acciones son suficientes para probar la funcionalidad. El modelo puede llamar a Math|add y después finalizar el flujo con AI|done.

NEWACTION('Math|add', {
    summary: 'Suma dos números.',
    input: '*a:Number,*b:Number',
    config: { limit: 5 },
    action: function($, model) {
        $.callback({ value: model.a + model.b });
    }
});

NEWACTION('AI|done', {
    summary: 'Finaliza el flujo de IA con la respuesta final.',
    input: '*response',
    config: { end: true, limit: 1 },
    action: function($, model) {
        $.callback(model.response);
    }
});

ACTION('AI', {
    user: 'Utiliza las herramientas y calcula 20 + 22. Finaliza con AI|done.',
    system: 'Eres un asistente matemático. Utiliza siempre las herramientas disponibles.',
    tools: 'Math|add,AI|done',
    think: true
}).callback(function(_, response) {
    console.log(response);
});
Enter fullscreen mode Exit fullscreen mode

Este ejemplo es intencionadamente pequeño, pero el mismo patrón puede ejecutar cualquier acción de Total.js: leer un documento, buscar en una base de datos, crear un ticket, llamar a una API interna o generar un componente de Flow.

Memoria para las conversaciones

Los flujos de trabajo de AIModel también pueden mantener el historial de una conversación.

let history = AIMEMORY[model.id];

if (!history) {
    history = AIMEMORY[model.id] = {
        expire: NOW.add('15 minutes'),
        messages: [],
        tools: []
    };
}

history.messages.push({ role: 'user', content: model.content });
Enter fullscreen mode Exit fullscreen mode

Esto permite crear asistentes que recuerdan la sesión actual, mantienen el contexto de un cliente, continúan tareas de generación de código o guían a un operador a través de un flujo de trabajo.

La memoria puede caducar automáticamente:

ON('service', function() {
    for (let key in AIMEMORY)
        if (AIMEMORY[key].expire < NOW)
            delete AIMEMORY[key];
});
Enter fullscreen mode Exit fullscreen mode

De nuevo, la aplicación mantiene el control.

Qué puedes construir

Con AIMODEL, NEWAIMODEL y AIPARSER, las aplicaciones Total.js pueden incorporar muchas funcionalidades basadas en IA:

  • un asistente de programación entrenado con las reglas del proyecto
  • un generador de componentes de Flow
  • un asistente para scripts de PostgreSQL
  • un resumidor de tickets de soporte
  • un asistente de documentación
  • un flujo de traducción
  • un asistente para búsquedas de productos
  • un asistente para análisis de incidencias
  • un asistente para operadores de back-office
  • una capa de automatización controlada utilizando acciones de Total.js como herramientas

Este es el potencial práctico de AIModel. No es únicamente un wrapper alrededor de un proveedor de IA. Es una base para crear flujos de trabajo impulsados por IA dentro de aplicaciones reales.

Conclusión

Total.js AIModel proporciona a los desarrolladores una forma limpia, ligera y flexible de añadir capacidades de IA a las aplicaciones Total.js.

NEWAIMODEL() mantiene la integración con el proveedor en un único lugar. AIMODEL() proporciona a la aplicación una API fluida y sencilla. AIPARSER() gestiona el streaming, la información de razonamiento y las llamadas a herramientas. Las acciones de Total.js pueden convertirse en herramientas de IA controladas.

El resultado es una arquitectura práctica para crear funcionalidades de IA útiles, mantenibles y preparadas para software empresarial real.

Top comments (0)