Esta guía es una contribución de Hubeet.com, impulsada por el equipo de Solúnika, como parte de nuestra misión de acercar inteligencia artificial aplicada a equipos humanos de verdad.
1.1 ¿Qué vamos a construir?
En este manual vas a desarrollar un agente inteligente desde cero, capaz de percibir detalles, recordarlos como memoria, entender su estado actual y anticipar lo que podría pasar a continuación. Este agente tendrá las siguientes capacidades:
- Multimodal: podrá procesar tanto texto como imágenes.
- Memoria secuencial: recordará eventos pasados y los usará para tomar mejores decisiones.
- Contextual: comprenderá su “presente” como una síntesis inteligente del pasado reciente.
- Predictivo: podrá proyectar el futuro cercano y actuar en consecuencia.
Todo esto lo vas a implementar en Node.js, con una arquitectura modular, simple y extensible.
1.2 ¿Para qué sirve esto?
Esta clase de agentes puede aplicarse en sistemas como:
- Asistentes personales introspectivos.
- Bots que aprenden del usuario en tiempo real.
- Sistemas de monitoreo con autoevaluación.
- Juegos con NPCs con memoria y personalidad real.
- Herramientas de productividad que se anticipan a tu próxima acción.
Este proyecto no es una prueba de concepto: es una base real para aplicaciones potentes. El código será didáctico pero profesional, optimizado para escalar a producción si lo deseás.
1.3 ¿Cómo lo vamos a encarar?
Dividiremos el desarrollo en cuatro módulos clave:
- Memoria: cómo representar y almacenar los eventos (detalles) que el agente percibe.
- Inferencia contextual: cómo entender el estado actual a partir del pasado reciente.
- Predicción de futuro: cómo anticipar lo que viene.
- Acción introspectiva: cómo decidir qué hacer con lo que se deduce y predice.
1.4 Tecnologías que usaremos
- Node.js (v18+)
- FAISS (via servidor Python o faiss-js)
- pgvector + PostgreSQL para persistencia vectorial
- CLIP (OpenAI) y sentence-transformers (via API) para embeddings multimodales
- Transformers ligeros vía API o worker Python
- WebSocket/HTTP/gRPC para comunicación entre módulos (según preferencia)
1.5 Empezamos a construir: Estructura base del proyecto
Creamos el esqueleto del proyecto:
mkdir agente-inteligente
cd agente-inteligente
npm init -y
npm install express pg dotenv uuid
Creamos esta estructura de carpetas:
/agente-inteligente
│
├── /src
│ ├── index.js # entrada del sistema
│ ├── config.js # configuración global
│ ├── db.js # conexión y queries a PostgreSQL
│ ├── memory/
│ │ ├── detailStore.js # inserción y recuperación de detalles
│ ├── embeddings/
│ │ ├── embedder.js # API de embeddings
│ ├── inference/
│ │ ├── contextBuilder.js # deduce estado presente
│ ├── prediction/
│ │ ├── predictor.js # anticipa eventos futuros
│ ├── agent/
│ ├── brain.js # orquestador y evaluador introspectivo
Archivo .env:
DATABASE_URL=postgresql://usuario:clave@localhost:5432/agente
1.6 Definimos la estructura de memoria
Creamos una tabla detail en PostgreSQL:
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "vector";
CREATE TABLE detail (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
ts TIMESTAMPTZ NOT NULL DEFAULT NOW(),
embedding VECTOR(768) NOT NULL,
type TEXT NOT NULL, -- 'text' | 'image'
content TEXT,
prev_id UUID REFERENCES detail(id),
next_id UUID REFERENCES detail(id)
);
Y una tabla opcional para predicciones:
CREATE TABLE prediction (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
detail_ref_id UUID REFERENCES detail(id),
horizon_min INT,
pred_ts TIMESTAMPTZ,
embedding VECTOR(768),
text TEXT,
policy_tag TEXT,
confidence REAL,
realized_id UUID,
reward REAL
);
1.7 Primer módulo: insertamos detalles
Creamos /src/db.js:
const { Pool } = require('pg');
require('dotenv').config();
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
module.exports = {
query: (text, params) => pool.query(text, params),
};
Creamos /src/memory/detailStore.js:
const db = require('../db');
const { v4: uuidv4 } = require('uuid');
async function insertDetail({ embedding, type, content, prevId = null }) {
const id = uuidv4();
await db.query(
`INSERT INTO detail (id, embedding, type, content, prev_id)
VALUES ($1, $2, $3, $4, $5)`,
[id, embedding, type, content, prevId]
);
return id;
}
module.exports = { insertDetail };
1.8 Probamos con un ejemplo
Creamos src/index.js:
const { insertDetail } = require('./memory/detailStore');
async function main() {
// Remplazar por un servicio de embedding real, esto es un mock
const dummyEmbedding = Array(768).fill(0).map(() => Math.random());
const id = await insertDetail({
embedding: dummyEmbedding,
type: 'text',
content: 'Reunión con cliente sobre IA en 15 min',
});
console.log('Detalle insertado con ID:', id);
}
main();
1.9 Próximo paso
En el Capítulo 2 vamos a:
- Implementar un servicio que genera embeddings reales de texto e imágenes.
- Integrar CLIP y Sentence Transformers como APIs locales o remotas.
- Insertar eventos automáticamente en el sistema a partir de inputs naturales.
Capítulo 2 — Darle sentidos al agente: Embeddings multimodales
2.1 ¿Qué son los embeddings y por qué los necesitamos?
Un embedding es una representación matemática (vectorial) de un concepto. En lugar de analizar palabras o imágenes directamente, las convertimos en vectores de números que capturan significado y contexto.
Para nuestro agente, cada “detalle” que percibe será convertido en un vector que:
- Tiene dimensión fija (ej: 768)
- Puede ser comparado con otros (similaridad)
- Puede ser utilizado para deducir estados, generar texto o anticipar eventos
2.2 Tipos de entradas
Vamos a aceptar dos tipos de entradas:
- Texto libre: frases, resúmenes, pensamientos del usuario, descripciones.
- Imágenes: fotos de pantalla, objetos, expresiones, entorno.
Ambos se convertirán a embeddings usando modelos preentrenados.
2.3 Modelos que usaremos
Para cada modalidad:
- Texto: sentence-transformers/all-MiniLM-L6-v2 (o similar)
- Imagen: openai/clip-vit-base-patch32 para convertir imágenes en vectores
Podés correrlos en:
- Un servidor Python local con Flask/FastAPI
- Un microservicio en otra máquina (API REST)
- En Node.js usando wrappers, pero menos recomendado
En este caso, vamos a usar la opción 1 por simplicidad y robustez.
2.4 Servidor de embeddings en Python
Creamos una carpeta aparte para el servidor:
/embedder-service
│
├── app.py
├── requirements.txt
requirements.txt
fastapi
uvicorn
sentence-transformers
transformers
torch
Pillow
app.py
from fastapi import FastAPI, UploadFile, File
from sentence_transformers import SentenceTransformer
from transformers import CLIPProcessor, CLIPModel
from PIL import Image
import torch
import io
app = FastAPI()
text_model = SentenceTransformer("all-MiniLM-L6-v2")
clip_model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
clip_processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
@app.post("/embed/text")
async def embed_text(data: dict):
text = data.get("text", "")
embedding = text_model.encode(text).tolist()
return {"embedding": embedding}
@app.post("/embed/image")
async def embed_image(file: UploadFile = File(...)):
image = Image.open(io.BytesIO(await file.read())).convert("RGB")
inputs = clip_processor(images=image, return_tensors="pt")
outputs = clip_model.get_image_features(inputs)
embedding = outputs[0].detach().numpy().tolist()
return {"embedding": embedding}
Para correrlo:
uvicorn app:app --host 0.0.0.0 --port 8001
2.5 Cliente Node.js del servicio
Creamos /src/embeddings/embedder.js:
const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');
const EMBEDDER_URL = 'http://localhost:8001';
async function embedText(text) {
const response = await axios.post(`${EMBEDDER_URL}/embed/text`, { text });
return response.data.embedding;
}
async function embedImage(path) {
const form = new FormData();
form.append('file', fs.createReadStream(path));
const response = await axios.post(`${EMBEDDER_URL}/embed/image`, form, {
headers: form.getHeaders(),
});
return response.data.embedding;
}
module.exports = { embedText, embedImage };
2.6 Probamos con texto
Editamos src/index.js:
const { insertDetail } = require('./memory/detailStore');
const { embedText } = require('./embeddings/embedder');
async function main() {
const text = 'Reunión estratégica de IA a las 15:00';
const embedding = await embedText(text);
const id = await insertDetail({
embedding,
type: 'text',
content: text,
});
console.log('Detalle insertado:', id);
}
main();
2.7 Probamos con una imagen
const { embedImage } = require('./embeddings/embedder');
async function main() {
const path = './images/reunion.png';
const embedding = await embedImage(path);
const id = await insertDetail({
embedding,
type: 'image',
content: 'reunion.png',
});
console.log('Imagen insertada con ID:', id);
}
2.8 Pensamos en el futuro: embeddings homogéneos
Cuando lleguemos a la inferencia contextual, necesitaremos comparar o relacionar directamente información proveniente de distintas modalidades, como texto e imagen. Para que esto sea posible, los embeddings generados por cada tipo de dato deben convivir en un mismo espacio vectorial o, al menos, ser proyectados a uno común que permita calcular similitudes, alineamientos o relaciones semánticas útiles.
Por eso elegimos CLIP y SentenceTransformers: - CLIP genera embeddings tanto de imágenes como de texto en un espacio compartido. Fue entrenado con pares imagen-texto, lo cual le da la capacidad de “entender” el significado visual y verbal de un concepto dentro del mismo sistema de coordenadas semánticas. - SentenceTransformers, en cambio, está optimizado para generar embeddings de texto con alta fidelidad semántica, y es ideal para tareas como recuperación de contexto, búsqueda y generación de prompts.
Para alinear o combinar embeddings de ambos mundos —cuando no están en el mismo espacio desde el inicio— existen técnicas como: - PCA (Análisis de Componentes Principales): permite reducir y proyectar vectores de diferentes dominios a un subespacio común, capturando las variaciones más relevantes y descartando ruido. - Autoencoders multimodales: redes neuronales diseñadas para aprender una codificación conjunta de datos heterogéneos (por ejemplo, una imagen y una descripción textual). - Pooling promedio (Average Pooling): útil para representar un grupo de embeddings (como varios textos o fragmentos de una imagen) como un único vector representativo, simplificando el cómputo de similitud y contextualización.
Más adelante veremos cómo aplicar estas estrategias para lograr que nuestro agente interprete imágenes y textos dentro de una misma lógica de contexto y significado.
2.9 Aseguramos coherencia
Agregamos validaciones básicas en detailStore.js:
if (!Array.isArray(embedding) || embedding.length !== 768) {
throw new Error("Embedding inválido. Debe tener 768 dimensiones.");
}
Podés también normalizar el vector antes de guardar:
function normalize(vec) {
const norm = Math.sqrt(vec.reduce((sum, x) => sum + x * x, 0));
return vec.map(x => x / norm);
}
2.10 Conclusión de este capítulo
Tu agente ya puede:
- Leer texto o imágenes del entorno.
- Convertirlos en embeddings numéricos.
- Guardarlos como detalles en una memoria persistente.
¡Acaba de percibir por primera vez! Ya tiene sentidos.
Capítulo 3 — Inferencia contextual: entender el “ahora”
3.1 ¿Qué es el estado presente?
El estado presente es un resumen vectorial de lo que está pasando ahora desde el punto de vista del agente. Es como una fotografía mental construida a partir de:
- Los eventos recientes (detalles que ha percibido)
- Su relevancia (cuán importantes o recientes son)
- Su combinación semántica
Este “embedding de ahora” lo vamos a llamar E_now.
3.2 ¿Cómo se calcula?
Usaremos una técnica conocida como attention pooling ponderado. La idea es:
- Tomar los últimos N detalles almacenados.
- Asignarles un peso wᵢ en función del tiempo y la relevancia.
- Combinar todos los vectores usando esos pesos:E_now = ∑ (wᵢ × embeddingᵢ)
Esto nos da un vector compacto que resume el contexto actual.
3.3 Implementación del módulo
Creamos /src/inference/contextBuilder.js:
const db = require('../db');
function expDecayWeight(ts, now, tau = 15 * 60 * 1000) {
const delta = now - new Date(ts).getTime(); // en ms
return Math.exp(-delta / tau);
}
function normalize(vec) {
const norm = Math.sqrt(vec.reduce((sum, x) => sum + x * x, 0));
return vec.map(x => x / norm);
}
function weightedAverage(vectors, weights) {
const sum = Array(vectors[0].length).fill(0);
for (let i = 0; i < vectors.length; i++) {
for (let j = 0; j < sum.length; j++) {
sum[j] += vectors[i][j] * weights[i];
}
}
const totalWeight = weights.reduce((a, b) => a + b, 0);
return normalize(sum.map(x => x / totalWeight));
}
async function buildCurrentState({ windowSize = 10, tau = 15 * 60 * 1000 }) {
const now = Date.now();
const res = await db.query(
`SELECT embedding, ts FROM detail ORDER BY ts DESC LIMIT $1`,
[windowSize]
);
const embeddings = res.rows.map(r => r.embedding);
const timestamps = res.rows.map(r => r.ts);
const weights = timestamps.map(ts => expDecayWeight(ts, now, tau));
const E_now = weightedAverage(embeddings, weights);
return E_now;
}
module.exports = { buildCurrentState };
3.4 Probamos el estado actual
Editamos src/index.js:
const { buildCurrentState } = require('./inference/contextBuilder');
async function main() {
const state = await buildCurrentState({});
console.log('Estado actual del agente (E_now):');
console.log(state.slice(0, 10), '...'); // mostramos primeras 10 dimensiones
}
main();
3.5 ¿Qué podemos hacer con
E_now
?
Este vector no es solo un resumen. Es una puerta de entrada a acciones. Podemos:
- Convertirlo en texto: “Estoy procesando múltiples eventos técnicos.”
- Clasificarlo: foco_alto, ansiedad_media, esperando estímulo
- Compararlo con estados previos
- Usarlo como entrada para predicción de eventos futuros
3.6 Proyección textual del presente (opcional)
Creamos un servicio adicional en el servidor Python para convertir un embedding a texto (decoding aproximado):
En app.py del servidor:
from fastapi import Body
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
decoder_model = AutoModelForSeq2SeqLM.from_pretrained("google/flan-t5-base")
decoder_tokenizer = AutoTokenizer.from_pretrained("google/flan-t5-base")
@app.post("/decode/embedding")
async def decode_embedding(data: dict = Body(...)):
prompt = f"Describe el estado a partir del siguiente embedding: {data['embedding'][:10]} ..."
inputs = decoder_tokenizer(prompt, return_tensors="pt")
outputs = decoder_model.generate(inputs, max_new_tokens=50)
decoded = decoder_tokenizer.decode(outputs[0], skip_special_tokens=True)
return {"description": decoded}
Y desde Node.js (embedder.js):
async function decodeEmbedding(embedding) {
const response = await axios.post(`${EMBEDDER_URL}/decode/embedding`, {
embedding,
});
return response.data.description;
}
module.exports = { embedText, embedImage, decodeEmbedding };
3.7 Probamos la descripción del estado
const { buildCurrentState } = require('./inference/contextBuilder');
const { decodeEmbedding } = require('./embeddings/embedder');
async function main() {
const E_now = await buildCurrentState({});
const texto = await decodeEmbedding(E_now);
console.log('Descripción del presente:', texto);
}
main();
3.8 ¿Qué sigue?
Ya tenemos un agente que:
- Registra percepciones como detalles
- Calcula el estado presente
- Puede describirlo en lenguaje natural
Capítulo 4 — Anticipación: predecir el futuro cercano
4.1 ¿Qué es una predicción en este contexto?
Una predicción es una estimación vectorial (y opcionalmente textual) de lo que probablemente ocurrirá en un horizonte próximo. Se puede expresar como:
- Un embedding futuro: lo que el agente espera sentir/ver.
- Una descripción anticipada: “Habrá un ticket urgente en 10 minutos.”
- Una acción sugerida: “Prepará el entorno técnico.”
4.2 ¿Con qué se predice?
El agente usará:
- El embedding del presente (E_now)
- La secuencia reciente de embeddings [Eₜ₋ₙ … Eₜ]
Opcionalmente, usamos:
- La posición temporal real (timestamps)
- Metadatos (tipo, urgencia, autor, etc.)
4.3 Arquitectura del predictor
Usaremos un modelo autoregresivo simple. Entrenado o inferido vía API externa, se comportará como:
Input: [Eₜ₋ₙ, …, E_now] → Output: [Eₜ₊₁, Eₜ₊₂, …]
Cada vector futuro puede luego traducirse a texto, clasificado o usado directamente.
4.4 Diseño del módulo
Creamos /src/prediction/predictor.js:
const db = require('../db');
const { buildCurrentState } = require('../inference/contextBuilder');
const axios = require('axios');
const PREDICTOR_URL = 'http://localhost:8002';
async function getRecentEmbeddings(windowSize = 10) {
const res = await db.query(
`SELECT embedding FROM detail ORDER BY ts DESC LIMIT $1`,
[windowSize]
);
return res.rows.map(r => r.embedding).reverse();
}
async function predictFutureEmbeddings({ horizons = [5, 30] }) {
const sequence = await getRecentEmbeddings(10);
const E_now = await buildCurrentState({});
const response = await axios.post(`${PREDICTOR_URL}/predict`, {
context: [...sequence, E_now],
horizons,
});
return response.data.predictions; // {horizon: embedding}
}
module.exports = { predictFutureEmbeddings };
4.5 Servidor Python de predicción
/predictor-service/app.py
from fastapi import FastAPI
from pydantic import BaseModel
import numpy as np
import torch
from torch import nn
app = FastAPI()
class DummyPredictor(nn.Module):
def __init__(self, dim):
super().__init__()
self.lstm = nn.LSTM(input_size=dim, hidden_size=dim, num_layers=1, batch_first=True)
self.linear = nn.Linear(dim, dim)
def forward(self, seq):
out, _ = self.lstm(seq)
pred = self.linear(out[:, -1, :])
return pred
model = DummyPredictor(768)
class PredictionRequest(BaseModel):
context: list
horizons: list
@app.post("/predict")
def predict(req: PredictionRequest):
context = torch.tensor([req.context], dtype=torch.float32)
out = model(context).detach().numpy()[0].tolist()
# mock para múltiples horizontes
return {"predictions": {h: out for h in req.horizons}}
Para correrlo:
uvicorn app:app --host 0.0.0.0 --port 8002
4.6 Traducción y acción
Agregamos función en embedder.js:
async function decodeEmbedding(embedding) {
const response = await axios.post(`${EMBEDDER_URL}/decode/embedding`, {
embedding,
});
return response.data.description;
}
Y en predictor.js, un wrapper completo:
const { decodeEmbedding } = require('../embeddings/embedder');
async function predictTextualFutures() {
const futureEmbeddings = await predictFutureEmbeddings({});
const results = {};
for (const [horizon, emb] of Object.entries(futureEmbeddings)) {
const desc = await decodeEmbedding(emb);
results[horizon] = desc;
}
return results;
}
module.exports = { predictTextualFutures };
4.7 Probamos la predicción
En index.js:
const { predictTextualFutures } = require('./prediction/predictor');
async function main() {
const futures = await predictTextualFutures();
console.log('Futuros anticipados:');
for (const [horizon, text] of Object.entries(futures)) {
console.log(`En ${horizon} minutos: ${text}`);
}
}
main();
4.8 Feedback loop
Creamos tabla en PostgreSQL:
CREATE TABLE prediction (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
detail_ref_id UUID REFERENCES detail(id),
horizon_min INT,
pred_ts TIMESTAMPTZ,
embedding VECTOR(768),
text TEXT,
confidence REAL,
realized_id UUID,
reward REAL
);
Cada predicción se guarda junto con su tiempo estimado. Un cronjob evalúa su cumplimiento comparando con eventos reales futuros.
4.9 ¿Qué sigue?
Ya tenemos un agente que:
- Percibe su entorno
- Construye su estado presente
- Predice lo que vendrá
Capítulo 5 — Introspección: actuar según lo que sabe y espera
5.1 ¿Qué es la introspección en un agente?
Introspección es la capacidad de:
- Observar su propio estado (emocional, operativo, contextual)
- Comparar eso con una expectativa, intención o patrón interno
- Decidir una acción correctiva, reflexiva o estratégica
Para lograr esto, necesitaremos un módulo central (el brain) que:
- Lea el estado presente (E_now)
- Evalúe las predicciones
- Compare con un “estado ideal” o plan
- Decida: actuar, esperar, redirigir, reflexionar
5.2 Diseño conceptual
┌────────────┐
│ Detalles │
└────┬───────┘
│
┌───────▼────────┐
│ E_now (context)│
└───────┬────────┘
│
┌────────────────┼──────────────────┐
│ │ │
Estado ideal Predicción Meta deseada
│ │ │
└──────┬─────────┴──────────┬───────┘
│ Comparación │
└───────┬────────────┘
▼
┌────────────┐
│ Decisión │
└────┬───────┘
▼
Acción, Log, Reflexión
5.3 Estado ideal
Definimos un estado ideal E_ideal con un propósito. Podés fijarlo por tipo de día, perfil, estilo o contexto (ej: “operativo productivo”).
Creamos /src/agent/brain.js:
const { buildCurrentState } = require('../inference/contextBuilder');
const { predictTextualFutures } = require('../prediction/predictor');
const { decodeEmbedding } = require('../embeddings/embedder');
// Simulación de un vector ideal fijo
const E_ideal = Array(768).fill(0).map((_, i) => Math.sin(i / 40));
function cosineSimilarity(a, b) {
const dot = a.reduce((sum, val, i) => sum + val * b[i], 0);
const normA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
const normB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
return dot / (normA * normB);
}
async function introspect() {
const E_now = await buildCurrentState({});
const similarity = cosineSimilarity(E_now, E_ideal);
const predicted = await predictTextualFutures();
console.log('Evaluando estado actual...');
if (similarity < 0.7) {
console.log(`Estado desalineado (${(similarity * 100).toFixed(2)}%)`);
console.log('Propuesta: reorganizar tareas o tomar pausa.');
} else {
console.log(`Estado alineado (${(similarity * 100).toFixed(2)}%)`);
console.log('Continuar operativo.');
}
console.log('\nAnticipaciones:');
for (const [h, text] of Object.entries(predicted)) {
console.log(`En ${h} min: ${text}`);
}
return { E_now, similarity, predicted };
}
module.exports = { introspect };
5.4 Probamos el cerebro
En src/index.js:
const { introspect } = require('./agent/brain');
async function main() {
await introspect();
}
main();
5.5 Agregamos acciones posibles
Podemos definir un archivo /src/agent/actions.js:
function ejecutarAccion(tag) {
const acciones = {
'reorganizar': () => console.log('[ACTION] Reorganizar tareas del día.'),
'descanso': () => console.log('[ACTION] Sugerencia: tomá un break.'),
'focus': () => console.log('[ACTION] Todo en orden, mantener el rumbo.'),
};
if (acciones[tag]) acciones[tag]();
else console.log('[ACTION] Sin acción definida para:', tag);
}
module.exports = { ejecutarAccion };
Y modificar el brain.js para disparar acciones según el análisis:
const { ejecutarAccion } = require('./actions');
if (similarity < 0.7) {
ejecutarAccion('reorganizar');
} else {
ejecutarAccion('focus');
}
5.6 Agregamos log introspectivo
Creamos tabla:
CREATE TABLE introspection_log (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
ts TIMESTAMPTZ DEFAULT now(),
similarity REAL,
action TEXT,
prediction JSONB,
embedding VECTOR(768)
);
Y guardamos el log:
await db.query(
`INSERT INTO introspection_log (similarity, action, prediction, embedding)
VALUES ($1, $2, $3, $4)`,
[similarity, similarity < 0.7 ? 'reorganizar' : 'focus', predicted, E_now]
);
5.7 Reflexión diaria
Podés agregar una función diaria que recorra los introspections y genere un resumen:
- ¿Cuántas veces estuvo alineado?
- ¿Qué predicciones se cumplieron?
- ¿Cuándo debió intervenir y no lo hizo?
Lo dejamos para el capítulo siguiente como desafío.
5.8 Conclusión
Tu agente ahora:
- Se autoevalúa
- Compara su estado con un ideal
- Anticipa y reacciona
- Aprende sobre sí mismo en tiempo real
Capítulo 6 — Memoria evolutiva: reflexionar y aprender de sí mismo
6.1 ¿Por qué necesita memoria a largo plazo?
Hasta ahora el agente tiene:
- Memoria de corto plazo (últimos detalles)
- Predicciones de corto alcance
- Introspección inmediata
Pero no recuerda lo vivido en bloque, ni puede detectar hábitos, errores o logros. La memoria evolutiva permite:
- Consolidar experiencias pasadas
- Detectar tendencias (fatiga recurrente, productividad cíclica)
- Construir un modelo propio de comportamiento
- Ajustar objetivos a largo plazo
6.2 ¿Qué vamos a construir?
- Un sistema de resumen periódico: toma los eventos de un día y genera un embedding resumen.
- Un repositorio de introspecciones pasadas, consultable.
- Un sistema de patrones: busca eventos repetidos, errores o aciertos.
- Una base para el aprendizaje continuo del agente.
6.3 Consolidación diaria: resumen del día
Creamos una nueva tabla:
CREATE TABLE daily_summary (
date DATE PRIMARY KEY,
embedding VECTOR(768),
text TEXT,
stats JSONB
);
Y una función /src/agent/reflection.js:
const db = require('../db');
const { decodeEmbedding } = require('../embeddings/embedder');
async function getDayEmbeddings(date) {
const res = await db.query(
`SELECT embedding FROM detail WHERE ts::date = $1`,
[date]
);
return res.rows.map(r => r.embedding);
}
function averageEmbedding(embeddings) {
const sum = Array(embeddings[0].length).fill(0);
for (const emb of embeddings) {
for (let i = 0; i < emb.length; i++) {
sum[i] += emb[i];
}
}
return sum.map(x => x / embeddings.length);
}
async function summarizeDay(date) {
const embeddings = await getDayEmbeddings(date);
if (embeddings.length === 0) return null;
const summaryEmbedding = averageEmbedding(embeddings);
const description = await decodeEmbedding(summaryEmbedding);
await db.query(
`INSERT INTO daily_summary (date, embedding, text, stats)
VALUES ($1, $2, $3, $4)
ON CONFLICT (date) DO UPDATE SET embedding = EXCLUDED.embedding`,
[date, summaryEmbedding, description, {}]
);
return { date, description };
}
module.exports = { summarizeDay };
6.4 Agregamos resumen automático diario
Podés correrlo con un cron diario tipo:
const { summarizeDay } = require('./agent/reflection');
const { format } = require('date-fns');
async function main() {
const yesterday = format(new Date(Date.now() - 86400000), 'yyyy-MM-dd');
const result = await summarizeDay(yesterday);
console.log('Resumen de ayer:', result?.description || 'Sin datos.');
}
main();
6.5 Análisis de patrones: evolución
Para detectar ciclos, temas recurrentes o patrones de evolución en la información semanal, creamos un módulo específico /src/agent/patterns.js
. Este módulo permite analizar la similitud entre los resúmenes diarios almacenados en la base de datos, apoyándose en representaciones numéricas (embeddings) de esos textos. Abajo se detalla el proceso y cada función relevante.
1. Extracción de resúmenes históricos
La base de datos contiene una tabla llamada daily_summary
, donde cada entrada incluye una fecha (date
), una representación vectorial (embedding
) y el texto resumido (text
).
async function getAllSummaries() {
const res = await db.query(`SELECT date, embedding, text FROM daily_summary ORDER BY date`);
return res.rows;
}
Esta función obtiene todos los resúmenes, ordenados por fecha, permitiendo hacer análisis cronológicos.
2. Cálculo de similitud entre vectores
Para comparar si dos resúmenes son conceptualmente similares, se calcula la similitud coseno entre sus embeddings. Es decir, medir “cuán alineados” son dos textos en el espacio vectorial. Cuanto más cercana a 1 sea la similitud, mayor es el parecido.
function similarity(a, b) {
const dot = a.reduce((sum, val, i) => sum + val * b[i], 0);
const normA = Math.sqrt(a.reduce((sum, x) => sum + x * x, 0));
const normB = Math.sqrt(b.reduce((sum, x) => sum + x * x, 0));
return dot / (normA * normB);
}
- Producto punto: suma de las multiplicaciones elemento a elemento entre dos vectores.
- Norma: magnitud de cada vector.
- Resultado: valor entre -1 (opuesto) y 1 (idénticos). Usamos el valor para decidir si dos resúmenes son “iguales” o muestran el mismo patrón.
3. Identificación de ciclos y patrones recurrentes
Se compara cada resumen con los posteriores para detectar pares con una similitud mayor o igual a un umbral (threshold
), que por defecto es 0.95 (muy parecido). Cada par encontrado se guarda en una lista con su fecha, nivel de similitud y textos asociados.
async function findCycles(threshold = 0.95) {
const summaries = await getAllSummaries();
const cycles = [];
for (let i = 0; i < summaries.length - 1; i++) {
for (let j = i + 1; j < summaries.length; j++) {
const sim = similarity(summaries[i].embedding, summaries[j].embedding);
if (sim >= threshold) {
cycles.push({
date1: summaries[i].date,
date2: summaries[j].date,
similarity: sim.toFixed(3),
summary1: summaries[i].text,
summary2: summaries[j].text,
});
}
}
}
return cycles;
}
¿Qué se obtiene?
- Cada elemento en el array
cycles
señala un potencial ciclo o repetición temática entre dos fechas. - Permite visualizar la evolución de las preocupaciones, desafíos o actividades del equipo a través del tiempo.
4. Exportación del módulo
Se expone la función findCycles
para que otros componentes del sistema puedan consultar los ciclos identificados y desplegarlos, reportar recurrencias o generar alertas de patrones repetidos.
module.exports = { findCycles };
Resumen
Este artefacto permite transformar datos secundarios (resúmenes diarios) en conocimiento estratégico, ayudando a identificar cuándo un problema o tema vuelve a surgir, si existe estancamiento en ciertas tareas, o si hay evolución real en la actividad semanal del equipo.---
6.6 Probamos la evolución
const { findCycles } = require('./agent/patterns');
async function main() {
const results = await findCycles();
console.log('Ciclos encontrados:');
for (const r of results) {
console.log(`[${r.date1}] ≈ [${r.date2}] (${r.similarity})`);
console.log(`→ ${r.summary1}`);
console.log(`→ ${r.summary2}\n`);
}
}
main();
6.7 Aplicaciones concretas
- Detectar que cada lunes el agente está disperso > sugerir rutina fuerte.
- Detectar días pico de atención > mover tareas críticas ahí.
- Ver si tras predicciones fallidas, el estado empeora > ajustar el modelo.
6.8 Próximos pasos opcionales
- Entrenar embeddings propios con feedback supervisado
- Integrar objetivos adaptativos (meta-learning)
- Incorporar emociones o energía como dimensiones latentes
- Aprender de otros agentes (transferencia de memoria)
6.9 Conclusión
Con este capítulo:
- Tu agente ahora recuerda sus días
- Detecta cuándo repite patrones
- Tiene capacidad de evaluación evolutiva
Deja de ser solo reactivo, ahora puede revisarse, ajustar y evolucionar.
Capítulo 7 — Activación total: despliegue y operación del agente
7.1 ¿Qué tenemos?
Durante los capítulos anteriores construimos:
- Percepción multimodal (texto + imágenes → embeddings)
- Memoria secuencial con detalle vinculado
- Inferencia contextual (E_now)
- Predicción de estados futuros
- Evaluación introspectiva
- Reflexión diaria y análisis de patrones
Ahora lo conectamos todo.
7.2 API de control y consulta
Instalamos:
npm install express cors
Creamos /src/api/server.js:
const express = require('express');
const { insertDetail } = require('../memory/detailStore');
const { embedText, embedImage, decodeEmbedding } = require('../embeddings/embedder');
const { buildCurrentState } = require('../inference/contextBuilder');
const { predictTextualFutures } = require('../prediction/predictor');
const { introspect } = require('../agent/brain');
const { summarizeDay } = require('../agent/reflection');
const { findCycles } = require('../agent/patterns');
const app = express();
app.use(express.json());
app.post('/input/text', async (req, res) => {
const { text } = req.body;
const embedding = await embedText(text);
const id = await insertDetail({ embedding, type: 'text', content: text });
res.json({ id });
});
app.get('/state/now', async (_, res) => {
const E_now = await buildCurrentState({});
const description = await decodeEmbedding(E_now);
res.json({ description, embedding: E_now });
});
app.get('/predict', async (_, res) => {
const result = await predictTextualFutures();
res.json(result);
});
app.get('/introspect', async (_, res) => {
const result = await introspect();
res.json(result);
});
app.get('/reflect/:date', async (req, res) => {
const result = await summarizeDay(req.params.date);
res.json(result || { message: 'No data' });
});
app.get('/patterns/cycles', async (_, res) => {
const result = await findCycles();
res.json(result);
});
module.exports = app;
Creamos el lanzador principal: src/index.js:
const app = require('./api/server');
app.listen(3000, () => {
console.log('Agente activo en http://localhost:3000');
});
7.3 CLI para testeo rápido
Creamos /cli.js:
#!/usr/bin/env node
const axios = require('axios');
async function run() {
const arg = process.argv[2];
if (arg === 'estado') {
const res = await axios.get('http://localhost:3000/state/now');
console.log('Estado actual:', res.data.description);
} else if (arg === 'predecir') {
const res = await axios.get('http://localhost:3000/predict');
console.log('Predicciones:');
console.log(res.data);
} else if (arg === 'introspección') {
const res = await axios.get('http://localhost:3000/introspect');
console.log('Introspección:', res.data);
} else {
console.log('Comandos disponibles: estado | predecir | introspección');
}
}
run();
Lo hacemos ejecutable:
chmod +x cli.js
Y lo corrés como:
./cli.js estado
7.4 Despliegue y persistencia
Recomendaciones:
- PM2 o Docker para mantener el proceso activo
- PostgreSQL remoto o RDS
- Agendador diario con cron o node-cron para summarizeDay
- FAISS en modo servidor o faiss-js para vector search
- Monitoreo con Grafana (usando métricas sobre introspection_log)
7.5 Evolución futura del agente
Este sistema es expansible. Ideas:
- Entrenar E_ideal dinámico (autoaprendizaje de propósito)
- Agregar “estados internos” como variables latentes (cansancio, flow)
- Enviar alertas proactivas (email, Slack, etc.)
- Comprimir semanas completas como “memoria episódica”
- Integrar logs de actividad del sistema operativo o tareas del usuario
7.6 Conclusión
Acabás de construir un agente inteligente completo, con:
- Percepción
- Memoria
- Evaluación introspectiva
- Predicción
- Reflexión
- Acción
Capítulo Extra — Integración de herramientas vía MCP: convertir al agente en operador
En este capítulo:
- Explicamos qué es MCP y cómo el agente lo usará como capa de abstracción para interactuar con APIs o aplicaciones.
- Construimos un módulo de MCP Client que:
- Envía queries en formato estructurado
- Recibe respuestas normalizadas
- Ejecuta acciones o decide en base a eso
- Le damos al agente la capacidad de actuar en herramientas externas, como si tuviera dedos.
Te propongo este flujo de integración MCP:
[Estado actual] [Predicción]
│ │
└────┬──────┬────┘
▼ ▼
[Necesidad de acción]
│
┌───────▼────────┐
│ MCP Query │ → ej: "consultar clima" / "crear tarea"
└───────┬────────┘
▼
[MCP Handler] → llama API
│
Respuesta estructurada
▼
Acción / reflexión del agente
Capítulo Extra — Integración de herramientas: el agente como operador via MCP
1. ¿Qué es el Model Context Protocol (MCP)?
El Model Context Protocol (MCP) es un patrón diseñado para estructurar la comunicación entre un agente inteligente (por ejemplo, un sistema basado en IA) y herramientas externas tales como APIs, servicios, plugins o aplicaciones. Su propósito principal es establecer una interfaz clara y robusta que facilite la interacción eficiente entre los agentes y los diferentes módulos o fuentes de información externas.
¿Qué aporta el MCP?
- Formato estandarizado de consulta y respuesta: Define reglas claras sobre cómo se debe estructurar la información que el agente solicita y la que recibe, facilitando la interoperabilidad entre diversos sistemas y módulos, y minimizando errores de interpretación.
- Separación de intención y ejecución: El agente primero expresa su intención (lo que necesita u objetivo), y luego delega la ejecución de las acciones a componentes externos. Esto desacopla la lógica de decisión (del agente) de la lógica de acción (de las herramientas o servicios).
- Compatibilidad total con modelos de lenguaje y pipelines de IA: MCP está concebido desde su origen para integrarse perfectamente con modelos de IA, especialmente modelos de lenguaje, permitiendo que éstos puedan consumir o generar acciones/consultas estructuradas como parte de procesos más amplios.
¿Cómo funciona en la práctica?
En otras palabras, MCP le permite al agente expresar peticiones como:
“Quiero obtener esta información, con estos parámetros, en este formato, y usarla como parte de mi contexto.”
Eso significa que cada interacción entre el agente y sus herramientas externas es completamente trazable, flexible y compatible con flujos de trabajo automatizados y escalables.
2. ¿Cómo se integra en nuestro agente?
Vamos a crear un módulo mcpClient que:
- Recibe un query estructurado (ej: "consultar clima en Buenos Aires").
- Lo convierte en una petición HTTP a una herramienta externa.
- Recibe la respuesta.
- La devuelve como objeto enriquecido listo para insertar en la memoria o usar como input de inferencia.
3. Estructura base del query MCP
Definimos el formato estándar (como JSON):
{
"tool": "weather",
"action": "get_forecast",
"params": {
"location": "Buenos Aires"
},
"format": "structured",
"use_case": "inform_context"
}
4. Diseño del módulo MCP Client
Creamos /src/tools/mcpClient.js:
const axios = require('axios');
const TOOLS = {
weather: {
get_forecast: async (params) => {
const res = await axios.get(`https://wttr.in/${params.location}?format=j1`);
const condition = res.data.current_condition[0];
return {
summary: `El clima en ${params.location} es ${condition.weatherDesc[0].value}, ${condition.temp_C}°C`,
raw: condition
};
}
},
tasks: {
create: async (params) => {
// Simulado: crear una tarea en sistema externo
return {
summary: `Tarea creada: ${params.title}`,
raw: { id: 'mock-1234', ...params }
};
}
}
};
async function handleMCPQuery(query) {
const tool = TOOLS[query.tool];
if (!tool || !tool[query.action]) {
throw new Error('Herramienta o acción desconocida');
}
const result = await tool[query.action](query.params);
return {
format: query.format || 'structured',
context_use: query.use_case || 'inform_context',
...result
};
}
module.exports = { handleMCPQuery };
5. Usamos el agente para operar
Creamos src/index.js:
const { handleMCPQuery } = require('./tools/mcpClient');
async function main() {
const query = {
tool: 'weather',
action: 'get_forecast',
params: { location: 'Buenos Aires' },
format: 'structured',
use_case: 'inform_context'
};
const result = await handleMCPQuery(query);
console.log('Resultado MCP:', result.summary);
}
main();
6. ¿Qué puede hacer el agente ahora?
Ya puede:
- Consultar servicios con un protocolo común
- Recibir respuestas contextuales
- Incorporarlas a su memoria o reflexión
- Tomar decisiones basadas en datos del mundo real
Esto convierte al agente en un verdadero operador contextual, no sólo un observador.
7. ¿Qué sigue?
En la próxima sección de este capítulo:
- Integramos el módulo MCP al flujo introspectivo
- Permitimos que el agente detecte cuándo necesita una herramienta
- Y haga la consulta como parte de su razonamiento automático
Capítulo Extra (Parte 2) — Agente autónomo: detectar, consultar y actuar vía MCP
1. ¿Cuándo debería el agente usar una herramienta?
Durante el proceso de introspección, el agente analiza su estado (E_now), lo compara con el ideal (E_ideal) y anticipa el futuro.
Pero hay momentos en los que:
- Le falta información contextual (ej: clima, calendario)
- Necesita consultar una fuente externa para confirmar una predicción
- Desea ejecutar una acción que va más allá de su memoria
Ejemplo:
Predicción: “Podría llover esta tarde.” → Acción: Consultar herramienta del clima para confirmar y decidir.
2. Integración en el módulo
brain.js
Ampliamos brain.js para incorporar lógica de consulta MCP basada en predicción o estado:
const { buildCurrentState } = require('../inference/contextBuilder');
const { predictTextualFutures } = require('../prediction/predictor');
const { decodeEmbedding } = require('../embeddings/embedder');
const { handleMCPQuery } = require('../tools/mcpClient');
const db = require('../db');
const E_ideal = Array(768).fill(0).map((_, i) => Math.sin(i / 40));
function cosineSimilarity(a, b) {
const dot = a.reduce((sum, val, i) => sum + val * b[i], 0);
const normA = Math.sqrt(a.reduce((sum, x) => sum + x * x, 0));
const normB = Math.sqrt(b.reduce((sum, x) => sum + x * x, 0));
return dot / (normA * normB);
}
async function introspect() {
const E_now = await buildCurrentState({});
const similarity = cosineSimilarity(E_now, E_ideal);
const predicted = await predictTextualFutures();
let extraContext = [];
// Detecta necesidad de herramienta
const needsWeather = Object.values(predicted).some(text =>
text.toLowerCase().includes("lluvia") || text.toLowerCase().includes("clima")
);
if (needsWeather) {
const weatherQuery = {
tool: 'weather',
action: 'get_forecast',
params: { location: 'Buenos Aires' },
format: 'structured',
use_case: 'confirm_prediction'
};
const weatherInfo = await handleMCPQuery(weatherQuery);
extraContext.push(weatherInfo.summary);
}
// Log introspectivo enriquecido
await db.query(
`INSERT INTO introspection_log (similarity, action, prediction, embedding)
VALUES ($1, $2, $3, $4)`,
[
similarity,
similarity < 0.7 ? 'reorganizar' : 'focus',
{ predicted, tools_used: extraContext },
E_now
]
);
return { similarity, predicted, tools_used: extraContext };
}
module.exports = { introspect };
3. Resultado: introspección activa y autónoma
Ahora el agente:
- Predice lo que puede pasar
- Detecta si necesita una herramienta
- Llama esa herramienta (vía MCP)
- La usa como parte de su razonamiento
Ejemplo de salida:
{
"similarity": 0.62,
"predicted": {
"30": "Es probable que llueva a la tarde."
},
"tools_used": [
"El clima en Buenos Aires es Lluvia moderada, 18°C"
]
}
4. Qué podemos extender desde acá
- Hacer que el agente proponga tareas si detecta un evento (ej: “crear recordatorio si llueve”)
- Integrar herramientas como calendar, crm, ERP, base de conocimiento
- Implementar un dispatcher automático de queries cuando la introspección detecta brechas contextuales
Capítulo Extra (Parte 3) — Dispatcher MCP: decisiones dinámicas de integración
1. ¿Qué es el dispatcher MCP?
Es un router inteligente de herramientas: recibe señales (estado, predicciones, metas), interpreta si falta contexto, y decide:
- Qué herramienta usar
- Qué acción ejecutar
- Cómo usar la respuesta
Funciona como una capa de decisión entre el agente y su arsenal de APIs, de forma autónoma.
2. ¿Cómo lo pensás?
El dispatcher:
- Recibe: E_now, predicciones, objetivos opcionales, flags
- Evalúa: ¿necesito una herramienta externa?
- Arma el query MCP
- Llama a handleMCPQuery()
- Devuelve un bloque contextual_enrichment
3. Creamos el módulo
/src/tools/mcpDispatcher.js
const { handleMCPQuery } = require('./mcpClient');
async function decideAndQuery({ predicted, stateDescription }) {
const toolsUsed = [];
// Heurística simple basada en predicción
if (
Object.values(predicted).some(t =>
t.toLowerCase().includes('lluvia') || t.toLowerCase().includes('clima')
)
) {
toolsUsed.push({
tool: 'weather',
action: 'get_forecast',
params: { location: 'Buenos Aires' },
format: 'structured',
use_case: 'confirm_prediction'
});
}
// Ejemplo: si el estado menciona reuniones, usar herramienta de agenda
if (stateDescription.toLowerCase().includes('reunión')) {
toolsUsed.push({
tool: 'calendar',
action: 'list_upcoming',
params: { window_min: 60 },
format: 'structured',
use_case: 'verify_conflict'
});
}
const results = [];
for (const q of toolsUsed) {
try {
const result = await handleMCPQuery(q);
results.push({ tool: q.tool, summary: result.summary });
} catch (e) {
results.push({ tool: q.tool, summary: 'Error de consulta', error: e.message });
}
}
return results;
}
module.exports = { decideAndQuery };
4. Lo conectamos al brain.js
Modificamos el flujo introspectivo:
const { decodeEmbedding } = require('../embeddings/embedder');
const { decideAndQuery } = require('../tools/mcpDispatcher');
async function introspect() {
const E_now = await buildCurrentState({});
const similarity = cosineSimilarity(E_now, E_ideal);
const predicted = await predictTextualFutures();
const stateText = await decodeEmbedding(E_now);
const extraContext = await decideAndQuery({ predicted, stateDescription: stateText });
await db.query(
`INSERT INTO introspection_log (similarity, action, prediction, embedding)
VALUES ($1, $2, $3, $4)`,
[
similarity,
similarity < 0.7 ? 'reorganizar' : 'focus',
{ predicted, tools_used: extraContext },
E_now
]
);
return { similarity, predicted, tools_used: extraContext };
}
5. El resultado
El agente ahora:
- Analiza lo que puede pasar
- Evalúa su estado actual
- Decide si necesita una herramienta
- Ejecuta la acción correcta sin ayuda humana
Ejemplo:
{
"predicted": {
"30": "Es probable que llueva a la tarde.",
"60": "Podrías tener una reunión importante"
},
"tools_used": [
{
"tool": "weather",
"summary": "El clima en Buenos Aires es lluvia ligera, 17°C"
},
{
"tool": "calendar",
"summary": "Reunión con equipo técnico a las 15:00"
}
]
}
Capítulo Extra (Parte 4) — Llevando al siguiente nivel: hacia un agente autoexpandible
1. ¿Qué significa “llevarlo al extremo”?
Significa convertir al agente en algo más que un consumidor de APIs:
- Que razone sobre qué necesita saber o hacer
- Que genere los queries MCP de forma dinámica
- Que aprenda de sus decisiones pasadas
- Que optimice sus interacciones con herramientas externas
- Y que, eventualmente, modifique su propio comportamiento
2. Componente clave: generador de intención MCP
¿Qué haría esto?
A partir de una predicción o estado actual, el agente le pregunta a un modelo LLM:
“¿Qué herramientas debería consultar y con qué parámetros para enriquecer mi contexto actual?”
Implementación conceptual
{
"input": {
"estado_actual": "Baja energía, posible lluvia, reunión inminente",
"predicciones": [
"Lluvia a la tarde",
"Conflicto de calendario"
]
},
"salida esperada": [
{
"tool": "weather",
"action": "get_forecast",
"params": { "location": "Buenos Aires" }
},
{
"tool": "calendar",
"action": "list_upcoming",
"params": { "window_min": 60 }
}
]
}
Cómo implementarlo
- Cargás un prompt preformateado en un LLM (local o remoto)
- Le pasás estado + predicción
- El modelo devuelve un bloque MCP-ready
- Lo ejecutás como siempre
3. Aprendizaje del uso de herramientas
Cada vez que el agente llama a una herramienta:
- Se registra el resultado, éxito o falla
- Se mide su impacto en la introspección (¿mejoró la predicción? ¿resolvió la duda?)
- Se ajusta un ranking interno de confianza o valor
Esto permite, por ejemplo:
- Preferir ciertas herramientas
- Evitar redundancias (“esto ya lo sé”)
- Pedir ayuda sólo cuando vale la pena
4. Optimización de queries
El agente puede:
- Reformular parámetros según contexto (ej: adaptar la ciudad a la geolocalización)
- Elegir el mejor formato de respuesta (structured, natural, raw)
- Ajustar frecuencia de consulta (no volver a consultar lo mismo en intervalos cortos)
Esto se logra con un módulo de control de diálogo interno o historial de acciones (tool_usage_log en PostgreSQL, por ejemplo).
5. Meta-introspección
El agente puede usar su propio log introspectivo para:
- Detectar qué tipo de predicciones fallan seguido
- Saber cuándo usar una herramienta anticipa mejor los eventos
- Identificar errores en su razonamiento y compensar
Ejemplo:
“Cada vez que ignoro el clima, termino sugiriendo tareas afuera que luego son fallidas.” → “Aumentar prioridad de la herramienta weather cuando hay tareas al aire libre.”
6. Multiplicación de agentes
Una vez este sistema funciona:
- Podés clonarlo para otros perfiles (agente de logística, agente financiero, agente emocional)
- Podés crear un agente supervisor que observe múltiples agentes y optimice su coordinación
- Podés permitir que agentes compartan información vía MCP como si fueran módulos entre sí
7. ¿Qué podría venir después?
- Integración con asistentes reales (Siri, Alexa, WhatsApp, Slack)
- Autoedición de su pipeline (el agente se reconfigura)
- Entrenamiento de un modelo de embeddings personalizado con datos históricos del agente
- Visualización gráfica de su línea de tiempo + decisiones
8. En resumen: lo que logramos
Nuestro agente:
- Tiene memoria, predicción, reflexión y acción
- Se conecta a herramientas, pero también decide cuándo y cómo
- Es capaz de evolucionar su contexto
- Puede llevar este poder a cualquier aplicación del mundo real