AUTOPSY

Can AI draw my network diagram?

It drafts well and it invents links. The fix is structural. Never ask a model for the picture; ask it for the code that builds the picture from your data, then check the rendered result against the data with a script rather than with your eyes.

Reading this, you will:
  • Prompt for a transform instead of an artifact, so the output can be reviewed.
  • Write a check that compares a generated diagram against the data it came from.
  • Recognize the failure that looks like success.

It drafts well and it invents links. Both are reliably true, and the second one is the reason this needs a procedure rather than a caution.

The diagrams as code article names the two failure modes. This note is the procedure that handles them.

What it is genuinely good at

The mechanical parts of diagram syntax, where the transformation is defined and the model is not being asked to know anything about your network.

  • Sanitizing and declaring. Turning forty hostnames into legal ids and node declarations is exactly the tedious, rule-following work models do well.
  • Converting between diagram types. You wrote a failover procedure as a flowchart and realize it is a message exchange. Restructuring it into a sequence diagram is mechanical.
  • Explaining syntax you inherited. Paste a diagram from a teammate, ask what each line does, then verify by changing one line and rerendering.
  • Writing the generator. The rest of this note explains why, and how to verify what it produces.

The failure that survives review

Ask for a diagram from a neighbor table and you can get output like this. The data had four links. The diagram has five:

flowchart TD
  acc_sw01["acc-sw01"]
  core_sw01["core-sw01"]
  core_sw02["core-sw02"]
  rtr_edge01["rtr-edge01"]
  acc_sw01 ---|"Gi1/0/48 to Gi1/0/1"| core_sw01
  acc_sw01 ---|"Gi1/0/47 to Gi1/0/1"| core_sw02
  core_sw01 ---|"Te1/1/1 to Gi0/0/0"| rtr_edge01
  core_sw01 ===|"Po1 to Po1"| core_sw02
  core_sw02 ---|"Te1/1/1 to Gi0/0/1"| rtr_edge01

The last line is invented. There is no second uplink to the edge router in the neighbor data. It is a reasonable guess, because a redundant core usually does have one. That is what makes it dangerous. It renders without error, and it looks exactly like the redundant design a reviewer expects to see.

A syntax error would have stopped the renderer and cost you ten seconds. This one gets found during a failover, when somebody expects a path that was never cabled.

Ask for the generator

This removes the class of error instead of catching it after the fact.

A diagram pasted back into chat is a one-off artifact. You verify it once, and next month you do the whole thing again with no accumulated confidence. With code you review it once and every future run inherits that review.

A prompt that produces something reviewable gives the model the shape of the input and asks for a transform:

I have LLDP neighbor records as a list of dicts with the keys local, local_intf, remote, and remote_intf. Write a Python function that returns a Mermaid flowchart TD string. Declare each device once, sorted by hostname. Emit one undirected link per record, sorted, with both interface names on the label. Sanitize hostnames into legal Mermaid ids and raise if two different hostnames produce the same id. Do not add any link that is not in the input.

Naming the key shape stops the model guessing at your data. Asking for sorted output makes the result diffable. The collision check catches a bug that hand-written generators often miss. The last sentence is worth including even though a correct program cannot invent a link, because it shapes what gets written.

Now the model never sees your topology. It writes a function that transforms records it never reads, and the function is right or wrong in a way you can test with three records at your desk.

Checking a diagram against its data

When you do end up with a diagram from a model, or from a colleague, or from a generator you have not reviewed, compare it to the source rather than reading it.

Parse the edges back out and compare the sets:

import re

EDGE = re.compile(r"^\s*(\w+)\s*[-=.]{2,}[->o x]*\|?[^|]*\|?\s*(\w+)\s*$")


def edges_in_diagram(mermaid_text):
    """Every node pair the diagram draws, direction ignored."""
    found = set()
    for line in mermaid_text.splitlines():
        match = EDGE.match(line)
        if match:
            found.add(frozenset(match.groups()))
    return found


def edges_in_data(links):
    """Every node pair the neighbor data supports."""
    return {
        frozenset([node_id(l["local"]), node_id(l["remote"])])
        for l in links
    }


def check(mermaid_text, links):
    drawn = edges_in_diagram(mermaid_text)
    real = edges_in_data(links)

    invented = drawn - real
    missing = real - drawn

    for pair in sorted(invented):
        print(f"INVENTED: {' to '.join(sorted(pair))} is not in the data")
    for pair in sorted(missing):
        print(f"MISSING: {' to '.join(sorted(pair))} is in the data, not drawn")

    return not (invented or missing)

Run that against the diagram above and it prints one line naming core_sw02 to rtr_edge01 as invented. Fifteen lines of code, and it finds the error that survives a careful read.

Two limits worth being honest about. Comparing node pairs does not check the interface labels, so a transposed port number still gets through; extend the key to include interfaces when you need that precision. And this checks the diagram against your data, not your data against the network. A diagram faithfully generated from a stale collection is faithfully wrong, which is a different problem covered in keeping diagrams from going stale.

Before you paste device output anywhere

A neighbor table carries hostnames, interface names, management addresses, and platform strings. Together that is a usable description of your infrastructure.

Check your organization’s policy before pasting it into any hosted model. If a sanitized version is allowed, sanitize it. And note that the generator approach above sidesteps this entirely: the model writes a function, you run it locally, and your topology never leaves the network. That is a reason to prefer it on its own, separate from the verification argument.

If you want to see the transform run with nothing sent anywhere, the network diagram generator does the parse in your browser, with no account and no upload.

The same two moves elsewhere

Neither move here is specific to Mermaid. Diagrams are a good place to practice them, because a wrong diagram costs you a confused colleague rather than a down site. The AI-Assisted Network Automation course points the same two moves at configuration, validation, and change records, where a plausible wrong answer is considerably more expensive.