在写技术方案、评审设计稿或者梳理业务逻辑时,画流程图往往是最后一道让人头疼的工序。过去常见做法是打开 draw.io 或 ProcessOn,手动拖拽矩形、菱形和箭头,再对着需求反复调整布局。现在,使用 Claude Code、Codex 这类支持自定义 skill 的 AI 编程终端的人,已经可以把它变成一句话的事:配上自定义 skill,AI 会直接根据需求生成流程图描述,渲染成图片,甚至输出可继续编辑的源文件。
这篇文章围绕“有了这个 skill,画流程图再也不用手搓了”这条主线,完整讲解一个流程图生成 skill 从设计、编写、安装、调试到落地使用的全过程。你会看到一个 skill 的标准目录结构、SKILL.md 的写法、自然语言转 Mermaid 的 Python 脚本、渲染导出的命令,以及最常见的加载失败、语法报错、字体缺失和布局混乱的排查方式。
文章不假设你已经写过 skill。先解释 skill 是什么、它和 MCP 有什么区别,再逐步实现一个最小可用的流程图生成工具,最终把它放到你自己的 AI 编程终端里使用。学完之后,你不仅可以画流程图,还能把“写文案、生成表格、批量处理脚本、固定格式汇报”这些重复任务同样封装成自己的 skill。
1. 画流程图的痛点为什么会落到“skill”上
1.1 手动画流程图的真实成本
很多团队在流程图这件事上浪费的时间,比想象中多得多。需求文档里描述的是一个流程,评审时讨论的是另一个流程,最终代码里实现的又是第三个流程。每次修改都要重新拖拽控件、调整连线、对齐位置,稍微复杂一点的业务分支,布局就会变得混乱。
更隐蔽的问题在于“流程图”和“需求描述”之间没有强关联。手工画图时,图形是独立的,文字描述是独立的,二者靠人的注意力维持同步。一旦需求变更,图忘记更新,文档和真实逻辑就脱节了。
如果让 AI 来生成流程图,核心价值不是省掉拖拽鼠标的时间,而是让流程描述和图形输出从同一个文本源产生。改文本,图形跟着变,这才是真正的效率提升。
1.2 skill 本质上是什么
在 Claude Code、Codex 这类 AI 编程终端里,skill 可以理解为“带说明书的外挂能力包”。它通常是一个目录,里面包含一个 SKILL.md 描述文件,以及若干脚本、模板、参考文档和资源文件。
AI 在响应你的请求时,会先判断当前任务是否匹配某个 skill 的描述。匹配成功后,它读取 SKILL.md 中的使用说明,按照里面定义的步骤去执行。和直接对话生成代码不同,skill 能把“固定流程”“工具调用”“输出格式”“错误处理”都固化下来。
可以这样理解:一段简单对话是找 AI 帮忙写一段临时代码,skill 则是交付一个“每次都能按固定流程执行的工具箱”。箱子里有操作手册,有工具脚本,有常见错误预案,AI 只需要照着说明执行。
1.3 skill 和 MCP 的区别,以及为什么先选 skill
很多人会把 skill 和 MCP 弄混。MCP(Model Context Protocol,模型上下文协议)是一种标准化协议,目的是让 AI 客户端与外部工具、数据源进行结构化通信。它可以连接数据库、GitHub、浏览器、企业内部系统,重点解决“AI 如何安全稳定地调用外部服务”这个问题。
skill 则更轻量,重点解决“AI 拿到一个任务时,如何按照你已经沉淀好的方法去执行”。skill 可以包含 MCP 工具的调用说明,MCP 是连接现实系统的通道,skill 是 AI 使用这些通道的“操作规范”。
选择从 skill 开始做流程图生成,是因为它不需要服务器、不需要额外协议、不需要申请外部 API,只需要本地 Python 环境和一个渲染工具链。学习成本低,效果直观,改造空间也大。流程图 skill 是从“会写代码”到“会给 AI 编写技能”的合适过渡项目。
| 对比项 | skill | MCP |
|---|---|---|
| 核心解决对象 | AI 执行任务的流程和规范 | AI 与外部工具的通信协议 |
| 典型载体 | 目录、SKILL.md、脚本、模板 | MCP server、JSON-RPC 接口 |
| 是否需要远程服务 | 通常不需要 | 大多数场景需要服务端 |
| 开发复杂度 | 低,本地脚本即可 | 中高,涉及协议和安全设计 |
| 适合场景 | 固定任务流程、格式输出、本地工具链 | 数据库查询、文件系统、网页操作、企业系统集成 |
实际项目中,两者不是替代关系,而是配合关系。用 MCP 把外部数据接进来,用 skill 把 AI 处理数据的流程固定下来,是一种很常见的设计。
2. 设计一个“流程图生成 skill”需要先拆解任务
2.1 输入和目标输出
写 skill 之前,先明确输入和输出。流程图生成 skill 的输入可以有很多种形态:
- 一句自然语言需求,例如“用户下单后检查库存,有库存就扣减并生成订单,没有库存就提示购买失败”
- 一段业务步骤清单,用短句逐条列出
- 一段代码,希望抽取其中的调用逻辑和分支
- 一份产品需求文档片段
输出目标则分为两层。第一层是流程图的描述文件,常见格式是 Mermaid 语法,因为文本简单、易于修改且和 GitHub、各大文档系统兼容。第二层是图片文件,常见格式是 PNG 和 SVG,用于插入文档、PPT 或分享给不熟悉技术的人。
如果希望后续继续编辑,还需要保留可编辑源文件,例如 draw.io 的 XML 格式。设计 skill 时,要让 AI 先生成结构化描述,再转换为图形文件,而不是让 AI 直接写一大段不可拆分的渲染脚本。
2.2 三种输出格式的取舍
| 格式 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| Mermaid | 文本化,易修改,支持内嵌到 Markdown | 复杂布局能力有限 | 技术文档、GitHub、快速迭代 |
| SVG | 矢量,无限缩放,便于二次加工 | 不适合直接放到 Word 或某些办公系统 | 网页展示、设计稿交流 |
| PNG | 兼容性最好,随处可用 | 修改一次就要重新生成 | 文档、PPT、IM 分享 |
| draw.io XML | 可继续手工编辑,支持复杂布局 | 文件结构较复杂,生成成本高 | 需要人工继续维护的大型流程图 |
一个成熟的 skill 应该同时输出 Mermaid 源文件和渲染后的图片,而不是只给其中一种。这样既保留了文本方案的可追溯性,又有直接可用的图片结果。
2.3 目录结构和依赖选型
流程图生成 skill 的目录设计,可以按照“描述文件 + 脚本 + 模板 + 输出目录”的方式组织:
flow-builder/ ├── SKILL.md ├── scripts/ │ ├── flow_to_mermaid.py │ ├── render.sh │ └── validate_flow.py ├── assets/ │ └── templates/ │ └── basic-flow.mmd └── output/依赖选型上,核心依赖有两个。第一个是 Python 3,用于把 AI 整理出的结构化 JSON 转成 Mermaid 文本。第二个是 Mermaid CLI,用于把 Mermaid 文件渲染成 PNG、SVG。Mermaid CLI 依赖 Node.js 环境以及 Chromium 或 Puppeteer,安装时要注意中文字体支持。
在常见项目中,可以按这个顺序处理依赖:先确认 Python 3 可用,再安装 Node.js,最后安装 mermaid-cli。如果原始材料没有给出明确版本,落地前要先确认依赖版本,不同版本的 mermaid-cli 参数略有差异。
3. 实现流程图生成 skill:SKILL.md 和核心脚本
3.1 目录结构和文件说明
实际动手时,先创建目录:
mkdir -p ~/.claude/skills/flow-builder/scripts mkdir -p ~/.claude/skills/flow-builder/assets/templates mkdir -p ~/.claude/skills/flow-builder/output这里把 skill 放在~/.claude/skills/下,是 Claude Code 这类终端常见的 skill 加载路径。Codex 或其他工具可能有自己的路径约定,落地时要先查看对应工具的文档,不要照搬目录。学习环境中,建议用一个固定的本地目录,例如~/dev/skills/flow-builder,开发测试完成后再复制到工具约定目录。
各文件职责如下:
| 文件 | 职责 |
|---|---|
SKILL.md | 告诉 AI 这个 skill 什么时候用、怎么用、输出什么 |
scripts/flow_to_mermaid.py | 把结构化 JSON 转成 Mermaid 语法文本 |
scripts/render.sh | 调用 mermaid-cli 渲染 PNG/SVG |
scripts/validate_flow.py | 检查 JSON 节点、边是否完整,避免生成残缺图 |
assets/templates/basic-flow.mmd | 基础模板,供脚本启动时参考 |
output/ | 统一输出目录,方便收集生成结果 |
3.2 编写 SKILL.md
SKILL.md 是 skill 的入口。它的作用不是给脚本写注释,而是让 AI 在运行时能准确理解“什么时候触发、按什么顺序执行、遇到问题怎么办”。
下面是一个最小可用的示例:
--- name: flow-builder description: 根据用户输入的需求描述、业务步骤或代码逻辑,生成流程图源文件和渲染图片。适合流程图绘制、流程梳理、需求评审、代码路径说明等场景。当用户提到“画流程图”“生成流程图”“用流程图表示”时使用。 version: 1.0.0 tools: - python3 - scripts/flow_to_mermaid.py - scripts/validate_flow.py - scripts/render.sh --- # flow-builder 根据用户的业务描述生成流程图。 ## 使用步骤 1. 阅读用户输入,提取流程节点、判断分支和流转关系。 2. 将流程整理成 JSON,写入临时文件 /tmp/flow_graph.json,格式见下文。 3. 运行 scripts/validate_flow.py 校验 JSON 完整性。 4. 运行 scripts/flow_to_mermaid.py 生成 Mermaid 源文件。 5. 运行 scripts/render.sh 渲染 PNG 和 SVG。 6. 把生成的 Mermaid 源码、PNG 路径和 SVG 路径一起展示给用户。 ## JSON 格式 {"nodes": [{"id": "start", "text": "用户提交订单", "type": "start"}], "edges": [{"from": "start", "to": "check_stock", "label": "下单"}]} ## 注意事项 - 节点 id 只允许英文字母、数字和下划线。 - 节点 text 不要使用特殊符号,必要时先转义。 - 如果用户输入过短,无法判断分支条件,先问清楚再生成,不要猜测。SKILL.md 描述越具体,AI 的执行稳定性越高。尤其是“使用步骤”部分,AI 会按照编号逐条执行。不要写含糊的话,比如“生成一张好看的图”,而要写明“先整理 JSON,再校验,再转换,再渲染”。
3.3 编写描述转 Mermaid 的生成脚本
脚本flow_to_mermaid.py的职责很简单:读入一个 JSON 文件,输出一个 Mermaid 流程图文件。这里刻意把“自然语言转结构化”的工作留给 AI,把“结构化转语法”的工作交给脚本。这样分工明确,AI 负责理解,脚本负责确定性输出。
#!/usr/bin/env python3 """将 flow_graph.json 转换为 Mermaid 流程图源文件。""" import json import re import sys from pathlib import Path def sanitize_text(text: str) -> str: """清理节点文本,避免破坏 Mermaid 语法。""" text = text.replace("\\", "\\\\") text = text.replace('"', '\\"') text = text.replace("\n", " ") return text.strip() def sanitize_id(node_id: str) -> str: """节点 id 只保留字母、数字和下划线。""" cleaned = re.sub(r"[^A-Za-z0-9_]", "_", node_id) if not cleaned: raise ValueError(f"invalid node id: {node_id}") return cleaned def build_mermaid(graph: dict, direction: str = "TD") -> str: nodes = graph.get("nodes", []) edges = graph.get("edges", []) lines = [f"graph {direction}"] for node in nodes: nid = sanitize_id(node["id"]) text = sanitize_text(node.get("text", nid)) node_type = node.get("type", "default") if node_type == "start": lines.append(f' {nid}["{text}"]:::start') elif node_type == "end": lines.append(f' {nid}["{text}"]:::end') elif node_type == "decision": lines.append(f' {nid}{{"{text}"}}') else: lines.append(f' {nid}["{text}"]') for edge in edges: src = sanitize_id(edge["from"]) dst = sanitize_id(edge["to"]) label = sanitize_text(edge.get("label", "")) if label: lines.append(f' {src} -->|{label}| {dst}') else: lines.append(f' {src} --> {dst}') lines.append("") lines.append("classDef start fill:#d9ead3,stroke:#82b366,stroke-width:2px;") lines.append("classDef end fill:#f4cccc,stroke:#cc0000,stroke-width:2px;") return "\n".join(lines) def main(): input_path = Path(sys.argv[1]) output_path = Path(sys.argv[2]) if len(sys.argv) > 2 else Path("flow.mmd") graph = json.loads(input_path.read_text(encoding="utf-8")) mermaid_content = build_mermaid(graph, direction=graph.get("direction", "TD")) output_path.write_text(mermaid_content, encoding="utf-8") print(f"mermaid file generated: {output_path}") if __name__ == "__main__": main()解释几个关键点。
sanitize_id处理节点 ID。用户输入中往往包含中文、空格、括号,这些字符放在 Mermaid 节点 ID 里会直接导致渲染失败。统一替换成下划线,可以避免大部分语法错误。
sanitize_text处理节点显示文字。节点文字中如果包含双引号、反斜杠或换行符,会破坏 Mermaid 语法结构。脚本里做简单转义,复杂文本建议在 JSON 生成阶段就清洗干净。
direction参数控制布局方向。TD表示从上到下,LR表示从左到右。默认使用TD,适合大多数业务流程;如果节点很多且文本较长,LR效果更好,避免图形横向过窄。
3.4 编写渲染和导出脚本
Mermaid 源文件生成后,还需要渲染成图片。渲染脚本render.sh负责这一步骤:
#!/usr/bin/env bash set -euo pipefail INPUT_FILE="${1:-flow.mmd}" OUTPUT_DIR="${2:-output}" mkdir -p "$OUTPUT_DIR" if command -v mmdc &>/dev/null; then MMDC=mmdc elif command -v npx &>/dev/null; then MMDC="npx -y @mermaid-js/mermaid-cli" else echo "error: mmdc or npx not found, please install mermaid-cli first." >&2 exit 1 fi # 渲染 SVG $MMDC -i "$INPUT_FILE" -o "$OUTPUT_DIR/flow.svg" # 渲染 PNG,注意设置宽度和背景色 $MMDC -i "$INPUT_FILE" -o "$OUTPUT_DIR/flow.png" -w 1600 -H 1200 -b white -s 2 echo "render done: $OUTPUT_DIR/flow.svg, $OUTPUT_DIR/flow.png"脚本先检查mmdc是否可用,不可用时尝试通过npx临时调用 mermaid-cli。渲染 SVG 用于矢量场景,渲染 PNG 用于文档和 IM 分享。-s 2表示双倍缩放,避免截图时模糊。
如果遇到中文字体变成方块,一般是系统缺少中文字体,或 mermaid-cli 的字体配置没有生效。处理方法是先安装中文字体,例如fonts-noto-cjk,再指定字体参数。不同版本参数名不同,实际以mmdc --help输出为准。
3.5 用 draw.io 格式保留可编辑能力
Mermaid 文本和渲染图片解决了“快速出图”的问题,但用户后续想微调布局时,还是希望用 draw.io 这类工具手工编辑。有两种常见做法。
第一种,把渲染出的 SVG 导入 draw.io,然后调整。这种方式简单,但导入后图形已经变成矢量元素,逻辑结构和布局信息不完整。
第二种,直接生成 draw.io 的 XML 格式。draw.io 文件本质是一个包含mxGraphModel的 XML 文件,里面定义每个图形的坐标、样式和连线。生成这类 XML 比生成 Mermaid 复杂,适合在 skill 的进阶版本中实现。
对于大多数场景,推荐先输出 Mermaid 源文件和 PNG/SVG 图片,当用户明确说“需要可编辑的 drawio 文件”时,再调用一个独立的drawio_xml_generator.py脚本生成 XML。不要让同一个脚本承担太多职责,否则排查起来会很困难。
4. 安装、加载与调试:让 AI 真正“会”用这个 skill
4.1 在 Claude Code 类工具中安装 skill
目录创建、脚本写完、SKILL.md 写好后,安装动作本身并不复杂。在 Claude Code 这类工具中,通常是目录放对位置、命名正确、工具重启后即可识别。
先用一条命令确认目录结构是否正确:
find ~/.claude/skills/flow-builder -type f | sort预期输出应该包含 SKILL.md、scripts 下的三个脚本以及 assets 模板文件。如果文件缺失,AI 加载时会找不到执行入口。
然后重启或重新加载终端会话,让 skill 列表刷新。不同工具刷新方式不同,有些需要重启进程,有些在对话中输入/skills就能看到列表。
加载时最容易犯的错误是目录层级不对。常见的错误结构是:
~/.claude/skills/flow-builder/flow-builder/SKILL.md多嵌了一层同名目录,导致工具扫描不到 skill。正确结构应该是 SKILL.md 直接位于flow-builder/下。
4.2 触发与自动加载
skill 的触发方式分为显式触发和自动匹配。
显式触发是在对话中直接告诉 AI 使用某个 skill。例如:
使用 flow-builder 技能,画一下用户登录的流程图自动匹配则依赖 SKILL.md 中的描述。当你的请求包含“流程图”“流程梳理”“生成流程图”等字眼,AI 会读取 skil l描述后判断是否使用。自动匹配的稳定性取决于 description 写得好不好。描述里应该包含触发词、适用场景和使用边界,而不是只说一句“生成流程图”。
实际项目中,显式触发更可靠。自动匹配在 prompt 复杂时容易选中不合适的 skill。这里要注意:不要同时安装多个描述过于相似的流程图 skill,否则 AI 每次都在选择上消耗上下文,甚至选错。
4.3 调试流程和日志验证
skill 不生效时,先不急着改代码,按下面的链路排查。
第一,确认 skill 是否被扫描到。在对话中问“列出当前可用的 skill”,或者查找工具的 skill 管理命令。如果列表中没有 flow-builder,说明加载路径或目录结构有问题。
第二,确认 SKILL.md 是否可以解析。有时候文件头部缺少---分隔符,或 YAML 字段写得不对,AI 会当成普通文档跳过。检查name和description两个字段是否都存在。
第三,独立运行脚本。不经过 AI,直接手动执行以下命令:
echo '{"nodes": [{"id":"start","text":"开始","type":"start"}], "edges": []}' | python3 scripts/flow_to_mermaid.py /dev/stdin /tmp/test.mmd如果脚本本身出错,那么 AI 无论怎么调用都会失败。先把脚本跑通,再排查 AI 环节。
第四,让 AI 输出执行过程。对话中要求“把每一步命令和结果都展示出来”,观察它在哪一步中断,是没找到脚本路径,还是脚本运行报错,还是渲染命令失败。
4.4 参数与行为调优
skill 的很多行为可以通过 SKILL.md 和脚本参数调节。这里整理成一张表,方便快速决策:
| 参数 | 作用 | 默认值 | 调大影响 | 调小影响 |
|---|---|---|---|---|
direction | 流程图方向 | TD | 布局横向变窄 | 竖向变窄,适合节点多的情况 |
-s 2 | 渲染缩放倍数 | 2 | 图片更清晰,文件更大 | 图片发虚 |
-w/-H | 画布宽高 | 1600 / 1200 | 画布大,留白多 | 文本容易截断 |
validate_flow严格度 | 是否强制每个节点都有出边 | 宽松 | 容易误报,影响生成 | 容易缺边漏点 |
| skill 触发方式 | 显式/自动 | 两者都用 | 自动时可能误命中 | 精确但需要每次手动指定 |
对于刚上手的开发,建议先使用默认参数,跑通一条完整链路后再逐步调整。画布宽度和缩放倍数是最常调的两个参数,业务流程图节点多、文字长,默认 1600×1200 往往不够,可以提高到 2000×1400。
5. 运行验证:从一句话到一张可导出图片
5.1 典型调用示例
完成安装后,在对话中给出这样的需求:
用 flow-builder 画一个订单提交流程图:用户提交订单,系统检查库存,库存充足就扣减库存并创建订单,库存不足则提示库存不足,最后结束。AI 依据 SKILL.md 的流程,会先生成一份结构化 JSON,内容类似:
{ "direction": "TD", "nodes": [ {"id": "start", "text": "用户提交订单", "type": "start"}, {"id": "check_stock", "text": "系统检查库存", "type": "decision"}, {"id": "deduct", "text": "扣减库存并创建订单", "type": "default"}, {"id": "fail", "text": "提示库存不足", "type": "default"}, {"id": "end", "text": "流程结束", "type": "end"} ], "edges": [ {"from": "start", "to": "check_stock", "label": "提交"}, {"from": "check_stock", "to": "deduct", "label": "库存充足"}, {"from": "check_stock", "to": "fail", "label": "库存不足"}, {"from": "deduct", "to": "end", "label": ""}, {"from": "fail", "to": "end", "label": ""} ] }之后脚本生成 Mermaid 源文件:
graph TD start["用户提交订单"]:::start check_stock{"系统检查库存"} deduct["扣减库存并创建订单"] fail["提示库存不足"] end_flow["流程结束"]:::end start -->|提交| check_stock check_stock -->|库存充足| deduct check_stock -->|库存不足| fail deduct --> end_flow fail --> end_flow classDef start fill:#d9ead3,stroke:#82b366,stroke-width:2px; classDef end fill:#f4cccc,stroke:#cc0000,stroke-width:2px;渲染脚本随后输出 SVG 和 PNG 文件。用户拿到的实际上是三样东西:可直接放进 Markdown 的 Mermaid 源码、可分享的 PNG、可继续前端加工的 SVG。
5.2 验证清单
一个 skill 是否合格,不能只看“能启动”。每次开发或修改 skill 后,按下面的清单验证:
| 检查项 | 预期结果 | 检查方式 |
|---|---|---|
| skill 被工具识别 | skills列表存在 flow-builder | 对话中询问或使用工具管理命令 |
| 脚本可独立运行 | 非零退出码或明确报错 | 直接执行 Python 脚本 |
| 正常输入能出图 | 输出 flow.mmd、flow.svg、flow.png | 查看 output 目录 |
| 分支能被生成 | 决策节点有多个出口 | 检查 edges 中来自 decision 的边数 |
| 中文不乱码 | 图片中的中文正常显示 | 打开 PNG 查看 |
| 错误输入有提示 | 给出具体 json 校验错误,而不是崩溃 | 传入空节点测试 |
| 不污染其他对话 | 不使用 skill 时回答保持正常 | 请求无关任务观察 |
不需要一次性全部通过,但至少要保证“正常输入能出图”和“错误输入有提示”这两项,才能交付给团队其他人使用。
5.3 与手动绘制对比的成本估算
对比手工绘制和 skill 生成,不能只看一次出图的时间。手工画一张中等复杂度的流程图,大约需要 10 到 30 分钟;用 skill 生成,一般在 1 到 3 分钟内完成,其中大部分时间花在 AI 理解需求上。
更重要的是修改成本。手工画的图,需求变化后往往要重新拖拽,等于重画一张;skill 生成的图,只需要把新的需求描述补充上去,AI 重新执行一遍流程即可。团队里如果每周要更新数十张流程图,这种差别会非常明显。
真实项目中的建议是:一次性的、展示给客户的流程图可以手工精修;频繁变更的、需要跟着需求走的流程图,一定要用文本化生成方案。把时间留给流程设计本身,而不是控件拖动。
6. 常见问题排查:skill 加载不到、渲染失败、布局混乱
6.1 skill 没有被加载
现象是对话中明确指出“使用 flow-builder”,AI 仍然像没有这个 skill 一样正常回答,不会进入流程图生成流程。
可能原因按优先级排列:
- 目录放错位置。
- SKILL.md 文件名大小写错误。
- SKILL.md 头部 YAML 格式错误。
- 工具进程未重启,skill 列表没有刷新。
- description 中没有覆盖用户表达方式。
检查方式:先确认目录名称和SKILL.md文件是否在正确层级,再查看工具日志中是否有 skill 扫描记录,最后在对话中主动询问“当前可用 skill 有哪些”。
解决建议:用find ~/.claude/skills -maxdepth 2 -name SKILL.md列出工具实际扫到的 skill 路径,如果缺失,就对照正确目录结构修正。
6.2 Mermaid 语法错误或节点内容乱码
现象是 AI 生成了 Mermaid 源码,但通过脚本转换时报Parse error,或者图片中节点文本出现错位、截断、乱码。
最常见原因是节点文本中包含括号、引号、反斜杠等特殊字符。例如“用户登录(包含验证码)”里的括号,如果直接放进A["文本"]中,Mermaid 解析器容易误判。
解决方式:在sanitize_text中统一处理特殊字符,同时要求 AI 在生成 JSON 时不要给 text 字段加入多余符号。如果文本太长,建议在 AI 生成阶段就拆分成多行或简化表达,而不是依赖脚本截断。
节点 ID 也要规范化。ID 使用中文、空格或-连字符,在某些 Mermaid 版本中不会立即报错,但引用边时可能失配。上面脚本中sanitize_id把所有非字母数字下划线转成下划线,能避免这类问题。
6.3 渲染失败:字体、浏览器和依赖问题
现象是 Mermaid 文件生成正常,但render.sh执行时报错,常见信息包括:
Could not find Chromium Error: Failed to launch the browser process Fontconfig error: Cannot load default config file原因分为三种:Node.js 环境缺失、mermaid-cli 依赖的浏览器没有安装、中文字体缺失。
检查顺序:
node -v npx -v mmdc --version fc-list | grep -i "noto.*cjk"如果 Node.js 未安装,先安装 Node.js 18 及以上版本。如果mmdc不存在,执行npm install -g @mermaid-js/mermaid-cli,或使用npx临时调用。如果浏览器报错,安装 Chromium 或在 puppeteer 配置中指定浏览器路径。如果中文字体缺失,安装fonts-noto-cjk(Debian/Ubuntu)或wqy-zenhei(CentOS)。
渲染失败和 skill 代码本身关系不大,更多是运行环境问题。生产环境建议把 mermaid-cli 也纳入统一版本管理,避免换一台机器就出现“本地能跑,服务器不能跑”的情况。
6.4 生成的流程层级不合理
现象是图能生成,但层级混乱,比如判断节点跑到了流程末尾,或者本应并列的分支被串联成一条长链。
原因多半在结构化 JSON 阶段。AI 只依赖自然语言描述,没有真正理解业务分支结构。例如“如果库存充足就扣减库存并创建订单,否则提示库存不足”转换成 JSON 时,容易出现漏掉汇合点的错误。
解决方式有两个层面。第一个层面是 prompt 控制,在 SKILL.md 中明确要求“所有决策节点必须有两个出口,所有分支最终必须汇合到同一个结束节点”。第二个层面是脚本校验,在validate_flow.py中加入“存在唯一开始节点和唯一结束节点”“每个 decision 类型节点出边数量不小于 2”这些规则。
def validate_graph(graph: dict) -> list[str]: errors = [] nodes = graph.get("nodes", []) edges = graph.get("edges", []) if not nodes: errors.append("nodes 不能为空") start_nodes = [n for n in nodes if n.get("type") == "start"] end_nodes = [n for n in nodes if n.get("type") == "end"] if len(start_nodes) != 1: errors.append("流程必须且只能有一个 start 节点") if len(end_nodes) == 0: errors.append("流程必须包含至少一个 end 节点") from_map = {} for e in edges: from_map.setdefault(e["from"], 0) from_map[e["from"]] += 1 for n in nodes: if n.get("type") == "decision" and from_map.get(n["id"], 0) < 2: errors.append(f"决策节点 {n['id']} 至少需要两个出口") return errors校验不通过时,让 AI 根据错误信息修正 JSON 后再渲染,而不是直接进入渲染步骤。在 SKILL.md 中把这一步写成强制流程,能明显提升复杂流程图的正确率。
6.5 AI 只输出代码但不进入执行流程
现象是用户要求生成流程图,AI 给出了一段 Python 代码或 Mermaid 文本,但没有实际运行脚本,也没有输出图片文件。
根本原因是 SKILL.md 中“运行脚本”的指令不够强制,或者 AI 的上下文里没有足够的信号让它判断自己应该执行而不是回答。解决方式是在 SKILL.md 中使用明确的祈使句,例如“必须运行”“不要只输出代码”,并在步骤列表中把“展示生成结果”和“提示文件路径”作为最后一步。
对话中如果 AI 已经偏离,可以用一句纠正提示拉回:
请严格按照 flow-builder 的步骤执行,现在需要生成图片文件,不要只输出代码。多次出现这个问题时,需要检查 SKILL.md 的步骤是否足够明确,以及 description 是否覆盖了用户的表达方式。真实原因往往是描述中缺少“不要只输出源码”的边界说明。
7. 学习环境与生产环境的落地差异
7.1 学习环境:本地终端快速验证
学习环境中,最重要的是快速跑通闭环,不需要追求完美。推荐在个人电脑上完成以下几件事:
- 创建 flow-builder 目录,写好 SKILL.md 和两个脚本。
- 用一段简单的业务描述测试,例如“用户注册后发送验证邮件”。
- 只验证三个结果:Mermaid 源码生成、SVG 渲染成功、PNG 输出可见。
- 故意给一个错误的 JSON,观察报错信息是否清晰。
学习环境中不推荐一开始就接入 draw.io XML 生成,也不推荐并行开发多个 skill。先把一个 skill 的链路研究透,再扩展到其他场景,能减少大量排查成本。
7.2 生产环境:版本管理、权限、日志和回滚
生产环境使用 skill 时,需要考虑的事情比本地多得多。
版本管理。skill 目录应该纳入 Git 仓库,每次修改都有记录。SKILL.md 中的version字段要随功能变更升级,避免团队里有人还在用旧版本。脚本改动后需要跑一遍第 5.2 节的验证清单,再发布到共享目录。
权限与安全。skill 内部会执行 Python 脚本和渲染命令,如果 AI 终端可以访问生产服务器的文件系统,那么脚本中的路径、参数都需要做白名单化。不要允许通过用户输入直接拼接 shell 命令,防止恶意输入触发命令注入。所有输入文件应该写到临时目录,而不是直接覆盖业务目录中的文件。
日志。生产环境的 skill 每次调用都应该记录输入摘要、脚本退出码、输出文件路径。最简单的方式是让render.sh把日志追加到固定文件:
echo "$(date '+%Y-%m-%d %H:%M:%S') input=$INPUT_FILE output=$OUTPUT_DIR" >> flow-builder.log这样出现问题时可以快速确认 AI 是否真的调用了脚本、调用了多少次、输出到哪里。
回滚。skill 升级后如果出现问题,最直接的方案是保留上一个版本目录,例如flow-builder-v1/、flow-builder-v2/。在 SKILL.md 中明确指定使用哪个版本目录,切换时只需要调整工具加载路径,不需要重新下载或安装。
7.3 发布前检查清单
把 skill 分享给团队前,逐项确认以下内容:
| 检查项 | 要求 |
|---|---|
| 目录结构 | SKILL.md 位于 skill 根目录,scripts 和 assets 相对路径正确 |
| SKILL.md 字段 | name、description、version 齐全,描述中包含触发词和输出物 |
| 脚本可独立运行 | Python 脚本不依赖 AI 生成的额外参考代码 |
| 输出路径 | 所有输出默认写入指定 output 目录,不使用绝对路径写死 |
| 依赖说明 | README 或 SKILL.md 中写明 Python、Node.js、mermaid-cli、中文字体要求 |
| 中文支持 | 中文节点文本渲染无乱码 |
| 错误处理 | JSON 校验失败时能给出可理解的错误信息 |
| 安全边界 | 不接受任意 shell 命令拼接,脚本对用户输入做转义或校验 |
这份清单也可以用于其他 skill 的评审。它的核心思想是:skill 不只是给 AI 看的提示词,更是一段需要在真实环境中可靠执行的工程代码。
8. skill 编写的通用最佳实践与扩展方向
8.1 skill 编写规范
从 flow-builder 这个例子可以提炼出几条通用的 skill 编写规范。
一个 skill 只解决一类任务。流程图 skill 就专注流程图,不要试图同时处理时序图、甘特图和数据可视化。任务范围越窄,SKILL.md 的描述越精确,AI 的匹配和执行越稳定。
把 AI 的任务边界写清楚。AI 负责理解需求、整理结构化数据、调用脚本,脚本负责确定性转换和渲染。不要让 AI 临时决定输出格式,格式应该由脚本固定。比如 JSON 的结构、节点类型、边字段,都要在 SKILL.md 中写明。
脚本要能独立运行。不依赖 AI 的临时生成代码,才是可测试、可维护的脚本。开发时直接执行 Python 命令,传一本测试 JSON,看到预期输出后再把流程集成到 skill 中。
优先使用标准工具。Mermaid、Graphviz、draw.io 都是成熟方案。自研生成器能解决一时的问题,但维护成本会随着图表类型增加而迅速上升。
错误信息要可读。validate_flow.py校验失败时,不要只输出Invalid,要输出“决策节点 check_stock 至少需要两个出口”这样的信息。AI 拿到具体错误,才有能力自我修正。
8.2 从流程图 skill 延伸出去的能力
画流程图只是一个起点。同样的“人机协作”模式可以扩展到多种任务:
- 时序图生成:输入“用户调用订单服务,订单服务调用库存服务”这样的描述,输出 Mermaid 时序图。
- 状态机图生成:把枚举状态和迁移条件整理成 JSON,绘制状态机图。
- 代码调用链抽取:输入项目源码路径,使用脚本分析函数调用关系,自动生成架构图。
- 日报和周报格式化:把对话内容整理成固定结构的 Markdown 文档,输出到指定目录。
- 批量文件处理:把“重命名、压缩、分类”这类操作封装成 skill,由 AI 统一调度。
每次扩展时都复用同一套设计原则:明确输入输出、拆成描述文件加脚本、脚本可独立测试、输出目录固定、错误信息可读。掌握这套方法论,比只学会 mermaid-cli 的参数用法更有价值。
真正想在 AI 工程化上走得更远的人,不应只停留在“让 AI 写代码”的层面,而应该开始设计“AI 怎么用你的代码和流程”。skill 就是这条路上一个很顺手的载体。下次遇到需要重复执行的任务,先想一想:如果把它封装成一个 skill,AI 能替我省掉多少手工时间。从画流程图开始,把第一个 skill 跑通,你会逐渐找到自己在 AI 工作流里的控制点。