写这篇文章的起因其实很简单:最近在做一个有状态流转的回单系统时,纯靠文字跟 AI 对齐需求,来回改了七版,每次它都自信满满地给我一段"逻辑完整"的代码,一跑就翻车。后来我把交互流程先用 Mermaid 画成图,再让 AI 照着图写,一次就过。从那以后,我的 AI 编程习惯彻底变了——凡是涉及分支选择、状态流转、多模块协作的需求,我都先把"思维"画成"Mermaid",再拿图去跟 AI 对话。这套做法,我把它叫做"可视化的思维协议"。
Mermaid 本身不是什么新东西,一个把文本转成图表的工具而已,但在 AI 编程这个场景里,它的价值被完全放大了。它弥补了人类空间化思维与大语言模型线性文本处理之间最致命的那道鸿沟。这篇内容我会把完整的应用范式拆开讲清楚:从为什么需要它,到核心落地模式,再到一个能直接抄走的实操项目,最后是几个我踩过的坑和对应的排查技巧。适合正在用 AI 辅助开发、但总觉得"差点意思"的工程师参考。
1. 为什么 AI 编程需要"可视化的思维协议"
先说一个被很多人忽略的事实:大语言模型本质上是一个"文字接龙机器"。你给它一段文字,它预测下一个词,再预测下一个词。这决定了它对"整体结构"的感知是隐式的、逐步推算出来的。而人脑不一样,人理解一个系统时,脑子里出现的是图:方框、箭头、分支、循环、依赖关系。这是结构化的、空间化的思维。
这两者之间天然存在一个"表达带宽"问题。你用文字描述一个流程,比如"用户下单后要先校验库存,库存够的话再走支付,支付成功后发送消息,失败则回滚库存并返回错误提示",这句话 AI 能听懂,但它理解的是"线性推进关系"而不是"带状态、带分支、带并发条件的流程图"。一旦逻辑复杂到十几个节点、四五个分支条件,文字描述就会产生歧义——这个分支到底是从哪个状态出来的?异常路径和正常路径会不会重叠?顺序敏感还是状态敏感?
Mermaid 在这里扮演的就是一个"思维翻译层"。
它把人类脑子里的图,用一套严格的、文本化的语法表达出来。这套语法足够简单,人写起来不费劲,AI 读起来也无歧义。更重要的是,Mermaid 是文本,text 是可以进 prompt、可以进上下文、可以被 diff 的。你不需要贴一张截图给 AI 看——直接贴上 Mermaid 源码,它就能精确解析出节点、边、分支、循环、状态关系。
我拿同一个需求做过对比实验。需求是"一个带超时确认的审批流程"。用纯文字描述让 AI 写代码,它给出的方案里,超时逻辑和人工审批逻辑经常会出现竞争条件,甚至在超时后用户还能操作。但把同样的需求画成 Mermaid 状态图丢给它,AI 生成的代码结构直接就对了:超时是一个独立的状态迁移事件,和人工审批互斥,边界非常清晰。
这就是我最想强调的第一件事:跟 AI 协作写代码,不是你说话它就能懂,而是要给它一个它天然擅长解析、且能无损保留你空间思维的结构化中间表示。Mermaid 恰好就是这个中间表示。它相当于你和 AI 之间约定好的一套"思维协议"。
1.1 文字、代码、Mermaid,三者的信息密度对比
为了说清楚这个"协议"为什么有效,我列过一个简单的对比:
| 表达方式 | 信息密度 | 歧义程度 | AI 友好度 | 人可读性 |
|---|---|---|---|---|
| 自然语言描述 | 低 | 高 | 中 | 高 |
| 伪代码 | 中 | 中 | 高 | 中 |
| Mermaid 图源码 | 高 | 极低 | 极高 | 高 |
注意"Mermaid 可读性高"有一个前提:它必须是源码形式,而不是渲染出来的图片。图片给人看很直观,但给 AI 看就没法直接解析了。所以我的习惯是,凡是给 AI 看的图,一律贴源码,渲染好的 PNG 只留给自己做人眼确认。
还有一个细节很多人没意识到:Mermaid 源码进 git 之后,每次改动了哪些节点、哪些路由,diff 清清楚楚。你用文字描述需求,改没改、改成啥了,只能靠人脑对比——但图不一样,图的演进历史就是项目的演进历史。这个特性在长周期项目里价值极大,后面我会专门讲到。
2. 我把 Mermaid 用进 AI 编程的五种核心模式
经过一段时间实践,我总结出五种最值得拿 Mermaid 跟 AI 协作的场景。不是所有代码都适合画图,但这五类,画图和不画图的效果天差地别。
2.1 流程图:拆解业务流程,让 AI 按图生成代码骨架
这是最基础、也最常用的模式。当你拿到一个需求,第一件事不是在编辑器里招架构,而是把业务流程画成 flowchart。流程图的每个节点对应一个函数或一个模块,每条边对应一次调用或一个返回。
举个例子。一个模拟订单退款系统,核心流程是:
- 用户发起退款申请
- 系统校验订单状态
- 校验通过,走财务回调
- 财务回调失败,进入重试队列
- 重试超过三次,标记人工介入
画成 Mermaid 就是:
flowchart LR A[用户发起退款] --> B{订单状态校验} B -->|有效| C[财务回调] B -->|无效| Z[返回错误] C -->|成功| D[退款完成] C -->|失败| E[进入重试队列] E -->|重试次数 < 3| C E -->|重试次数 >= 3| F[人工介入标记]这段源码丢给 AI,配合一句"按这个流程图生成服务端代码,每个节点对应一个独立函数",它生成的代码就是模块化的、单向依赖的、边界清晰的。而如果你只写一句话"帮我写个退款功能",你得到的就是一大坨 if-else 糊在一起的代码。
2.2 状态图:处理状态机类逻辑,专业的事交给专业的图
流程图能表达"先后顺序",但表达不了"状态之间如何迁移"。比如订单有"待支付、已支付、已发货、已完成、已取消"这些状态,从"已支付"能不能到"已取消"?哪些事件触发哪些迁移?这种逻辑用 flowchart 硬画会很别扭,这时候要用 stateDiagram-v2。
AI 在解析状态图方面简直就是天赋异禀。因为状态迁移本质上就是"事件 -> 条件 -> 新状态"的三元组,这跟软件工程里的状态模式、状态机引擎、甚至数据库中的状态字段流转,是同构的。你给它一张状态图,它写出来的状态机代码几乎不需要改。
我给你看一个新版状态图的写法:
stateDiagram-v2 [*] --> 待支付 待支付 --> 已支付: 支付成功 待支付 --> 已取消: 用户取消 已支付 --> 已发货: 商家发货 已支付 --> 退款中: 用户申请退款 已发货 --> 已完成: 确认收货 已发货 --> 退款中: 售后发起 退款中 --> 已退款: 退款成功 退款中 --> 待人工处理: 退款异常 已取消 --> [*] 已退款 --> [*]注意里面每一条迁移都带了一个事件标签。我给 AI 的指令是:"把这张状态图翻译成 TypeScript 类型定义加一个状态机实现,迁移事件作为 action 命名。"这个组合拳打下来,状态机相关的 bug 基本绝迹。以前用文字描述这种逻辑,AI 经常自己脑补出一些不存在的迁移关系,比如待支付直接到退款中,有了状态图,它想脑补都补不出来——边上就那么几条,它不会乱加。
2.3 时序图:搞定跨模块协作,减少"接口对齐"来回拉扯
多模块、多系统协作的时候,最大的痛点是每个模块之间怎么调用、谁先谁后、回调怎么处理。这种场景时序图比任何文字描述都管用。Mermaid 的 sequenceDiagram 可以轻松表达参与者、消息、嵌套调用和返回。
举个例子,模拟一个对接第三方支付渠道的场景:
sequenceDiagram participant U as 客户端 participant S as 服务端 participant P as 支付渠道 U->>S: 创建支付订单 S->>S: 生成订单号,落库 S->>P: 发起支付请求 P-->>S: 返回支付凭证 S-->>U: 返回支付链接 U->>P: 打开支付页面完成支付 P->>S: 异步通知支付结果 S->>S: 校验签名,更新订单状态 S-->>U: 推送支付成功消息把这段源码丢给 AI,它就能清楚每个接口该由谁提供、谁消费、是同步还是异步。我实际测过:用这种时序图驱动编写接口层代码,AI 生成的接口签名和调用顺序基本一次就对了。而用文字描述,它经常把回调接口的实现体乱分配,该服务端做的逻辑塞给了客户端。
2.4 类图/架构图:定义领域模型与依赖关系
涉及领域建模、模块拆分的时候,classDiagram 派得上用场。虽然 Mermaid 的类图能力比不上专门的 UML 工具,但对 AI 编程来说已经完全够用。
classDiagram class Order { +string id +string status +money totalAmount +calculateTotal() +completePayment() } class OrderItem { +string productId +int quantity +money subtotal } class Payment { +string channel +string txnId +refund() } Order "1" --> "n" OrderItem Order "1" --> "1" Payment这个类图直接驱动 AI 生成数据模型和领域对象。我一般会让 AI"按这个类图生成数据库表结构设计和对应的实体类代码"。由于类图自带关系、自带属性,AI 生成的表结构往往连外键关系都合理。以前纯文字让它设计表,它总是忘记加关联索引,有了类图,这个概率大大降低。
2.5 思维导图:用 Mermaid 做需求拆解与任务规划
最后一种模式比较跳脱,但非常实用——用 mindmap 来拆解需求、做任务规划。有了它,AI 编程不再局限于"代码生成",还能延伸到"项目规划"。
mindmap root((订单退款模块)) 退款入口 申请表单 校验规则 业务逻辑 库存回滚 财务回调 消息通知 失败处理 重试队列 人工介入 数据变更 退款记录 订单状态这种图的用法很特别:不是给 AI 当 prompt,而是给自己当"思维脚手架"。我会先在 Mermaid 里把需求拆成树状结构,然后再基于这棵树去写 prompt。这样做的好处是:需求拆解和代码生成分离,先想清楚"要做什么",再让 AI 想办法"怎么做"。很多 AI 编程翻车的原因,不是 AI 能力不行,而是你自己也没想清楚要什么。思维导图帮你把"没想清楚"的问题前置暴露出来。
3. 深度实操:一个完整的 Mermaid 驱动 AI 编程项目示例
理论说得再多,不如完整走一个项目。我用一个模拟的"库存扣减与回滚"功能来做演示。这是一个非常典型的、又容易出错的逻辑,非常适合拿来讲 Mermaid + AI 编程的完整链路。
3.1 第一步:把需求拆成流程图
需求背景:用户购买商品后,系统需要扣减库存。如果后续支付失败或用户取消订单,需要回滚库存。
我一开始先在白板(或者说 Mermaid 编辑器)里画出流程图,重点标出三个关键分支:库存足够、库存不足、并发冲突。Mermaid 源码如下:
flowchart TD A[收到订单创建请求] --> B{库存查询} B -->|库存充足| C[预占库存] B -->|库存不足| Z[返回库存不足错误] C --> D{支付调用} D -->|支付成功| E[确认扣减] D -->|支付失败| F[回滚预占库存] F --> Z E --> G[完成]画图的过程本身就是思考的过程。我在画的时候就会发现一个之前忽略的问题:"预占库存"和"确认扣减"是两个动作,它们之间如果程序崩溃了怎么办?这就引出了一个关键的容错设计问题。这个洞见,如果我没有画图,直接写 prompt,是绝对暴露不出来的。
3.2 第二步:把 Mermaid 图作为核心上下文,构造精确驱动指令
有了图,接下来就是写 prompt。我总结出一个高复现率的提示词模板:
你是资深的后端工程师。下面是一个库存扣减与回滚的流程图,每个节点代表一个明确的业务动作,每条边代表调用关系与条件分支。 请按以下要求生成 TypeScript 代码: 1. 图里的每个节点对应一个独立函数,函数名自拟,但必须在注释里标注对应节点编号。 2. 图里的每个分支条件对应一个明确的返回值类型,用联合类型表达。 3. 预占库存和确认扣减之间需要能应对进程崩溃的情况,请设计一个补偿机制。 4. 并发扣减时,确保库存不会变成负数。 流程图源码: flowchart TD A[收到订单创建请求] --> B{库存查询} B -->|库存充足| C[预占库存] B -->|库存不足| Z[返回库存不足错误] C --> D{支付调用} D -->|支付成功| E[确认扣减] D -->|支付失败| F[回滚预占库存] F --> Z E --> G[完成]注意几个关键点。
一是"每个节点对应一个独立函数"。这句话极其重要。如果不加这句,AI 会把整个流程图压缩成一个函数,里面一堆 if-else。加了这句,它自然就会把代码模块化。
二是把"补偿机制"单独作为硬性要求。这不是流程图里有的内容,而是我画图时暴露出来的设计盲区。流程图负责表达业务流程,prompt 里的额外要求负责表达非功能性需求。二者各司其职。
三是注意给 AI 一个"自由发挥"的许可,它需要在节点之外自行补充异常处理逻辑。实操中我发现,如果你过度强调"照着流程图写",AI 会变得畏首畏尾,该加的 try-catch 也不加了。所以 prompt 里最后要加一句"允许在图中未显示的边界情况下增加防御性代码"。
3.3 第三步:校验 AI 产出代码与图的对应关系
AI 生成代码之后,最关键的环节来了:必须校验代码和流程图之间的映射关系。
我一般会让 AI 自己生成一份映射清单:
请为刚才生成的代码输出一份节点对照表,格式为表格:函数名 | 对应节点 | 职责说明这一步非常有效。AI 在输出对照表的过程中,会自己发现自己哪里对不上,很多时候它甚至会主动修正代码。这个过程我称之为"让 AI 自省"。它比你自己一行行读代码找问题高效得多。
最终生成的代码,函数结构大致会是:
createOrderAndCheckStock()对应节点 BreserveStock()对应节点 CconfirmDeduction()对应节点 ErollbackReservedStock()对应节点 F
每一个函数的职责边界清晰到不可思议。你甚至会怀疑这是不是 AI 写的代码——不,它只是忠实地把你的流程图翻译成了 TypeScript。
3.4 第四步:用状态图补充边界情况
流程图画完了,代码也能跑了,但我觉得还不够。因为流程图表达的是"主要路径 + 部分异常路径",它没覆盖"系统在运行过程中发生状态迁移"这层逻辑。尤其是库存扣减,它的状态不是"流程跑完了就结束",而是在不同状态之间跳转。
所以我又补了一张状态图:
stateDiagram-v2 [*] --> 待预占 待预占 --> 已预占: 预占成功 待预占 --> 预占失败: 库存不足 已预占 --> 已扣减: 支付成功 已预占 --> 预占回滚: 支付失败/超时 预占失败 --> [*] 预占回滚 --> [*] 已扣减 --> [*]把这张状态图也丢给 AI,让它"根据状态图检查生成的代码是否覆盖所有迁移,并补齐缺失的状态处理"。这一步直接让它抓出了一个 bug:原来的代码在"支付超时"场景下没有触发预占回滚,因为超时本质上是个异步事件,流程图里根本没法表达这种"事件驱动的迁移"。状态图一给,它就老老实实补了一个定时任务来兜底。
这就是我在第 2 节说的:流程图解决"顺序",状态图解决"迁移"。二者配合使用,才能形成完整的思维协议。
4. 常见问题与排查技巧实录
任何方法论落到实操里,都会冒出一堆问题。这套 Mermaid + AI 编程打法,我自己也踩了不少坑,挑几个典型的分享一下。
4.1 AI 不遵守图的约束,擅自添加不存在的路径
最开始我最烦的就是这个。我明明给了一张"只有三条边"的状态图,AI 生成的代码里居然出现了一个图上完全没有的状态迁移。后来我琢磨明白了:这不是 AI 不听话,是我给的 prompt 不够"封闭"。AI 有一个默认行为——它会主动"补全"它认为应该有的逻辑,哪怕图里没有。
解决办法是在 prompt 里加一句约束:"只实现图中明确出现的节点与边,不得新增图中不存在的状态或迁移关系。若必须新增,需先用文字向我说明理由。"
这句强调之后,AI 就老实多了。它仍然保留了一部分"提出异议"的能力,但不再擅自加代码逻辑了。
4.2 图太大,超出上下文窗口,AI 开始遗漏关键节点
当流程图节点超过二十五个到三十个的时候,AI 就开始"忘记"最前面的节点了。这不是玄学,是上下文注意力分布的自然限制。
解决办法不是让 AI 一次处理完整张图,而是"分层拆图"。我会先让 AI 看一张顶层概要图,理清模块关系;然后再把每个模块对应的子图分别发给它,让它细化实现。
举个例子。一个完整的电商交易流程,顶层图可能有十二个节点,其中"支付模块"是一个聚合节点。我不会把这十二个节点全塞给 AI 一次生成,而是:
- 先发顶层图,让它生成模块骨架。
- 再单独发"支付模块"的子流程图,让它细化支付模块内部。
- 最后发接口对接的时序图,让它生成模块间的调用层。
这种"金字塔式"的图组织结构,既能保证整体不失焦,又能保证细节不遗漏。
4.3 迭代开发时,代码改了,图没改,两者逐渐脱节
这是最隐蔽、也最有破坏性的问题。某次迭代你让 AI 改了一个函数逻辑,但你没同步更新对应的 Mermaid 图。几天后这个图已经不能反映真实代码了。到时候你再拿旧图去驱动 AI,它就会生成一堆跟现有代码冲突的内容。
我现在对自己的要求是:凡是落入 git 的 Mermaid 图,必须和代码同步更新。如果代码改了,图不改,那这个图宁愿删了也不要留在仓库里误导人。因为"过时的图"比"没有图"更糟糕——它会给 AI 传递错误的思维协议。
我推荐的做法是:把 Mermaid 图源码存放在代码库的 docs 目录下,并在代码文件顶部加一行注释:"变更此文件逻辑时,请同步检查 docs/xxx-flow.md 中的对应图。"这是一个很简单的约定,但能避免大部分同步问题。
4.4 Mermaid 语法复杂写不对,AI 又不会帮我修
这是很多人一开始最容易卡住的地方。Mermaid 虽然简单,但新手写 flowchart 经常搞混节点形状、箭头方向、标签语法。特别是给 AI 的 prompt 里,语法错误越多,AI 理解越偏。
我的建议是:写图的时候不要纠结语法,先用最朴素的写法把节点和连线画出来,再让 AI 帮你修成合法 Mermaid。
A -> B -> C B -> D这四行虽然简陋,但意思清楚。然后你加一句 prompt:"把下面这个粗糙的流程图改写成合法的 Mermaid flowchart 语法,并为每个节点命名,名词使用描述性命名。" 这招在大多数情况下都好用,AI 对 Mermaid 语法的掌握比普通人熟多了。
另外强烈建议装一个本地 Mermaid 预览插件或者在线的 Mermaid 编辑器,写图的过程中随时渲染、随时检查。所见即所得,能帮你省掉大量"语法错了但没发现"的时间。
4.5 同样的图给不同的 AI,产出的代码风格差异巨大
不同模型的代码风格确实有差异。有的喜欢啰嗦的防御性编程,有的喜欢简洁的样板代码。我的解决办法是在 prompt 里固定一套"代码风格契约",比如:
- 使用 TypeScript,类型必须显式声明。
- 错误处理:返回 Result 联合类型,不直接抛异常。
- 日志:每个节点函数入口必须打印结构化日志。
把风格契约加在 Mermaid 图源码之前,AI 的输出稳定性立刻提升一个档次。因为图的语义约束帮你解决了"做什么",风格契约帮你解决了"怎么做、长什么样"。
5. 让 Mermaid 成为 AI 协作的思维基础设施
最后再分享一点个人体会。我过去一年最大的变化,不是学会了用更多工具,而是改变了跟 AI 协作时的思维方式。以前拿到一个需求,第一反应是"直接让 AI 写",写出来不对再让它改,来回拉锯,效率极低。现在我的第一反应是"先画图,再让 AI 写"——把思考的时间前置,把返工的时间消掉。
这个过程其实是在建立一种"思维协议":你把自己的逻辑结构化,用 Mermaid 表达出来,形成一份人和 AI 都能读懂、都能改、都能 diff 的中间产物。这份产物既是需求文档,又是设计文档,还是与 AI 对话的提示词原材料。它不依赖任何具体的 AI 工具,不需要多复杂的工程体系,只需要你愿意多花十分钟画一张图。
我自己实测下来,这个习惯让复杂需求的 AI 生成代码一次通过率从不到一半提升到了七成以上。哪怕有时候图还没给 AI 看,光是画图这个动作本身,就已经把设计盲区暴露得差不多了——这在以前是不可想象的。
撇开工具本身,我觉得更深层的好处是:Mermaid 让"设计"这件事重新变得廉价和自由。你不需要是架构师才能画出系统关系图,也不需要掌握 UML 那些繁重的规范。用不到十行文本,就能把脑子里的想法变成一张不会撒谎的图。然后 AI 再把这张图变成不会撒谎的代码。这两件事加在一起,就是 Mermaid 在 AI 编程中最深的应用范式——它不是很多人以为的"文档美化工具",而是一种让人类思维与机器智能对齐的协议层。这套打法未来还会有更多演变空间,但核心的那一步,永远是:动手之前,先把图铺开。