AI生成PLC梯形图:从自然语言到JSON中间表示的落地实践
最近大半年陆续有做工控的朋友问我同一个问题AI到底能不能直接画梯形图在车间里拿手机说一句电机启停带自锁停止按钮用常闭再加5秒延时点亮指示灯然后导出一段能下到PLC里跑的LD程序说实话我一开始也觉得这多半是标题党。但当我真正把大语言模型的输出方式和梯形图Ladder Diagram, LD的表示方法放到一起研究之后发现这件事不仅可行而且已经有一条相当清晰的落地路径——只是它和你想象的让AI直接画图不太一样。这篇文章我想聊的是AI生成PLC梯形图的工程实现问题先说清楚梯形图的逻辑本质到底难在哪里再对比三条技术路线的取舍然后把我测试下来最稳的方案——大模型输出结构化JSON中间表示再通过渲染器和校验器把它变成可仿真、可导入的梯形图程序——完整拆给你看。文章里会包含数据结构定义、Prompt写法、渲染思路、校验逻辑以及三批真实测试里翻车和补救的记录。适合正在做AI工控方向研究的工程师也适合想给自己工作流加一个AI画梯图能力的自动化从业者。1. 梯形图的图形本质决定了AI生成的切入点1.1 梯形图到底是个什么东西梯形图是从继电器控制电路直接演化过来的图形化编程语言属于IEC 61131-3标准定义的几种PLC编程语言之一。它长得像电路图最左边是电源母线最右边是返回母线中间是一级一级的梯级Rung。每一级梯级上串联、并联各种元素从左到右分别是输入条件最右侧是输出线圈。核心元素就四类常开触点正常状态下不导通条件满足对应位为ON时导通。画法就是两条竖线记作-| |-。常闭触点正常状态下导通条件满足时断开。画法在竖线上加一条斜杠记作-|/|-。输出线圈类似继电器的线圈左边逻辑导通它就吸合对应位写1。画法是两个圆括号-( )-。功能块TON定时器、CTU计数器、比较指令、运算指令这些画成方框有输入端、输出端。执行语义也很关键PLC运行时从第一条梯级开始逐级从上往下扫描执行每一级内部从左到右计算逻辑导通状态然后把结果写到输出线圈对应的映像区。这个扫描周期的概念后面讲校验的时候还要用到。1.2 文本模型与图形之间的鸿沟为什么不能直接出图大语言模型本质上是在预测下一个文本token它能老老实实输出一大段文字也能输出SVG、HTML这种带坐标的文本图形但问题在于直接让LLM生成一张梯形图图片布局和走线完全不可控逻辑对不对也没法校验。SVG虽然能画但让模型同时兼顾逻辑正确和坐标美观十次有八次要出幺蛾子。我后来想明白一个关键点梯形图的信息本质不是图形而是图形背后那棵逻辑树。一个梯级不管画得多复杂最终表达的不过是这样一种结构若干条件通过串联AND和并联OR组合最后驱动一个输出或者调用一个功能块。图形只是这棵逻辑树的视觉表达形式而已。既然如此AI真正应该生成的就不是图片而是这棵逻辑树的结构化文本描述。谁能让模型稳定输出逻辑树谁就掌握了AI生成梯形图的钥匙。这就是我后续所有方案的核心出发点。2. 三条实现路线我为什么选了JSON中间表示想清楚生成逻辑树而不是生成图片之后剩下的问题就是用什么载体让大模型输出这棵逻辑树我前前后后试过三种路线从结果看差异非常大。2.1 路线一让大模型直接输出PLCopen XMLPLCopen XML是PLCopen组织定义的开放交换格式CODESYS、Beremiz、OpenPLC这些环境都支持导入导出。理论上最理想模型直接生成XML导入IDE就能用少写一套渲染器。实际测试下来痛苦至极。一个只有三个串联元素的梯级在PLCopen XML里就是几十行嵌套标签包含坐标、连线、连接器ID这些图形信息。大模型生成这种长XML时标签闭合、ID引用、坐标一致性都容易出错。我自己测了大概二十次能一次性通过导入校验的不到三分之一。而且XML里大量图形坐标信息对LLM来说是纯噪音输出越长错误率越高。2.2 路线二先让AI生成ST再转LD结构化文本ST是文本语言大模型写ST非常顺手——if、and、or、ton这些都很像通用编程语言。思路是先让AI写ST再用转换工具把ST翻译成LD。这个路线卡在表达能力不对等上。ST有IF/CASE/FOR这类结构化控制语句有复杂表达式和函数调用而LD本质上只有三种基本结构串联、并联、功能块调用。ST里一段CASE状态机逻辑转到LD会膨胀成一大片set/reset线圈和比较触点转换器非常难写。我见过一些商业工具做了ST转LD面对简单逻辑还行碰到状态机、数组遍历这些立刻投降。而且ST本身品牌方言严重——西门子的ST和CODESYS的ST写法有不少差异——LLM很难记住这些细节。2.3 路线三用JSON中间表示这是我现在的主力方案我把梯形图的逻辑树定义成一个JSON Schema让大模型只输出JSON——只要JSON合法就拿到了一棵完整的逻辑树接下来渲染成SVG给人看、导出成PLCopen XML给仿真器跑或者映射成ST给真机用都是确定性代码的事。选JSON有三个理由LLM对JSON的生成能力是所有结构化格式里最强的配合Schema约束后极少出现结构错误树形嵌套和LD的逻辑树天然同构一个series节点对应串联一个parallel节点对应并联不需要转换JSON可以脱离图形坐标独立存在渲染、校验、转换各环节解耦每个环节都能单独测试。三条路线对比放在这里路线模型生成难度逻辑校验难度生态通用性我的结论直接出PLCopen XML高标签嵌套坐标信息中强CODESYS等可导入放弃出错率太高ST转LD低ST好生成中中品牌方言差异简单场景可玩复杂逻辑断裂JSON中间表示低JSON最稳高树形结构好分析高可多端转换主力方案推荐3. 从需求描述到JSON数据结构与提示词的工程细节3.1 一个够用的数据模型我的JSON模型设计得很克制节点类型就五种contact触点、coil线圈、series串联组、parallel并联组、fb功能块。整个JSON是一棵树根节点就是一个梯级电路。看一个最典型的例子——电机启停自锁电路。需求是按下启动按钮I0.0电机Q0.0启动并自锁按下停止按钮I0.1电机停止我把这段逻辑翻译成JSON中间表示就是这样{ programName: MotorCtrl, rungs: [ { rungId: 1, comment: 电机启停自锁, circuit: { nodeType: series, children: [ { nodeType: parallel, children: [ {nodeType: contact, operand: I0.0, negated: false, comment: 启动按钮}, {nodeType: contact, operand: Q0.0, negated: false, comment: 自锁触点} ] }, {nodeType: contact, operand: I0.1, negated: true, comment: 停止按钮}, {nodeType: coil, operand: Q0.0, comment: 电机接触器} ] } } ] }仔细看这棵树最外层是series表示这是一串从左到右串联的条件第一个child是parallel里面并联了启动按钮和自锁触点这就是梯形图里的那根竖线分支第二个child是常闭的停止按钮最后是输出线圈。整个树结构跟梯形图画出来是一一对应的没有任何信息丢失。带定时器的场景再加一种功能块节点。比如电机运行5秒后指示灯Q0.1点亮中间表示长这样{ rungId: 2, comment: 运行5秒后点亮运行指示灯, circuit: { nodeType: series, children: [ {nodeType: contact, operand: Q0.0, negated: false}, { nodeType: fb, type: TON, instance: TON_MotorRun, inputs: {IN: Q0.0, PT: 5000}, outputs: {Q: Q0.1} } ] } }TON的IN接电机运行状态PT是5秒对应的5000毫秒定时器输出Q直接驱动指示灯线圈。这样功能块和触点、线圈在同一个电路树里统一了。这里有一个很重要的设计决策JSON里保存的是符号名比如Start_Btn而不是物理地址比如I0.0。物理地址映射放到单独的符号表里。这样一套JSON逻辑可以同时渲染成西门子风格I0.0/Q0.0、三菱风格X0/Y0或者CODESYS风格%IX0.0的梯形图换品牌不换逻辑。3.2 提示词设计把隐性的PLC常识写进规则数据模型定好之后Prompt就是整个管线里最关键的环节。我是踩了不少坑才总结出现在这版提示词的。梯形图有很多写了没人说的隐性规则大模型不通过提示词显式约束几乎必犯。我目前用的System Prompt核心规则就这几条你是资深PLC工程师。将用户的中文控制要求转换为严格的JSON结构遵循给定Schema。 硬性规则 1. 输入地址用I前缀输出用Q前缀中间继电器用M前缀 2. 所有时间参数单位必须为毫秒ms例如5秒写5000 3. 中文描述中的停止/急停/复位按钮默认使用常闭触点negated: true且必须串联在主回路中 4. 描述电机、泵、阀等需要保持状态的执行机构时必须设计自锁回路输出线圈的触点并联在启动条件旁 5. 当两个设备动作相反正转/反转、上升/下降时必须互相串联对方的常闭触点实现互锁 6. 只输出JSON不要输出任何解释、注释或Markdown代码块标记。几条规则背后都有血泪教训我在第五部分会展开讲。规则1是地址体系规则2是单位问题规则3和4和5是梯形图逻辑的行业共识——这些对老工程师来说是肌肉记忆对模型来说却是最容易丢的隐性知识最后一条是为了省掉解析步骤直接拿干净的JSON。另外每次对话只给一个任务少样本示例给2到3个就够给太多反而会让模型学会照着样子硬套而不是理解后生成。我实际测试下来一个电机自锁的示例JSON加上一个定时器示例JSON生成效果就非常稳定了。3.3 解析与后处理大模型输出的JSON不一定合法模型再强偶尔也会输出莫名奇妙的JSON字段名拼错、多了一层花括号、把negated拼成negate、注释和JSON混在一起。所以我在解析层做了三层兜底先用正则把代码块围栏和前后解释文字剥掉用Python的json.loads解析失败就尝试json.loads配合简单的括号修复比如删除最后一个多余的逗号再用Pydantic做严格Schema校验字段类型不对、缺字段直接打回重试。最后这道校验最关键。我给每个节点类型都写了Pydantic模型fb节点强制校验instance字段在同一个程序内唯一coil节点不允许同一个operand出现在多个梯级的输出位置。这些在后处理阶段就过滤掉了不会流到渲染阶段才暴露。4. 从JSON到可仿真梯形图渲染器、校验器与仿真闭环4.1 渲染器坐标计算与图形绘制拿到合法的JSON逻辑树之后要做的是把它画成人能看的梯形图。这一步我用SVG输出好处是矢量图缩放清晰、可以直接嵌入网页或导出PNG。渲染器最核心的部分是递归布局计算。简单说就是先算出每个子树占多大宽高再根据布局信息给每个元素分配坐标。算法思路是这样series节点子节点从左到右排列总宽度等于所有子节点宽度之和加间隔高度取子节点最大高度parallel节点子节点从上到下排列总高度等于所有子节点高度之和加间隔宽度取子节点最大宽度并预留竖线连接的横向空间触点、线圈、功能块这些叶子节点宽度固定比如触点60像素、功能块120像素高度固定40像素。布局算完之后画起来就简单了最左侧画一条竖直母线所有梯级的左端都从母线出发触点画两条竖线常闭就在斜杠上加一条直线线圈画一对圆括号功能块画矩形输入引脚接到左边的逻辑链上输出引脚引到线圈或下一级。我甚至把渲染器做成了两个输出模式SVG预览模式给工程师看逻辑对不对PLCopen XML导出模式给仿真器跑。渲染逻辑共用同一棵逻辑树只是输出目标不同。4.2 校验器布尔逻辑仿真与静态检查校验器是我认为整个方案里比渲染更重要的环节。因为AI生成的代码逻辑正确性必须靠程序验证不能靠肉眼。静态检查项包括重复输出同一个线圈在多个梯级被赋值直接报错未声明地址触点和线圈里出现的操作数不在符号表里报错功能块实例重名同一个TON/CTU实例名出现两次报错常开常闭语义检查比如停止对应的操作数必须是常闭如果是常开就告警。逻辑仿真部分我写了一个极简的布尔电路解释器直接对JSON树求值def evaluate(node, io_values, state_values): t node[nodeType] if t contact: bit state_values.get(node[operand], io_values.get(node[operand], False)) return bit if not node.get(negated) else not bit if t series: return all(evaluate(c, io_values, state_values) for c in node[children]) if t parallel: return any(evaluate(c, io_values, state_values) for c in node[children]) if t fb: return evaluate_fb(node, io_values, state_values) return False这个求值器配合输入状态表就能把所有输入组合跑一遍生成真值表。比如电机自锁电路我输入I0.01瞬间检查Q0.0是否置1然后I0.00检查Q0.0是否保持1再I0.11检查Q0.0是否变成0。三组断言全过这梯级才算通过仿真。注意一个细节PLC扫描是离散的上一轮扫描的输出值会作为下一轮扫描的输入条件这就是自锁的物理基础。所以仿真时我按扫描周期迭代执行for i in range(scan_count): for rung in program[rungs]: out_value evaluate(rung[circuit], input_image, output_image) output_image[rung[output_operand]] out_value输出映像区在每轮迭代末尾统一更新模拟真实PLC的IO刷新机制。这种仿真虽然简单但足够发现绝大多数逻辑错误。4.3 导出与仿真用OpenPLC把闭环走通校验通过的JSON我会导出成PLCopen XML然后导入OpenPLC的编辑器做最终验证。OpenPLC是开源PLC运行时环境它的图形式LD编辑器基于Beremiz原生支持PLCopen XML导入。整个流程是LLM生成JSON → 2. 渲染器出SVG人工预览 → 3. 校验器做静态检查和真值表仿真 → 4. 导出PLCopen XML → 5. OpenPLC导入并软仿真运行 → 6. 人工确认后映射到真实PLC地址。这套闭环最大的价值是AI输出的东西在没上真机之前就被验证了好几轮。我在第五部分会讲这个验证前置的设计帮我拦截了至少一半的翻车现场。5. 三批实测记录AI画梯图最容易在哪里翻车聊完方案说点真实的。我从春节后开始做压测把常见的工控逻辑场景分了三批喂给模型每批都记录了典型的翻车点。这些坑你有心做这个方向的话大概率也会踩到。5.1 第一批电机启停——自锁触点丢了我第一个测试用例就是最经典的电机启停。需求原话按下启动按钮I0.0电机Q0.0启动按下停止按钮I0.1电机停止。模型第一次输出的逻辑是I0.0串联常闭I0.1驱动Q0.0——逻辑树本身画得完全正确串联、常闭都没错但没有自锁触点。也就是说松开启动按钮的瞬间Q0.0就断电了和实际电机控制需求完全不符。根因在于中文的启动在继电器控制语境里隐含了点动变自锁的需求这是行业常识但模型的预训练知识里这个常识权重不够高。对策就是我在提示词里加的规则4描述电机、泵、阀这类执行机构时强制设计自锁回路。加上这条之后连续测试二十次自锁触点全部出现。顺带补一个更隐蔽的变体如果需求是按下I0.0点动运行就必须去掉自锁。所以我在提示词里还加了一句只有点动关键字出现时才禁止自锁。这两个规则放一起模型基本不会搞混。5.2 第二批延时与闪烁——定时器的单位、实例名、类型选择第二批我测了定时场景坑密集很多。第一个坑是单位。延时5秒模型直接给了PT: 5没按毫秒换算成5000。这个靠提示词规则2解决同时后处理里我加了一个单位修正器凡是看到PT/ET字段检查数值是否小于10小于则自动按秒处理乘1000——当然这有点粗暴实际产品里还是靠规则人工确认稳。第二个坑是实例名。同一个程序里出现三个TON模型给其中两个起了相同的实例名TON_Time。这会导致PLC编译报错。对策是后处理阶段自动编号TON_1、TON_2、TON_3。第三个坑是关于TOF和TON的选择。按钮松开后延时3秒关灯这种需求模型有时候会选TON有时候选TOF逻辑上完全相反。我后来在提示词里加了一条需求描述的是动作后保持一段时间再复位用TON描述的是信号消失后延迟复位用TOF。模型有了这个判断标准后准确率高了很多。5.3 第三批正反转互锁与按钮抖动——深层语义问题第三批我上了稍微复杂的场景正转按钮I0.0启动正转接触器Q0.0反转按钮I0.1启动反转接触器Q0.1正反转必须互锁。模型输出了两个互锁触点——Q0.0的常闭串在Q0.1回路里Q0.1的常闭串在Q0.0回路里——结构完全正确。但仔细检查发现一个更隐性问题正转切换到反转时如果操作员同时按了两个按钮或者按钮有机械抖动可能导致两个接触器短暂同时导通。虽然互锁逻辑在稳态上是对的但缺少切换延时或边沿触发这类处理在实际设备上还是存在隐患。这类深层安全性问题单纯靠提示词很难彻底解决因为模型不知道现场工况。我的处理方式是把AI生成定位成高速草稿人必须做工程审查。尤其是急停回路、安全门锁、光栅信号这类安全相关逻辑我从一开始就明确绝不直接采用AI生成的版本最多让它推导参考最终接线和程序必须由有资质的人确认。这不是保守是底线。5.4 我对AI生成梯形图现状的客观判断压测做下来我的总体结论是AI生成梯形图在结构化逻辑转换层面已经实用——你给我一段逻辑清晰、设备不多的控制需求它能画出一份合格率超过80%的草稿但还远没到替代PLC工程师的程度。它在隐性规则自锁、互锁、单位、深层语义安全性、时序抖动、状态机和厂家特定方言上仍然需要人类兜底。所以我现在的工作流很明确AI负责把自然语言快速变成一版逻辑树草稿程序负责把草稿校验到物理上可仿真工程师负责最终审查与安全确认。每一层都做自己最擅长的事。6. 如果你也想搭一套我的建议清单6.1 模型选型约束输出比模型大小更重要很多人问我要上多大的模型才能干这个活。我的实测感受是这个任务的核心不是模型智商而是输出约束和规则记忆。用API类的大模型GPT-4级别或者国产的DeepSeek、Qwen系列配合严格的System Prompt生成质量完全够用如果你对数据隐私有要求本地部署一个7B到14B的量化模型针对JSON生成任务做几十条LoRA微调效果也能达到可用的水平。我甚至测试过一些轻量模型只要提示词里的规则写得足够死、少样本示例给得足够准它能输出的JSON在结构上几乎不出错——真正拉开差距的是模型对PLC隐性规则的记忆深度这时候模型越大越稳。我的建议是先拿大模型API把完整管线跑通确认业务模式成立再考虑本地化部署和微调。顺序不要反否则你会同时面对模型调优和管线设计两个难题。6.2 值得反向做的一件事把已有梯形图翻译成自然语言做正向生成的同时我还发现一个价值更大的反向场景把已有的梯形图程序转成自然语言说明文档用于设备维护和交接。实现方式很简单把PLC梯形图程序的结构化格式比如从OpenPLC或CODESYS导出的XML解析成我上面定义的JSON树再让大模型把树翻译成中文描述。比如看到电机自锁那个JSON就生成该梯级实现电机启停自锁控制启动按钮与电机接触器触点并联实现自锁停止按钮为常闭串联实现失电停机。这在老产线改造时特别好用老师傅看一眼程序能讲出来但没人有时间写文档——现在这个事AI能干。6.3 后续扩展思路最后给想深入做的朋友几个方向逻辑模式库把自锁、互锁、点动、延时、顺序启动、星三角切换这些高频模式做成模板让模型在模板上做组合而不是从零推理准确率会有质的提升RAG注入厂家手册把西门子、三菱、汇川这些品牌的手册喂给检索增强生成管线让模型在生成前先查清楚当前目标型号的地址规则和指令集解决品牌方言问题IDE插件化把这条管线封装成TIA Portal、GX Works或者CODESYS的扩展工程师在IDE里选中一段注释右键就生成对应逻辑——这是我认为最贴近实际使用场景的形态。我个人走了大半年弯路才意识到AI生成梯形图这件事最大的瓶颈从来不是画图而是把工程师脑子里的隐性规则显性化。你让模型输出一百遍JSON都不如在提示词里写清楚停止按钮默认常闭这一条来得有效。如果你也打算做类似的东西我劝你先从自己最熟的几个逻辑模式开始把规则和校验做扎实再往外扩——这条路走得通而且走起来比想象中更有意思。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →