IB_Robot Mermaid 语法验证:必做上下文检查(context-checks)的五项门禁与脚本化实现

原创2026-10-13 13:58:24659 阅读
文章标签:人工智能具身智能机器人AI Agent模型推理服务多模态计算机视觉语音本地部署

IB_Robot Mermaid 语法验证:必做上下文检查(context-checks)的五项门禁与脚本化实现

本篇技术指南围绕 IB_Robot 仓库内 AI Agent 技能库中的 mermaid-syntax-validation 技能展开,完整讲解其「必做上下文检查(context-checks)」的设计动机、触发时机、门禁规则与五项检查的具体操作命令(Linux/bash 主路径与 Windows PowerShell 扩展),并结合同目录脚本的源码实现说明每项检查的判定逻辑与证据输出。读完本文,你将掌握在修复任何 Mermaid 图之前,如何系统性地确认文档栈、本地 runtime 资源、fence 统计、含图 HTML 页面与 script 标签/CDN 引用这五类上下文,从而避免"静态扫描通过但浏览器仍渲染失败"的典型问题。

背景:为什么修复 Mermaid 之前必须先做上下文检查

在 IB_Robot 的文档工作流中,.agents 目录维护了面向 AI Agent 的技能插件(技能清单总览),其中 mermaid-syntax-validation 技能 负责对 Markdown/Sphinx 文档中的 Mermaid 图执行"检查 → 修复 → 构建 → 浏览器验证"的完整闭环。仓库内 docs/unify.md(统一模型推理架构文档)与 docs/roadmap.md 中便包含多段 ```mermaid fence,属于该技能的典型作用对象。

该技能把检查分成两个层次:

  • 无条件门禁:不依赖任何前置条件、每次执行都必须满足的规则,定义在 SKILL.md 中,例如"没有脚本输出不得开始编辑任何 Markdown 文件""最终报告字段必须取自脚本输出"。
  • 条件性规则(本文主体):只有在特定场景触发时才需要执行的规则与手工核对清单,即 references/context-checks.md 文档所承载的内容。

context-checks.md 明确声明了自己的职责边界:它只保留按条件触发的规则与手工核对清单;命令与无条件门禁见 SKILL.md 的「必做上下文检查」一节。因此,理解本文的前提是先通读 SKILL.md 的主流程。

触发时机(When to Read)

context-checks.md 定义了以下四种需要阅读本清单的场景:

  1. context_check.py 脚本报告 WARNING,需要确定处置方式时——例如检测到 CDN 引用,或生成 HTML 中存在 mermaid 容器但没有本地 runtime 引用;
  2. 需要人工核对脚本未覆盖的检查项时——主要是 conf.py 中的 monkey patch / override 语义、以及 Sphinx 配置组合是否合理;
  3. 需要理解 context_check.py 各检查项的原始定义时——脚本只是把本文档的检查规则自动化,规则源头在此;
  4. 需要手工执行某项检查时——例如 fence 统计、查找含图 HTML 页面、检查 script 标签。

这四种场景的共同特征是:脚本给出了结果但需要人工判断,或者脚本覆盖不到。清单的意义就在于把"机器能自动做的"和"必须人来判断的"明确切分。

门禁规则:触发上述场景时必须满足

当触发上述场景时,有三条硬性门禁:

  1. WARNING 必须显式处置:脚本报告 WARNING(如 CDN 引用、有 mermaid 容器但无本地 runtime 引用)时,必须在最终报告中明确列出并说明处置方式,不允许忽略。
  2. 人工判断项必须逐项核对:脚本未覆盖的人工判断项(conf.py 中 monkey patch / override 的语义、Sphinx 配置组合是否合理),必须按下方第 1、2 节清单逐项核对,并在报告中说明。
  3. 脚本输出是证据基线:脚本输出是第 1–5 项检查的证据基线;当手工核对结论与脚本输出不一致时,以脚本输出为准并排查差异原因。

这三条规则体现了该技能的核心哲学:机器证据优先于人工印象,任何与脚本输出不符的判断都必须先解释"为什么不一样",而不是直接覆盖脚本结果。

第 1 项检查:确认文档栈(docs stack)

第 1 项检查用于回答"当前文档用的是哪一套渲染栈"。核对要点包括:

  • docs/source/conf.py:Sphinx 配置文件的定位。如果仓库的 docs 根目录下找不到 conf.py,说明可能对接的是外部 Sphinx 项目,此时脚本会输出 conf.py: NOT FOUND under docs root (external Sphinx project?),这本身就是一个需要说明的结论(IB_Robot 当前的 docs/migration 目录即属于通过 doc_config.json 描述的迁移文档结构,可作为此类场景的参考)。
  • extensions:必须包含 myst_parser 和/或 sphinxcontrib.mermaid。
  • myst_fence_as_directive = ["mermaid"]:当 Markdown 使用 ```mermaid fence 时,应保留该配置,让 MyST 把 fence 转成 mermaid directive。
  • Mermaid 扩展配置项:mermaid_output_format、mermaid_version、mermaid_include_elk、mermaid_fullscreen、mermaid_init_config。
  • html_js_files:加载浏览器 runtime 的条目,例如 js/mermaid.min.js、js/mermaid-run.js、js/mermaid.esm.min.mjs,或旧的自定义文件如 js/mermaid-init.js。
  • 项目自定义 monkey patch / override:是否有用于禁用 sphinxcontrib-mermaid 自动注入 JavaScript 的补丁,这属于脚本无法判断的语义问题,必须人工核对。

该检查的脚本化实现位于 scripts/context_check.py,其中 CONF_KEYS 常量精确枚举了需要从 conf.py 提取的配置键:

CONF_KEYS = [
    "extensions",
    "myst_fence_as_directive",
    "html_js_files",
    "mermaid_version",
    "mermaid_output_format",
    "mermaid_init_config",
    "mermaid_include_elk",
    "mermaid_fullscreen",
    "mermaid_use_local",
    "mermaid_elk_use_local",
    "mermaid_zenuml_use_local",
    "d3_use_local",
]

脚本通过正则 ^\s*<key>\s*=\s*(.+)$ 逐行提取这些键的值并截断到 120 字符输出;如果 conf.py 内容中既没有 sphinxcontrib.mermaid 也没有 myst_parser,则输出 WARNING。注意 CONF_KEYS 中后四项(mermaid_use_local、mermaid_elk_use_local、mermaid_zenuml_use_local、d3_use_local)正是第 2 项检查所关心的"本地化依赖开关"。

第 2 项检查:确认本地 runtime 资源

第 2 项检查回答"浏览器端渲染 Mermaid 的 JavaScript 运行时是否在本地、是否完整"。核对要点:

  • UMD/全局对象 runtime:docs/source/_static/js/mermaid.min.js 以及 runner 脚本,例如 docs/source/_static/js/mermaid-run.js。runner 的职责包括:等待 window.mermaid 存在、调用 window.mermaid.initialize({ startOnLoad: false, ... })、页面加载后调用 window.mermaid.run()、绑定项目自定义交互(如点击放大 modal)。
  • ESM runtime:docs/source/_static/js/mermaid.esm.min.mjs 以及必需的相对 docs/source/_static/js/chunks/ 目录树——ESM 入口文件旁边缺少 chunks/ 目录即视为 runtime 不完整。
  • 可选本地依赖:通过 Sphinx 配置项指定的 mermaid_use_local、mermaid_elk_use_local、mermaid_zenuml_use_local、d3_use_local。
  • CDN 红线:除非用户明确接受在线文档,否则 Mermaid/Panzoom/D3 runtime 不应从 cdn.jsdelivr.net、unpkg.com 或其他 CDN 拉取。对要求离线可用的文档,引入 CDN 依赖属于违规。

脚本实现方面,context_check.py 的 check_runtime() 遍历 docs 根目录下所有 _static 目录(同时检查 _static/js/ 与 _static/ 两个位置),查找 RUNTIME_FILES 常量定义的四类文件,并单独识别 chunks/ ESM 目录:

RUNTIME_FILES = ["mermaid.min.js", "mermaid-run.js", "mermaid.esm.min.mjs", "mermaid-init.js"]

其中 mermaid-init.js 被标注为"旧的自定义文件",对应 SKILL.md 中"把 mermaid.init() 示例视为旧写法,因为 Mermaid v10+ 已废弃该 API"的提示。

第 3 项检查:统计 Mermaid fence(Linux/bash 主路径)

第 3 项检查统计 docs 下所有 Markdown 文件中 ```mermaid fence 的总数,用于建立"有多少图需要被验证"的基线。Linux/bash 主路径使用内联 Python:

python3 - <<'PY'
from pathlib import Path

print(sum(1 for path in Path("docs").rglob("*.md") for line in path.read_text(encoding="utf-8").splitlines() if line.strip() == "```mermaid"))
PY

Windows PowerShell 可选扩展:

Get-ChildItem -LiteralPath "docs" -Recurse -File -Filter "*.md" |
  Select-String -Pattern '^```mermaid\s*$' |
  Measure-Object |
  Select-Object -ExpandProperty Count

注意脚本化的 check_fences() 与手工命令的一个细节差异:手工命令用 encoding="utf-8" 读取,而 context_check.py 用 encoding="utf-8-sig"(自动剥离 BOM),避免带 BOM 的 Markdown 文件首行出现 \ufeff 导致匹配失败。fix_labels.py 在写回文件时也会保留原有 BOM。以 IB_Robot 当前仓库为例,docs/ 下 ```mermaid fence 分布在 docs/unify.md(9 处)与 docs/roadmap.md(1 处),合计 10 处,可直接用本命令复核。

第 4 项检查:找出生成 HTML 中包含 Mermaid 的页面

第 4 项检查在构建产物 docs/build/html 中定位所有包含 mermaid 容器的 HTML 页面,用于确定"哪些页面必须进入浏览器验证"。判定依据是 class="mermaid" 或包含 mermaid 子串的 class 属性。Linux/bash 主路径:

python3 - <<'PY'
from pathlib import Path
import re

pattern = re.compile(r'class="mermaid"|class="[^" ]*mermaid')
for path in sorted(Path("docs/build/html").rglob("*.html")):
    if pattern.search(path.read_text(encoding="utf-8", errors="ignore")):
        print(path)
PY

Windows PowerShell 可选扩展:

Get-ChildItem -LiteralPath "docs/build/html" -Recurse -File -Filter "*.html" |
  Select-String -Pattern 'class="mermaid"|class="[^" ]*mermaid' |
  ForEach-Object { $_.Path } |
  Sort-Object -Unique

脚本实现中,context_check.py 的 check_html() 使用同一正则 MERMAID_CLASS_RE,并对构建目录缺失的情况做了优雅处理——若 --build-dir 不存在,则跳过第 4/5 项并打印 build dir not found, skipped,因为仓库可能尚未执行过构建。这也解释了为什么该技能在 SKILL.md 中把"真实文档构建"作为独立环节:静态源码检查与构建产物检查是两个不同的证据层。

第 5 项检查:检查生成 HTML 的 Mermaid script 标签

第 5 项检查在生成 HTML 中扫描两类内容:

  1. 本地 runtime 引用:mermaid.min.js、mermaid-run.js、mermaid.esm.min.mjs 等 script 引用是否出现;
  2. CDN 泄漏:cdn.jsdelivr.net、unpkg.com 是否被意外引入。

Linux/bash 主路径:

python3 - <<'PY'
from pathlib import Path
import re

pattern = re.compile(r'mermaid\.min\.js|mermaid-run\.js|mermaid\.esm\.min\.mjs|cdn\.jsdelivr\.net|unpkg\.com')
for path in sorted(Path("docs/build/html").rglob("*.html")):
    text = path.read_text(encoding="utf-8", errors="ignore")
    if pattern.search(text):
        print(path)
PY

Windows PowerShell 可选扩展:

Select-String -Path "docs/build/html/**/*.html" `
  -Pattern 'mermaid\.min\.js|mermaid-run\.js|mermaid\.esm\.min\.mjs|cdn\.jsdelivr\.net|unpkg\.com'

这项检查存在一个重要的交叉判断逻辑:脚本会把"含 mermaid 容器的页面数"与"引用了本地 runtime 的页面数"对比,若 pages 非空而 runtime_pages 为空,则输出 WARNING: mermaid containers exist but no local runtime script referenced in HTML——这正是 context-checks.md 门禁规则 1 所要求的"必须在报告中明确列出并说明处置"的典型场景。

五项检查的脚本化:context_check.py 的自动化实现

context-checks.md 的说明性命令与 scripts/context_check.py 之间是"规则"与"执行器"的关系:脚本把 5 项手工检查合并为一条命令,避免 Agent 依赖自然语言描述逐步执行:

python -X utf8 <skill_dir>/scripts/context_check.py --docs-root docs [--build-dir docs/build/html]

脚本执行时按 [1/5] docs stack → [2/5] local mermaid runtime assets → [3/5] mermaid fence count → [4/5] generated HTML pages containing mermaid → [5/5] script tags / CDN references in generated HTML 的顺序输出五段证据,<skill_dir> 指该技能目录(scripts/、references/ 的父目录),--docs-root 等目标路径参数以当前工作目录为基准。

脚本退出码语义明确:

  • 0 = 检查已执行(发现的问题仍可能需要人工判断,例如 CDN 引用对离线文档是否构成违规);
  • 2 = 用法或路径错误(例如 --docs-root 不存在)。

conf.py 或构建目录缺失时不视为错误,只打印提示继续执行——因为仓库可能对接外部 Sphinx 项目或尚未构建。这一点与构建后扫描脚本 scripts/html_scan.py 的语义不同:后者在构建目录缺失或其中没有 HTML 文件时以退出码 2 报错,此时不得视为验证通过,必须先修正 --build-dir 或重新构建。

context_check.py 还精确复刻了 context-checks.md 中的正则:

CDN_RE = re.compile(r"cdn\.jsdelivr\.net|unpkg\.com")
MERMAID_CLASS_RE = re.compile(r'class="mermaid"|class="[^" ]*mermaid')
SCRIPT_RUNTIME_RE = re.compile(r"mermaid\.min\.js|mermaid-run\.js|mermaid\.esm\.min\.mjs")

脚本输出即为 SKILL.md 报告格式中"context check 摘要(文档栈、runtime 文件、fence 数、含图页面数)"字段的直接证据来源,缺失该项即视为未执行门禁步骤。

从上下文检查到完整验证闭环:context-checks 在技能中的位置

context-checks.md 只是 mermaid-syntax-validation 技能三个组成部分之一,理解其定位才能正确执行:

组成部分 文件 职责
主流程 SKILL.md 无条件门禁、修复循环、构建验证、浏览器验证、报告格式
上下文检查清单 references/context-checks.md 条件性规则 + 5 项检查的手工定义(本文主体)
语法修复规则 references/syntax-scan-and-fix-rules.md 高风险模式表、flowchart/state diagram 修复规则、静态语法初筛回退

上下文检查在整个闭环中的位置是最先执行的门禁:任何修复开始之前,先运行 context_check.py 完成 5 项检查,再进入"诊断 → 预览 → 修复 → 复验"循环:

node <skill_dir>/scripts/parse_check.mjs <target_dir>                   # 1. 诊断:定位失败块
python -X utf8 <skill_dir>/scripts/fix_labels.py <target_dir> --dry-run  # 2. 预览将修改的内容
python -X utf8 <skill_dir>/scripts/fix_labels.py <target_dir>            # 3. 应用自动修复
node <skill_dir>/scripts/parse_check.mjs <target_dir>                   # 4. 复验:必须全绿

随后执行真实 Sphinx 构建,用 html_scan.py --scan errors 扫描生成 HTML 中的 Mermaid 错误文本(Syntax error in text / Parse error / mermaid version / Diagram error)、用 --scan cdn 复查在线依赖泄漏、用 --scan runtime 确认本地 runtime 资产已复制进 _static,最后启动临时 HTTP 服务做浏览器渲染与点击放大交互验证。

上下文检查之所以被定义为"必做",是因为它解决的是修复动作的目标环境问题:不确认文档栈就无法判断 sphinxcontrib-mermaid 是否参与渲染;不确认本地 runtime 就无法判断离线要求是否满足;不统计 fence 就无法核对"修复前后图数量守恒"。从源码结构看,context_check.py、html_scan.py 与 context-checks.md 对 runtime 文件名、CDN 域名、mermaid class 正则均保持一致(html_scan.py 注释明确写着"Keep in sync with context_check.py RUNTIME_FILES"),这也解释了 context-checks.md 中"以脚本输出为准"这条门禁规则的底气所在:规则文档、自动化脚本与构建后扫描器共享同一套判定标准,任何一处人工结论与之冲突,都应先怀疑人工核对过程。

实战建议:IB_Robot 文档维护中如何落地这五项检查

针对 IB_Robot 仓库的实际情况,落地本清单的推荐顺序是:

  1. 首次接触:先通读 SKILL.md 建立完整流程认知,再阅读本清单,避免把条件性规则误当无条件门禁。
  2. 每次修复前:直接运行 context_check.py --docs-root docs --build-dir docs/build/html,以脚本输出为证据基线;当前仓库 docs/ 下未发现 conf.py,脚本会提示 external Sphinx project 场景,此时第 1 项检查中"确认文档栈"的含义变为"确认迁移文档(docs/migration/doc_config.json)所对接的渲染流程"。
  3. 关注 WARNING 与交叉判断:若出现"含 mermaid 容器但无本地 runtime 引用"的 WARNING,需在报告中给出处置;若文档要求离线可用,任何 cdn.jsdelivr.net / unpkg.com 匹配都是失败。
  4. 浏览器验证不可省略:Sphinx 构建成功不代表 Mermaid 语法正确——Mermaid 的语法通常是在浏览器端才真正解析。上下文检查提供的是"环境正确性"证据,parse_check.mjs(与浏览器同解析器的 mermaid.parse())和浏览器渲染提供的是"图本身正确性"证据,两者互补。
  5. 保留证据链:最终报告必须包含 context_check.py 输出摘要、修改的文件、修复的语法类别(注明依据)、parse_check.mjs 的 N/N 通过数、runtime 文件清单(本地/CDN)、构建结果、浏览器验证统计与临时服务关闭确认——这正是 context-checks.md 门禁规则要求的"可审计、可复核"交付形态。
登录后查看全文
IB_Robot