产品经理甩过来一段八百字的流程说明,末尾跟一句"麻烦画成流程图"。你打开绘图工具,拖了十几个框,箭头连得歪歪扭扭,评审会上被人指着问"库存扣减失败这个分支去哪了",才发现原文里压根没写,而你也没追问。于是推翻重来,第二版、第三版,两小时就没了。这几年我一直在折腾文字改流程图这件事,最后稳定下来的一套做法是:用Skill把"怎么问、怎么抽、怎么校验"这套动作固化下来,用Mermaid做渲染层,让整条链路从"手工摆框"变成"可重复执行的工序"。这篇就把原理、踩过的坑和可直接抄的配置全摊开讲。
如果你属于下面几类人,这篇大概能省你不少时间:经常要把需求文档、操作手册、故障处理经验转成流程图的产品和运营;写技术方案时需要快速出一版草图给同事对齐的开发;以及手里有一堆零散的口语化流程描述、想批量转成图的人。哪怕你完全没接触过Mermaid,看完也能自己跑通一条最小链路。
1. 文字改流程图真正的难点,从来不在"画"上
很多人以为这件事的门槛是绘图工具用得不熟,其实不是。把一段文字变成一张图,机械动作只占两成时间,剩下八成全耗在"原文没说清楚的地方你该怎么办"上。这也是我后来愿意花力气去做技能封装的原因——难点既然不在手上,就得让流程去兜住它。
1.1 三次返工踩出来的同一个教训
我第一次认真做这件事,是给一个内部审批流程出图。原文写得很整齐:"申请人提交,主管审批,通过后财务复核,复核通过则归档。"看起来很完美,我照着画了四个框一条直线,交上去被打回来。原因很简单:主管审批不通过怎么办?财务复核不通过退回给谁?归档之后还要不要通知申请人?原文一个字没提。
第二次我学乖了,把"不通过"的分支都补上了,画成一个标准的双向分支。结果又被指出:主管审批如果是"驳回",跟"退回补充材料"是两回事,路径不一样。第三次我才意识到,问题不在于我会不会画菱形,而在于我有没有一套固定的追问清单,在动手画之前把原文的隐含分支全部逼出来。
这个教训后来变成了我整套方法的第一条原则:先补全语义,再谈渲染。原文里凡是出现"审批""校验""判断""如果"这类词,后面必须跟至少两条出边,出边标签不能是空的。凡是出现"然后""之后""接着",就要确认这两个动作之间有没有可能被中断。这些规则听着啰嗦,但写成清单之后,每次照着走一遍,返工率能降一大截。
再往深一层想,为什么口语化的流程描述总是漏分支?因为写的人脑子里有一套默认路径,他描述的是"正常情况下怎么走",异常情况对他来说太熟悉了,熟到觉得不用说。你做图的人如果不主动问,那张图就只是一条主干道,没有匝道。流程图的价值恰恰在匝道上——主干道谁都知道,出问题的地方永远在分支。
1.2 Skill在这个链路里到底干什么活
先把这个词说清楚。我这里说的Skill,指的是一套固化下来的操作规程:包含触发条件、输入要求、处理步骤、输出格式、交付前自查项。它可以是一段结构化的指令文本,也可以是带示例和脚本的技能包,本质是把"某个人脑子里的经验"变成"任何一次执行都能复现的工序"。
放到文字改流程图这个场景里,Skill 承担的是三件事。
第一件是约束输入。它会先检查你给的原文够不够:有没有明确起点终点、有没有条件判断词、有没有并列动作。不够就直接告诉你"缺哪几类信息",而不是硬着头皮生成一张看着像那么回事、实则漏洞百出的图。
第二件是规范抽取。原文里的句子是流水账,Skill 要把它拆成四类要素:角色(谁在做)、动作(做什么)、条件(什么情况下走哪条路)、状态(结果是什么)。这四类要素抽不齐,图就画不准。
第三件是固定输出。这一点特别关键。如果没有输出契约,同一个技能每次生成的结构都不一样,一会儿横排一会儿竖排,一会儿用圆角矩形一会儿用平行四边形,评审的人每次都要重新适应。我在技能包里把节点命名规范、分支标签格式、图的方向、配色分层全部写死,出图风格就稳定了。
还有一件容易被忽略的事:Skill 要负责自检。生成完不算完,得回头把图读一遍,看是不是每个判断都有两个出口、每个节点都有入边、有没有孤立节点。这步人工做很枯燥,写进技能包让流程自动跑,效果立竿见影。
2. 渲染层为什么锁死在Mermaid的文本描述上
选定渲染方式这件事,我前前后后换过三轮。最早用通用绘图软件,后来试过用代码调图形库,最后停在Mermaid上没再动。不是因为它功能最强,而是因为它在"文字改流程图"这个特定场景下,恰好把最痛的几个点都解决了。
2.1 文本即图表带来的三个实际收益
第一个收益是改动可追溯。图形文件是二进制的,你改了一个框的位置,版本库里只显示"文件已修改",谁也不知道改了什么。而文本描述的图,改一行就是一行差异,评审时可以直接看"这次把'财务复核'的失败分支从退回主管改成了退回申请人",一目了然。这个能力在多人协作的场景里价值极大,尤其是流程还在反复调整的阶段。
第二个收益是可批量生成。手里有二十份操作手册要转图,手工画就是二十次重复劳动。文本描述可以用脚本批量产出,改一个模板参数,二十张图一起更新。我做过一次统计,同样一批流程,手工方式平均每张四十分钟,文本方式算上调试语法的时间,平均每张十二分钟,而且第二张之后越来越快,因为模板和技能包都复用了。
第三个收益是出图成本极低。手工画图最烦的不是画框,是对齐和连线。箭头穿过文字、线条交叉、框大小不统一,调这些能调半小时。文本描述里位置是自动排的,你只需要关心"谁连谁",不用关心"线怎么绕"。虽然自动布局有时候也会排得很难看,但难看和画错是两码事,前者调一调参数就行。
顺带说一个副作用:因为要写文本,你会被迫把每个节点的文字压缩到极短。这个约束反而提升了图的质量。我见过太多手工画的流程图,一个框里塞了三行字,读图的人得停下来念。文本方式下你不得不提炼,一个节点就是"动词+宾语",干净利落。
2.2 几种常见做法的取舍对照
我把试过的几种方式列成表,方便你按自己的场景选。
| 方式 | 上手成本 | 改动可追溯 | 批量生成 | 复杂布局能力 | 适合的场景 |
|---|---|---|---|---|---|
| 通用绘图软件手拖 | 低 | 几乎没有 | 基本不可能 | 强 | 一次性、对外汇报用图 |
| 代码调图形库绘制 | 高 | 强 | 强 | 强 | 需要精确坐标的复杂图表 |
| 文本描述自动渲染 | 中 | 强 | 强 | 中等 | 流程、时序、状态类图 |
| 纯文字大纲替代 | 极低 | 强 | 强 | 无 | 逻辑简单、分支少的说明 |
看这张表就能明白我为什么停在第三行。文字改流程图这个需求,绝大多数情况下逻辑复杂度中等、分支数量可控、需要反复迭代、需要多人看,正好落在文本描述自动渲染的优势区间里。至于"复杂布局能力中等"这个短板,实际影响没有想象中大——真到了需要精细排版的场合,那通常是对外材料,本来也不该由这套流程来产出。
提示:选型时先问自己一个问题——这张图是一次性的还是要维护的。一次性的,怎么快怎么来;要维护的,一定要选改动可追溯的方式,否则半年后没人敢动那张图。
3. 拆开一个可复用的"文字转流程图"技能包
技能包这东西最怕写成"帮我画个流程图"这种空话,那不叫技能,那叫许愿。真正能跑起来的技能包,结构上必须把模糊空间压到最小。我现在的版本分成四块,缺一块都会出问题。
3.1 技能包的四个必备组成
第一块是触发条件与输入契约。触发条件写清楚什么情况下用这个技能,比如"当输入包含三个以上连续动作且存在条件判断时启用"。输入契约写清楚至少要提供什么:起始动作、结束状态、至少一条判定条件。如果缺,技能就应该先反问,而不是自己编。
这一步看着像形式主义,实际能挡掉大量垃圾输出。我早期的版本没有输入检查,随手丢一段话过去,它也能生成一张图,但那图是把所有句子串成一条直线,毫无信息量。加了契约之后,它会先回一句"这段描述里没有出现任何条件判断,是否需要补充异常分支",一语中的。
第二块是抽取规则。这是整个技能包的核心。我的规则是这样的:先扫条件词(如果、当、若、除非、超过、低于、失败、超时),每命中一个就标记为一个判断节点候选;再扫动作词(提交、审核、写入、通知、归档、退回),每个动作是一个处理节点;最后扫角色和系统名,用来做分组。扫描顺序不能乱,先条件后动作,因为条件往往跨句,先抓出来才能正确切分后面的动作归属。
第三块是输出契约。我会明确规定:图的方向、节点文本长度上限、节点命名规则、分支标签必须以动词开头、判断节点的出边必须是两条以上且标签互斥、禁止出现无标签的连接线。这些规则写死在技能包里,出图风格才稳定。举个具体例子,分支标签我要求写成"通过 / 不通过 / 超时"这种短词,不允许写"如果审核结果是同意的话就走这条路"这种长句,长句在图上会把布局撑爆。
第四块是自检清单。交付前跑一遍:有没有孤立节点、有没有只有一个出口的判断、有没有写了"结束"但还连着出边的节点、有没有重复的节点标识。这几条查完,基本不会出低级错误。
3.2 中间表示:先压成节点清单,再渲染
这一步是我后来加上的,收益特别大。早期我让技能直接把原文变成图,出错的时候很难定位——到底是理解错了原文,还是语法写错了?两者混在一起,排查起来很难受。
现在的做法是中间加一层:先输出一份结构化的节点清单,格式上可以用表格或者简短的键值结构,包含节点编号、类型、显示文本、上游节点、下游节点、分支标签。这一层只关心语义,不关心语法。确认无误之后,再把清单渲染成最终图表。
这么拆的好处有三个。第一,语义错误和语法错误被分开了,清单错就是理解错,清单对而图错就是渲染错,排查路径清晰。第二,清单可以复用,同一份清单可以输出成不同风格的图,也可以给不同的人看。第三,清单本身可读,非技术同事也能看懂"哦这里少了一个分支",不用让他们去读图。
清单长这样,我一般用表格呈现:
| 编号 | 类型 | 显示文本 | 上游 | 下游 | 分支标签 |
|---|---|---|---|---|---|
| N1 | 起点 | 提交申请 | 无 | N2 | - |
| N2 | 判断 | 材料是否齐全 | N1 | N3 / N4 | 齐全 / 缺件 |
| N3 | 处理 | 主管审批 | N2 | N5 / N6 | - |
| N4 | 处理 | 退回补充 | N2 | N1 | - |
| N5 | 判断 | 审批结论 | N3 | N7 / N8 | 通过 / 驳回 |
| N6 | 终点 | 流程终止 | N3 | 无 | - |
有了这张表,渲染几乎是机械劳动。而且这张表拿去跟业务方对齐,比拿图去对齐效率高得多——他们改文字比改图快。
4. Mermaid语法里真正会绊倒人的那些细节
语法这东西,文档上写得清清楚楚,但你真上手写,绊倒你的永远是那几个文档里一笔带过的地方。我把踩过的坑整理了一下,都是血泪。
4.1 节点标识与显示文本必须分开写
新手最容易犯的错,是直接把中文句子当节点标识用。比如写成"提交申请 --> 主管审批",看着没问题,能跑。但只要文本里带括号、斜杠、引号、井号、&符号,立刻报错。我遇到过最典型的一句:"主管审批(三级权限)",括号一出现,解析直接崩。
正确做法是标识和文本分离:用一个简短的英文标识做节点名,后面用方括号包显示文本。标识只用字母、数字和下划线,显示文本随便写,但特殊字符要处理。具体规则我总结成下面这张表。
| 文本里的字符 | 问题表现 | 处理方式 |
|---|---|---|
| 中文或英文圆括号 | 解析中断,报语法错误 | 显示文本整体用双引号包裹 |
| 斜杠、反斜杠 | 被当成特殊符号 | 同上,用引号包裹 |
| 井号 | 被当成注释起始 | 同上,或者改成"第N步" |
| 与号、尖括号 | 被当成标签语法 | 同上,必要时用字符实体 |
| 换行 | 直接写在方括号里会断行 | 用换行标记标签代替 |
| 冒号 | 部分场景下与语法冲突 | 用引号包裹 |
记住一条:只要显示文本里出现了除中文、字母、数字、空格之外的任何字符,就整体加双引号。这条能挡掉九成的语法错误。
标识命名我建议加个语义前缀,比如n1_submit、n2_check、n3_approve,调试的时候一眼能看出是哪个节点出的问题。纯数字标识n1、n2也行,但节点一多就分不清了。
4.2 判断菱形、分支标签与分组框的边界
判断节点的写法是节点标识{显示文本},花括号。这里有两个硬性要求,违反了图就废了。
要求一:判断节点必须有两个以上出边,且标签必须写。我见过太多图,判断节点只连出一条线,或者连了两条但线上光秃秃的。这种图在评审时基本等于没画,因为读图的人不知道什么情况下走哪边。标签的写法也有讲究,要写成互斥的短词,比如"是 / 否"、"通过 / 驳回"、"在库 / 缺货",别写成"如果满足条件则"。
要求二:分支标签不要重复。同一个判断节点出来的两条线,如果都写"否",那等于没说。我踩过一次坑,判断节点是"金额是否超过阈值",两个出口都标成"否",因为原文写的是"未超过走A,超限走B",我抄的时候脑子一抽两个都写了否。图能渲染,但逻辑完全错了,而且这种错很难靠自己发现,得靠回读校验。
分组框的坑在嵌套。分组框用来表示"这段流程属于某个角色"或者"这个阶段",很好用,但嵌套超过两层之后布局会乱得没法看,而且很容易出现跨组的连线被画得绕一大圈。我的经验是:分组最多两层,超过两层就拆图。一张图讲一件事,别指望一张图装下整个系统。
至于图的方向,流程类我一般用纵向,因为阅读习惯是从上往下。但如果节点超过十五个,纵向会拉得很长,滚动起来累,这时候改成横向、配合分组,反而更好读。这个没有绝对标准,我通常在节点数超过十二个时切成横向。
5. 一次完整的端到端跑通
光讲原理没用,走一遍完整流程你才知道哪里有坑。下面这段是我虚构的一个示例流程,原文来自一份内部说明,风格和真实文档差不多,都是那种"看起来说清楚了其实没说清楚"的样子。
5.1 原始文字与第一轮抽取
原始文字是这样的:
用户提交订单后,系统先做风控校验,校验通过的进入库存扣减环节,扣减成功的生成发货单并通知仓库,扣减失败的提示用户重新下单。风控校验不通过的订单进入人工复核队列,复核完成后根据结论决定放行还是关闭订单。
这段文字看着挺完整,实际上至少缺了四块信息:人工复核有没有时限?复核放行之后回到主流程的哪一步?扣减失败后用户重新下单,是新建订单还是复用原订单?通知仓库失败怎么办?
第一轮抽取我先不看这些缺口,先把确定的要素抓出来。扫条件词,命中"校验通过""扣减成功""扣减失败""校验不通过""复核完成后",五个判断点。扫动作词,命中"提交订单""风控校验""库存扣减""生成发货单""通知仓库""提示重新下单""人工复核""放行""关闭订单",九个动作。角色上分两类:系统和人工。
这轮的清单出来后,缺口很明显——人工复核节点只有入边没有出边,因为原文用的是"根据结论决定",没有具体说明结论有哪几种。这时候就该回头问,而不是自己猜。我通常一次性把缺口列成问题清单发给业务方,避免来回拉扯。
实际问下来的结果:复核结论只有放行和关闭两种;放行后回到库存扣减;关闭订单后流程结束并通知用户;扣减失败用户重新下单是新建订单,回到风控校验;通知仓库失败会重试三次,三次失败转人工。这些补充信息如果没问,图就是断的。
5.2 生成、渲染、回读校验的三轮循环
拿到补充信息后,重出一版清单,然后进入渲染。渲染出来的文本描述大致长这样(这里展示的是源码结构,方便你对照写法):
flowchart TD A["用户提交订单"] --> B{"风控校验"} B -->|通过| C{"库存扣减"} B -->|不通过| D["进入人工复核"] D --> E{"复核结论"} E -->|放行| C E -->|关闭| F["关闭订单并通知用户"] C -->|成功| G["生成发货单"] C -->|失败| H["提示重新下单"] H --> A G --> I["通知仓库"] I --> J{"通知是否成功"} J -->|成功| K["流程结束"] J -->|失败| L{"重试次数是否达三次"} L -->|未达| I L -->|已达| M["转人工处理"]生成完不能直接交,得做回读校验。方法是:把图重新用文字描述一遍,然后逐句和原文对照,看有没有多、少、错。
这轮回读我发现两个问题。第一个是"提示重新下单"这个节点,我连回起点 A 了,但原文说的是新增订单,连回起点在语义上是对的,不过读图的人可能会以为是同一笔订单重跑。解决办法是在节点文本里写清楚"提示用户新建订单"。第二个是"转人工处理"这个终点,原文没说人工处理后怎么办,是个悬空节点。我把它标成终点,但在交付说明里注明"此处需业务方补充后续处置",避免有人以为流程到此就闭环了。
第三轮我把清单里的所有判断节点单独列出来,检查每个是不是都有两条以上出边、标签是否互斥。查出来一处:风控校验的"不通过"和人工复核的"关闭"最终都指向终止类节点,但一个是"关闭订单",一个是"转人工处理",这没问题。真正的问题在于"库存扣减失败"和"复核关闭"都可能通知用户,原文用了两个不同的说法,我在图里统一成"通知用户",结果丢失了"提示重新下单"和"关闭订单通知"的区别。改回来之后才准确。
这三轮看起来繁琐,但熟练之后每轮也就几分钟,比交上去被打回来重画省事得多。
6. 让图不出错的校验与失败定位
写文本描述最大的心理负担是怕报错。报错本身不可怕,可怕的是报错信息不精确,明明错在第五十行,提示却指向第三行。我总结了一套自己的排查顺序,基本上能在一两分钟内定位。
6.1 渲染前的静态检查清单
与其等它报错,不如提前查。我现在每次生成完先跑这几条:
| 检查项 | 检查方法 | 不合格的处理 |
|---|---|---|
| 是否有孤立节点 | 逐个节点看有没有入边或出边 | 补连线或删节点 |
| 判断节点出口数 | 数每个判断节点的连线数 | 少于两条补齐 |
| 判断节点标签 | 看每条出边有没有标签 | 补互斥短标签 |
| 标识是否重复 | 扫描标识列 | 加序号区分 |
| 显示文本特殊字符 | 扫括号、斜杠、井号、冒号 | 整体加双引号 |
| 分组嵌套层数 | 数分组起止标记 | 超过两层拆图 |
| 节点总数 | 数一下 | 超过二十个考虑拆图 |
这几条里,孤立节点和判断节点只有单出口是最常见的两个问题,前者通常是漏了连线,后者通常是漏了分支。两个问题都会让图"看起来对但没法用"。
节点总数这条容易被忽视。一张图超过二十个节点,读的人就开始疲劳了,尤其是评审会上投影出来,字小得看不清。我的做法是超过二十个就拆成主图加子图,主图只画主干,每个关键环节用一个小框标"详见附图X"。
6.2 渲染失败后的定位顺序
真报错了,按这个顺序查,效率最高:
第一步,看最后一行。报错信息通常指向的位置不精确,但最后一行往往是最接近问题的地方。如果提示的是语法错误,先看那一行有没有未闭合的引号或括号。
第二步,查最近改动。如果上一版能跑通,这版跑不通,问题一定在改动范围内。把改动的那几行单独拎出来看,别从头读。
第三步,查引号配对。这是最高频的原因。中文引号和英文引号不通用,显示文本里如果用中文引号,有些情况下会被当成普通字符,有些情况下会出问题。我的规矩是统一用英文双引号包裹,里面不再嵌套引号,需要引号的内容换成书名号或者直接去掉。
第四步,查特殊字符。逐个扫描显示文本,看有没有括号、斜杠、井号、与号。有就加引号。
第五步,二分法注释。如果以上都查不出来,把后半部分的连线全注释掉,看能不能渲染。能,说明问题在后半部分;不能,问题在前半部分。逐段缩小范围,一般三轮就能定位。
注意:不要试图一次性写一大段描述然后祈祷它能跑通。正确姿势是写三五个节点就渲染一次,确认没问题再往下写。这个习惯能把调试成本压到最低,我吃过一次性写五十行的亏,排查花的时间比重新写还长。
7. 这套做法在几类场景里的变体
同一套技能包加渲染层的组合,在不同场景下要调整的重心完全不一样。我按自己的使用频率排一下。
7.1 需求评审场景:重点是分支完整性
给需求文档出图,最怕的是漏分支。这类场景我会把技能包的自检项加重,判断节点的出边数必须严格大于等于二,而且要检查每条出边是不是都有对应的处理节点,不允许出现"待定"结尾。评审会上最常被问的就是"这个分支失败了呢",提前查一遍能省掉尴尬。
另一个调整是把节点文本压到最短。评审时是投影看的,一个字都嫌多。我一般控制在八个汉字以内,超过就拆成两个节点。这么做还有个好处,逼着写需求的人把模糊表述说清楚——"进行相应处理"这种话在图上是没法落地的。
7.2 故障排查场景:重点是回溯路径
排查树和普通流程的区别在于,它是"从现象倒推原因",所以图的方向和阅读顺序是反的。这类场景我会用横向布局,左端是现象,往右逐层分解原因。技能包也要改规则:条件词从"如果"变成"是否出现",动作词从"执行"变成"检查"。
排查树还有一个特殊要求:每个叶子节点必须给出可执行的处置动作,不能停在"检查网络"这种模糊指令上。我的做法是在自检清单里加一条,所有终点节点必须包含动词,否则打回重写。这条规则救过我很多次,因为写排查树的人习惯停在"定位到原因"这一步,但看的人需要知道下一步干什么。
7.3 技能包的拆分粒度:别贪大
我一开始想做一个万能技能包,输入任何流程描述都能出图。结果就是什么都不精,出图风格飘忽,一会儿把并列动作画成串行,一会儿把循环画成回头线。后来拆成三个独立技能:流程类、排查类、状态流转类,每个各自有输入契约和自检项,效果好得多。
拆的判据很简单:如果两类任务的抽取规则不一样,就该拆成两个技能。流程类关注的是"下一步做什么",排查类关注的是"为什么出问题",状态流转类关注的是"当前处在哪个状态、怎么迁移",抽取逻辑完全不同,硬塞在一起只会互相干扰。
拆完之后还有个附加好处:每个技能包都变得很短,短到可以通读一遍,改起来也方便。我现在的流程类技能包正文不到两页,但把该有的约束全写进去了。
最后分享一个我自己一直在用的小技巧:写完图之后,把图里的每个节点连起来念一遍,念不通的地方就是有问题的地方。人脑对文字逻辑的敏感度远高于对图形的敏感度,很多分支错误念一遍就露馅了。比如念到"扣减失败,提示重新下单,重新下单,风控校验"读着很顺,但如果念成"复核关闭,流程结束,转人工处理"就会卡住——到底结没结束?这种卡壳的地方,往往就是原文没说清、而你在图里含混带过的地方。
这个技巧我用了两年多,比任何语法检查工具都管用。工具能查语法,查不出逻辑,逻辑还得靠人念一遍。真要是流程特别复杂,我会找个人坐旁边,我念他听,他听得皱眉的地方,就是需要改的地方。