Back to "Matlagning med diSE (Del 4): Byggsystem som lär, anpassar och utvecklar"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

AI Architecture Bot Detection DiSE Machine Learning Systems Design

Matlagning med diSE (Del 4): Byggsystem som lär, anpassar och utvecklar

Monday, 08 December 2025

De flesta programvaruarkitekturer antar att systemet är statiskt. DiSE antar att systemet är vid liv.

Anmärkning: Detta är del 4 i serien "Cooking with DiSE". Se Häfte 1, Del 2: Utexaminerade lärlingsutbildningar, och Del 3: Otillförlitliga Gudar För bakgrund. Denna artikel är den arkitektoniska översikten - och nu har vi en fungerande C# genomförande: mestadels lucid.botdetektion.

Nyckelkoncept: Beteenderouting. Denna arkitektur möjliggör en ny kategori - där transparenta, justerbara "team" av detektorer och inlärningssystem reflexivt rutttrafik baserat på inlärda beteendemönster, inte statiska regler. YARP- inkörsport, bots når aldrig din backend. Eller använda middleware för att bygga beteende routing direkt i din app lager.

Problemet: Statiska system i en dynamisk värld

I åratal har vi byggt mjukvara som klockverk: ingångar, utgångar, regler, pipelines, tester, utplaceringar.

Men moderna system - speciellt AI-augmenterade - beter sig inte längre som klockor. De beter sig som ekosystem:

  • Angripare utvecklar sina tekniker
  • Användarna ändrar sitt beteende
  • Kraven förskjuts över tiden
  • Miljön förändras hela tiden

Statiska arkitekturer kan inte hålla jämna steg. Du lappar ett hål, tre till dyker upp. Du justerar en tröskel, något annat går sönder. Du reagerar alltid, anpassar dig aldrig.

DiSE-arkitektur (Directed Synthetic Evolution) behandlar programvara på samma sätt som biologer behandlar organismer: som något som måste anpassas, självkorrigeras och förbättras under tryck.

Kärnan Idé: System som utvecklande organismer

Traditionell arkitektur:

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

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

DiSE-arkitektur:

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

Ett diSE-system har fyra grundläggande beteenden:

"Behavande" Vad det gör "biologiska motsvarigheter" |-----------|--------------|----------------------| | Uppfattning Samla in signaler från miljön på Sensoriska organ | Utvärdera på Score signaler mot mål på Nervsystemet | Mutat på Generera varianter av strategier på Genetisk mutation | Välj Bevara det som fungerar, kasta det som inte är naturligt val

Det är bokstavligen så ditt system utvecklar smartare beteenden med tiden.

Ett konkret exempel: Bot-detektion

mestadels lucid.botdetektion är den första C# genomförandet av DiSE principer. Låt oss spåra arkitekturen:

Perception: Blackboard-arkitekturen

Systemet använder en orkestrator för svarta tavlan - Detektorer bidrar med bevis till ett delat tillstånd, vilket utlöser andra detektorer när signaler ansamlas:

// 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; }
}

Flera detektorer körs i parallella vågor. Var och en bidrar med en bit bevis. Systemet uppfattar miljön genom många linser:

// 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;
}

Utvärdering: Viktat samförstånd med Sigmoid

Bevisaggregat till ett beslut med sigmoidtransformering - detta utnyttjar starka signaler från högviktsdetektorer på rätt sätt:

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);
}

Utvärderingen är inte en enda modell som fattar ett beslut. Vägt samförstånd över flera specialiserade detektorer - och avgörande, när AI inte har kört, sannolikheten är fastspänning För att undvika övertro:

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

Tidig avfärd: snabb vägoptimering

Systemet kör inte alltid alla detektorer.

// 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
};

Vid tillverkning Högt självförtroende begär utträde på mindre än 10 ms Efter bara 2-3 detektorer håller med. Hela rörledningen körs endast i osäkra fall.

Kretsbrytare: Självläkande

Detektorer kan misslyckas. Systemet skyddar sig självt:

// 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
    }
}

Misslyckade detektorer är tillfälligt inaktiverade. Efter en nedkylning prövas de igen (halvöppen tillstånd). Urvalstryck på infrastrukturnivå.

Mutation: Lärandesystemet

När systemet upptäcker med stort självförtroende, lär sig Genom att publicera till inlärningsbussen:

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
        }
    });
}

Detta matas in i viktaffären, uppdaterar den heuristiska detektorns inlärda vikter över tiden.

Den kognitiva stacken

I stället för en enda "AI-hjärna" använder DiSE skiktad kognition:

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

Varvtal på lager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |-------|-------|---------|----------------------| | Statisk heuristik Känd bot UA-mönster | Detektorer på < 10 ms på grund av förarens iakttagelse på huvudet, IP-kontroller | Lärd heuristisk på 1-5ms med dynamisk klassificering på logistisk regression med inlärda vikter | LLM Ordförande 50-500 ms på djupet resonemang och analys av nya mönster | Lärande och bakgrund på minnesbildning på Viktuppdateringar, ryktesförändringar

Nyckelinsikten: systemet lär sig sina egna vikter i realtid. Inga externa ML-modeller krävs. Den heuristiska detektorn börjar med förnuftiga standardvärden och utvecklas baserat på detektionsfeedback.

Framtiden: ONNX modeller med RAG och inbäddning planeras för v2. Den nuvarande heuristiska modellens resultat fungerar som märkta träningsdata för framtida modellträning. Arkitekturen har redan de "genetiska" artefakter (bidrag, vikter, signaler) som gör lägga till riktad syntetisk evolution enkelt - den är utformad som en plugin punkt.

Detta speglar biologisk kognition:

  • Medfött immunsystem → Statisk heuristik
  • Adaptivt immunsystem → Lärd heuristisk modell
  • Minnesceller → Vikt butik + rykte

Den heuristiska detektorn: Att lära sig utan externa modeller

Här är den smarta biten. Istället för att frakta en extern ML-modell, lär sig systemet sin egen klassificering med hjälp av enkel logistisk regression med dynamisk funktion extraktion:

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);
    }
}

Funktionerna extraheras dynamiskt från begäran och aggregerade bevis:

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;
    }
}

Nya funktioner får automatiskt standardvikter och lär sig med tiden. Systemet upptäcker vad som är viktigt.

Viktmagasinet: Ihärdigt lärande

Vikter kvarstår i SQLite och uppdateras via exponentiellt glidande medelvärde:

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, ...);
    }
}

Det här är mutation genom observation. Varje upptäckt lär systemet något. Med tiden konvergerar vikterna mot optimala värden för dina specifika trafikmönster.

Hallucination som mutation

I DiSE, LLM hallucination är inte en bugg. Det är det generativa substratet för evolution.

En hög temperatur LLM föreslår tio varianter av en detektion regel är inte "hallucinerande" - det är mutering av arvsmassan i systemet:

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);
}

Mutationerna utvärderas sedan mot bakgrund av historiska data:

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;
}

Endast de starkaste överlever till produktionen. Detta omvandlar LLMs från sköra chatbots till Utvecklingsaktörer.

Genome: Policybaserad inställning

I centrum av DiSE är Politiksystem - namngivna konfigurationer som definierar hur detektion beter sig:

{
  "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
    }
  }
}

Politiken fastställer följande:

  • FastPath-detektorer - köra parallellt, sub-10ms
  • AI- sökväg - Heuristisk (1-5 ms) och/eller LLM (500 ms+)
  • Tröskelvärden - när man ska gå ut tidigt, när man ska blockera
  • Övergångsbestämmelser - automatisk upptrappning till andra politikområden när det är osäkert
  • Försäkringstekniska avsättningar – försäkringstekniska avsättningar beräknade som helhet (efter återförsäkring/specialföretag) - trimma detektorns betydelse per användningsfall

Systemet kan Övergång mellan politiken efter begäran. Osäkra snabba resultat eskalerar till full demo pipeline. Detta är Adaptive routing (adaptive routing) - genet reagerar på bevis i realtid.

Ni skeppar inte statiska konfigurationer. beteendearter som anpassar sig till trafiken.

Fitness funktioner: Vad som överlever

Varje DiSE-system optimeras mot ett fitnesslandskap:

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
    }
}

Vi optimerar inte precisionen ensam. överlevnad i en dynamisk miljö.

För mycket AI → hög kostnad, dålig latency. För lite AI → dålig upptäckt av nya attacker. För aggressiv → falska positiva, arga användare. För mild → bot översvämningar.

Systemet måste hitta en stabil jämvikt. Tryck driver utvecklingen.

AI som lärare, inte arbetare

Ett moget DiSE-system förskjuter AI ur den heta vägen:

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

Över tid:

  • Statiska detektorer förbättras (utbildas av AI-etiketter)
  • Heuristik blir mer exakt (vald av kondition)
  • AI hanterar endast nyhet och mutation

AI blir:

  • och Örter och ätliga blommor, även ångkokta, kokta eller på annat sätt värmebehandlade, men inte kokta eller på annat sätt värmebehandlade, inte nämnda eller inbegripna någon annanstans för nya beteenden
  • och generator för mutationer
  • och driftdetektor
  • och lärare Att märka gränsfall

Inte ett beroende av löptid, adaptiv byggnadsställning.

Beteenderuttering: En ny kategori

och YARP- inkörsport, denna arkitektur möjliggör något nytt: Beteendeplanering.

Traditionell routing är statisk: väg → backend. Beteende routing är reflexiv: trafikegenskaper → dynamiska routing beslut.

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

De viktigaste begreppen:

  • Detektorgrupper - konfigurerbara grupper av detektorer som arbetar tillsammans, justerbara per policy
  • Genomskinliga avgöranden - varje beslut om tilldelning kan förklaras (se fördelning av bidraget)
  • Omflexibel justering - systemet lär sig av sina beslut och justerar vikter över tid
  • Skydd på kantnivå - bots når aldrig din backend; blockeras vid routern

Detta är inte bara "bot upptäckt vid kanten." Det är en ny routing primitiv där trafikflöden formas av inlärda beteendemönster, inte bara statiska regler.

Varför detta är viktigt

De flesta ingenjörskulturer fruktar:

  • Nondeterminism
  • Drivkraft
  • Mutering
  • Hallucination
  • Emergent beteende

DiSE använder dem som byggnadsmaterial.

Statiska system dör.

Varje industri som har att göra med motståndare, drift eller skaltryck kommer så småningom att behöva arkitekturer som denna:

  • Botdetektering
  • Bedrägerimotorer
  • Adaptiva brandväggar
  • LLM-ekosystem
  • Självoptimerande mikrotjänster
  • Autonoma felsökningssystem
  • Beteendeutflykter - trafikformning baserad på inlärda mönster

Vad DiSE inte är

Låt mig vara tydlig med vad detta inte är:

  • Inte "stora LLM överallt" - LLM är dyra, använd dem strategiskt.
  • Inte "utbyta affärslogik med AI" - Heuristik är snabbare och mer förutsägbart.
  • Inte "låt systemet köras vilt" - Evolutionen är styrd, begränsad, styrd.
  • Inte "AutoML på steroider" - Det handlar om beteende, inte bara modellstämning.

DiSE är kontrollerad, förklarande utveckling:

  • Gränsade av begränsningar
  • Styrd av explicita fitnessfunktioner
  • Minnesmedveten
  • Versioner
  • Säker att använda

Det är riktad evolution - guidad, inte slumpmässig.

Försök.

mestadels lucid.botdetektion genomföra dessa principer,

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

Anpassa för produktion med inlärning aktiverad:

{
  "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
      }
    }
  }
}

Se den utvecklas. Den heuristiska detektorn lär sig från varje begäran, uppdatera dess vikter för att matcha dina trafikmönster.

Slutsatser

DiSE Architecture är övergången från programvara som maskiner till programvara som organismer.

Det är arkitekturen av:

  • Anpassningsförmåga
  • Motståndskraft
  • Kontrollerad utveckling
  • Layrad kognition
  • Minnesdrivet lärande
  • Mutering + markering
  • Strategiskt beteende

Statiska arkitekturer kan inte hålla jämna steg med dynamiska miljöer. Anfallare utvecklas. Användare utvecklas. Krav utvecklas.

Systemen måste också utvecklas.

Om du vill ha system som bara körs, bygga dem på det gamla sättet. Om du vill ha system som överleva - Bygg dem med DiSE.

logo

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