过去的一年里,我相信大部分人都已经看到了大语言模型(后文简称LLM)所具备的自然语言理解和文本生成的能力,还有很多人将其应用于日常工作中,比如文案写作、资料查询、代码生成……今天我要向大家介绍LLM的一种新使用方式——绘图。这里说的绘图不是像StableDifusion或者Midjourney那样的文生图,而是偏严格的图表,比如流程图、甘特图、时序图……。
Mermaid介绍
Mermaid.js 是一个强大的基于文本的图表生成工具,它通过使用类似Markdown的语法,可以通过简单的文本描述来生成复杂的图表,完全不依赖于繁琐的图形编辑软件。这极大地简化了图表的创建过程,尤其是很多Markdown渲染软件已经完全集成了Mermaid,完全可以做到仅使用一个Markdown编辑器完成写作和绘图的工作。
Mermaid.js 目前支持多种类型的图表,可以满足绝大多数的日常使用场景:
- 流程图(Flowcharts):用于展示过程或系统的操作流程。
- 序列图(Sequence diagrams):适合描述对象或参与者之间的交互序列。
- 甘特图(Gantt charts):常用于项目管理中,显示项目的时间线和阶段。
- 类图(Class diagrams):用于展示系统中类的结构和类之间的关系。
- 状态图(State diagrams):描述系统状态的变化和触发这些状态变化的事件。
- 实体关系图(ER diagrams):用于描述数据库结构和实体之间的关系。
- 饼图(Pie chart):用于简单的比例和统计显示。
- Git图:git合并记录。
- 思维导图、象限图、柱状图、折线图:不过说实话,这些图样式略丑。
具体类型可以在官方编辑器中体验到:官方编辑器。
即便是作者在极力去简化它的语法,但它仍然存在比较高的上手门槛,尤其是对一些没有编程基础的同学来说极难使用。然而在有了LLM之后,这一切都变得简单了。我们不再需要完全掌握Mermaid的语法,只需要用自然语言将数据和需求描述出来,LLM就可以生成Mermaid图表,然后再借助一些Markdown渲染器直接渲染出来。
示例
我们来看几个实际使用示例:
已知2015年-2024年高考人数分别为942万, 940万, 940万, 975万, 1031万, 1071万, 1078万, 1193万, 1291万, 1342万,而对应1997-2006年之间的人口出生人数分别为2028万, 1934万, 1827万, 1765万, 1696万, 1641万, 1594万, 1588万, 1612万, 1581万。
我们可以直接让大模型将这两份数据放在一张图里,方便对比出生人口和高考人数变化趋势。于是我得到了下面这张图(使用 Notion 渲染,很多Markdown编辑器都支持):
温馨提示:Marmaid 中折线图还是 beta 版本,各大 LLM 对这种图支持不太好,我在提示词中给出了官方示例代码后,gpt-4o才能在无语法错误的情况下给出,这里我贴出我的提示词供大家参考。
已知2015年-2024年高考人数分别为 942万, 940万, 940万, 975万, 1031万, 1071万, 1078万, 1193万, 1291万, 1342万,而对应 1997-2006 年之间的人口出生人数分别为2028万, 1934万, 1827万, 1765万, 1696万, 1641万, 1594万, 1588万, 1612万, 1581万
mermaid
xychart-beta
title "Sales Revenue"
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [4000, 4000, 4500, 4200, 5500, 10500, 10000, 10200, 9200, 8500, 7000, 6000]
请参考以上mermaid中xychart-beta示例,用 mermaid 将两份数据画在一起。
再来举个时序图的例子。我曾经用LLM+Mermaid快速生成过一个时序图,向别人解释过线上一个bug产生的过程。这个bug的原因是我们数据库做了读写分离,从库数据延迟,导致另外一个流程读到了旧数据,做出错误的决策。这类的问题用语言向别人解释,对解释双方都是一个考验。我先用语言描述下这个bug,然后再让LLM生成对应的时序图,大家看下是不是对着图理解这个问题的成本就低很多。
首先背景是我们服务操作数据库做了读写分离。数据修改时操作的是主库,数据读取的是从库。用户打开网页要看摄像头直播时,网页会向我们后端服务发起一个请求。我们后端服务会在数据库里标记这个摄像头有人在看直播,之后后端服务会向摄像头下发开启直播的指令。然而同时还有另外一个直播检测的流程,如果到数据库中摄像头没有被标记为有人看直播,会给摄像头下发指令关闭直播。这两个流程加上主从延时导致数据不一致,偶尔会出现时序图收到开启直播后又立即收到关闭直播的情况,导致用户看不了直播。
以上描述我直接让LLM生成了对应的时序图,看起来是不是清晰明了很多了。提示词也很简单:“请用Mermaid画一个时序图,描述下上面这个问题产生的过程。”然后用Notion渲染出了下面这个图。
对于绘制这些折线图、时序图、饼图、甘特图这些简单图表,LLM和Mermaid大部分情况下还是很得心应手的。那么在绘制复杂流程图的情况下,LLM+Mermaid的方式是否还能保持高效和准确?其实这对操作人的表述能力和LLM的理解能力都有非常大的挑战,但也不是完全不可能。我这里给出一个可以尝试的方法——分而治之。其实就是将大的复杂的问题,拆分成多个小而简单的问题挨个解决,然后将所有的结果汇总到一起。
这里我就以一个稍微复杂一点的流程为例,展示下这个过程。还是以我们智慧工地这边工地绑定摄像头的流程为例,其实绑定大流程就两步:校验以及操作绑定。但细分流程里就有很多细节,比如校验的流程又可以细分出摄像头合法性校验,以及操作合法性校验,然后摄像头合法性又可以拆成多个校验……有些还可以细分好几层才能到最终的if else。下面我就用分而治之的思路,描述下整个摄像头绑定的流程(其实就是金字塔原理),然后让LLM将这个流程画出来,看对不对。
摄像头绑定工地核心就是两个步骤,绑定前的校验 加上操作绑定。
# 绑定前校验
校验的流程里可以细分出摄像头合法性校验,以及操作合法性校验
## 摄像头合法性校验
1. 首先判断这个摄像头是否真实存在。
2. 判断这个摄像头是否是在这个租户下面。
3. 判断这个摄像头是否还在服务期内。
以上任意一条校验未通过直接结束。
## 操作合法性校验
1. 这个摄像头是否还绑定了其他工地。
2. 这个摄像头是否可以绑定这个工地。
3. 操作人是否有权限做这个操作?
以上任意一条校验未通过直接结束。
# 绑定操作
1. 更新摄像头和工地的绑定关系。
2. 记录摄像头操作记录。
3. 如果摄像头在线,立即初始化摄像头。
结语
通过上文中的介绍和示例,我们不难看出,只要我们能够清晰地通过自然语言描述需求,LLM就可以帮助我们用Mermaid生成符合需求的图表展示。在LLM和Mermaid的加持下,有些图表的绘制过程变得异常简单,甚至都不需要用绘图软件。不过不得不说这种方法也有一些缺陷:
- 生成的图表样式很丑,无法放在一些很正式的场合使用。
- 图中的布局无法控制,比如在上文摄像头绑定流程中,几个子图的位置我就完全无法调整。
- 图表种类和样式局限性,支持的图形就上文中那么多,而且样式有限,比如折线图这种常用图表居然在Mermaid中还是beta版本。
- 语言描述、LLM理解和Mermaid展示的局限性,导致很难绘制出复杂的图表。简单来说,有些内容你可能用语言描述不出来,即便能描述出来,LLM也理解不了,甚至即便LLM理解了,用Mermaid也很难画出来。
不过这些局限性仍然有弥补的可能性。如果你不满意LLM用Mermaid绘制出来的图表,你还可以把它贴到Draw.io里做二次编辑(操作路径:工具栏/➕/高级/Mermaid),借助专业的绘图工具,就可以绘制出更专业好看的图表。我经常的使用习惯就是让LLM用Mermaid快速打个稿,然后贴到Draw.io里再改改,也是能极大节省时间成本的。
最后感谢大家阅读这篇文章,希望大家能有所收获。