---
id: ARQUITECTURA-IA-ERP-CORE
title: Arquitectura IA - ERP Core
type: Architecture
status: Published
version: 1.0.0
created_date: 2026-01-10
updated_date: 2026-01-10
---

# Arquitectura IA - ERP Core

> Detalle de la arquitectura de inteligencia artificial

## Resumen

ERP Core implementa una arquitectura de IA que permite integracion con multiples modelos de lenguaje (LLM), herramientas de negocio via MCP, y comunicacion inteligente a traves de WhatsApp.

---

## 1. Diagrama de Arquitectura

```mermaid
graph TB
    subgraph "Clientes"
        WA[WhatsApp]
        WEB[Web Chat]
        MOB[Mobile App]
        API[API REST]
    end

    subgraph "Capa de Orquestacion"
        WAS[WhatsApp Service]
        MCP[MCP Server]
    end

    subgraph "Gateway LLM"
        OR[OpenRouter]
        subgraph "Modelos"
            CL[Claude 3]
            GPT[GPT-4]
            GEM[Gemini]
            MIS[Mistral]
        end
    end

    subgraph "Herramientas MCP"
        T1[Products Tools]
        T2[Inventory Tools]
        T3[Orders Tools]
        T4[Customers Tools]
        T5[Fiados Tools]
    end

    subgraph "Backend"
        BE[Express API]
        PRED[Prediction Service]
    end

    subgraph "Database"
        PG[(PostgreSQL)]
        MSG[messaging schema]
        AI[ai schema]
    end

    WA --> WAS
    WEB --> MCP
    MOB --> MCP
    API --> MCP

    WAS --> MCP
    MCP --> OR
    OR --> CL
    OR --> GPT
    OR --> GEM
    OR --> MIS

    MCP --> T1
    MCP --> T2
    MCP --> T3
    MCP --> T4
    MCP --> T5

    T1 --> BE
    T2 --> BE
    T3 --> BE
    T4 --> BE
    T5 --> BE

    BE --> PG
    WAS --> MSG
    MCP --> AI
    PRED --> PG
```

---

## 2. MCP Server (Model Context Protocol)

### 2.1 Concepto

El MCP Server implementa el protocolo Model Context Protocol de Anthropic, que permite exponer herramientas (tools) de negocio a los modelos de lenguaje de manera estandarizada.

### 2.2 Herramientas Disponibles

#### 2.2.1 Products Tools

```typescript
// Herramientas de productos
const productTools = {
    list_products: {
        description: 'Lista productos filtrados por categoria, nombre o precio',
        parameters: {
            category?: string,
            search?: string,
            min_price?: number,
            max_price?: number,
            limit?: number
        },
        returns: 'Array de productos con id, nombre, precio, stock'
    },

    get_product_details: {
        description: 'Obtiene detalles completos de un producto',
        parameters: {
            product_id: string
        },
        returns: 'Producto con todos sus atributos, variantes y precios'
    },

    check_product_availability: {
        description: 'Verifica si hay stock suficiente de un producto',
        parameters: {
            product_id: string,
            quantity: number
        },
        returns: '{ available: boolean, current_stock: number }'
    }
};
```

#### 2.2.2 Inventory Tools

```typescript
const inventoryTools = {
    check_stock: {
        description: 'Consulta el stock actual de productos',
        parameters: {
            product_ids?: string[],
            warehouse_id?: string
        },
        returns: 'Array de { product_id, quantity, location }'
    },

    get_low_stock_products: {
        description: 'Lista productos que estan por debajo del minimo',
        parameters: {
            threshold?: number
        },
        returns: 'Array de productos con stock bajo'
    },

    record_inventory_movement: {
        description: 'Registra un movimiento de inventario',
        parameters: {
            product_id: string,
            quantity: number,
            movement_type: 'in' | 'out' | 'adjustment',
            reason?: string
        },
        returns: 'Movimiento registrado'
    },

    get_inventory_value: {
        description: 'Calcula el valor total del inventario',
        parameters: {
            warehouse_id?: string
        },
        returns: '{ total_value: number, items_count: number }'
    }
};
```

#### 2.2.3 Orders Tools

```typescript
const orderTools = {
    create_order: {
        description: 'Crea un nuevo pedido',
        parameters: {
            customer_id: string,
            items: Array<{ product_id: string, quantity: number }>,
            payment_method?: string,
            notes?: string
        },
        returns: 'Pedido creado con id y total'
    },

    get_order_status: {
        description: 'Consulta el estado de un pedido',
        parameters: {
            order_id: string
        },
        returns: 'Estado del pedido y detalles'
    },

    update_order_status: {
        description: 'Actualiza el estado de un pedido',
        parameters: {
            order_id: string,
            status: 'pending' | 'confirmed' | 'preparing' | 'ready' | 'delivered' | 'cancelled'
        },
        returns: 'Pedido actualizado'
    }
};
```

#### 2.2.4 Customers Tools

```typescript
const customerTools = {
    search_customers: {
        description: 'Busca clientes por nombre, telefono o email',
        parameters: {
            query: string,
            limit?: number
        },
        returns: 'Array de clientes encontrados'
    },

    get_customer_balance: {
        description: 'Obtiene el saldo actual de un cliente',
        parameters: {
            customer_id: string
        },
        returns: '{ balance: number, credit_limit: number }'
    }
};
```

#### 2.2.5 Fiados Tools (Credito)

```typescript
const fiadoTools = {
    get_fiado_balance: {
        description: 'Consulta el saldo de credito de un cliente',
        parameters: {
            customer_id: string
        },
        returns: '{ balance: number, available_credit: number }'
    },

    create_fiado: {
        description: 'Registra una venta a credito',
        parameters: {
            customer_id: string,
            amount: number,
            order_id?: string,
            description?: string
        },
        returns: 'Registro de fiado creado'
    },

    register_fiado_payment: {
        description: 'Registra un abono a la cuenta de credito',
        parameters: {
            customer_id: string,
            amount: number,
            payment_method?: string
        },
        returns: 'Pago registrado y nuevo saldo'
    },

    check_fiado_eligibility: {
        description: 'Verifica si un cliente puede comprar a credito',
        parameters: {
            customer_id: string,
            amount: number
        },
        returns: '{ eligible: boolean, reason?: string }'
    }
};
```

### 2.3 Recursos MCP

```typescript
const mcpResources = {
    'erp://config/business': {
        description: 'Configuracion del negocio',
        returns: '{ name, address, phone, hours, policies }'
    },

    'erp://catalog/categories': {
        description: 'Categorias de productos',
        returns: 'Array de categorias'
    },

    'erp://inventory/summary': {
        description: 'Resumen de inventario',
        returns: '{ total_products, total_value, low_stock_count }'
    }
};
```

---

## 3. Gateway LLM (OpenRouter)

### 3.1 Arquitectura

```mermaid
graph LR
    APP[Aplicacion] --> OR[OpenRouter API]
    OR --> |"Route"| M1[Claude 3 Haiku]
    OR --> |"Route"| M2[Claude 3 Sonnet]
    OR --> |"Route"| M3[GPT-4o-mini]
    OR --> |"Route"| M4[GPT-3.5 Turbo]
    OR --> |"Route"| M5[Mistral 7B]
    OR --> |"Route"| M6[Llama 3]
```

### 3.2 Modelos Soportados

| Modelo | ID | Input/1M | Output/1M | Uso Recomendado |
|--------|----|---------:|----------:|-----------------|
| Claude 3 Haiku | anthropic/claude-3-haiku | $0.25 | $1.25 | Default (rapido) |
| Claude 3 Sonnet | anthropic/claude-3-sonnet | $3.00 | $15.00 | Premium |
| GPT-4o-mini | openai/gpt-4o-mini | $0.15 | $0.60 | Fallback economico |
| GPT-3.5 Turbo | openai/gpt-3.5-turbo | $0.50 | $1.50 | Fallback |
| Mistral 7B | mistralai/mistral-7b | $0.06 | $0.06 | Ultra-economico |
| Llama 3 | meta-llama/llama-3-8b | $0.20 | $0.20 | Open source |

### 3.3 Configuracion por Tenant

```typescript
interface TenantLLMConfig {
    provider: 'openrouter' | 'openai' | 'anthropic' | 'ollama';
    api_key: string; // encriptada
    model: string;
    max_tokens: number;
    temperature: number;
    system_prompt: string;
}

// Ejemplo de configuracion
const config: TenantLLMConfig = {
    provider: 'openrouter',
    api_key: 'sk-or-v1-...',
    model: 'anthropic/claude-3-haiku',
    max_tokens: 1000,
    temperature: 0.7,
    system_prompt: 'Eres un asistente de ventas amigable...'
};
```

### 3.4 Estrategia de Fallback

```typescript
async function callLLM(messages: Message[]): Promise<Response> {
    const models = [
        config.model,           // Modelo preferido del tenant
        'anthropic/claude-3-haiku',  // Fallback 1
        'openai/gpt-3.5-turbo'       // Fallback 2
    ];

    for (const model of models) {
        try {
            const response = await openrouter.chat({
                model,
                messages,
                max_tokens: config.max_tokens,
                temperature: config.temperature
            });
            return response;
        } catch (error) {
            if (error.code === 'rate_limit_exceeded') {
                continue; // Intentar siguiente modelo
            }
            throw error;
        }
    }

    // Si todos fallan, respuesta predefinida
    return { content: 'Lo siento, no puedo procesar tu solicitud ahora.' };
}
```

### 3.5 Tracking de Tokens

```sql
-- Schema: ai

CREATE TABLE ai.configs (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id UUID NOT NULL REFERENCES tenants.tenants(id),
    provider VARCHAR(20) NOT NULL,
    model VARCHAR(100) NOT NULL,
    temperature DECIMAL(3,2) DEFAULT 0.7,
    max_tokens INTEGER DEFAULT 1000,
    system_prompt TEXT,
    is_active BOOLEAN DEFAULT true,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE ai.usage (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id UUID NOT NULL,
    model VARCHAR(100) NOT NULL,
    operation VARCHAR(50), -- chat, completion, embedding
    input_tokens INTEGER NOT NULL,
    output_tokens INTEGER NOT NULL,
    cost_usd DECIMAL(10,6),
    latency_ms INTEGER,
    success BOOLEAN DEFAULT true,
    error_message TEXT,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Indice para reportes de uso
CREATE INDEX idx_ai_usage_tenant_date
    ON ai.usage(tenant_id, created_at DESC);
```

---

## 4. WhatsApp Service con IA

### 4.1 Flujo de Mensaje

```mermaid
sequenceDiagram
    participant C as Cliente
    participant WA as WhatsApp
    participant META as Meta API
    participant WS as WhatsApp Service
    participant LLM as LLM Service
    participant MCP as MCP Server
    participant BE as Backend

    C->>WA: Envia mensaje
    WA->>META: Webhook
    META->>WS: POST /webhook
    WS->>WS: Verificar firma
    WS->>WS: Extraer tenant
    WS->>LLM: Procesar mensaje
    LLM->>LLM: Cargar contexto
    LLM->>MCP: Llamar con tools

    alt Necesita datos
        MCP->>BE: Ejecutar tool
        BE-->>MCP: Resultado
    end

    MCP-->>LLM: Respuesta con datos
    LLM-->>WS: Texto de respuesta
    WS->>META: Enviar mensaje
    META->>WA: Entrega
    WA->>C: Muestra mensaje
```

### 4.2 Tipos de Mensaje Soportados

#### Entrantes

| Tipo | Descripcion | Procesamiento |
|------|-------------|---------------|
| text | Texto simple | Directo a LLM |
| audio | Nota de voz | Whisper -> LLM |
| image | Imagen | Vision/OCR -> LLM |
| location | Ubicacion | Extraer coords -> LLM |
| interactive | Respuesta de botones | Mapear a accion |

#### Salientes

| Tipo | Uso |
|------|-----|
| text | Respuestas de texto |
| template | Templates pre-aprobados |
| interactive | Botones o listas |
| media | Imagenes, documentos |

### 4.3 Contexto de Conversacion

```typescript
interface ConversationContext {
    tenant_id: string;
    customer_id?: string;
    customer_name: string;
    phone_number: string;
    history: Message[]; // Ultimos 20 mensajes
    pending_action?: string;
    cart?: CartItem[];
}

// Sistema mantiene contexto por 30 minutos de inactividad
```

### 4.4 System Prompts

#### Para Clientes

```
Eres el asistente virtual de {{BUSINESS_NAME}},
una tienda de barrio en Mexico.

Ayudas a los clientes con:
- Informacion sobre productos y precios
- Hacer pedidos
- Consultar su cuenta de fiado
- Estado de sus pedidos

Reglas:
1. Responde en espanol mexicano casual y amigable
2. Se breve pero calido
3. Nunca inventes precios, usa las herramientas
4. Para fiados, siempre verifica primero el saldo
5. Se proactivo sugiriendo opciones
```

#### Para Duenos

```
Eres el asistente de negocios de {{BUSINESS_NAME}}.

Ayudas al dueno con:
- Analisis de ventas y tendencias
- Gestion de inventario
- Recordatorios de cobranza
- Sugerencias de negocio

Se directo, profesional y accionable.
Proporciona numeros concretos siempre.
Sugiere acciones si detectas problemas.
```

---

## 5. Prediccion de Inventario

### 5.1 Algoritmo de Demanda

```typescript
// Promedio movil ponderado (4 semanas)
function predictDemand(salesHistory: WeeklySales[]): number {
    const weights = [0.40, 0.30, 0.20, 0.10];

    // Ultimas 4 semanas
    const recentWeeks = salesHistory.slice(-4).reverse();

    let weightedSum = 0;
    for (let i = 0; i < weights.length; i++) {
        weightedSum += (recentWeeks[i]?.quantity ?? 0) * weights[i];
    }

    return Math.ceil(weightedSum);
}
```

### 5.2 Punto de Reorden

```typescript
function calculateReorderPoint(
    dailyDemand: number,
    leadTimeDays: number = 3,
    safetyStockDays: number = 2
): number {
    const safetyStock = dailyDemand * safetyStockDays;
    const reorderPoint = (dailyDemand * leadTimeDays) + safetyStock;
    return Math.ceil(reorderPoint);
}

// Ejemplo:
// dailyDemand = 10 unidades/dia
// leadTime = 3 dias
// safetyStock = 10 * 2 = 20 unidades
// reorderPoint = (10 * 3) + 20 = 50 unidades
```

### 5.3 Dias de Inventario

```typescript
function daysOfInventory(currentStock: number, dailyDemand: number): number {
    if (dailyDemand === 0) return Infinity;
    return Math.floor(currentStock / dailyDemand);
}

// Alertas
// < 3 dias: CRITICO
// < 7 dias: BAJO
// > 30 dias: EXCESO
```

### 5.4 Endpoints de Prediccion

```typescript
// GET /inventory/predictions
{
    products: [
        {
            product_id: 'uuid',
            name: 'Coca-Cola 600ml',
            current_stock: 24,
            predicted_weekly_demand: 50,
            reorder_point: 30,
            days_of_inventory: 3.4,
            suggested_order: 50,
            urgency: 'HIGH'
        }
    ]
}

// GET /inventory/low-stock
{
    products: [
        {
            product_id: 'uuid',
            name: 'Coca-Cola 600ml',
            current_stock: 5,
            minimum_stock: 20,
            shortage: 15
        }
    ]
}

// GET /inventory/slow-moving
{
    products: [
        {
            product_id: 'uuid',
            name: 'Cafe Premium',
            current_stock: 10,
            days_without_sale: 45,
            last_sale_date: '2025-11-25'
        }
    ]
}
```

---

## 6. Modelo de Datos IA

### 6.1 Schema: messaging

```sql
CREATE TABLE messaging.conversations (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id UUID NOT NULL,
    phone_number VARCHAR(20) NOT NULL,
    contact_name VARCHAR(100),
    conversation_type VARCHAR(20) DEFAULT 'general',
    status VARCHAR(20) DEFAULT 'active',
    last_message_at TIMESTAMPTZ,
    last_message_preview TEXT,
    unread_count INTEGER DEFAULT 0,
    wa_conversation_id VARCHAR(100),
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE messaging.messages (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    conversation_id UUID NOT NULL REFERENCES messaging.conversations(id),
    direction VARCHAR(10) NOT NULL, -- in, out
    message_type VARCHAR(20) NOT NULL, -- text, audio, image, template
    content TEXT,
    media_url TEXT,
    media_mime_type VARCHAR(50),

    -- IA Processing
    processed_by_llm BOOLEAN DEFAULT false,
    llm_model VARCHAR(100),
    tokens_used INTEGER,
    tool_calls JSONB,

    -- WhatsApp
    wa_message_id VARCHAR(100),
    wa_status VARCHAR(20), -- sent, delivered, read, failed
    wa_timestamp TIMESTAMPTZ,

    created_at TIMESTAMPTZ DEFAULT NOW()
);
```

### 6.2 Indices

```sql
-- Busqueda rapida de conversaciones
CREATE INDEX idx_conversations_tenant_phone
    ON messaging.conversations(tenant_id, phone_number);

CREATE INDEX idx_conversations_last_message
    ON messaging.conversations(tenant_id, last_message_at DESC);

-- Busqueda de mensajes
CREATE INDEX idx_messages_conversation
    ON messaging.messages(conversation_id, created_at DESC);
```

---

## 7. Patrones de Extension IA

### 7.1 Agregar Herramientas MCP

```typescript
// En vertical: erp-construccion

// Registrar herramientas adicionales
mcpServer.registerTool('construction.get_budget', {
    description: 'Obtiene presupuesto de construccion',
    parameters: {
        budget_id: { type: 'string', required: true }
    },
    handler: async ({ budget_id }) => {
        return constructionService.getBudget(budget_id);
    }
});

mcpServer.registerTool('construction.estimate_materials', {
    description: 'Estima materiales para un proyecto',
    parameters: {
        area_m2: { type: 'number', required: true },
        project_type: { type: 'string', required: true }
    },
    handler: async ({ area_m2, project_type }) => {
        return constructionService.estimateMaterials(area_m2, project_type);
    }
});
```

### 7.2 System Prompts por Vertical

```typescript
// Configuracion por vertical
const systemPrompts = {
    'erp-core': 'Eres un asistente de negocios general...',
    'erp-construccion': 'Eres un asistente especializado en construccion...',
    'erp-retail': 'Eres un asistente de punto de venta...'
};
```

### 7.3 Modelos por Caso de Uso

```typescript
// Diferentes modelos para diferentes tareas
const modelConfig = {
    chat_simple: 'anthropic/claude-3-haiku',      // Rapido y economico
    chat_complex: 'anthropic/claude-3-sonnet',   // Alta calidad
    analysis: 'openai/gpt-4o',                    // Analisis profundo
    embedding: 'openai/text-embedding-3-small'   // Embeddings
};
```

---

## 8. Seguridad IA

### 8.1 Checklist

- [ ] API keys encriptadas en base de datos
- [ ] Rate limiting por tenant
- [ ] Limite de tokens por request
- [ ] Logs de todas las llamadas LLM
- [ ] Sanitizacion de inputs
- [ ] No exponer datos sensibles a LLM

### 8.2 Rate Limiting

```typescript
// Limites por plan
const rateLimits = {
    free: { tokensPerDay: 1000, requestsPerMinute: 5 },
    starter: { tokensPerDay: 10000, requestsPerMinute: 20 },
    pro: { tokensPerDay: 100000, requestsPerMinute: 60 },
    enterprise: { tokensPerDay: -1, requestsPerMinute: 200 }
};
```

---

## Referencias

- [VISION-ERP-CORE.md](VISION-ERP-CORE.md) - Vision general
- [INTEGRACIONES-EXTERNAS.md](INTEGRACIONES-EXTERNAS.md) - Integraciones
- [Anthropic MCP](https://github.com/anthropics/anthropic-cookbook) - Documentacion MCP
- [OpenRouter](https://openrouter.ai/docs) - Documentacion API

---

*Actualizado: 2026-01-10*
