Cocinar con DiSE (Parte 4): Sistemas de construcción que aprenden, adaptan y evolucionan (Español (Spanish))

Cocinar con DiSE (Parte 4): Sistemas de construcción que aprenden, adaptan y evolucionan

Monday, 08 December 2025

//

16 minute read

La mayoría de las arquitecturas de software asumen que el sistema es estático. DiSE asume que el sistema está vivo.

Nota: Esta es la Parte 4 de la serie "Cocinar con DiSE". Parte 1, Parte 2: Aprendizajes graduados, y Parte 3: Dioses no confiables Este artículo es el resumen arquitectónico - y ahora tenemos una implementación C# de trabajo: mayormente lucid.botdetection.

Concepto clave: Enrutamiento conductual. Esta arquitectura permite una nueva categoría - donde "equipos" transparentes y ajustables de detectores y sistemas de aprendizaje recorren el tráfico reflexivamente basado en patrones de comportamiento aprendidos, no en reglas estáticas. YARP Gateway, los robots nunca llegan a tu motor. O utiliza el middleware para crear un enrutamiento de comportamiento directamente en tu capa de aplicación.

El problema: los sistemas estáticos en un mundo dinámico

Durante años, hemos construido software como relojería: entradas, salidas, reglas, tuberías, pruebas, despliegues, todo lineal, todo predecible.

Pero los sistemas modernos - especialmente los reforzados con IA - ya no se comportan como relojes. Se comportan como ecosistemas:

  • Los atacantes evolucionan sus técnicas
  • Los usuarios cambian su comportamiento
  • Las necesidades varían con el tiempo
  • El medio ambiente cambia constantemente

Arquitecturas estáticas no pueden mantenerse al día, parcheas un hoyo, tres más aparecen, sintonizas un umbral, algo más se rompe, siempre reaccionas, nunca te adaptas.

DiSE Architecture (Directed Synthetic Evolution) trata el software de la manera en que los biólogos tratan a los organismos: como algo que debe adaptarse, autocorregirse y mejorar bajo presión.

La idea central: los sistemas como organismos en evolución

Arquitectura tradicional:

flowchart LR
    B[Build] --> S[Ship] --> P[Patch] --> B

    style B stroke:#6366f1,stroke-width:2px
    style P stroke:#ef4444,stroke-width:2px

Arquitectura DiSE:

flowchart LR
    P[Perceive] --> E[Evaluate] --> M[Mutate] --> S[Select] --> P

    style P stroke:#10b981,stroke-width:2px
    style M stroke:#f59e0b,stroke-width:2px
    style S stroke:#6366f1,stroke-width:2px

Un sistema DiSE tiene cuatro comportamientos esenciales:

Comportamiento # # Lo que hace # # Equivalente Biológico

|-----------|--------------|----------------------| | Percibir Recoger señales del ambiente Órganos sensoriales | Evaluar Señales de puntuación contra objetivos Sistema nervioso | Mutar Generar variantes de estrategias Mutaciones genéticas | Seleccionar Mantenga lo que funciona, descarte lo que no lo hace Selección natural

Esto no es metáfora, es literalmente la forma en que tu sistema evoluciona comportamientos más inteligentes con el tiempo.

Un ejemplo concreto: Detección de bots

mayormente lucid.botdetection es la primera implementación C# de los principios DiSE. Rastreemos la arquitectura:

Percepción: La arquitectura de pizarra

El sistema utiliza un orquestador de pizarra - los detectores aportan evidencia a un estado compartido, desencadenando otros detectores a medida que las señales se acumulan:

// Detectors emit contributions (evidence), not verdicts
public sealed record DetectionContribution
{
    public required string DetectorName { get; init; }
    public required string Category { get; init; }

    // Positive = bot signal, Negative = human signal
    public required double ConfidenceDelta { get; init; }
    public double Weight { get; init; } = 1.0;

    public required string Reason { get; init; }
    public BotType? BotType { get; init; }

    // Signals for triggering other detectors
    public ImmutableDictionary<string, object> Signals { get; init; }
}

Múltiples detectores funcionan en ondas paralelas. Cada uno aporta una pieza de evidencia. El sistema percibe el medio ambiente a través de muchos lentes:

// Wave 0: All detectors with no trigger conditions run in parallel
// Wave N: Detectors whose triggers are now satisfied run in parallel
while (waveNumber < MaxWaves && !cancellationToken.IsCancellationRequested)
{
    var readyDetectors = availableDetectors
        .Where(d => !ranDetectors.Contains(d.Name))
        .Where(d => CanRun(d, state.Signals))
        .ToList();

    await ExecuteWaveAsync(readyDetectors, state, aggregator, ...);

    // Check for early exit on high confidence
    if (aggregator.ShouldEarlyExit)
        break;
}

Evaluación: Consenso ponderado con Sigmoid

La evidencia se agrega en una decisión utilizando la transformación sigmoide - esto aprovecha adecuadamente las señales fuertes de los detectores de alto peso:

private (double botProbability, double confidence) CalculateWeightedScore()
{
    var weighted = _contributions
        .Where(c => c.Weight > 0)
        .Select(c => (delta: c.ConfidenceDelta, weight: c.Weight))
        .ToList();

    var weightedSum = weighted.Sum(w => w.delta * w.weight);

    // Sigmoid maps any real number to (0, 1)
    // Strong human signal (-3) → ~5% bot probability
    // Neutral (0) → 50% bot probability
    // Strong bot signal (+3) → ~95% bot probability
    var botProbability = 1.0 / (1.0 + Math.Exp(-weightedSum));

    return (botProbability, confidence);
}

La evaluación no es un solo modelo para tomar una decisión. consenso ponderado a través de múltiples detectores especializados - y crucialmente, cuando la IA no ha funcionado, la probabilidad es sujetados para evitar el exceso de confianza:

// CRITICAL: Clamp probability when AI hasn't run
var botProbability = aiRan
    ? rawBotProbability
    : Math.Clamp(rawBotProbability, 0.20, 0.80);

Salida Temprana: Optimización del Camino Rápido

El sistema no siempre ejecuta todos los detectores.

// Early exit on verified bots (good or bad)
public static DetectionContribution VerifiedGoodBot(
    string detector, string botName, string reason) => new()
{
    DetectorName = detector,
    Category = "Verification",
    ConfidenceDelta = 0,
    TriggerEarlyExit = true,
    EarlyExitVerdict = EarlyExitVerdict.VerifiedGoodBot
};

En producción, las solicitudes de alta confianza salen en menos de 10 ms Después de 2-3 detectores están de acuerdo. La tubería completa sólo funciona para casos inciertos.

Interruptores de circuitos: autocuración

Los detectores pueden fallar. El sistema se protege a sí mismo:

// Circuit breaker per detector
private void RecordFailure(string detectorName)
{
    var state = _circuitStates.GetOrAdd(detectorName, _ => new CircuitState());
    state.FailureCount++;
    state.LastFailure = DateTimeOffset.UtcNow;

    if (state.FailureCount >= CircuitBreakerThreshold)
    {
        state.State = CircuitBreakerState.Open;
        // Detector disabled until reset time passes
    }
}

Los detectores fallidos se deshabilitan temporalmente. Después de un enfriamiento, se vuelven a probar (estado semiabierto). presión de selección a nivel de la infraestructura.

Mutación: El sistema de aprendizaje

Cuando el sistema detecta con alta confianza, aprende publicando en el bus del evento de aprendizaje:

private void PublishLearningEvent(AggregatedEvidence result, ...)
{
    var eventType = result.BotProbability >= 0.8
        ? LearningEventType.HighConfidenceDetection
        : LearningEventType.FullDetection;

    _learningBus.TryPublish(new LearningEvent
    {
        Type = eventType,
        Confidence = result.Confidence,
        Label = result.BotProbability >= 0.5,
        Metadata = new Dictionary<string, object>
        {
            ["botProbability"] = result.BotProbability,
            ["categoryBreakdown"] = result.CategoryBreakdown,
            ["contributingDetectors"] = result.ContributingDetectors
        }
    });
}

Esto se alimenta en la tienda de pesas, actualizando los pesos aprendidos del detector heurístico con el tiempo.

La pila cognitiva

En lugar de un solo "cerebro AI", DiSE utiliza cognición en capas:

flowchart TB
    subgraph Fast["Fast Path (< 100ms)"]
        H[Static Heuristics]
        D[Detectors]
        ML[Learned Heuristic Model]
    end

    subgraph Slow["Slow Path (Async)"]
        LLM[Ollama LLM]
    end

    subgraph Learn["Learning Layer"]
        W[Weight Store]
        Rep[Reputation]
    end

    Fast --> |escalate uncertain| Slow
    Slow --> |label| Learn
    Learn --> |update weights| Fast

    style Fast stroke:#10b981,stroke-width:2px
    style Slow stroke:#6366f1,stroke-width:2px
    style Learn stroke:#f59e0b,stroke-width:2px

Capa # # Velocidad # # Propósito # # Ejemplo de detección de bots

|-------|-------|---------|----------------------| | Heurística estática <1ms Respuestas instintivas Patrones de UA de bot conocidos | Detectores <10ms Observación del rasgo Análisis del encabezado, comprobaciones del IP | Heurística aprendida 1-5ms Clasificación dinámica Regresión logística con pesos aprendidos | LLM 50-500ms Razonamiento profundo Analizar patrones novedosos | Aprendizaje Antecedentes Formación de memoria Actualizaciones de peso, cambios de reputación

La visión clave: el sistema aprende sus propios pesos en tiempo real. No se requieren modelos externos de ML. El detector heurístico comienza con valores predeterminados sensibles y evoluciona basado en la retroalimentación de detección.

Futuro: Los modelos ONNX con RAG e incrustación están planeados para v2. La producción actual del modelo heurístico sirve como datos de entrenamiento etiquetados para futuros entrenamientos de modelos. La arquitectura ya tiene los artefactos "genéticos" (contribuciones, pesos, señales) que hacen que la adición directa de la evolución sintética - está diseñada como un punto de plugin.

Esto refleja la cognición biológica:

  • Sistema inmunitario innato → Heurística estática
  • Sistema inmunológico adaptativo → Modelo heurístico aprendido
  • Células de memoria → Tienda de pesas + reputación

El detector heurístico: aprendizaje sin modelos externos

Aquí está el bit inteligente. En lugar de enviar un modelo ML externo, el sistema aprende su propio clasificador usando regresión logística simple con extracción dinámica de características:

public class HeuristicDetector : IDetector
{
    // Default weights - sensible starting points
    private static readonly Dictionary<string, float> DefaultWeights = new()
    {
        // Human-like patterns (negative = more likely human)
        ["hdr:accept-language"] = -0.6f,
        ["hdr:referer"] = -0.4f,
        ["fp:received"] = -0.7f,      // Fingerprint = strong human signal
        ["fp:legitimate"] = -0.8f,

        // Bot indicators (positive = more likely bot)
        ["ua:contains_bot"] = 0.9f,
        ["ua:headless"] = 0.8f,
        ["ua:selenium"] = 0.7f,
        ["ua:curl"] = 0.6f,
        ["accept:wildcard"] = 0.4f,
    };

    private (bool IsBot, double Probability) RunInference(Dictionary<string, float> features)
    {
        // Simple linear model: score = bias + Σ(feature * weight)
        float score = _bias;

        foreach (var (featureName, featureValue) in features)
        {
            var weight = _weights.TryGetValue(featureName, out var w)
                ? w
                : DefaultNewFeatureWeight;
            score += featureValue * weight;
        }

        // Sigmoid gives us probability
        var probability = 1.0 / (1.0 + Math.Exp(-score));
        return (probability > 0.5, probability);
    }
}

Las características se extraen dinámicamente de la solicitud y de las pruebas agregadas:

public static class HeuristicFeatureExtractor
{
    public static Dictionary<string, float> ExtractFeatures(
        HttpContext context,
        AggregatedEvidence evidence)
    {
        var features = new Dictionary<string, float>();

        // Request metadata
        features["req:header_count"] = Math.Min(headers.Count / 20f, 1f);
        features["req:cookie_count"] = Math.Min(cookies.Count / 10f, 1f);

        // Header presence
        features["hdr:accept-language"] = headers.ContainsKey("Accept-Language") ? 1f : 0f;

        // UA patterns (dynamic - only present if detected)
        if (ua.Contains("bot")) features["ua:contains_bot"] = 1f;
        if (ua.Contains("selenium")) features["ua:selenium"] = 1f;

        // Detector results (named by actual detector)
        foreach (var contrib in evidence.Contributions)
            features[$"det:{contrib.DetectorName}"] = contrib.ConfidenceDelta;

        // Client-side fingerprint - STRONG human signal
        if (hasFingerprint)
        {
            features["fp:received"] = 1f;
            features["fp:legitimate"] = 1f;
        }

        return features;
    }
}

Las nuevas características automáticamente obtienen pesos predeterminados y aprenden con el tiempo. El sistema descubre lo que importa.

El Almacén de Pesos: Aprendizaje Persistente

Los pesos persisten en SQLite y se actualizan a través de un promedio móvil exponencial:

public class SqliteWeightStore : IWeightStore
{
    public async Task RecordObservationAsync(
        string signatureType,
        string signature,
        bool wasBot,
        double detectionConfidence,
        CancellationToken ct = default)
    {
        // EMA update: weight = weight * (1 - α) + new_value * α
        var alpha = 0.1; // Learning rate
        var weightDelta = wasBot ? detectionConfidence : -detectionConfidence;

        var sql = @"
            INSERT INTO learned_weights (signature_type, signature, weight, ...)
            VALUES (@type, @sig, @delta, ...)
            ON CONFLICT(signature_type, signature) DO UPDATE SET
                weight = weight * (1 - @alpha) + @delta * @alpha,
                confidence = MIN(1.0, confidence + @conf * 0.01),
                observation_count = observation_count + 1,
                last_seen = @now
        ";

        await ExecuteAsync(sql, ...);
    }
}

Esto es mutación a través de la observación. Cada detección enseña al sistema algo. Con el tiempo, los pesos convergen hacia valores óptimos para sus patrones de tráfico específicos.

Alucinación como mutación

En DiSE, la alucinación LLM no es un insecto, es el sustrato generativo de la evolución.

Un LLM de alta temperatura que propone diez variantes de una regla de detección no es "alucinante" - es mutar el genoma del sistema:

public async Task<List<DetectionRule>> GenerateMutationsAsync(DetectionContext context)
{
    var prompt = $"""
        Given this traffic pattern:
        {JsonSerializer.Serialize(context)}

        Generate 5 variant detection rules that might catch similar patterns.
        Return JSON array of rules with: pattern, weight, confidence.
        Be creative. Some variants should be strict, some lenient.
        """;

    var response = await _ollama.GenerateAsync(new GenerateRequest
    {
        Model = "gemma3:1b",
        Prompt = prompt,
        Options = new RequestOptions { Temperature = 0.9 } // High creativity
    });

    return ParseRules(response.Response);
}

Las mutaciones se evalúan a partir de los datos históricos:

public async Task<DetectionRule?> SelectFittestAsync(
    List<DetectionRule> mutations,
    List<LabeledRequest> testData)
{
    var results = new List<(DetectionRule Rule, double Fitness)>();

    foreach (var rule in mutations)
    {
        var tp = testData.Count(r => rule.Matches(r) && r.IsBot);
        var fp = testData.Count(r => rule.Matches(r) && !r.IsBot);
        var fn = testData.Count(r => !rule.Matches(r) && r.IsBot);

        // F1 score as fitness
        var precision = tp / (double)(tp + fp);
        var recall = tp / (double)(tp + fn);
        var f1 = 2 * (precision * recall) / (precision + recall);

        results.Add((rule, f1));
    }

    return results.OrderByDescending(r => r.Fitness).First().Rule;
}

Sólo el más apto sobrevive a la producción. Esto transforma LLMs de chatbots quebradizos en operadores evolutivos.

El genoma: configuración basada en políticas

En el centro de DiSE se encuentra la sistema de políticas - configuraciones nombradas que definen cómo se comporta la detección:

{
  "Policies": {
    "fastpath": {
      "Description": "Fast path + Heuristic for sync decisions",
      "FastPath": ["UserAgent", "Header", "Ip", "Behavioral", "ClientSide", "Inconsistency", "VersionAge"],
      "AiPath": ["Heuristic"],
      "EscalateToAi": true,
      "EarlyExitThreshold": 0.15,
      "ImmediateBlockThreshold": 0.90,
      "Weights": {
        "ClientSide": 0.2,
        "Heuristic": 1.5
      },
      "Transitions": [
        { "WhenRiskExceeds": 0.5, "WhenRiskBelow": 0.85, "GoTo": "demo" }
      ]
    },
    "demo": {
      "Description": "Full pipeline sync for demonstration",
      "FastPath": [],
      "AiPath": [],
      "BypassTriggerConditions": true,
      "ForceSlowPath": true
    }
  }
}

Las políticas definen:

  • Detectores FastPath - ejecutar en paralelo, sub-10ms
  • Ruta de la IA - Heurística (1-5ms) y/o LLM (500ms+)
  • Umbrales - cuando salir temprano, cuando bloquear
  • Transiciones - Recrudecimiento automático de otras políticas cuando es incierto
  • ponderaciones por políticas - Afinar la importancia del detector por caso de uso

El sistema puede transición entre las políticas solicitud intermedia. Inciertos resultados fastpath escalar a la totalidad de la tubería de demostración. Esto es encaminamiento adaptativo - el genoma responde a la evidencia en tiempo real.

No envías configuraciones estáticas. especies conductuales que se adaptan al tráfico.

Funciones de fitness: Lo que sobrevive

Cada sistema DiSE optimiza contra un paisaje de fitness:

public class FitnessEvaluator
{
    public double Evaluate(GenomeConfig genome, EvaluationData data)
    {
        var fpRate = data.FalsePositives / (double)data.TotalHumans;
        var fnRate = data.FalseNegatives / (double)data.TotalBots;
        var latency = data.P99LatencyMs;
        var cost = data.AiCallsPerRequest * _config.CostPerAiCall;

        // Multi-objective fitness
        return 1.0
            - (fpRate * _config.FalsePositivePenalty)   // Don't block humans
            - (fnRate * _config.FalseNegativePenalty)   // Don't miss bots
            - (latency / _config.MaxLatencyMs)          // Stay fast
            - (cost / _config.MaxCostPerRequest);       // Stay cheap
    }
}

No estamos optimizando solo para la precisión. supervivencia en un entorno dinámico.

Demasiada IA → alto costo, mala latencia. Muy poca IA → mala detección de nuevos ataques. Demasiado agresivo → falsos positivos, usuarios enojados. Demasiado indulgente → inundaciones de bot.

El sistema debe encontrar un equilibrio estable. La presión impulsa la evolución.

AI como profesor, no como trabajador

Un sistema DiSE maduro desplaza la IA fuera del camino caliente:

flowchart TB
    subgraph Early["Early Stage"]
        AI1[AI handles most cases]
    end

    subgraph Middle["Middle Stage"]
        AI2[AI handles edge cases]
        H1[Heuristics handle common cases]
    end

    subgraph Mature["Mature Stage"]
        AI3[AI teaches and mutates]
        H2[Heuristics handle almost everything]
        M[Memory provides context]
    end

    Early --> Middle --> Mature

    style Early stroke:#ef4444,stroke-width:2px
    style Middle stroke:#f59e0b,stroke-width:2px
    style Mature stroke:#10b981,stroke-width:2px

Con el tiempo:

  • Los detectores estáticos mejoran (entrenados por etiquetas de IA)
  • Heurística obtener más precisa (seleccionado por la aptitud)
  • La IA sólo maneja la novedad y la mutación

AI se convierte en:

  • Los oráculo para comportamientos novedosos
  • Los generador de mutaciones
  • Los detector de deriva
  • Los profesor que etiqueta casos limítrofes

No es una dependencia de tiempo de ejecución, andamios adaptativos.

Enrutamiento conductual: Una nueva categoría

Con el YARP Gateway, esta arquitectura permite algo nuevo: Encaminamiento conductual.

El enrutamiento tradicional es estático: ruta → motor. El enrutamiento conductual es reflexivo: características del tráfico → decisiones de enrutamiento dinámico.

flowchart LR
    subgraph Gateway["YARP Gateway"]
        D[Detector Team]
        P[Policy Engine]
        R[Router]
    end

    Traffic[Traffic] --> D
    D --> P
    P --> R
    R -->|Human| App[Your App]
    R -->|Bot| Block[403]
    R -->|Uncertain| Challenge[Challenge]
    R -->|Learning| Queue[Async Analysis]

    style Gateway stroke:#10b981,stroke-width:2px

Los conceptos clave:

  • Equipos detectores - grupos configurables de detectores que trabajan juntos, ajustables por política
  • Decisiones transparentes - cada decisión de enrutamiento es explicable (ver el desglose de la contribución)
  • Ajuste reflexivo - el sistema aprende de sus decisiones y ajusta los pesos con el tiempo
  • Protección a nivel de borde - los bots nunca llegan a tu motor; bloqueados en el router

Esto no es sólo "detección de robots en el borde". Es una nueva ruta primitiva donde los flujos de tráfico están formados por patrones de comportamiento aprendidos, no sólo reglas estáticas.

¿Por qué importa esto?

La mayoría de las culturas de ingeniería temen:

  • No determinismo
  • Corriente
  • Mutación
  • Alucinación
  • Comportamiento emergente

DiSE utiliza los como Materiales de construcción.

Los sistemas estáticos mueren, los sistemas evolutivos sobreviven.

Cada industria que trata con adversarios, deriva, o presión de la escala eventualmente necesitará arquitecturas como esta:

  • Detección de bots
  • Motores de fraude
  • Firewalls adaptativos
  • Ecosistemas LLM
  • Microservicios autooptimizantes
  • Sistemas de depuración autónomos
  • Encaminamiento conductual - Conformación del tráfico basada en patrones aprendidos

Lo que DiSE no es

Déjame ser claro sobre lo que esto no es:

  • No "grandes LLMs en todas partes" - Los LLM son caros, úsalos estratégicamente.
  • No "reemplazar la lógica de negocios con IA" - La heurística es más rápida y predecible.
  • No "dejar que el sistema se descontrole" - La evolución está dirigida, limitada, gobernada.
  • No "AutoML con esteroides" - Se trata de comportamiento, no sólo de afinación de modelos.

DiSE es controlado, evolución explicable:

  • Limitados por limitaciones
  • Gobernado por funciones de fitness explícitas
  • Conservador de memoria
  • Versión
  • Seguridad de despliegue

Es dirigida evolución - guiado, no al azar.

Pruébalo.

mayormente lucid.botdetection aplica estos principios:

dotnet add package Mostlylucid.BotDetection
builder.Services.AddBotDetection();
app.UseBotDetection();

Configurar para la producción con el aprendizaje habilitado:

{
  "BotDetection": {
    "BotThreshold": 0.7,
    "Policies": {
      "default": {
        "FastPath": ["UserAgent", "Header", "Ip", "Behavioral", "ClientSide", "Inconsistency", "VersionAge"],
        "AiPath": ["Heuristic", "Llm"],
        "EscalateToAi": true,
        "EarlyExitThreshold": 0.85
      }
    },
    "AiDetection": {
      "Provider": "Heuristic",
      "Heuristic": {
        "Enabled": true,
        "LoadLearnedWeights": true,
        "EnableWeightLearning": true,
        "LearningRate": 0.01
      }
    }
  }
}

El detector heurístico aprende de cada solicitud, actualizando sus pesos para que coincidan con sus patrones de tráfico.

Conclusión

DiSE Architecture es el cambio de software como máquinas a software como organismos.

Es la arquitectura de:

  • Adaptabilidad
  • Resiliencia
  • Evolución controlada
  • Cognición en capas
  • Aprendizaje basado en la memoria
  • Mutación + selección
  • Comportamiento estratégico

Las arquitecturas estáticas no pueden mantenerse al día con los entornos dinámicos. Los atacantes evolucionan. Los usuarios evolucionan. Los requisitos evolucionan.

Los sistemas también deben evolucionar.

Si quieres sistemas que simplemente funcionen, constrúyelos a la antigua. Si quieres sistemas que Sobrevivir - ...constrúyelos con DiSE.

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.