1. 为什么要做这个)
PLC工程师写SCL代码有个很烦的事——语法规矩特别多。等于号在C语言里是==,在SCL里是=。赋值在别处用=,SCL非得用:=。IF后面忘了END_IF,CASE漏了ELSE,编译器只告诉你错了,不告诉你哪错,更不会帮你改。一个工程师来回编译、报错、猜、改能折腾很长时间。后来发现大模型也能写SCL,但写出来的更离谱——&&、!=这些C语言习惯全带进来,true/false小写不认,IF/CASE各种缺胳膊少腿。思路很简单:既然LLM犯的错就那么几类,每类长什么样我们也知道,写一套固定规则帮它改就行了。不用重新训练模型,写死规则,来一个修一个,结果永远确定。
2. 能干什么
拆成四块:第一,让大模型写代码。用大白话描述控制需求,背后接了好几个大模型可以换着用。第二,帮它补骨架。LLM经常忘了关IF、关CASE,用一个叫下推自动机的方法跟踪成对关键字,哪缺了自动在正确位置补上。本质是聪明的括号匹配,但能处理嵌套——IF里套CASE,正则搞不定,必须用栈。第三,帮它改小毛病。&&改AND,!=改<>,true改TRUE,一共11种常见错误,8种自动改,3种标记提醒。改等于号最危险——在IF条件里它是合法比较符不能瞎改,设了三层保护确保不破坏逻辑。第四,浏览器打开就能用,代码直接复制到TIA Portal编译。
3. 怎么用
三步:网页上用大白话写控制逻辑,选PLC型号。点生成等几秒,大模型出初稿。工具自动修一遍语法错误,拷走拿去编译。想再改可以手动编辑或者对话精修。从需求到能编译的代码,快的就几分钟。
1. 整体架构和设计思路
整个系统分三层。最底层是大模型调度层,用TypeScript写了一个统一的dispatcher,同时接了DeepSeek、Gemini、Qwen三个模型,哪个出活稳定用哪个,支持流式输出给前端实时展示。中间层是核心纠错管线——也是纯TypeScript实现,不依赖任何AI推理。L1用栈结构做关键字配对校验,19种结构关键字的状态转移表驱动;L2用规则引擎做词法级修复,11类错误按一对一映射去匹配替换。两层都是纯函数,同样的输入永远出同样的结果。最上面是React前端,Vite构建,Tailwind CSS做界面,Framer Motion做动效,浏览器里直接写需求看代码。后端Express扛API请求,natapp隧道公网暴露,前端SSE长连接接收生成进度。
2. 我负责的模块和结果
我主要做了核心纠错管线——L1栈式校验和L2规则引擎,还有整个后端的API层和SSE流式管道。L1这边,定义了19种结构关键字的栈匹配规则表,支持IF/CASE/FOR/WHILE/REPEAT五类控制流嵌套,以及FUNCTION_BLOCK、VAR区段等程序单元的配对校验。在47个工业场景样本上跑下来,结构错误全检出,缺失关键字自动补全位置准确。L2规则引擎覆盖了11类高频错误,其中8类自动修复准确率100%——因为都是确定性映射,不存在误判。3类告警(变量活性、定时器校验、安全模式)在47个样本中触发了[待实测]次。赋值修复的三重约束设计保证了不改变任何布尔表达式真值,零副作用。后端API层撑住了并发生成、流式输出、会话管理这些需求,单次生成延迟控制在LLM响应时间+后处理50ms以内。
3. 遇到的难点和解决方案
最大的坑是等于号的替换。SCL里等于号有三个身份:赋值应该用:=(motor = TRUE → motor := TRUE),比较应该用=(IF x == 1 → IF x = 1),连续赋值a:=b:=c里已经是:=。一刀切替换必定引入逻辑错误。最后的方案是三重约束:先判断当前行是不是条件行(IF/ELSIF/WHILE/UNTIL开头),非条件行才把=改:=,条件行只把==改=,已经是:=的不管。这样保证所有布尔表达式的真值不变。第二个坑是管线顺序——L1补全缺失关键字会改变行号偏移,如果L2先跑了再补L1,分号插到错行。结论是强制L1优先,且两层之间不做任何缓存行号的跨层引用。第三个是SSE超时,LLM调用有时候很慢,浏览器端超时断开。加了TCP Keep-Alive和10秒心跳,隧道不断,连接不断。