基于大语言模型的自然语言转Mermaid图表工具设计与实现

发布时间:2026/8/14 9:57:24
基于大语言模型的自然语言转Mermaid图表工具设计与实现 1. 项目缘起从“查语法”到“一句话成图”的痛点转变作为一名经常需要画流程图、时序图、架构图的开发者或文档工程师你肯定对 Mermaid 不陌生。这个基于文本的图表描述语言以其简洁、可版本控制、易于嵌入文档的特性几乎成了技术写作的标配。但说实话每次画图你是不是都得先打开 Mermaid 的官方文档或者翻出自己以前的笔记去查“这个节点怎么加边框”、“这个箭头是实线还是虚线”、“子图subgraph的语法怎么写来着”。这种“写代码-查语法-预览-再调整”的循环极大地打断了思路的流畅性让本应专注于逻辑梳理的我们把大量精力浪费在了记忆和查找语法细节上。我自己就深受其苦。在写技术方案、设计系统交互流程时脑子里明明已经有了清晰的画面却要花上好几分钟甚至更长时间去把画面“翻译”成正确的 Mermaid 语法。这个过程不仅低效还容易出错一个标点符号或者缩进不对图就渲染不出来又得回头去排查。这种体验让我萌生了一个想法能不能让工具来理解我的意图而不是我去迁就工具的语法于是text2mermaid这个小工具的想法就诞生了。它的核心目标非常简单粗暴你只需要用一句自然语言描述你想画的图它就能自动生成对应的、可立即渲染的 Mermaid 代码。比如你说“画一个用户登录的时序图包含用户、前端、后端服务和数据库”它就应该能生成一个结构清晰、语法正确的 Mermaid 时序图代码块。这不仅仅是“偷懒”更是将创作重心从“如何写”拉回到了“画什么”的本质上来。2. 核心设计思路如何让机器理解“一句话”要实现“一句话生成图”听起来像是需要接入大型语言模型LLM的复杂AI应用。没错这确实是当前最可行的技术路径。但我们的目标不是做一个臃肿的全能应用而是一个轻量、快速、聚焦的“语法翻译官”。整个设计思路可以拆解为以下几个关键环节。2.1 意图识别与场景分类用户的一句话描述是模糊且开放的。第一步也是最重要的一步就是让机器理解用户到底想画哪种类型的图。Mermaid 支持十几种图表类型常见的有流程图graph TD/LR、时序图sequenceDiagram、类图classDiagram、状态图stateDiagram等。我们的工具需要从用户的自然语言描述中提取出图表类型的关键词。例如描述中出现“流程”、“步骤”、“先...然后...”大概率是流程图。描述中出现“顺序”、“交互”、“消息”、“请求响应”很可能是时序图。描述中出现“类”、“属性”、“方法”、“继承”、“实现”则是类图。描述中出现“状态”、“切换”、“事件触发”对应状态图。这里不能简单做关键词匹配因为用户的描述可能很口语化。比如“给我画个系统架构展示数据从采集到处理的流水线”这既可能理解为流程图也可能理解为带有时序意味的组件图。因此我们需要一个更聪明的分类器。一个实用的方案是利用一个轻量级的文本分类模型如经过微调的 BERT 或更小的 Sentence Transformer或者直接利用大语言模型LLM的零样本/小样本分类能力将用户的输入语句分类到预定义的几种图表类型中。注意在初期或资源有限的情况下可以采取“关键词匹配 用户确认”的降级方案。即工具识别出可能的图表类型后提供一个简单的选择按钮让用户确认这比完全猜错要好得多。2.2 实体与关系抽取确定了图表类型接下来就要从句子中抽取出图的“骨架”——即节点实体和边关系。这是自然语言处理NLP中经典的“命名实体识别NER”和“关系抽取RE”任务。对于流程图我们需要识别出各个“步骤”或“环节”作为节点以及连接它们的“顺序”、“条件”如果...那么...否则...作为边。 对于时序图我们需要识别出“参与者”如用户、服务A、数据库和它们之间传递的“消息”如“发送登录请求”、“返回查询结果”。例如对于输入“用户在前端点击登录前端将用户名密码发给后端验证后端查询数据库后返回成功或失败。”实体用户、前端、后端、数据库。关系/消息点击登录、发送用户名密码、验证、查询数据库、返回成功、返回失败。这个过程同样可以借助预训练的NLP模型来完成。我们可以为每种图表类型定义一套实体和关系的schema然后使用模型进行抽取。LLM在此处同样表现出色可以通过精心设计的提示词Prompt让它以固定的JSON格式输出识别出的实体和关系极大简化了开发流程。2.3 语法模板填充与美化有了图表类型、实体和关系我们就掌握了生成Mermaid代码所需的全部“原材料”。下一步就是将这些原材料按照Mermaid的语法规则“组装”成正确的代码。这里最直接的方法是使用模板引擎。我们为每一种支持的图表类型预先编写好一个Mermaid代码模板。这个模板中预留了“占位符”用于填充动态内容。以时序图为例一个基础的模板可能是这样的sequenceDiagram participant A as [参与者A] participant B as [参与者B] A-B: [消息1] B--A: [消息2] ...我们的工具在完成实体和关系抽取后会将“用户”映射为participant User将“前端”映射为participant Frontend并将“点击登录”这条关系根据方向填充为User-Frontend: 点击登录。如此循环将所有识别出的元素按逻辑顺序填充到模板中。实操心得模板的设计需要有一定的灵活性。比如用户描述中可能没有明确指定参与者的别名as工具可以默认使用实体名。对于消息的箭头类型-实线箭头--虚线箭头可以根据消息的语义请求/响应、同步/异步进行智能判断如果无法判断则提供一个默认值如实线箭头并允许用户在生成的代码上微调。2.4 集成与交互设计为了让这个小工具真正好用它不能只是一个孤立的API。它需要被无缝集成到我们日常的工作流中。我设想了以下几种形态浏览器插件这是最便捷的方式。安装后在任何一个支持文本编辑的网页如GitHub、Confluence、Notion、甚至在线Markdown编辑器选中一段描述文字右键点击插件图标即可生成Mermaid代码并插入到光标处。命令行工具CLI对于喜欢终端操作的开发者一个text2mermaid “描述文字”命令直接将代码输出到控制台或剪贴板非常高效。编辑器插件为VS Code、IntelliJ IDEA等主流编辑器开发插件在编辑器内直接调用体验最原生。Web单页应用一个简单的网页提供输入框和实时预览窗口适合快速试用和轻量级使用。无论哪种形态核心交互流程都应保持一致输入描述 - 智能生成 - 预览与微调 - 复制使用。其中“预览与微调”环节至关重要。AI生成不可能100%准确提供一个实时渲染的预览图并允许用户直接编辑生成的Mermaid代码形成一个“AI生成 人工校对”的混合工作流这才是最实用的。3. 技术实现选型与核心环节明确了设计思路接下来就是技术选型和具体实现。这里我们以构建一个Web单页应用SPA为核心因为它最直观也涵盖了所有关键技术点。3.1 前端轻量交互与实时预览前端的目标是提供一个干净、响应迅速的界面。技术栈可以选择流行的React或Vue.js。描述输入区一个大文本输入框允许用户输入多行描述。可以增加一个示例按钮填入几个典型例子方便用户快速理解工具能力。图表类型选择可选提供一个下拉菜单让用户手动指定图表类型。如果我们的意图识别足够自信这个可以隐藏或作为高级选项。生成按钮点击后将描述文本发送到后端服务。结果展示区分为两栏。左栏生成的Mermaid代码。以高亮代码块的形式展示并且设置为可编辑。这样用户发现小错误时比如某个参与者名称不准确可以直接修改。右栏实时预览图。使用Mermaid的JavaScript库mermaid.js实时渲染左栏的代码。当用户编辑左栏代码时预览图应随之即时更新。这个“所见即所得”的体验是关键。// 示例使用 mermaid.js 进行实时渲染 import mermaid from mermaid; // 初始化 mermaid.initialize({ startOnLoad: false, theme: default }); // 当代码变化时重新渲染 function renderMermaid(code, containerId) { mermaid.render(mermaid-svg, code, (svgCode) { document.getElementById(containerId).innerHTML svgCode; }); } // 监听代码编辑器的变化 codeEditor.on(change, () { const newCode codeEditor.getValue(); renderMermaid(newCode, preview-container); });3.2 后端AI能力集成与业务逻辑后端是工具的大脑负责处理自然语言。目前最经济高效的方式是集成大语言模型的API如OpenAI的GPT系列、Anthropic的Claude或国内的一些大模型API。API设计提供一个简单的RESTful端点例如POST /api/generate接收{ description: 用户输入的描述文字 }返回{ mermaidCode: 生成的代码, chartType: 识别的图表类型 }。提示词工程这是决定生成质量的核心。我们需要为每种图表类型设计精炼、明确的提示词Prompt引导大模型严格按照Mermaid语法输出。一个针对时序图的Prompt示例你是一个Mermaid图表生成专家。请将以下自然语言描述转换为标准的Mermaid时序图代码。 要求 1. 只输出Mermaid代码不要有任何解释。 2. 使用规范的语法以 sequenceDiagram 开头。 3. 识别描述中的所有参与者用 participant 声明。 4. 识别所有交互消息用 - 或 -- 表示。 5. 消息文本尽量简洁使用中文。 描述{用户输入}错误处理与降级网络请求或模型调用可能失败。后端需要做好错误捕获并返回友好的错误信息。例如当模型返回的内容不是有效的Mermaid代码时可以尝试用更简单的规则进行回退处理或者直接返回错误提示用户重新描述。3.3 模型调用优化与成本控制直接调用大模型API可能产生费用且响应时间受网络影响。为了提升体验和控制成本可以考虑以下策略缓存对相同的描述文本生成的结果是确定的。可以在后端建立缓存如使用Redis将描述文本作为键生成的Mermaid代码作为值。这样重复的请求可以瞬间返回节省大量API调用。本地轻量模型对于非常明确、简单的图表类型如一个只有几个节点的线性流程图可以尝试用规则引擎或小型的本地NLP模型来处理完全避免网络调用速度极快。提示词优化通过迭代优化Prompt让模型输出更精准、更简洁的代码减少无效的token消耗从而降低成本。4. 避坑指南与实操心得在开发和内测类似工具的过程中我积累了一些宝贵的经验教训这里分享给大家希望能帮你少走弯路。4.1 意图识别的模糊性处理用户输入是千变万化的。“画个架构图”这种描述非常模糊它可能指流程图、组件图、部署图甚至是思维导图。我们的工具不能卡在这里。策略一提供默认值并预览。当分类置信度不高时可以默认选择最通用的类型如流程图同时生成代码并预览。在预览图旁边给出提示“我们将其理解为流程图如果不是您想要的请手动选择图表类型重新生成。” 这比让用户等待一个完全错误的图要好。策略二主动询问。对于非常简短或模糊的描述前端可以弹出一个简单的选择框列出最可能的2-3种图表类型让用户选择。虽然多了一步交互但确保了方向的正确性。4.2 生成代码的“风格”问题不同的LLM甚至同一模型的不同版本生成的代码风格可能有差异。比如有的喜欢给每个participant都加as别名有的则不加有的在消息文本上加引号有的不加。虽然都能渲染但会影响代码的统一性和可读性。解决方案后处理格式化。在将模型返回的代码发送给前端之前后端增加一个“代码格式化”层。使用一个统一的格式化规则例如总是使用participant A而不加as除非名称中有空格消息文本统一不加引号对代码进行清洗和标准化。这能保证输出的一致性。4.3 复杂逻辑的生成挑战对于包含复杂条件判断if/else、循环loop、并行par的流程图或者有时序约束activate/deactivate的时序图仅靠一句描述很难让模型生成完全准确的代码。应对方法分步引导与高级模式。我们可以设计一个“高级模式”或“分步引导”功能。例如先让用户描述主干流程生成基础图然后提供图形化按钮让用户在预览图上直接添加“判断框”、“循环框”等元素工具同步更新背后的代码。这实际上是将工具从一个“全自动生成器”变成了一个“智能辅助编辑器”实用性更强。4.4 实时预览的性能与体验在代码编辑区频繁输入时如果每次按键都触发一次完整的Mermaid渲染可能会导致界面卡顿。优化技巧防抖渲染。使用防抖函数只在用户停止输入一段时间比如500毫秒后才触发渲染预览。这能大幅提升编辑流畅度。let renderTimeout; codeEditor.on(change, () { clearTimeout(renderTimeout); renderTimeout setTimeout(() { const newCode codeEditor.getValue(); renderMermaid(newCode, preview-container); }, 500); // 延迟500毫秒执行 });5. 扩展思考不止于Mermaid当text2mermaid的核心能力——即“自然语言转结构化图表描述”——被验证可行后它的想象力可以进一步打开。多图表类型支持从基础的流程图、时序图扩展到甘特图、饼图、象限图等更多Mermaid支持的图表。多输出格式除了生成Mermaid代码是否可以同时生成PlantUML代码甚至直接导出为PNG/SVG图片这为用户提供了更多选择。与知识库/文档系统集成想象一下在公司的Confluence或Wiki里你直接输入“画出我们微服务A调用服务B再访问数据库的时序图”页面里就自动嵌入了可交互的图表。这能极大提升技术文档的编写和维护效率。逆向工程图转描述既然能“文生图”那“图生文”呢提供一个功能让用户上传已有的Mermaid代码或图表图片工具尝试反向生成一段文字描述。这在理解他人绘制的复杂图表时非常有用。这个项目的核心价值不在于使用了多么高深的AI模型而在于它精准地捕捉并解决了一个高频、细微但确实影响效率的痛点。它降低了技术表达的门槛让我们能更专注于思考和设计本身。从“查语法”到“说想法”这一个小小的转变或许就是工具进化的意义所在。