Back to "StyloFlow: Signale fuzzy restreint-Flois de travail dirigés"

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 C# RAG Signals Workflows

StyloFlow: Signale fuzzy restreint-Flois de travail dirigés

Sunday, 11 January 2026

J'ai construit StyloFlow parce que j'ai continué à écrire les mêmes caractéristiques de façon répétée: les composants qui réagissent à ce qui s’est passé avant , émettent des notes de confiance M SK2 et parfois doivent progresser vers une analyse plus coûteuse . Les moteurs de travail existants m’ont demandé d’envisager en termes de DAG ou de machines étatiques MSC4 J’ai voulu penser dans le sens des signaux

REMARQUE: StyloFlow n'est pas encore un produit fini; car j'ai construit lucidRAG et StyloBot IM SK2m ajoutant des fonctionnalités manquantes et polissant l'API sur les deux styloFllow et éphémèresMST3 IlMSC4 est toujours en développement actifMst5 mais vous pouvez essayer et fournir le feedbackMSt6 Je vais mettre à jour ici plus tard M st7le signalSink stuff, par exemple, changera pour une version éphéméraire vMstr8 pour être M st9read onlyM str10

StyloFlow est une bibliothèque d'orchestrement dirigée par un signal- qui correspond comment je pense sur le sujet Pipelines d'AI: les composants déclarent ce qu’ils produisent et ce dont ils ont besoin

C'est l'infrastructure qui alimente lucideRAG - un outil RAG de graphe modique croiséM SK1 qui combine DocSummarizer (documents), Système de gestion des données (données structurées ), et ImageSummarizer (imagesM SK1 en une question unifiée- système de renforcement avec visualisation graphique des connaissances . Il permet également Stylobot (un système de protection avancée des robots ) et met en œuvre le RAG réduit pattern.

Interface lucidRAG

Source: GitHub - StyloFlow


Qu'est-ce que cela est

StyloFlow est un prototype opérationnel d’un modèle d’orchestrement dirigé par un signal- L’API et la forme évolueront au fur et à mesure que je construis lucidRAG et Stylobot, mais les sémantiques d’exécution et les patrons décrits ici sont les signaux de pointeM SK1 comme premiers-faits de classeMSC3confidence -branchement dirigé+, et escalation en tant qu’un modèle structurel=.

Ce n’est pas une nouvelle langue DSL ou de travail. sémantique de l'exécution built around signals, confidence, and bounded escalationM SK2 Aujourd’hui, il fonctionne dans un processus de coïncidence limitée . Demain, il distribuera des voies entre les machines tout en gardant les signaux comme la limite stableMSC5


Le problème des flux de travail traditionnels

Voici ce que la plupart des moteurs de travail ressemblent à :

// ❌ Traditional: Hardcoded dependencies
public async Task ProcessDocumentAsync(string path)
{
    var text = await ExtractTextAsync(path);
    var chunks = await ChunkTextAsync(text);
    var embeddings = await GenerateEmbeddingsAsync(chunks);
    var entities = await ExtractEntitiesAsync(chunks);
    await StoreEverythingAsync(embeddings, entities);
}

Cela fonctionne jusqu’à ce que:

  • Vous voulez passer à l'extraction des entités pour les demandes simples
  • Vous devez exécuter l'extraction et la mise en place parallèlement.
  • Vous voulez progresser vers un meilleur modèle fondé sur la confiance
  • Vous devez ajouter une nouvelle étape de traitement sans toucher le code existant.

Vous obtiendrez soit:

  1. Lignes de conduite rigides qui ne peuvent pas s’adapter
  2. Massif si/else arbres pour le routage
  3. Classes de Dieu qui connaissent tout

La Fondation: Exécution provisoire

StyloFlow s'appuie sur mostlylucid.éphémère - une bibliothèque pour l'exécution asynchrone traçable de bounded,

Résumé rapide de ce que fournit l’éphéméral:

// Bounded concurrent processing with full visibility
var coordinator = new EphemeralWorkCoordinator<DocumentJob>(
    async (job, operation, ct) => {
        await ProcessAsync(job, ct);
        operation.Signal("document.processed");
    },
    new EphemeralOptions { MaxConcurrency = 4 });

// Enqueue work
await coordinator.EnqueueAsync(new DocumentJob(filePath));

// Full observability
Console.WriteLine($"Active: {coordinator.ActiveCount}");
Console.WriteLine($"Completed: {coordinator.TotalCompleted}");

Principaux avantages de l’épheméral:

  • Compétence limitée (pas de mémoire en fuiteM SK1
  • Éviction des LRU d'anciennes opérations
  • Publication de signaux pour la coordination des composants cross-
  • Operation pinning pour empêcher l'évacuation prématurée

Pour plus de détails, voir Fire and Don't Quite Forget.


Ce que ce modèle permet

Ce modèle d’orchestrement étend la durée éphémère avec:

  1. Manifestes de composants dirigés par YAML- - Configuration de déclaration
  2. Triggers basés sur le signal- - Components fonctionnent lorsque des signaux apparaissent
  3. Coordination des ondes - Priorité-exécution basée sur des voies de croisement
  4. Méthodes d'évacuation - Reporter l’analyse coûteuse jusqu’à ce que cela soit nécessaire
  5. Contrats d'entités - TypeM SK1entrée sécuritaire / spécifications de sortie
  6. Gestion budgétaire - Limites de symboleM SK1 plafonds des coûts , échéances

Voici le changement architectural clé :

graph TD
    subgraph Traditional["❌ Traditional: Hardcoded"]
        T1[Component A] -->|calls| T2[Component B]
        T2 -->|calls| T3[Component C]
        T3 -->|calls| T4[Component D]
    end

    subgraph StyloFlow["✅ StyloFlow: Signal-Driven"]
        S1[Component A]
        S2[Component B]
        S3[Component C]
        S4[Component D]
        SS[Signal Sink]

        S1 -.emits.-> SS
        S2 -.emits.-> SS
        S3 -.emits.-> SS
        SS -.triggers.-> S2
        SS -.triggers.-> S3
        SS -.triggers.-> S4
    end

    style T1 stroke:#ff6b6b
    style T2 stroke:#ff6b6b
    style T3 stroke:#ff6b6b
    style T4 stroke:#ff6b6b
    style S1 stroke:#51cf66
    style S2 stroke:#51cf66
    style S3 stroke:#51cf66
    style S4 stroke:#51cf66
    style SS stroke:#339af0

Ils émettent des signaux et réagissent aux signaux.


Concept de base: Signaux et propriété

Les signaux sont des faits sur ce qui s'est passé., ne sont pas des commandes ou des événements . Ils' sont immuablesM SK3 ont un timbre de temps,, et portent des cotes de confianceMSC5 Chaque atome possède ses signaux.

public record Signal
{
    public required string Key { get; init; }           // "document.chunked"
    public object? Value { get; init; }                 // Optional payload
    public double Confidence { get; init; } = 1.0;      // 0.0 to 1.0
    public required string Source { get; init; }        // Which component
    public DateTime Timestamp { get; init; }
    public Dictionary<string, object>? Metadata { get; init; }
}

Point architectural critique: SignalSink est une vision historique persistante.

SignalSink fournit une vue consultable de toutes les opérations sur tous les coordonnateurs qui la partagent. Les signaux persistent dans l’ensemble des cycles de vie du coordonneur - lorsqu’une opération évaque son coordonateur , les signaux restent dans le bassin jusqu’à ce qu’ils soient nettoyés manuellementM SK3

// Create a shared signal sink (no parameters, signals persist)
var sink = new SignalSink();

// Coordinators manage operation lifetime, NOT signal lifetime
var coordinator = new EphemeralWorkCoordinator<string>(
    ProcessAsync,
    new EphemeralOptions
    {
        MaxConcurrency = 8,
        MaxTrackedOperations = 100,         // Operations evict after this
        MaxOperationLifetime = TimeSpan.FromMinutes(5),  // Or after this time
        Signals = sink                      // Share the persistent view
    });

// Operations emit via their emitter
public async Task ProcessAsync(string docId, SignalEmitter emitter, CancellationToken ct)
{
    // Store actual data externally (cache, database, blob storage)
    await cache.SetAsync($"doc-{docId}", documentData);

    // Signal carries a REFERENCE, not the data
    emitter.Emit("document.chunked", key: docId); // Key references external data
}

// SignalSink is readonly - it cannot alter signals
// Signals persist until their operation evicts from the coordinator

SignalSink fournit deux modèles de coordination:

1. Push-basé sur SubscribeM SK3

// Subscribe to the sink for push notifications
sink.Subscribe(signal => {
    if (signal.Is("document.chunked"))
    {
        // React immediately - signal includes OperationId
        Console.WriteLine($"Op {signal.OperationId} chunked doc at {signal.Timestamp}");
    }
});

// Returns IDisposable for cleanup
using var subscription = sink.Subscribe(HandleSignal);

2. PullM SK1based (Query):

// Get all signals for a specific operation
var opSignals = sink.GetOpSignals(operationId);

// Detect if any operation has emitted a signal
if (sink.Detect("embeddings.generated"))
{
    // At least one operation has generated embeddings
}

// Sense all signals matching a condition
var recentErrors = sink.Sense(s =>
    s.Signal.StartsWith("error.") &&
    s.Timestamp > DateTimeOffset.UtcNow.AddMinutes(-5)
);

// Get operation summary from its signal history
var summary = sink.GetOp(operationId);
Console.WriteLine($"Operation ran for {summary?.Duration}");

Pourquoi cela importe:

  • Voir seul - SignalSink ne peut modifier les signaux; il n'offre qu'un accès à la demande
  • Les signaux persistent - Les signaux restent en vue jusqu’à ce que leur opération ne soit évacuée du coordonnateur
  • Les signaux sont de coordination, non de transport - Les signaux portent des clésM SK1références aux données externes , NON les données elles-mêmes
  • Indépendance du coordonnateur - Plusieurs coordonnateurs peuvent partager un puits ; l'historique des signaux les englobe tous
  • Thread-safe - Lock-les lectures libres pour les opérations de recherche
  • Appuyer et attirer - InscrireM SK1 pour le vote réactif, Sens ()/ DétecterMSC4 pour l’élection
  • Correlation opérationnelle - Chaque signal comprend l’OpérationId pour le traçage entre les coordonnateurs
  • Correspondance entre les paramètres - Demande par correspondance exacte

Principe de conception clé: Entreposer de grandes données (documentsM SK1 images, vecteursMSC3 dans des caches ou des bases de données . Les signaux ne portent que les références comme "cache://doc-123" ou des clés de fonctionnement.

Examen de la coordination:

// Operation emits signal via ISignalEmitter interface
public async Task ProcessAsync(Item item, ISignalEmitter emitter, CancellationToken ct)
{
    // Emit to the sink
    emitter.Emit("processing.started");

    await DoWorkAsync(item, ct);

    emitter.Emit("processing.completed");
}

// Wave checks if it should run by querying sink
public bool ShouldRun(string path, AnalysisContext ctx)
{
    // Pull pattern: query the sink via context
    return ctx.Detect("document.chunked");
}

// UI subscribes to sink for reactive updates
sink.Subscribe(signal => {
    if (signal.Signal.StartsWith("document."))
    {
        // Push pattern: react immediately
        UpdateProgressUI(signal);
    }
});

L’escalade se produit à deux niveaux:

  1. Au sein d'un coordonnateur - Les ondes vérifient la fiabilité du signal et procèdent à une analyse coûteuse sous condition
  2. Entre les coordonnateurs - EscalateurAtom transmet des signaux à partir d'un coordonnateur rapide → Coordonnateur coûteux selon les critères de signalisation
// Pattern 1: Intra-coordinator escalation (wave checks signals)
public bool ShouldRun(string path, AnalysisContext ctx)
{
    var quality = ctx.GetSignal("quality.score");
    return quality?.Confidence < 0.7; // Only run if quality is low
}

// Pattern 2: Inter-coordinator escalation (atom routes to another coordinator)
// Option A: Explicit escalation signal
typed.Raise("escalate.to.expensive", payload, key: "doc-123");

// Option B: EscalatorAtom examines signals and decides
new EscalatorAtomOptions<T> {
    ShouldEscalate = evt => evt.Payload.Confidence < 0.7
}

Des coordonnateurs multiples fonctionnent indépendamment. EscalatorAtom surveille les signaux d’un coordonneur et transmet le travail à un autre lorsqu’il y a lieu.

Pour la théorie qui sous-tend cette étude, voir Traçage de contexte fuzzy restreint.

Signals Transport de références, Non Données

Critique: Les signaux sont des événements de coordination.

// ❌ BAD: Carrying data in signals (memory pressure, boxing)
var imageBytes = await ProcessImageAsync(input);
emitter.Emit("image.processed", metadata: new { Data = imageBytes });

// ✅ GOOD: Store externally, signal the reference
var imageBytes = await ProcessImageAsync(input);
var cacheKey = $"processed/{docId}";
await cache.SetAsync(cacheKey, imageBytes);
emitter.Emit("image.processed", key: cacheKey);

// Later: Retrieve when needed
if (sink.Detect("image.processed"))
{
    var signals = sink.GetOpSignals(operationId);
    var imageKey = signals.FirstOrDefault(s => s.Signal == "image.processed")?.Key;
    if (imageKey != null)
    {
        var bytes = await cache.GetAsync<byte[]>(imageKey);
    }
}

Pratiques exemplaires:

  • Utiliser les caches (inM SK1memory ou distribués) pour les données éphémères
  • Utiliser des bases de données pour les données durables
  • Utiliser le stockage de blobs pour les fichiers grands
  • URIs de signaux: "cache://key", "blob://container/file", "db://table/id"
  • Maintenir les signaux légers - clés simples , cotes de confianceM SK2 échéanciers

Concept de base: Manifestes des composants

Les manifestes déclarent les contrats (ce qui me déclenche , ce que j’émets M SK2 ce qu’il coûte ) Separation de la mise en œuvre. Cette séparation existe pour que vous puissiez comprendre le flux de travail sans lire le code.

name: BotDetector
priority: 10              # Lower runs first
enabled: true

# What kind of component is this?
taxonomy:
  kind: analyzer          # sensor|analyzer|proposer|gatekeeper
  determinism: probabilistic
  persistence: ephemeral

# When should this run?
triggers:
  requires:
    - signal: http.request.received
      condition: exists

# What does it produce?
emits:
  on_complete:
    - key: bot.detected
      confidence_range: [0.0, 1.0]

  conditional:
    - key: bot.escalation.needed
      when: confidence < 0.7

# Resource limits
lane:
  name: fast              # fast|normal|slow|llm
  max_concurrency: 8

budget:
  max_duration: 100ms

# Configuration values
defaults:
  confidence:
    bot_detected: 0.6
  timing:
    timeout_ms: 100

Avantages:

  1. Configuration du temps d'exécution - Changer la priorité sans recompiler
  2. Environnement est supprimé - Supprimer par l'intermédiaire des réglages d'applications.json
  3. Éclaircissement des contrats - Voir les signaux qui déclenchent ce
  4. Self-documentation - Manifeste est la spécification

Créateur de flux de travail visuels

Bien que vous puissiez écrire les manifestes YAML à la main, StyloFlow comprend un constructeur de flux de travail visuel qui vous permet de concevoir des mouvements de travail dirigés par le signal -en utilisant un module modulaire-synthM SK3patching de styleMSC4

StyloFlow Workflow Builder

L’interface fournit:

  • Drag-and-drop components de la taxonomie (sensors,analystesM SK2propriétaires , etc.
  • Fabrication de câbles de signalisation - Connexion visuelle des sorties aux intrants
  • Prévision du manifeste en direct - Voir le YAML généré pendant la construction
  • Visualisation d'un déclencheur - Voir quels signaux déclenchent quelles composantes
  • Répartition des voies - Traîner les composants dans des voies rapidesM SK1normales /slow/llm
  • Validation en temps réel - Prendre immédiatement des références de signal in valide

Ainsi, il est facile d’expérimenter différentes formes de flux de travail sans écrire YAML à la main.


Concept de base: Étendues

Une onde est un stade d’analyse composable. Cette interface existe pour faire de "la première décision de la classe -est-ce que nous devrions exécuter ?, n’est pas un détail de mise en œuvre caché dans la logique conditionnelle.

public interface IContentAnalysisWave
{
    string Name { get; }
    int Priority { get; }               // Higher runs first
    bool Enabled { get; set; }

    // Quick filter - avoid expensive work
    bool ShouldRun(string contentPath, AnalysisContext context);

    // Do the analysis
    Task<IEnumerable<Signal>> AnalyzeAsync(
        string contentPath,
        AnalysisContext context,
        CancellationToken ct);
}

Exemple de vague simple:

public class FileTypeWave : IContentAnalysisWave
{
    public string Name => "FileType";
    public int Priority => 100;
    public bool Enabled { get; set; } = true;

    public bool ShouldRun(string path, AnalysisContext ctx)
    {
        // Skip if we already know the type
        return ctx.GetSignal("file.type") == null;
    }

    public async Task<IEnumerable<Signal>> AnalyzeAsync(
        string path,
        AnalysisContext ctx,
        CancellationToken ct)
    {
        var extension = Path.GetExtension(path);
        var mimeType = GetMimeType(extension);

        return new[]
        {
            new Signal
            {
                Key = "file.type",
                Value = mimeType,
                Confidence = 1.0,
                Source = Name
            }
        };
    }
}

Coordination des ondes:

L'article 5 de la Loi sur l'immigration et le statut des réfugiés WaveCoordinator effectue les ondes dans l’ordre prioritaire:

var coordinator = new WaveCoordinator(waves, profile);
var context = new AnalysisContext();

var results = await coordinator.ExecuteAsync(filePath, context, ct);

// All signals from all waves
foreach (var signal in context.GetAllSignals())
{
    Console.WriteLine($"{signal.Key}: {signal.Value}");
}

Voies de compétition:

Les ondes courent dans les voies avec des limites de convergence différentes:

Voie de circulation But SSK2 Concurrence MSC3
fast Contrôles rapides
normal Traitement normal ( Parsage
io IM SK1O lié (les fichiers liés par les appels de l'API,Les appels d'API
llm Demandes de téléphonie LLM coûteuses

Cela empêche les opérations coûteuses de bloquer celles bon marché.


Architecture: Comment il convient ensemble

Voici le tableau complet de '

graph TB
    subgraph Input["Input Layer"]
        REQ[HTTP Request]
        FILE[File Upload]
        JOB[Background Job]
    end

    subgraph Ephemeral["Ephemeral Layer"]
        COORD[Work Coordinator]
        OPS[Operations<br/>own signals]
        SINK[SignalSink<br/>read-only view]
    end

    subgraph StyloFlow["StyloFlow Layer"]
        MAN[Manifests]
        WAVE[Wave Coordinator]
        ATOMS[Atoms<br/>own signals]
    end

    subgraph Execution["Execution"]
        FAST[Fast Lane]
        NORM[Normal Lane]
        LLM[LLM Lane]
    end

    subgraph Output["Output"]
        RES[Results]
        ESCAL[Escalation]
        STORE[Persistence]
    end

    REQ --> COORD
    FILE --> COORD
    JOB --> COORD

    COORD --> OPS
    SINK -.queries.-> OPS

    WAVE -.reads.-> SINK
    MAN -.configures.-> WAVE
    WAVE --> ATOMS

    ATOMS --> FAST
    ATOMS --> NORM
    ATOMS --> LLM

    SINK -.queries.-> FAST
    SINK -.queries.-> NORM
    SINK -.queries.-> LLM

    SINK -.read for.-> RES
    SINK -.read for.-> ESCAL
    SINK -.read for.-> STORE

    style COORD stroke:#339af0
    style SINK stroke:#339af0
    style WAVE stroke:#51cf66
    style ATOMS stroke:#51cf66

Flow:

  1. L'entrée arrive (requête HTTP, fichierM SK2 tâcheMSC3
  2. Coordonnateur éphémère crée l'opération (qui possède une liste de signaux vides)
  3. L'opération ajoute des signaux à sa liste de propriété
  4. Coordonnateur de la vague RECHERCHE les signaux par l'entremise de la vue SignalSink pour vérifier les conditions de déclenchement
  5. Les ondes dont les déclencheurs correspondent courent en ordre de priorité à l'intérieur des voies concurrentielles
  6. Chaque onde ajoute des signaux à son fonctionnement.
  7. Le coordonnateur de la vague continue à lire les signaux pour trouver des déclencheurs nouvellement satisfaits
  8. Demandes finales de sortie SignalSink pour lire les signaux et déterminer les actions

Modèle de propriété: Chaque opération/atom possède ses signaux. SignalSink fournit une vue de lecture -seulement dans toutes les opérationsM SK3 Les signaux peuvent être élargis MSC4copiésMST5 ou échoés MST6conservés lorsqu'ils sont évacués M ST7 mais la liste détenue est immutable à l'extérieurM ST8

Modèle d'exécution actuel: Opérations observables avec l'évacuation de LRU

Modèle d’exécution futur: Routes réparties entre les machines, SignalSink demande des opérations à distance, atomes exécutent sur différents hôtes . Les signaux demeurent la limite stable Le modèle de propriété ne change pas.

La mise en oeuvre du processus in- valide la sémantique . La distribution consiste à élargir le substrat de l’exécution, sans changer le modèle d’orchestrementM SK3


Utiliser le cas: lucidRAG Traitement des documents

Let's voir comment lucidRAG Utilise StyloFlow:

Étape 1: Détection initiale

public class FileTypeDetectorWave : IContentAnalysisWave
{
    public int Priority => 100;  // Run first

    public async Task<IEnumerable<Signal>> AnalyzeAsync(...)
    {
        var extension = Path.GetExtension(path);

        return new[]
        {
            new Signal
            {
                Key = "file.extension",
                Value = extension,
                Source = "FileTypeDetector"
            }
        };
    }
}

Étape 2: dubbing ( trigger par fichierM SK2extension)

// In manifest:
// triggers:
//   requires:
//     - signal: file.extension
//       condition: in
//       value: [".pdf", ".docx", ".md"]

public class ChunkingWave : ConfiguredComponentBase, IContentAnalysisWave
{
    public int Priority => 80;

    public async Task<IEnumerable<Signal>> AnalyzeAsync(...)
    {
        var chunks = await ChunkDocumentAsync(path);

        ctx.SetCached("chunks", chunks);  // Share with other waves

        return new[]
        {
            new Signal
            {
                Key = "document.chunked",
                Value = chunks.Count,
                Source = Name
            }
        };
    }
}

Étape 3: Emplacement ( déclenché par le document

public class EmbeddingWave : ConfiguredComponentBase, IContentAnalysisWave
{
    public int Priority => 60;

    public bool ShouldRun(string path, AnalysisContext ctx)
    {
        // Only run if chunking succeeded
        return ctx.GetSignal("document.chunked") != null;
    }

    public async Task<IEnumerable<Signal>> AnalyzeAsync(...)
    {
        var chunks = ctx.GetCached<List<Chunk>>("chunks");
        var embeddings = await GenerateEmbeddingsAsync(chunks);

        ctx.SetCached("embeddings", embeddings);

        return new[]
        {
            new Signal
            {
                Key = "embeddings.generated",
                Value = embeddings.Count,
                Source = Name
            }
        };
    }
}

Étape 4: Extraction d'entités ( parallèle à l'incorporation)

public class EntityExtractionWave : ConfiguredComponentBase, IContentAnalysisWave
{
    public int Priority => 60;  // Same as embedding - runs in parallel

    public async Task<IEnumerable<Signal>> AnalyzeAsync(...)
    {
        var chunks = ctx.GetCached<List<Chunk>>("chunks");

        // Use deterministic IDF scoring, not LLM per chunk
        // (See Reduced RAG pattern)
        var entities = await ExtractEntitiesAsync(chunks);

        return new[]
        {
            new Signal
            {
                Key = "entities.extracted",
                Value = entities.Count,
                Confidence = CalculateConfidence(entities),
                Source = Name
            }
        };
    }
}

Étape 5: Contrôle de la qualité

public class QualityCheckWave : ConfiguredComponentBase, IContentAnalysisWave
{
    public int Priority => 40;  // After embedding + entities

    public async Task<IEnumerable<Signal>> AnalyzeAsync(...)
    {
        var embeddingSignal = ctx.GetSignal("embeddings.generated");
        var entitySignal = ctx.GetSignal("entities.extracted");

        var embeddingCount = (int)embeddingSignal.Value;
        var entityConfidence = entitySignal.Confidence;

        var quality = CalculateQuality(embeddingCount, entityConfidence);

        var signals = new List<Signal>
        {
            new Signal
            {
                Key = "quality.score",
                Value = quality,
                Source = Name
            }
        };

        // Trigger escalation if quality is poor
        if (quality < GetParam<double>("quality_threshold", 0.7))
        {
            signals.Add(new Signal
            {
                Key = "escalation.needed",
                Value = "low_quality_document",
                Source = Name
            });
        }

        return signals;
    }
}

Avantages de cette approche:

  1. Exécution parallèle - La mise en place et l'extraction des entités fonctionnent simultanément
  2. Branchement conditionnel - La vérification de la qualité détermine si une escalation est nécessaire
  3. Contexte partagé - Les ondes accèdent aux chunks sans les transmettre explicitement
  4. Facile à élargir - Ajouter une nouvelle vague sans changer celles existantes
  5. Observables - Chaque étape émet des signaux que vous pouvez surveiller

Il s’agit de RAG réduit pattern in action: extraction déterministe à l'avant, LLMs seulement pour la synthèseM SK2


Utiliser Case: Stylobot Bot Detection

Stylobot est un système de détection avancée qui utilise StyloFlow pour l'analyse des menaces multiples.


Paramètres d’orchestrement dirigé par le signal-

Pattern 1: FanM SK1Out

Un signal déclenche plusieurs vagues:

graph LR
    S1[document.uploaded] --> W1[ChunkingWave]
    S1 --> W2[MetadataWave]
    S1 --> W3[LanguageDetectionWave]

    W1 -.signal.-> S2[document.chunked]
    W2 -.signal.-> S3[metadata.extracted]
    W3 -.signal.-> S4[language.detected]

    style S1 stroke:#339af0
    style S2 stroke:#339af0
    style S3 stroke:#339af0
    style S4 stroke:#339af0
    style W1 stroke:#51cf66
    style W2 stroke:#51cf66
    style W3 stroke:#51cf66

Pattern 2: dépendance séquentielle

Les ondes attendent les signaux antérieurs:

graph LR
    W1[ExtractWave] -.signal.-> S1[text.extracted]
    S1 --> W2[ChunkWave]
    W2 -.signal.-> S2[text.chunked]
    S2 --> W3[EmbedWave]
    W3 -.signal.-> S3[embeddings.generated]

    style S1 stroke:#339af0
    style S2 stroke:#339af0
    style S3 stroke:#339af0
    style W1 stroke:#51cf66
    style W2 stroke:#51cf66
    style W3 stroke:#51cf66

Modèle 3: Branche conditionnelle

Différentes ondes fonctionnent selon les signaux:

graph TD
    W1[DetectorWave] -.signal.-> S1{confidence}

    S1 -->|< 0.4| W2[RejectWave]
    S1 -->|0.4-0.7| W3[EscalateWave]
    S1 -->|> 0.7| W4[AcceptWave]

    W2 -.signal.-> S2[rejected]
    W3 -.signal.-> S3[escalated]
    W4 -.signal.-> S4[accepted]

    style S1 stroke:#ffd43b
    style S2 stroke:#ff6b6b
    style S3 stroke:#ff922b
    style S4 stroke:#51cf66
    style W1 stroke:#339af0
    style W2 stroke:#ff6b6b
    style W3 stroke:#ff922b
    style W4 stroke:#51cf66

Modèle 4: Aggrégation

Plusieurs signaux déclenchent une vague:

graph LR
    W1[Wave A] -.signal.-> S1[a.complete]
    W2[Wave B] -.signal.-> S2[b.complete]
    W3[Wave C] -.signal.-> S3[c.complete]

    S1 --> T{All Ready?}
    S2 --> T
    S3 --> T

    T -->|Yes| W4[AggregatorWave]
    W4 -.signal.-> S4[aggregation.complete]

    style S1 stroke:#339af0
    style S2 stroke:#339af0
    style S3 stroke:#339af0
    style S4 stroke:#51cf66
    style T stroke:#ffd43b
    style W4 stroke:#51cf66

Paramètres d'évacuation

StyloFlow appuie l'escalade à deux niveaux:

  1. Coordonnateur intra-: Les ondes vérifient la fiabilité du signal et suivent des étapes coûteuses sous condition
  2. Coordonnateur inter-: EscalateurRoutes atomiques signalées par un coordonnateur rapide → Coordonnateur coûteux

Exemple de lucidRAG: L'extraction d'entités rapide se fait d'abord. Si la qualité M SK2 0.7, EscalatorAtom dirige le document vers un coordonnateur coûteux de raffinement du LLMMSC4 Cela permet d'économiser 20x sur les coûts en évitant des appels coûteux par le LLM pour obtenir des extraits de haute qualitéMST6M ST7


Forme minimale

Il ne s’agit pas d’un guide de démarrage rapide.

Installation:

dotnet add package StyloFlow.Complete

Point d’entrée conceptuel:

// 1. Define a wave
public class MyAnalysisWave : IContentAnalysisWave
{
    public string Name => "MyAnalysis";
    public int Priority => 50;
    public bool Enabled { get; set; } = true;

    public bool ShouldRun(string path, AnalysisContext ctx) => true;

    public async Task<IEnumerable<Signal>> AnalyzeAsync(
        string path,
        AnalysisContext ctx,
        CancellationToken ct)
    {
        // Your analysis logic here
        var result = await AnalyzeAsync(path);

        return new[]
        {
            new Signal
            {
                Key = "my.signal",
                Value = result,
                Confidence = 1.0,
                Source = Name
            }
        };
    }
}

// 2. Register waves
var waves = new List<IContentAnalysisWave>
{
    new MyAnalysisWave(),
    new AnotherWave(),
};

// 3. Create coordinator
var coordinator = new WaveCoordinator(
    waves,
    CoordinatorProfile.Default);

// 4. Execute
var context = new AnalysisContext();
var results = await coordinator.ExecuteAsync(filePath, context);

// 5. Read signals
foreach (var signal in context.GetAllSignals())
{
    Console.WriteLine($"{signal.Key}: {signal.Value} ({signal.Confidence})");
}

Avec les manifestes:

// Load manifests from directory
var loader = new FileSystemManifestLoader("./manifests");
var manifests = await loader.LoadAllAsync();

// Build waves from manifests
var waves = manifests
    .Where(m => m.Enabled)
    .OrderBy(m => m.Priority)
    .Select(m => WaveFactory.Create(m))
    .ToList();

var coordinator = new WaveCoordinator(waves, profile);

Pour des exemples complets,, voir le StyloFlow GitHub repository.


Discoverability des flux de travail: Manifestes YAML

Les manifestes déclarent ce qui déclenche une vague, ce qu’elle émet , les limites de ressourcesM SK2 et les coûts - faire fonctionner les flux de travail eux-mêmes

Exemple: Vague déterministe

name: ChunkingWave
priority: 80
description: Splits documents into semantic chunks

taxonomy:
  kind: extractor
  determinism: deterministic

triggers:
  requires:
    - signal: file.extension
      condition: in
      value: [".pdf", ".docx", ".md"]

emits:
  on_complete:
    - key: document.chunked
      type: integer

lane:
  name: normal
  max_concurrency: 8

budget:
  max_duration: 30s

defaults:
  chunking:
    max_chunk_size: 512
    overlap: 50

Exemple: escalation conditionnelle

name: QualityCheckWave
priority: 40
description: Validates extraction quality

triggers:
  requires:
    - signal: embeddings.generated
    - signal: entities.extracted

emits:
  on_complete:
    - key: quality.score
      confidence_range: [0.0, 1.0]

  conditional:
    - key: escalation.needed
      when: quality.score < 0.7  # Trigger LLM refinement

lane:
  name: fast
  max_concurrency: 16

Avantages:

  • Ordre d'exécution visible à partir des numéros de priorité
  • Dépendances claires des signaux requis
  • Ressources limitées explicitement (lanesM SK1budgétaires )
  • Déclaratif de logique conditionnelle

Propriétés émergentes

1. Composition de déclaration

Les composants déclarent leurs contrats (triggersM SK1 signaux , budget), non pas leurs dépendancesMSC4 Le système détermine l’ordre d’exécutionMST5 Ce n’est pasMSSK6t une fonction MST7 c’est ce qui se produit lorsque vous faites les signaux de la première foisM ST9classeM st10

2. Observer par défaut

Chaque action est un signal.

3. Exécution adaptative

Les scores de confiance favorisent la branchement sans logique explicite de routage. Passer les étapes coûteuses lorsqu’elles sont inutiles , escalader lorsque l’on est incertainM SK2 abroger tôt à un niveau élevé- défaillances en matière de confianceMSC4 Le flux de contrôle résulte des patrons de signalisationMNK5

4. Testabilité sans montage de cadres

Signales de détournement, non composants:

var context = new AnalysisContext();
context.AddSignal(new Signal
{
    Key = "document.chunked",
    Value = 10,
    Confidence = 1.0,
    Source = "Test"
});

var wave = new EmbeddingWave();
var results = await wave.AnalyzeAsync(path, context, ct);

Assert.Single(results);
Assert.Equal("embeddings.generated", results.First().Key);

5. Complexité croissante

Démarrer simple:

var coordinator = new EphemeralWorkCoordinator<Job>(ProcessAsync);

Ajouter des signaux au besoin:

new EphemeralOptions { Signals = signalSink }

Ajouter des vagues pour multi-stageM SK1

var waveCoordinator = new WaveCoordinator(waves, profile);

Ajouter des manifestes pour la configuration déclarationnelle:

name: MyWave
triggers: [...]
emits: [...]

Comparaison avec d'autres moteurs de travail

Caractéristiques StyloFlow MSC2 Temporal MSC3 Airflow SMC4 Functions d'étape MESC5
Coordination Système de signalisation -conduite par un conducteur PCR -basé sur S DAG MESK5basée sur |Machine d'État |
Déclaration ✅ Manifestes YAML
Conditionnelle ✅ Triggers de signalisation MSC2 3 Conditions MSC4 ✅ Branchement MSC6 SMC7 Énoncé d’option MSC8
Évacuation ✅ Fabricé-dans le cadre de l’installation MSC3 4 Manuel 6 Manual MSC7 8 manuel
Observabilité ✅ Trace de signaux MSC2 3 Historique du flux de travail MSC4 ✅ Logs des tâches MSC6 SMC7 History de l'exécution MSC8
Contrôle budgétaire ✅ Token/limites de coûts \❌ Méthode d'utilisation \ ❌ Méthodes d'emploi
Exécution locale ✅ Dans le processus de - \ ❌ Besoin d'un regroupement
Voies de concurrence

Aux endroits où ce modèle convient naturellement:

  • AI/ML pipelines with escalation M SK1cheap → expensive)
  • Traitement des documents avec étapes conditionnelles
  • Détection de bottes avec analyse multi-stage
  • Systèmes RAG avec génération hybride de recherche +
  • Tout flux de travail où les composants réagissent aux cotes de confiance

Lorsqu’il ne le fait pas, 't (et a remporté

  • Travaux séquentiels simples (un coordonnateur éphémère est suffisantM SK1
  • Les flux de travail distribués matures à travers les centres de données (Temporal permet de résoudre ce problème)
  • Long-flows de travail en cours avec approbation humaine M SK1Temporaux/Flois d'airMSC3
  • Versionnement des flux de travail avec migration du schéma (Temporal)

Où mène ce modèle

Il s’agit là d’extensions naturelles du modèle, non pas de l’engagement à une mise en œuvre spécifique.

À mesure que la sémantique se stabilise grâce au développement de lucidRAG et Stylobot, ces patrons deviennent viablesM SK1

1. Apprentissage à partir des signaux

Suivre les chemins d’escalade qui fonctionnent le mieux:

// Did the LLM escalation improve accuracy?
// Learn to skip it if behavioral analysis is sufficient

2. Optimisation des coûts

Répartition automatique des voies en fonction de la performance historique:

// If a "slow" wave completes quickly, promote to "normal"

3. Replay du signal

Débugging par reproduction de séquences de signaux:

var replay = SignalReplay.FromFile("trace.jsonl");
await coordinator.ReplayAsync(replay);

Coordination de la machine

Distribuer les voies à travers les machines tout en gardant les signaux centralisés.


Pourquoi les signaux sont importants

Le principal point de vue est ce qui suit : dans les systèmes d’AI, chaque composant a confiance.

Les flux de travail traditionnels supposent le succès/faillance.Les flux de travaux d’AI sont nécessairesM SK2

  • Notes de confiance - Quelle est notre certitude?
  • Exécution conditionnelle - Passer les étapes coûteuses si vous êtes sûr
  • Évacuation - Essayez plus dur lorsque vous êtes incertain
  • L'agrégation - Combiner plusieurs signaux

Les signaux la fournissent naturellement:

// Multiple detectors vote
var signals = context.GetSignals("bot.detected");

// Aggregate by confidence
var verdict = signals
    .OrderByDescending(s => s.Confidence)
    .First();

// Or majority vote
var isBot = signals
    .Count(s => (bool)s.Value) > signals.Count() / 2;

// Or weighted average
var score = signals
    .Sum(s => (bool)s.Value ? s.Confidence : -s.Confidence)
    / signals.Count();

C'est pourquoi StyloFlow fonctionne bien pour RAG réduit - chaque étape d’extraction produit une note de confianceM SK1 et la synthèse ne se produit que lorsque la confiance est suffisamment élevée.


Résumé

Le modèle d'exécution:

  • Signales en tant que faits de première classe- M SK1pas d'événements ou de messages)
  • Confidential scores drive control flow
  • Coordonner les ondes par l’intermédiaire de déclencheurs, non des appels directs
  • Les voies imposent des limites en matière de ressources
  • Élaboré sur mostlylucid.éphémère

Pourquoi les signaux sont-ils importants:

  1. Limite de distribution stable - Serialisable , Timestamped, selfM SK3contained
  2. Composition déclarative - Les manifestes définissent les contrats , le temps d’exécution calcule l’exécution
  3. Routage adaptatif - Confidence permet l'escalade sans branchement codé
  4. Observabilité héréditaire - Chaque action est déjà un signal
  5. Éclaircissement de la propriété - Systèmes propres des atomesM SK1 l'immutabilité externe empêche l'action

Applications de travail:

  • lucidRAG - CrossM SK1document modique Q&A avec extraction conditionnelle des entités
  • Stylobot - Détection de bottes avec confianceM SK1escalade dirigée IP → comportement SSK4 LLM
  • RAG réduit - Extraction déterministe + synthèse de LLM limitée

Articles connexes:

Code de source: GitHub - StyloFlow


L'incertitude fondamentale

Les moteurs de travail traditionnels vous demandent de déclarer ce qui se passera ultérieurement. Ce modèle demande aux composants de déclarer ce qu’ils produisent et ce dont ils ont besoin, alors permet aux signaux de coordonner l'exécutionM SK1

Le changement de clé: signals decouple, guides de confianceM SK1 protection des voies.

Il ne s’agit pas de choisir StyloFlow par rapport à Temporal ou Airflow - ceux-ci résolvent différents problèmes ( exécution durable , versionnement des flux de travail MSC4 coordination distribuée entre les centres de données M SK5 Il s’agissait d’articuler un modèle d’orchestrement différent MST6 un modèle où le flux de commande émerge des patrons de signaux plutôt que d’être explicitement programmed Mst7

Si vous construisez des pipelines AI/ML où

  • La confiance est importante (non pas seulement le succès /l’échecM SK2
  • L’évacuation est structurale (pas un cas spécialM SK1
  • Les composants ne devraient pas se connaître
  • L’observabilité doit être inhérente (ne doit pas être boulée sur )

... alors ces sémantiques d’exécution pourraient correspondre à ce que vous pensez

L'article 5 de la Loi sur l'immigration et le statut des réfugiés Bibliothèque temporaire est le fondement stable. StyloFlow ajoute la couche d’orchestre dirigée par - sur le haut de l’aéronef. Les deux sont en voie d’évolution grâce à leur utilisation réelle dans lucidRAG et Stylobot.

Pour des questions ou des commentaires,, voir le GitHub repository.

logo

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