nyxcore-systems
5 min read

Visualizing LLM Insights: Bringing Reports to Life with Mermaid Diagrams

We just shipped a feature that integrates Mermaid diagrams into our LLM-generated reports, transforming raw text insights into compelling, easy-to-understand visuals. Here's how we did it.

LLMMermaidPrompt EngineeringReport GenerationFrontendBackendTypeScript

Anyone who's worked with LLM-generated content knows its power, but also its potential Achilles' heel: a wall of text. While incredibly insightful, sometimes you just need a picture to grasp the essence of a complex idea. That's exactly the challenge we tackled this week: integrating visual explanations into our LLM-generated reports using Mermaid diagrams.

Our goal was simple: instruct the LLM to generate Mermaid syntax within its report output, which our existing frontend could then pick up and render. The beauty of Mermaid is its simplicity – plain text descriptions convert into stunning diagrams, perfectly aligned with our markdown-first approach.

Guiding the LLM to Visualize: The Prompt Engineering Deep Dive

The heavy lifting for this feature happened entirely in our prompt engineering. We needed to tell the LLM what kind of diagrams to generate and, crucially, how to generate them correctly within a markdown context. This involved two main components injected into our system prompt:

1. Contextual Diagram Types via STYLE_TEMPLATES

First, we enhanced our STYLE_TEMPLATES in src/server/services/report-generator.ts. Each report style (executive, security, marketing, technical) now includes specific instructions for the LLM on which Mermaid diagram types are most appropriate. This ensures the visuals complement the report's purpose. For instance, a 'technical' report might lean towards flowcharts or component diagrams, while a 'marketing' report would benefit from pie charts.

typescript
// src/server/services/report-generator.ts (simplified example)
const STYLE_TEMPLATES = {
    executive: `... Include 2-3 concise pie charts or flowcharts summarizing key metrics or processes.`,
    security: `... Generate 1-2 flowcharts or sequence diagrams illustrating attack vectors or mitigation steps.`,
    technical: `... Use 2-3 detailed flowcharts or component diagrams to explain system architecture or data flows.`,
    marketing: `... Focus on 1-2 engaging pie charts or bar charts for market share or campaign performance.`,
};

2. Strict Mermaid Syntax Guidance (MERMAID_GUIDANCE)

Crucially, we also added a MERMAID_GUIDANCE constant. This isn't just about what diagrams, but how to construct them. LLMs are powerful, but they benefit immensely from clear constraints. Our guidance included:

  • Conciseness: Max 15 nodes per diagram (to prevent overwhelming visuals).
  • Clarity: Short, descriptive labels.
  • Purity: No special characters in node labels (Mermaid can be finicky).
  • Placement: Inline using ```mermaid ... ``` blocks.
  • Quantity: A limit of 2-3 diagrams per report (to maintain readability and focus).
typescript
// src/server/services/report-generator.ts (simplified)
const MERMAID_GUIDANCE = `
When generating Mermaid diagrams:
- Keep diagrams concise, max 15 nodes.
- Use short, descriptive labels for nodes.
- Avoid special characters like quotes or brackets within node labels.
- Place diagrams inline using \`\`\`mermaid ... \`\`\` blocks.
- Include 2-3 diagrams per report where relevant.
`;

// ... later in generateReport() function
const systemPrompt = assembleSystemPrompt(
    reportStyle,
    MERMAID_GUIDANCE, // Injected here!
    // ... other contextual instructions
);

This MERMAID_GUIDANCE was then injected directly into our system prompt assembly within the generateReport() function, ensuring the LLM had all the necessary context before generating its output.

Frontend: A Seamless Integration Story

One of the most satisfying parts of this feature rollout was the lack of frontend changes required. Our existing src/components/markdown-renderer.tsx component was already equipped to handle ```mermaid code blocks. This is thanks to our MermaidDiagram component, which lazy-loads mermaid v11.12.3 and applies our dark theme.

It's a testament to planning for extensibility – when you build a robust markdown renderer, new markdown-based features often slot right in without a hitch. This saved us significant development time and kept the deployment footprint minimal.

Lessons Learned: Navigating Database Quirks

This particular session was remarkably smooth – a rare single-file prompt change, clean typecheck, and immediate results. However, every developer knows that "smooth" often hides a "gotcha" from a previous or future task. My recurring "pain" note from the session handoff is a good example of an operational detail worth sharing:

Database Schema Drift with db:push: We've encountered an intermittent issue where running db:push (our Prisma migration command) can drop the embedding vector(1536) column on our workflow_insights table. This isn't directly related to the Mermaid feature, but it's a critical operational detail that requires attention.

The immediate workaround is always to restore that column manually after a db:push. Longer term, we're investigating why this specific column is susceptible to being dropped – perhaps a nuance in how Prisma handles custom types or a specific migration strategy we need to refine. It's a reminder that even when your feature code is clean, infrastructure nuances can always sneak up on you. Always keep an eye on those recurring "minor" issues – they often point to deeper architectural considerations.

What's Next: Polishing the Visual Experience

With the core integration complete and committed (b2b1920), our immediate next steps are focused on quality assurance and refinement:

  1. Comprehensive QA: Verify mermaid diagrams render correctly across all report styles and ensure graceful handling of any syntax errors from the LLM (falling back to raw code blocks if the diagram can't parse).
  2. Token Management: We'll be closely monitoring maxTokens. Adding diagrams naturally increases prompt and completion length. If we see truncation in longer reports, increasing the maxTokens from 4096 will be our next adjustment.

Conclusion

Bringing Mermaid diagrams into our LLM-generated reports is a significant step towards making our insights more accessible and impactful. It's a great example of how thoughtful prompt engineering, combined with a flexible frontend, can unlock powerful new capabilities without a complete overhaul. Happy visualizing!

json
{
  "thingsDone": [
    "Enhanced LLM prompt templates for each report style to specify appropriate Mermaid diagram types (executive, security, marketing, technical).",
    "Created and injected `MERMAID_GUIDANCE` constant outlining Mermaid syntax rules (max nodes, labels, special characters, placement, quantity) into the system prompt.",
    "Verified existing frontend `markdown-renderer.tsx` component already supports ` ```mermaid ` code blocks via `MermaidDiagram` component (lazy-loaded mermaid v11.12.3, dark theme).",
    "Committed and pushed feature (`b2b1920`) to main."
  ],
  "pains": [
    "Recurring `db:push` issue intermittently dropping `embedding vector(1536)` column on `workflow_insights` table, requiring manual restoration. This was noted as an operational concern, not a blocker for the current feature."
  ],
  "successes": [
    "Smooth, single-file prompt change with no major issues encountered during development.",
    "Clean typecheck and immediate positive results in LLM output.",
    "No frontend changes required, validating robust architectural decisions for markdown rendering.",
    "Successfully integrated visual elements into LLM-generated reports, enhancing readability and impact."
  ],
  "techStack": [
    "TypeScript",
    "Node.js",
    "LLM (Large Language Model - e.g., OpenAI GPT series)",
    "Mermaid.js",
    "React (for frontend components)",
    "Prisma (for database interaction)",
    "Markdown"
  ]
}