文生图两步法::

  1. 大模型解析自然语言 → 生成图描述代码

    • 大模型并不会直接画图,而是生成 中间层 DSL(Domain Specific Language)

      • Mermaid:流程图、时序图、ER 图、甘特图等。

      • PlantUML:UML 图(类图、用例图、时序图)。

      • DOT (Graphviz):复杂关系图、拓扑图。

    • 优点:

      • 可追溯(存 DSL 代码即可做版本对比)。

      • 可控(只要保证 DSL 符合语法,渲染就稳定)。

      • 易扩展(换渲染引擎也能兼容)。

  2. 渲染引擎 → 将 DSL 渲染为图像/交互图

    • 前端渲染:Mermaid.js、PlantUML.js → 直接在浏览器展示。

    • 后端渲染:Mermaid-cli、PlantUML Server、Kroki → 导出 SVG/PNG/PDF。

    • 可编辑化:在 Draw.io、Miro、tldraw 等可视化工具中再次打开、修改。


0. 目标与选型

  • 目标:把自然语言(流程/规范/需求)→ 转成 Mermaid 语法 → 渲染为流程图/时序图/ER图等。

  • 选型

    • 生成:DeepSeek(或任一兼容 OpenAI 风格的推理/指令模型)

    • 渲染:Mermaid.js(前端);如需服务器端出图或导出 PDF/SVG,补充 mermaid-cli / Kroki


1. 整体架构(推荐)

[用户输入] 
   → [LLM(DeepSeek): 生成 Mermaid 代码]
   → [语法校验/自修复: Mermaid parse/compile]
   → [渲染层: 前端 mermaid.js 或 后端 mmdc/kroki → SVG/PNG]
   → [前端展示 + 二次编辑 + 版本管理]
  • 只把 Mermaid 代码存库(不是图片),便于版本对比、可编辑、可重渲。

  • 失败自动修复:校验报错 → 把错误信息喂回 LLM 进行 代码自修复(最多 2 次)。


2. Prompt 约束(核心!)

让模型“只产出 Mermaid 代码”,并且可编译

System(示例)

你是“Diagram DSL 生成器”。严格按照 Mermaid v10 语法生成图表。
只输出代码块,不要解释。
优先使用 flowchart TD(流程图)。节点文案 ≤ 20 字,单图节点 ≤ 40。
不要使用 HTML/JS 片段。

User(示例)

需求:画“用户下单→支付→发货→签收”的流程,体现失败重试(最多 1 次)。加泳道:用户/系统/仓库。

期待模型输出(仅供理解)

flowchart TD
  subgraph 用户
    U1[下单]
    U4[签收]
  end
  subgraph 系统
    S1[支付] -->|失败| S2{是否重试?}
    S2 -->|是| S1
    S2 -->|否| S3[取消订单]
  end
  subgraph 仓库
    W1[发货]
  end
  U1 --> S1 --> W1 --> U4

附加规则

  • 只允许以下起始:flowchart, sequenceDiagram, classDiagram, erDiagram, gantt

  • 产出务必包在 三引号围栏 + mermaid 语言标记。


3. 后端:调用 DeepSeek 生成 Mermaid(示例)

以下用“OpenAI 风格”接口书写,保留 baseURL/apiKey 占位,避免绑定具体厂商细节。

Node.js(TypeScript/Express)

import express from "express";
import fetch from "node-fetch";

const app = express();
app.use(express.json());

const DEEPSEEK_API_BASE = process.env.DEEPSEEK_API_BASE; // e.g. https://api.deepseek.com/v1
const DEEPSEEK_API_KEY  = process.env.DEEPSEEK_API_KEY;
const MODEL = process.env.DEEPSEEK_MODEL || "deepseek-chat"; // or deepseek-reasoner/xxx

app.post("/api/text2mermaid", async (req, res) => {
  const { userInput } = req.body;

  const messages = [
    { role: "system", content: "你是“Diagram DSL 生成器”。严格输出 Mermaid 代码块,符合 v10 语法,不要解释。" },
    { role: "user", content: `把以下需求转成 Mermaid:\n${userInput}\n只输出\`\`\`mermaid 代码块。` }
  ];

  const resp = await fetch(`${DEEPSEEK_API_BASE}/chat/completions`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${DEEPSEEK_API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      model: MODEL,
      temperature: 0.2,
      messages
    })
  });

  const data = await resp.json();
  const raw = data?.choices?.[0]?.message?.content || "";

  // 提取 ```mermaid ... ``` 代码块
  const match = raw.match(/```mermaid([\s\S]*?)```/i);
  if (!match) return res.status(400).json({ error: "NO_MERMAID_BLOCK", raw });

  const mermaid = match[1].trim();
  res.json({ mermaid });
});

app.listen(3000, () => console.log("server on :3000"));

Python(FastAPI)

from fastapi import FastAPI
from pydantic import BaseModel
import os, requests, re

app = FastAPI()
BASE = os.getenv("DEEPSEEK_API_BASE")  # e.g. https://api.deepseek.com/v1
KEY  = os.getenv("DEEPSEEK_API_KEY")
MODEL = os.getenv("DEEPSEEK_MODEL", "deepseek-chat")

class Query(BaseModel):
    userInput: str

@app.post("/api/text2mermaid")
def text2mermaid(q: Query):
    payload = {
        "model": MODEL,
        "temperature": 0.2,
        "messages": [
            {"role": "system", "content": "你是“Diagram DSL 生成器”。严格输出 Mermaid 代码块,符合 v10 语法,不要解释。"},
            {"role": "user", "content": f"把以下需求转成 Mermaid:\n{q.userInput}\n只输出```mermaid 代码块。"}
        ]
    }
    r = requests.post(f"{BASE}/chat/completions", json=payload, headers={
        "Authorization": f"Bearer {KEY}",
        "Content-Type": "application/json"
    })
    data = r.json()
    raw = data.get("choices", [{}])[0].get("message", {}).get("content", "")
    m = re.search(r"```mermaid([\s\S]*?)```", raw, re.I)
    if not m:
        return {"error": "NO_MERMAID_BLOCK", "raw": raw}
    return {"mermaid": m.group(1).strip()}

说明:

  • 生产里建议走 流式(server-sent events)降低首帧延迟。

  • 对“只输出代码块”的约束非常关键,能极大降低后续清洗难度。


4. 语法校验与自修复(强烈建议)

前端快速校验(基于 mermaid 的 parse)

import mermaid from "mermaid";
mermaid.initialize({ startOnLoad: false, securityLevel: "strict" });

export async function tryCompile(code: string) {
  try {
    // 仅尝试渲染(若语法错误会 throw)
    await mermaid.render("x", code);
    return { ok: true };
  } catch (e: any) {
    return { ok: false, error: String(e?.message || e) };
  }
}

后端自修复(把错误回传给 LLM 让它修正)

async function fixMermaidWithLLM(badCode: string, errorMsg: string) {
  const messages = [
    { role: "system", content: "修复 Mermaid 代码。只输出```mermaid ...```。" },
    { role: "user", content: `这段 Mermaid 无法通过编译,请修复:\n\`\`\`mermaid\n${badCode}\n\`\`\`\n错误:${errorMsg}` }
  ];
  // 调用同一 LLM 接口,省略…
}

策略:最多尝试 2 次;仍失败则提示用户“切换到简化模式/分段生成”。


5. 渲染层实现

5.1 前端渲染(React 组件示例)

import { useEffect, useState } from "react";
import mermaid from "mermaid";

mermaid.initialize({ startOnLoad: false, securityLevel: "strict", theme: "default" });

export default function MermaidViewer({ code }: { code: string }) {
  const [svg, setSvg] = useState<string>("");

  useEffect(() => {
    let canceled = false;
    (async () => {
      try {
        const { svg } = await mermaid.render(`mmd-${Date.now()}`, code);
        if (!canceled) setSvg(svg);
      } catch (e) {
        if (!canceled) setSvg(`<pre style="color:#c00">${String(e)}</pre>`);
      }
    })();
    return () => { canceled = true; };
  }, [code]);

  return <div dangerouslySetInnerHTML={{ __html: svg }} />;
}

securityLevel: "strict" 以减少 XSS 风险。可按需允许 loose 但务必做 HTML 清洗。

5.2 服务器端出图(导出 PNG/SVG/PDF)

  • mermaid-cli(mmdc):适合离线批量导出、PDF 报告。

    npx @mermaid-js/mermaid-cli -i input.mmd -o output.svg
    
  • Kroki:一个网关支持 Mermaid/PlantUML/Graphviz,多格式返回。

    POST /mermaid/svg
    { "code": "flowchart TD; A-->B;" }
    

6. 前端交互与体验

  • 双模编辑:“自然语言”与“Mermaid 源码”可相互切换;

    • 用户手改源码 → 重新渲染;

    • 点“再优化” → 触发 LLM 重写 DSL(带上当前代码作为上下文)。

  • 布局选项flowchart TD/LR、主题、节点形状(矩形/圆角/菱形)。

  • 大图策略:节点 > 60 时提示“切分子流程”;或切换到时序图/分组子图。

  • 可访问性:SVG <title>/aria-label


7. 存储与版本管理(结合你们知识库/EA)

  • Mermaid 源码 + 渲染参数(主题、方向、时间戳、作者、来源文档 ID)。

  • 版本对比:基于文本 diff,展示“增加/删除的节点/边”。

  • 可追溯:在图的 metadata 里标注“由哪些知识库文档生成(文档ID/段落ID)”。


8. 权限、审计、合规

  • 读写权限按知识库分组/项目分配。

  • 审计:记录“谁在何时用什么提示生成了哪张图,是否手改过”。

  • 安全:前端渲染前做 XSS 清洗;服务端渲染走隔离容器。


9. 质量与评估

  • 自动化用例:给一组标准输入 → 校验编译成功、节点/边数量、关键文案是否出现。

  • 人工评审:每周抽样 20% 图,标注“可读性/一致性/是否贴合元模型”。

  • 点击流:看“生成后是否被二次编辑、导出率、被文档引用率”。


10. 最小可行版本(两周内可落地)

  1. 前端:输入框 + MermaidViewer;

  2. 后端:/api/text2mermaid 调用 DeepSeek + 代码块提取;

  3. 校验:前端 mermaid.render try/catch;失败 → 弹窗“自动修复”;

  4. 存储:把 Mermaid 源码与关联知识库文档 ID 入库;

  5. 导出:提供 SVG 下载。


常见坑 & 解决

  • 模型输出夹带解释 → 强 System 约束 + 只提取代码块;

  • 语法小错误 → 启用“自修复回路”;

  • 大图渲染缓慢 → 预警并建议拆分;或改用服务端渲染并缓存;

  • 标签太长 → 限制 20 字内、超出省略;

  • 安全securityLevel: "strict"、DOMPurify 清洗 SVG。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐