Skip to content

.NET: Internal "Batcher" nodes clutter workflow visualizations in concurrent patterns #1496

@joslat

Description

@joslat

Summary

When using AgentWorkflowBuilder.BuildConcurrent() or fan-out/fan-in patterns with multiple agents, the workflow visualizations (Mermaid and DOT diagrams) display mysterious "Batcher" nodes with cryptic identifiers. These appear to be internal framework components for managing concurrent agent execution, but they create significant visual noise and make diagrams difficult to understand.

These Batcher nodes serve no purpose for end users trying to understand workflow structure and should either be:

  1. Hidden from visualizations (preferred)
  2. Simplified into a single fan-in aggregation node
  3. Clearly labeled with meaningful names if they must be shown

Related Issues

#1495

Current Behavior

When building a concurrent workflow with multiple agents, the visualization output includes intermediate "Batcher" nodes:

// Build a concurrent workflow with 3 translation agents
var workflow = AgentWorkflowBuilder.BuildConcurrent(
    from lang in new[] { "French", "Spanish", "English" }
    select GetTranslationAgent(lang, chatClient)
);

// Generate visualization
Console.WriteLine(workflow.ToMermaidString());

Actual Output (Mermaid):

flowchart TD
    Start["Start (Start)"];
    4eaedcde6c56467e8fd92a68b98fb057["4eaedcde6c56467e8fd92a68b98fb057"];
    cc0c636b920b4dd1ba5000ccfdadf6de["cc0c636b920b4dd1ba5000ccfdadf6de"];
    1524c98619994e4fbb45bd2b26414a4e["1524c98619994e4fbb45bd2b26414a4e"];
    Batcher/4eaedcde6c56467e8fd92a68b98fb057["Batcher/4eaedcde6c56467e8fd92a68b98fb057"];
    Batcher/cc0c636b920b4dd1ba5000ccfdadf6de["Batcher/cc0c636b920b4dd1ba5000ccfdadf6de"];
    Batcher/1524c98619994e4fbb45bd2b26414a4e["Batcher/1524c98619994e4fbb45bd2b26414a4e"];
    ConcurrentEnd["ConcurrentEnd"];

    fan_in::ConcurrentEnd::BAD20FD4((fan-in))
    Start --> 4eaedcde6c56467e8fd92a68b98fb057;
    Start --> cc0c636b920b4dd1ba5000ccfdadf6de;
    Start --> 1524c98619994e4fbb45bd2b26414a4e;
    4eaedcde6c56467e8fd92a68b98fb057 --> Batcher/4eaedcde6c56467e8fd92a68b98fb057;
    cc0c636b920b4dd1ba5000ccfdadf6de --> Batcher/cc0c636b920b4dd1ba5000ccfdadf6de;
    1524c98619994e4fbb45bd2b26414a4e --> Batcher/1524c98619994e4fbb45bd2b26414a4e;
    Batcher/4eaedcde6c56467e8fd92a68b98fb057 --> fan_in::ConcurrentEnd::BAD20FD4;
    Batcher/cc0c636b920b4dd1ba5000ccfdadf6de --> fan_in::ConcurrentEnd::BAD20FD4;
    Batcher/1524c98619994e4fbb45bd2b26414a4e --> fan_in::ConcurrentEnd::BAD20FD4;
    fan_in::ConcurrentEnd::BAD20FD4 --> ConcurrentEnd;

Which renders beautifully as:
Image

Issues:

  1. Three mysterious "Batcher" nodes appear between agents and the fan-in aggregator
  2. Each Batcher node has a GUID-based identifier (e.g., Batcher/4eaedcde6c56467e8fd92a68b98fb057)
  3. Doubles the visual complexity - what should be 3 agents + 1 aggregator becomes 3 agents + 3 batchers + 1 fan-in node
  4. No user-facing purpose - these appear to be internal implementation details
  5. Same issue as agent GUIDs - both problems compound to make diagrams nearly unreadable

Expected Behavior

Batcher nodes should be hidden from end-user visualizations or simplified into the fan-in aggregation node:
Option 1: Hide Batchers

flowchart TD
    Start["Start"];
    FrenchAgent["French Translation Agent"];
    SpanishAgent["Spanish Translation Agent"];
    EnglishAgent["English Translation Agent"];
    ConcurrentEnd["Aggregator"];

    Start --> FrenchAgent;
    Start --> SpanishAgent;
    Start --> EnglishAgent;
    FrenchAgent --> ConcurrentEnd;
    SpanishAgent --> ConcurrentEnd;
    EnglishAgent --> ConcurrentEnd;

✅ Clean, understandable, shows only user-defined components

Option 2: Single Aggregation Node (Preferred)

flowchart TD
    Start["Start"];
    FrenchAgent["French Translation Agent"];
    SpanishAgent["Spanish Translation Agent"];
    EnglishAgent["English Translation Agent"];
    FanIn((Fan-In Aggregator));
    ConcurrentEnd["Output"];

    Start --> FrenchAgent;
    Start --> SpanishAgent;
    Start --> EnglishAgent;
    FrenchAgent --> FanIn;
    SpanishAgent --> FanIn;
    EnglishAgent --> FanIn;
    FanIn --> ConcurrentEnd;

✅ Shows aggregation explicitly but keeps it simple

Option 3: Meaningful Names (If Must Show)

flowchart TD
    Start["Start"];
    FrenchAgent["French Translation Agent"];
    SpanishAgent["Spanish Translation Agent"];
    EnglishAgent["English Translation Agent"];
    FrenchBatcher["French Output Batcher"];
    SpanishBatcher["Spanish Output Batcher"];
    EnglishBatcher["English Output Batcher"];
    ConcurrentEnd["Aggregator"];

    Start --> FrenchAgent;
    Start --> SpanishAgent;
    Start --> EnglishAgent;
    FrenchAgent --> FrenchBatcher;
    SpanishAgent --> SpanishBatcher;
    EnglishAgent --> EnglishBatcher;
    FrenchBatcher --> ConcurrentEnd;
    SpanishBatcher --> ConcurrentEnd;
    EnglishBatcher --> ConcurrentEnd;

⚠️ Still cluttered but at least understandable

Benefits:

  1. Clarity: Diagrams show only meaningful workflow components
  2. Simplicity: Reduced visual noise for complex workflows
  3. Professionalism: Diagrams are presentation-ready
  4. Consistency: Matches user expectations (no internal implementation leaking)

Root Cause Analysis (Hypothesis)

The "Batcher" executors appear to be an internal framework mechanism for:

  1. Managing concurrent agent execution and message distribution
  2. Collecting agent outputs before passing to fan-in aggregators
  3. Possibly handling streaming/buffering of agent responses
    Possible reasons they appear in visualizations:
    • Batchers are registered as graph nodes during workflow construction
    • Visualization logic includes ALL executors without filtering internal ones
    • No distinction between "user-facing" and "internal" executors
    Why this is problematic:
    • Leaks implementation details into user-facing API
    • Makes abstraction layer transparent when it should be opaque
    • Violates principle of least surprise

Workaround

Current workaround: None available. Developers must:
• Manually edit generated diagrams to remove Batcher nodes
• Ignore Batcher nodes when reading diagrams (confusing for new users)
• Avoid using workflow visualizations for documentation

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions