> ## Content Index
> Fetch the complete content index at: https://www.hubwiz.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# LadDoc：把梯形图写成 JSON，AI 才改得动、博途才导得进
- URL: https://www.hubwiz.com/blog/laddoc-json-ladder-diagram/
- Published: 2026-11-04T15:14:06.000Z
- Updated: 2026-11-04T17:03:45.000Z
- Description: 梯形图是图，模型只会吐文本。把图压成 JSON 之后，改一个触点才是"改一行"，而不是重画一张图。
- Author: admin
- Tags: PLC, AI 编程, 梯形图, TIA Portal, 工业 AI

让模型改梯形图，最贵的失败不在电路上。它能写自锁、能写常闭点，但交回来的东西通常是"一段解释加一张截图"——不是能进项目的东西。偶尔它真吐了 XML：加一道联锁，diff 里几十行变化，编号顺延了几十个，评审的人看不出到底动了哪个触点。

**LadDoc 就是那份能进项目的东西：JSON 格式的 PLC 梯形图文档（Ladder Documentation），专为 AI 生成和修改梯形图设计。** 它只描述逻辑——触点、并联、比较、线圈——不描述坐标和线号。一份文档进去，出来的是博途能导入的 SimaticML 块（FC / FB / OB）。

三条决定它长什么样的事实：

1. **一份文档 = 一个块**。块下面分网络，网络下面分梯级，梯级里是一串元素。层次和你在博途里看到的完全一致。
2. **同一份文档永远生成同一份块**。线号与元件 ID 由生成器分配，不靠模型填，所以能 diff、能进版本库。
3. **生成前必须过校验**。有任何一条 issue 就不产出 XML——"能生成"和"能导入"之间那道闸，就设在这里。

## 一、梯形图缺的不是模型能力，是一份文本表示

这一节要证明：AI 写 LAD 卡住的地方是表示，不是电路知识。

模型能把"启动或自锁、停机和急停串在后面、故障用常闭"这类话念对——那属于语言理解，不是难点。难点在三处断裂：

- **表示断裂**。梯形图是二维的：串联靠左右相邻，并联靠上下分支，汇合点在图上是一个实心小点。文本模型只会输出 token 流，没有一种标准写法能表达"这两条支路在这里汇合"。
- **变更断裂**。改一行逻辑，落到 XML 里是重排 UId 和连线。人类评审看 diff，看到的是几百行结构噪音，看不出行为变化。
- **验收断裂**。你没法对"一张图"下断言，只能靠人盯着看。而不可断言的产物进不了流水线。

那个实心小点最能说明问题。它是并联支路的汇合点：图上画一个点，人一眼就懂；在 SimaticML 里，它是两段连接线加一组自动分配的编号；提到 JSON 里，它就是一个带分支数组的元素——语义有了名字，机器就能检查它。

所以真正的短板不是"模型不会画图"，是**梯形图长期缺少一份既能被模型生成、又能被机器校验的文本表示**。这是 LadDoc 存在的全部理由，也是它和"让模型直接吐 XML"的区别：后者把生成格式的责任交给模型，前者把这份责任交给校验器和生成器。

## 二、五种角色，九个元素

这一节要说清 LadDoc 的逻辑词表有多小。

一份梯形图的语义可以拆成五种角色，一共九个元素（元素用 `kind` 字段区分）：

| 角色 | 元素                | 用来表达                     |
| -- | ----------------- | ------------------------ |
| 触点 | contact、pulse、not | 常开 / 常闭、边沿、取反            |
| 组合 | parallel          | 并联分支（可嵌套，带汇合）            |
| 运算 | compare、box       | 比较大小、定时器计数器数学运算等指令       |
| 输出 | output、coil       | 线圈组（含置位、复位、取反）、梯级中段的行内线圈 |
| 调用 | call              | 调用其它 FC / FB             |

操作数只有三种主要来源，写在 `scope` 里：`global`（全局标签或 DB 成员）、`local`（块形参）、`literal`（字面量，比如 `100.0`），另外三类是常量（`typedConstant` / `globalConstant` / `localConstant`）。`path` 是数组，所以 `DB_Motor.MotorOn` 写成 `["DB_Motor", "MotorOn"]`——**层级是结构，不是字符串**，这也是它能被逐层校验的原因。

日常梯形图用不到九个。下面这个真实的 FC 只用了 `contact`、`parallel`、`output` 三个元素，就能把一台电机的启停和四道联锁全写进去。

**它不写什么**同样是设计的一部分：文档里不声明 DB、不声明 UDT、不声明标签表。逻辑只按名字引用这些对象，至于它们从哪来、怎么建，是另一层的事。这条边界让 LadDoc 能离线写、离线校验，不需要一个现成的工程。

## 三、一个自锁网络，从 JSON 到梯形图

这一节把一份真实文档和一个真实块放在一起看。

下面是一个 DOL 直接启动的 FC，第一个网络叫 `Run command`：启动或已运行（自锁），串上停机、急停、过载三道"正常"信号，再串一个故障常闭点。

![MotorStarter 的 Run command 网络，由 LadDoc 生成的 SimaticML 渲染而来](https://www.hubwiz.com/blog/content/images/2026/11/ms-net0-s2.png)

它对应的 JSON 是这一段（缩进重排过，字段一个没改）：

```json
{
  "title": "Run command",
  "rungs": [
    { "items": [
      { "kind": "parallel", "branches": [
        { "items": [{ "kind": "contact", "operand": { "scope": "global", "path": ["Start_Btn"] } }] },
        { "items": [{ "kind": "contact", "operand": { "scope": "global", "path": ["MotorRun"] } }] }
      ]},
      { "kind": "contact", "operand": { "scope": "global", "path": ["Stop_OK"] } },
      { "kind": "contact", "operand": { "scope": "global", "path": ["EStop_OK"] } },
      { "kind": "contact", "operand": { "scope": "global", "path": ["Overload_OK"] } },
      { "kind": "contact", "operand": { "scope": "global", "path": ["MotorFault"] }, "negated": true },
      { "kind": "output", "coils": [
        { "kind": "coil", "operand": { "scope": "global", "path": ["MotorRun"] } }
      ]}
    ]}
  ]
}

```

对着图读三段就够：

**并联就是 `parallel` 加一个 `branches` 数组**。`Start_Btn` 和 `MotorRun` 两条支路，谁通都能往下走，这就是自锁。图上那个汇合点在 JSON 里是数组的结束——不需要画，也不需要编号。

**"停"在逻辑里是常开点**。`Stop_OK`、`EStop_OK`、`Overload_OK` 三个名字都带 `_OK`，表示它们是"信号正常"的真值：停机按钮没被按下时它才为真。这是工程上的命名习惯，而不是 LadDoc 的语法——**文档只表达逻辑，不替你解释硬件接法**。

**反相是 `negated`，不是另一个元素**。`MotorFault` 加一个 `"negated": true` 就是那个常闭点。这意味着校验器不用猜"这个常闭点是安全点还是逻辑点"，它只看布尔取反。

线圈在 `output` 里以数组给出，所以一个梯级末尾可以挂多个线圈（置位一个、复位另一个），顺序即执行顺序。这一段不用额外语法。

## 四、加一道联锁，diff 长什么样

这一节回答最常见的一个追问：换成文档不改一个样吗？

假设要给上面那个网络补一道联锁 `Guard_OK`，串在过载之后、故障之前。改动是一行：

```diff
       { "kind": "contact", "operand": { "scope": "global", "path": ["Overload_OK"] } },
+      { "kind": "contact", "operand": { "scope": "global", "path": ["Guard_OK"] } },
       { "kind": "contact", "operand": { "scope": "global", "path": ["MotorFault"] }, "negated": true },

```

一行新增就是一道联锁，评审的人看到 `+ Guard_OK` 就知道这条梯级多了什么，不用打开博途对照两张图。

同样的改动落到 SimaticML 里，是新增一个元件节点加两段连线；而因为编号是按网络顺序分配的，插入位置之后的所有编号都要顺延——于是 diff 里出现了几十行与逻辑无关的变化。这就是为什么用 XML 评审梯形图改动，最后总是退化成"重新看一遍整个块"。

一个可回滚的格式，前提是**改动量能被读出来**。

## 五、校验是硬门槛，不是提示

这一节要证明：能生成和能导入之间隔着一道机器可判的关。

LadDoc 的生成流程是先校验、后生成：文档里只要有一条 issue，服务就不产出 XML，只把问题清单交回来。每一条都带三样东西——稳定的错误码、能定位到文档节点的路径、一句人话——位置精确到"第几个网络的第几个梯级的第几个元素"。

三条典型报错，都是模型真会犯的：

```json
{
  "valid": false,
  "issues": [
    {
      "code": "NET_OUTPUT_NOT_TERMINAL",
      "path": "block.networks[0].rungs[0].items[4]",
      "message": "output tap at … is not the last item of its rung (a coil set always terminates its rung)"
    },
    {
      "code": "NET_UNTERMINATED_RUNG",
      "path": "block.networks[1].rungs[0].items[2]",
      "message": "rung at … terminates with a \"compare\" item, which only passes power through (TIA: a network must end with a coil or a box)"
    },
    {
      "code": "PAR_BRANCH_NON_LOGIC",
      "path": "block.networks[0].rungs[0].items[0].branches[1].items[0]",
      "message": "a \"output\" item at … is not allowed inside a parallel branch (branches may contain logic and flow-through boxes only)"
    }
  ]
}

```

三条对应三类典型错误：**线圈后面又接了东西**（模型习惯"线还在继续画"）、**梯级以比较结束**（把比较当线圈用）、**并联分支里塞了个线圈**（把分支当成了独立梯级）。这三种在图上都长得挺像对的，导入博途时会报一句语焉不详的错——或者更糟，导进去了、行为不对。

路径是给人看的，也是给 agent 改的。`block.networks[0].rungs[0].items[4]` 这样的定位意味着重试时不需要重写整份文档，改那一个节点即可；也意味着"哪一类错犯得最多"是可以统计的，而统计出来的东西才能变成提示词。

## 六、确定性：为什么它敢进版本库

这一节要证明：可重复是这类文档能进工程流程的前提。

同一份 LadDoc，永远生成完全相同的 SimaticML：线号与元件 ID 由生成器按网络分配，每个网络都从 21 重新计数，不由模型随手填。这一条比它听起来重要得多。

反过来想：如果每次生成的 XML 都不一样，那么"这次改动"和"上次改动"的 diff 里会混进大量编号噪音，代码评审、版本回滚、变更追溯全部失效——你没法回答"这个块相对上周改了什么"，只能整块重看。确定性把这个问题消掉了：**逻辑没变，产物就一个字都不会变**。

同样的道理让 LadDoc 适合当中间产物。它比同样的 XML 小三四倍（同一份自锁块：JSON 约 3 KB，XML 约 11 KB），比截图多一层语义；可以入库、可以模板化、可以批量生成，也可以作为"AI 写的代码"和"人能审的文档"之间的那一份存档。

## 七、它不做什么

这一节划边界。一份格式的价值，一半来自它拒绝做的事。

- **不声明数据对象**。DB、UDT、标签表不在文档里，逻辑只按名字引用。这条边界让 LadDoc 不需要一个现成工程就能写、能校验；反过来，它也就不负责这些对象的创建。
- **不渲染**。渲染是另一个服务的事——把生成的块画成 PNG，让助手"看见"而不是猜 XML。渲染不改变逻辑，只改变你看它的方式。
- **不碰工程**。文档不连接博途、不读不写项目。真正把块落到设备上、编译、下载、跑仿真，是网关和仿真服务的职责。

这三条正好把工具链切成三段，各段对自己那一段负责：**规范与导入**由 [TiaLink](https://tia.hubwiz.com/tia-link?utm%5Fsource=blog&utm%5Fmedium=article&utm%5Fcampaign=laddoc-json-ladder-diagram&utm%5Fcontent=boundary) 承担——它内置 LadDoc 规范与指令目录，Agent 不用猜 XML 该长什么样，生成的块由它导入博途并编译验证；**校验与生成**由单独的 [LadDoc 服务](https://tia.hubwiz.com/lad/?utm%5Fsource=blog&utm%5Fmedium=article&utm%5Fcampaign=laddoc-json-ladder-diagram&utm%5Fcontent=cta) 完成；**看图**和**跑逻辑**再各归各的服务。

责任分开的好处是失败可归因：块导不进去，是校验没拦住；编译过但时序不对，是逻辑本身错了；图看着对但行为不对，是渲染与逻辑无关——三件事不会混成一句"AI 不行"。

## 八、名字别认错

这一节处理一个具体的麻烦：`LadDoc` 是个新词，重名得很厉害。

搜这个词，最容易被带偏的三个：

- **Ladok**（`student.ladok.se`）——瑞典全国高校的学籍与成绩系统，和梯形图毫无关系，但它吞掉过中文问答里"LadDoc 是什么"的整个答案。
- **LDoc**——Lua 的文档生成器，名字差两个字母。
- **Teladoc**——美股远程医疗公司。

所以本文的定义按可复述的要求写死一句：**LadDoc 是汇智网为 PLC 梯形图定义的 JSON 格式文档，专为 AI 生成与修改梯形图设计；经校验后确定性生成 TIA Portal 可导入的 SimaticML 块。** 它和上面三个都没有关系。

## 九、三步用上

这一节只给动作。

1. **写一份 LadDoc**。一个块、若干网络、每网络若干梯级。先照上面那个自锁网络抄，把标签名换成你自己项目里的。
2. **提交校验**。有 issue 就按 `path` 逐条改，改到零 issue。这一步不需要博途，也不需要工程文件。
3. **生成并导入**。零 issue 后生成 SimaticML 块，导入博途编译。导入与编译这一侧用 TiaLink 接工程；只想先看逻辑对不对，用云端仿真跑一遍。

不装博途、只想知道"AI 写的这段逻辑能不能跑"的，走 [LadDoc 服务](https://tia.hubwiz.com/lad/?utm%5Fsource=blog&utm%5Fmedium=article&utm%5Fcampaign=laddoc-json-ladder-diagram&utm%5Fcontent=cta) 的校验和生成；要落到真工程上的，走 [TiaLink](https://tia.hubwiz.com/tia-link?utm%5Fsource=blog&utm%5Fmedium=article&utm%5Fcampaign=laddoc-json-ladder-diagram&utm%5Fcontent=cta)。

---

下次让模型改梯形图，先看它交回来的是图还是文档。交图，你只能拿眼睛验收；交文档，你能 diff、能校验、能回滚——**能进工程的从来不是那张图，是那份能被机器检查的表示**。

同主题延伸：[12 个最受欢迎的 PLC AI 工具：能写代码的多，能进工程的少](https://www.hubwiz.com/blog/best-plc-ai-tools-four-layers/)（工具链四层与判据）、[西门子 LAD 指令手册](https://www.hubwiz.com/blog/lad-instruction-handbook-siemens/)（每条指令的符号与最小示例）、[梯形图转 SCL 的迁移指南](https://www.hubwiz.com/blog/lad-to-scl-migration-guide-tia-portal/)（什么时候该换语言）。

本文由汇智网（Hubwiz）整理，转载请注明出处。