我第一次接触 Mermaid 语法,是在一次方案评审前,同事把流程图丢进PPT,我为了改一个判断分支,整整折腾了二十分钟。从那时候起我就意识到:凡是"图比文字贵"的地方,一定需要一种能用文本描述图表的方式。Mermaid 就是干这个的——它用类似代码的简练语法画流程图、时序图、状态图、类图,渲染出来是清晰的 SVG 图片,底层却是纯文本,天然支持 diff、版本管理和多人协作。如果你写技术方案、维护接口文档、做个人知识库,或者只是想让会议上的逻辑图不再每次重画,Mermaid 都值得花半小时入门。这篇文章我会从最基本的 graph 语法开始,一路拆到 CLI 渲染和自动化校验,把我实际踩过的坑一并讲清楚。
1. 为什么我在所有文档里都改用 Mermaid 画图
1.1 从一段"画完就没人维护"的流程图说起
以前画流程图,我最常用的工具是 Draw.io 和 PowerPoint。图形界面的问题不在于"画不出来",而在于"画完就没人愿意改"。一张图放在文档里,过两周业务规则变了,想找到源头文件都麻烦,更别说让多个同事同时编辑。最痛的一次,是核心流程改动后,图还停在旧逻辑上,评审会上被当场指出,场面非常尴尬。
Mermaid 把"画图"变成了"写代码"。节点用A[开始],连线用-->,整张图就是一个纯文本文件。你不需要拖动方块,不需要对齐箭头,只需要在编辑器里改一个字符。因为内容是文本,用 Git 管理时能看到每一行变化;同事 review 流程图,就像 review 代码一样,指出"第 7 行的判断条件不对"就行。这种"含金量"是图形工具给不了的。
所以我的使用场景很明确:架构设计、接口调用链、发布流程、故障排查手册、个人笔记。凡是可能被反复修改的图,我一律用 Mermaid;只有面向客户演示、需要精致排版的少数场景,才会导出 SVG 后再用图形工具补一层。Mermaid 的目标不是取代所有画图软件,而是让"图"回归到"信息表达"本身。
1.2 Mermaid 与"语法"这件事的关系
严格说起来,Mermaid 不是编程语言,而是一种领域特定语言(DSL)。它的语法范围被刻意控制在"描述图表"这个领域里,关键字不多,没有变量作用域,没有函数调用,学习成本很低。你只需要记住:节点怎么声明、连线怎么连、不同图类型有哪些专属关键字,就够了。
它与我们熟悉的 Markdown 语法是天然的搭档。Markdown 负责排版文字,Mermaid 负责插图。GitHub、GitLab、Hexo、VuePress、Docusaurus、Typora、Obsidian,这些常见平台都已经内置或通过插件支持 Mermaid。也就是说,你在写 README、Wiki、接口文档时,不需要把图片文件单独存一个目录,只要把 Mermaid 源码放在 Markdown 的围栏代码块里,页面打开时自动渲染成图。
很多从编程语言过来的人,会把 Mermaid 的简写记法称为"语法糖"。比如A --> B代表一条带箭头的连线,A --- B代表一条无箭头连线,A ==文字==> B代表一条加粗且带文字的连线。这些符号本质上都是"完整写法的简化形式",和你在代码里用for循环省略步进变量一样,看着简单,表达能力却不弱。对不会编程的人来说也不用怕:你不需要理解什么叫 AST,只需要把语法当作"画图的约定符号"来记,就像记住交通标志一样自然。
1.3 解析思路:看着像文本,其实是 AST
我第一次遇到 Mermaid 报错时,第一反应是"这也能报错?"。后来查了一下它的实现,才明白 Mermaid 并不是把文本直接翻译成 HTML,它要经过一个真正的解析过程:先做词法分析,把文本切分成关键字、括号、引号、ID、箭头等 token;再根据当前图类型,生成一个抽象语法树(AST);最后再由渲染器遍历这棵树,输出 SVG。这也是为什么 Mermaid 能在浏览器和 Node.js 环境里共用同一套语法——图和平台无关,只和输入的文本结构有关。
理解这一点,对你排查语法问题特别有帮助。比如graph TD里,graph是图类型关键字,TD是方向关键字,它们之间的顺序不能乱;再比如A[开始]中,A是节点 ID,[开始]是显示文本,方括号在语法树里就是一个"形状标记",你用成中文全角括号【】,解析器就认不出来了。还有缩进,Mermaid 不是靠缩进确定结构的语言,但在subgraph子图内部,缩进可以大幅提升可读性;如果缩进混乱导致end不匹配,渲染结果会差很远。
所以遇到报错,别急着怀疑工具,先看它提示的行号和 token,再去对照官方关键字。大部分 Mermaid 报错,本质都是"你写的东西不在语法树的设计范围里"。
2. 流程图语法拆解:节点、连线、子图的每一处细节
2.1 最小的 graph 声明:为什么方向关键字不能随便写
流程图的 Mermaid 语法从graph开始,后面跟着方向关键字。常见的有TB(从上到下)、TD(从上到下,和 TB 等价)、BT(从下到上)、LR(从左到右)、RL(从右到左)。如果你不写方向,默认也是从上到下排列,但建议还是显式写清楚,因为方向影响布局,布局又会直接影响别人对流程的理解。
一个最简单的图只需要三行文本:
graph TD A[开始] --> B{是否就绪?} B -- 是 --> C[执行任务] B -- 否 --> D[等待]在支持 Mermaid 的编辑器里,把这段源码放进围栏代码块并标记为 mermaid 语言,就能看到:开始节点指向一个菱形判断,判断分两条路径流出。这里A、B、C、D都是节点 ID,方括号内是显示文本,花括号代表判断节点。刚开始学的时候最容易犯的错,是把方向写成TR或DT,这类错误解析器会直接抛Lexical error,而且报错位置很可能离真实问题不远。
节点 ID 的命名也要养成习惯。虽然 Mermaid 允许中文 ID,但建议统一用英文 ID 加中文标签,例如user[用户]、server[服务端]。因为后面你可能会给节点加样式、绑定点击事件,甚至用脚本生成文档,英文 ID 在自动化处理时远比中文可靠。不规范命名的代价,在只有几行的小图里不明显,一旦图超过二十个节点,就会混乱到连自己都分不清。
2.2 节点形状的"语法糖":用最少字符表达最清晰的结构
Mermaid 节点形状是一组很容易记的"语法糖",用不同的括号包裹显示文本,就能切换形状。下面是我自己经常用的对照表:
| 写法 | 渲染形状 | 常用语义 |
|---|---|---|
A[文本] | 矩形 | 普通步骤、动作 |
A(文本) | 圆角矩形 | 也可表示步骤,或温和的开始/结束 |
A((文本)) | 圆形 | 开始、结束、入口、出口 |
A{文本} | 菱形 | 判断、条件分支 |
A[[文本]] | 子程序 | 调用外部流程 |
A[/文本/] | 平行四边形 | 输入、输出、数据 |
A>文本] | 不对称矩形 | 请求方、客户端角色 |
我实际用下来的体会是:不要贪多。大部分流程图只需要三种形状——矩形表示步骤、菱形表示判断、圆形或圆角表示开始结束。其他形状用于特定场景,比如数据流图用平行四边形,架构图用子程序样式。全图花里胡哨反而失去重点。团队里如果还没有约定,我建议直接在文档规范里写死:业务流程图只用矩形 + 菱形 + 圆形三种,其余形状杜绝滥用。
另外,形状括号必须成对出现,而且要在英文半角状态下输入。中文【文本】和英文[文本]在屏幕上看着相似,解析结果完全不同。这个坑我踩过很多次,尤其在习惯使用中文输入法的情况下。如果你发现图渲染不出来,先检查所有括号是不是半角。
2.3 连线不只有箭头:实线、虚线、粗线、带文字
流程图的连线语法,是 Mermaid 里变体最多的地方。最基本的-->是实线箭头,表示流程从上一个节点流向下一个节点;---是无箭头实线,表示关联但不强调方向;-.->是虚线箭头,我通常用来表示"可选的、异步的、消息类的流转";==>是粗线箭头,表示主路径或者强依赖关系。具体选哪种没有绝对标准,关键是整个图要保持一致,否则读者会困惑。
给连线加文字是最常见的需求。写法有好几套,例如:
graph LR A[提交订单] -- 包含商品 --> B[库存校验] B -- 库存不足 --> C[提示失败] B -- 库存充足 --> D[扣减库存]这里-- 包含商品 -->表示实线箭头加文字标签。你也可以写成A -->|包含商品| B,两种方式都能渲染出相同效果,我比较推荐后者,因为它在处理复杂长文本时更容易对齐。虚线加文字则是A -. 可选步骤 .-> B,粗线加文字是A == 主路径 ==> B。
还有一个容易被忽略的写法是"链式连线":A --> B --> C。它等价于A --> B和B --> C两条线,节点 B 会自动出现在中间。这种写法在流程简单时很清爽,但我建议不超过五六层,否则中间节点很难插入分支。分支多的时候,还是老老实实写成一行的两个判断,清晰度远胜"一条线串到底"。
2.4 子图和样式类:让大图不至于失控
当流程图节点超过二十个,最有效的整理手段不是调字号,而是子图subgraph。它的作用是把一组节点圈进一个容器,视觉上形成"模块分区"。语法如下:
graph TD subgraph 订单服务 A[创建订单] --> B[支付] B --> C[发货] end subgraph 物流服务 D[揽收] --> E[运输] E --> F[签收] end C --> D子图可以嵌套,也可以带 ID:subgraph s1[订单服务]。这里要特别提醒:子图标题如果直接跟在subgraph后面,Mermaid 会把它当作 ID,再看后面的空格当作显示文本,容易产生歧义。我习惯始终显式写成subgraph s1[标题]这种带 ID 的形式,避免解析问题。
节点样式方面,Mermaid 支持style和classDef。classDef类似于给一组节点定义一个样式类,再用class 节点ID 类名去应用;也支持在节点定义时直接加:::类名。比如:
graph TD classDef ok fill:#e6ffed,stroke:#2da44d,stroke-width:2px classDef warn fill:#fff8c5,stroke:#d4a72c,stroke-width:2px A[完成]:::ok --> B[重试]:::warn这套写法和 CSS 的思路很像。它不是你画完图之后需要用鼠标一点点调色,而是在文本里声明好"哪些节点是什么语义"。颜色在这里不只是装饰,它传递状态:绿色代表正常,黄色代表需要注意,红色代表错误。团队一旦接受这套约定,评审流程图的时候就不需要一张张问"这个节点什么含义"。
2.5 从 pipeline 脚本语法看 Mermaid:文本即结构
如果你写过 Jenkins Pipeline 或者 GitLab CI Pipeline,你会发现 Mermaid 的思路和 pipeline 脚本语法出奇地一致。Pipeline 用stage、steps、when把一段部署流程结构化;Mermaid 用graph、subgraph、节点和箭头把业务流程图结构化。两者都是"用文本描述过程",都强调层级和顺序,也都支持条件分支。
我见过不少团队,Jenkins 的 pipeline 脚本写得规规矩矩,一到画架构图就回到 PPT。其实完全可以把写 pipeline 的思维搬过来:先画骨架,把大阶段列出来,再往每个阶段里补节点。比如一次发布流程,如果写成 pipeline 大概是"构建 -> 测试 -> 部署 -> 验证"四个 stage,对应到 Mermaid 里就是一个从左到右的graph LR,每个 stage 用一个subgraph包起来,stage 内部再写具体步骤。这种转换几乎没有学习成本,只需要记住 Mermaid 的关键字就行。
从更广的角度看,GitHub Actions 的job/steps、Docker Compose 的services、Ansible 的tasks,这些都是同一种思维模型。你越熟悉任何一种"声明式流程语法",学 Mermaid 就越快。反过来,Mermaid 也能帮你直观检查这些脚本里的依赖关系——把脚本里的步骤节点和连线画出来,阶段之间的依赖看不清楚的问题往往一目了然。
3. 时序图、状态图、类图的差异化语法:别把四种图写成一种形状
3.1 时序图:参与者、消息箭头、激活框
流程图适合表达"分支和决策",但如果你要表达的是"多个角色之间按时间顺序发送消息",时序图是更准确的选择。Mermaid 的时序图由sequenceDiagram开头,参与者用participant声明,消息用箭头表示。一个最小例子是这样:
sequenceDiagram participant U as 用户 participant S as 服务端 U->>S: 发起请求 activate S S-->>U: 返回结果 deactivate S这里participant U as 用户把参与者的 ID 设为 U,显示名设为"用户"。U->>S是实线箭头,表示同步请求;S-->>U是虚线箭头,表示响应。activate S和deactivate S配对使用,会在服务端生命线上画出激活框,直观展示处理时长。箭头方向是"从发送方到接收方",千万不要写反,否则整张图的消息顺序会误导人。
时序图的箭头类型还有几种:-)表示异步消息,--x表示带叉号的失败响应,-)表示异步完成。我在画接口调用链时,习惯用->>表示 HTTP 请求,用-->>表示响应,用-)表示 MQ 这种异步消息。Note left of U、Note right of S可以给参与者加解释性备注,适合标注超时、重试、缓存等补充信息。
时序图最常见的坑是activate和deactivate不配对。如果激活了服务端,后面忘了释放,渲染出来的图就会多出一段奇怪的竖条。另一个坑是参与者 ID 重名或大小写不一致,Server和server会被当成两个不同的参与者。命名规范越早定,后面维护越省心。
3.2 状态图:先把有限状态机想清楚
状态图stateDiagram-v2是我在订单流程、审批流程、前端页面状态里最喜欢用的图。它本质上就是有限状态机:每个节点是一个状态,箭头是一个迁移事件,箭头上的文字是触发条件。示例:
stateDiagram-v2 [*] --> 待处理 待处理 --> 处理中 : 开始 处理中 --> 已完成 : 成功 处理中 --> 待处理 : 失败回退 已完成 --> [*]这里的[*]是特殊的初始状态和终止状态。第一次写状态图的时候,我把它当普通节点处理,结果渲染出来的图里多了一个带中括号的奇怪节点。正确的做法是:初始状态用[*] --> 状态,结束状态用状态 --> [*],普通状态之间用-->连接,迁移条件用冒号跟在箭头后面。
状态图最值钱的地方在于,它逼你先想清楚"状态有哪些、什么条件下跳到哪个状态"。很多人把状态图画成了流程图,满图都是判断菱形,其实状态机的核心是"当前状态遇到事件后迁移到新状态",而不是"怎么一步步执行"。举个订单例子:待支付、已支付、已取消、退款中、已退款,这些是状态;"支付成功""用户取消""超时关闭"是事件;状态图展示的是事件触发后的状态转移,而不是整个支付接口的调用流程。
Mermaid 的状态图还支持并发状态--和组合状态,不过日常使用中,先把有限状态机的五种状态和四条迁移线画清楚,比堆叠复杂语法更实用。注意版本差异:旧版是stateDiagram,新版推荐stateDiagram-v2,后者的语法更严谨,渲染样式也更统一。
3.3 类图:用 UML 关系记录领域模型
类图是所有 Mermaid 图里最像"编程"的一种。它用classDiagram开头,类内部可以声明属性、方法,类之间可以声明继承、组合、聚合、依赖等关系。一个最小例子:
classDiagram class Animal { +String name +move() } class Dog { +bark() } Animal <|-- Dog这里Animal <|-- Dog表示"Dog 继承 Animal",箭头指向父类。属性和方法前的+表示公有,-表示私有,#表示保护。如果你不关心访问修饰符,也可以直接写String name和move(),但养成标+/-的习惯之后,图能承载的信息量会大很多。类图关系符号还有*--组合、o--聚合、-->关联、..>依赖。组合关系表示"整体与部分同生共死",聚合关系表示"可以独立存在",依赖关系表示"临时使用"。别把这些符号混用,否则领域模型会传达错误语义。
类图很适合做一次小型的领域建模。比如你在设计一个会员系统,先用类图把用户、订单、优惠券的关系画出来,再交给后端写代码。Mermaid 的类图不是代码生成器,它的价值在于把领域对象和关系落到文本里,方便评审和迭代。用 C++ 结构体链表、Java 类这类概念来类比也成立:类图上的+move()就是方法签名,-String name就是私有字段,语言本身是什么并不重要,关键是你把结构表达清楚了。
和类图思维更接近的,还有图数据库的 Cypher 基本语法。Cypher 用MATCH (a)-[r]->(b)表达节点和关系,Mermaid 类图也天然是"节点 + 关系线"。我记得第一次看到MATCH (user)-[:PAID]->(order)时,脑海里自动就浮现出一张类图:user和order是两个节点,PAID是关系。语法不同,底层思维一致。
3.4 一张语法速查表,比什么都管用
网上各种"语法大全"很多,从正则表达式语法大全到 nmap 参数表,本质上都是给工具使用者提供一个索引。Mermaid 也值得你维护一张自己的速查表。不用多复杂,四行就能概括大部分需求:
| 图类型 | 起始关键字 | 核心要素 | 最常踩的坑 |
|---|---|---|---|
| 流程图 | graph TD/LR | 节点、连线、判断、子图 | 方向关键字写错、中文括号 |
| 时序图 | sequenceDiagram | 参与者、消息箭头、激活框 | activate/deactivate 不配对 |
| 状态图 | stateDiagram-v2 | 状态、迁移事件、初始结束 | 把 [*] 当普通节点 |
| 类图 | classDiagram | 类、成员、关系符号 | 泛化箭头方向画反 |
这张表不是让你背下来,而是让你在每周只有零星几次画图需求时,不用每次都翻完整本官方文档。从我自己的经验看,流程图用量最大,时序图和状态图次之,类图在专门做领域设计时才有存在感。刚开始学的时候,先把流程图练熟,再扩展其他图类型,不要一次把四种图的语法全塞进脑子里。
我也见过有人搞出"markdown 语法 + 谷歌语法"混合检索,甚至想用搜索语法查找学号这类个人信息。这里必须说清楚:搜索引擎的布尔语法确实强大,但任何以获取他人隐私为目的的用法都越过了边界,不光是合规问题,更是基本尊重。Mermaid 也一样,语法本身是工具,怎么使用完全取决于你的意图,别把检索能力用在错误的地方。
4. 从"能出来图"到"敢放进生产文档":命令行渲染、自动化校验与排错
4.1 不要只依赖编辑器,命令行渲染才是自动化基础
Mermaid 的源码在 Obsidian、Typora 里都能直接预览,但你要是只想"看图",很容易陷入一个误区:图只有自己打开编辑器才能看到。真正要把 Mermaid 用进生产环境,你需要一个命令行工具:@mermaid-js/mermaid-cli,装好后一般提供mmdc命令。基本用法是这样:
npx -y @mermaid-js/mermaid-cli -i demo.mmd -o demo.svg这条命令会把demo.mmd渲染成demo.svg。你也可以输出 PNG、PDF,比如-o demo.png,需要时用-w 1200 -s 2控制宽度和缩放倍数。主题切换用-t default、-t dark、-t forest,我习惯在文档站里统一使用某个主题,避免不同文章截图风格不一致。
为什么命令行重要?因为你的文档流程可以自动化了:本地写完.mmd文件,跑一遍命令批量生成图片,再把图片提交到文档站点,整个过程不需要打开图形界面,也不需要任何人手工截图。这也就意味着,流程图可以放进 CI 流程,文档变更时自动渲染、自动发布。市面上所谓"破解版、高级版下载"完全没必要碰,Mermaid 和它的 CLI 都是开源免费的,官方文档写得比任何二手教程都清楚,用最新稳定版就够。
有一点要提前有心理准备:mermaid-cli 依赖于浏览器内核来渲染。首次运行可能要下载一个无头浏览器,如果你的环境比较特殊,下载可能比较慢,或者需要配置离线缓存。解决办法通常是提前在构建机把浏览器装好,然后再运行 CLI。这不是 Mermaid 的问题,而是所有浏览器渲染方案都逃不开的环节。
4.2 用 Playwright 做批量校验,杜绝"图渲染出来但节点是错的"
命令行解决了"生成图片",但还没解决"图里的内容是否正确"。我们曾经遇到过一个场景:文档里二十多张 Mermaid 图,某次改动后大部分能渲染,但几张小图的节点名被复制粘贴错了,文字层面完全看不出来。后来我引入 Playwright 对渲染后的页面做批量断言,问题才被系统性地拦住。
Playwright 是浏览器自动化框架,适合做这类文档级校验。思路是:把 Mermaid 源码渲染进一个 HTML 页面,等待 SVG 生成,然后截图并检查 SVG 里是否存在关键文本。一段最小脚本大致长这样:
const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('file:///path/to/rendered-doc.html'); await page.waitForSelector('svg'); const content = await page.textContent('svg'); if (!content.includes('订单服务')) { throw new Error('图中缺失关键节点:订单服务'); } await page.screenshot({ path: 'diagram.png', fullPage: true }); await browser.close(); })();这个脚本会打开本地 HTML,等待 Mermaid 渲染出的svg出现,然后取整个 SVG 的文本内容,判断关键节点是否存在。你还可以把目录下所有 HTML 文件都跑一遍,发现任何一张图缺节点就报错,这样就不至于把错误图直接发布上线。截图拿到后,再配合 diff 工具比较不同版本的图,很容易定位"这次改动影响了哪些图"。
Playwright 的能力不止于此,你还可以用它模拟鼠标悬停、点击 Mermaid 节点的绑定事件,甚至把渲染错误捕获下来。不过对大部分文档团队来说,先做到"自动截图 + 自动断言关键节点"已经足够。自动化不是要把事情变复杂,而是把最重复、最容易被忽略的检查交给脚本。
4.3 常见语法报错和排查思路:别一次改一整段
Mermaid 的报错信息这些年已经很友好,但仍然有几种高频问题值得单独拿出来说。
第一,方向关键字写错。比如graph TR,正确的是TB、TD、BT、LR、RL。这个错误经常出现在从别人代码里复制时,方向没改全。第二,括号不匹配。中英文括号混用是灾难源:A[开始]里的方括号必须是半角,A[开始)会导致解析器在期望]时遇到)。第三,subgraph少了end。子图开了一个,结尾没有end,后面的节点全部被套进子图,布局全乱。第四,节点 ID 使用了特殊字符,比如.、#、&,它们在部分图类型里会被当作语法符号,轻则渲染警告,重则直接失败。
排查这类问题,我推荐的链路是"最小化复现 + 二分注释"。先删掉一半节点和连线,看问题是否还在;如果不在,再还原一半,逐步缩小区间。不要一次改一整段,因为你不知道到底是哪一行引起的,改完可能另一个问题浮出来。报错信息里的行号非常关键,但它的含义在不同图类型里略有不同,有时候行号指向的是"解析停止的位置",并不一定就是真正有问题的位置。这时候需要你把可疑行的每一个关键字、括号、空格都和官方示例比对。
版本差异也要注意。Mermaid 的 v9、v10、v11 之间,某些图的语法和主题系统有变化。网上搜到的教程很可能基于旧版本,照抄时如果渲染结果不对,先看官方文档对应的版本。我个人遇到最多的是状态图:老教程写stateDiagram,新版本更推荐stateDiagram-v2,看起来只差一个后缀,实际行为差很多。与其纠结,不如把项目的 Mermaid 版本锁死,README 里写明"本仓库使用 v10.x",避免队友用了不同版本来渲染同一份源码。
4.4 复用模板,比背语法更重要
我在实际项目中踩过不少坑之后,最大的体会是:Mermaid 真正提升效率的方式不是"背熟所有语法",而是"建立一套自己的模板库"。比如我会在本地维护一个mermaid-templates目录,里面放着常用图的骨架:
flow-basic.mmd:基本流程图,包含开始、判断、结束节点sequence-api.mmd:时序图,包含参与者、同步请求、响应、异常分支state-order.mmd:订单状态机,包含待支付、已支付、退款等状态class-domain.mmd:类图,包含实体、值对象、聚合和关联关系
每次新项目需要画图,复制对应模板,改节点名和连线即可。这样既保证风格统一,又不需要每次重新敲一遍基础结构。模板里的样式类classDef也尽量固定下来,绿色表示完成、黄色表示等待、红色表示失败,团队成员看多了就形成条件反射,一眼扫过就知道整张图的状态分布。
另外一个小技巧:给.mmd文件取名字的时候,不要叫未命名1.mmd,用2025-05-订单支付流程.mmd这类带日期和业务名的格式。文件一旦多起来,你会感谢当初这个习惯。图文文档不是"画完就结束"的一次性工作,它是一个持续演进的资产,命名规范、模板统一、版本管理,这三件事比任何花哨的语法都重要。
最后再分享一个长期养成的习惯:画图之前,先在纸上或者直接在文本里列一下"节点清单"和"连线清单",字段也不复杂,就是"从谁到谁、线代表什么关系"。很多时候画图卡的其实不是语法,而是你自己没想清楚逻辑。Mermaid 的文本特性反而是一种约束,它逼你把"流程是什么"写得明明白白,而不是靠鼠标拖动慢慢找感觉。语法只是表达,真正值得花时间的,永远是你要表达的那件事本身。