上个月有个兄弟问我:AI写的PLC代码能不能用?我说你先别管AI写的,你先试试让AI读读你写的。
为啥这么说?因为过去两个月,我拿大模型干了一件之前没人写的事——用ChatGPT和Claude做PLC程序的代码审查(Code Review)。不是让AI写代码,是让AI当那个挑刺的。
故事的起因
去年底做了一套涂布机的控制系统,用的是西门子S7-1500,程序量大概三万步出头,主要是SCL,混了一些LAD。程序写完自己也review了两遍,又让同事过了一遍,觉得没啥问题了才下装的。
结果现场调试第三天,半夜一点,涂布头莫名其妙停了。查了俩小时——一个计时器的DB块地址写串了,导致两个互锁条件同时满足了。我坐在配电柜前面,拿手机拍了张程序截图,顺手扔给AI看了看,问了一句”这段有问题吗”。
AI回了我四行分析,最后一行说:这个计时器的PT输入端引用的是DB100.DBW4,但DB100的声明里DBW4是一个WORD变量,而PT需要的是TIME类型,如果赋值时没有做类型转换,可能导致计时器行为不可预测。
我翻了程序一看——好家伙,还真是。底层一个函数块里,给PT赋值的语句是”TimerDB.PT := DataBlock.PresetValue”,PresetValue声明成WORD,但PT是TIME。SCL隐式转换把FFFF(WORD最大值65535)转成了Time的65535ms。现场参数设的是15秒,实际上计时器一直按65秒跑。涂布头该停的时候没停,不该停的时候停了。
那天开始,我就认真搞起了AI Code Review。
我是怎么干的
说白了一点都不高大上。就是:
- 把SCL程序段(函数块、函数、DB块声明)复制出来
- 按功能模块拆成10-20段的逻辑单元
- 扔给AI,提示词大概这样:”你是一个资深西门子PLC工程师,请审查以下SCL代码,找出潜在的逻辑错误、数据类型不匹配、计时器溢出风险、数组越界、未初始化变量、死锁条件等问题。请逐行分析。”
- 收到分析结果后,逐条验证真伪
花了两个周末,把整个项目三万多步的程序分模块审了一遍。两个大模型(GPT-4o和Claude 3.5 Sonnet)各走一轮。
真实挖出来的bug清单
总数:9个真实bug,3个误报。误报率不算高,但也不算低——三分之一是瞎说的,这就是为什么你不能直接信AI,必须自己验证。
真bug 1 — 类型隐式转换(上面那个案例)
WORD→TIME。AI发现的,现场参数设15s实际跑65s。如果不改,涂布头动作时序全乱,估计要烧一卷几百米的涂布膜——一卷几万块。
真bug 2 — 计时器溢出
一个TP定时器的PT设的是T#3600S(1小时),但调用的周期是每100ms一次。当一个计时器累计运行超过32767秒时,S7-1500的IEC Timer内部计数器溢出,计时器会意外复位。AI指出:这个计时器在连续运行9小时后会溢出。我还真没想过这事。解决方案是改用IEC_Time库里的LTPTime,支持更大范围。
真bug 3 — 数组越界风险
一个数组定义的是ARRAY[0..19] OF INT,但有个FOR循环用的是FOR i := 1 TO 20。AI说:当i=20时,访问Array[20]超出数组上限19,SCL在运行时不会报错,但会读到相邻DB块的数据。这个bug现场还没暴露,因为实际生产中那个循环最多跑18次——但万一哪天配方变了?想想都后怕。
真bug 4 — 死条件(Always True)
一个IF语句的条件是”IF #TempVar >= 100 AND #TempVar <= 100″。等于号两边写反了。第二段应该是”<= 100″但实际写作了”>= 100″。所以这个条件永远成立。AI一眼就看出来了。我自己review了三遍都没发现——因为太”自然”了,大脑会自动补全成正确的逻辑。
真bug 5 — 未初始化的变量
一个静态变量#Counter在函数块里声明了但没有初始值。第一次调用时如果R_TRIG没触发,#Counter是垃圾值。AI指出后补了个:= 0。
真bug 6-9 — 剩下的四个包括:CASE语句缺少ELSE分支(万一传了未定义值程序会卡住)、一个UDT里两个BOOL变量用了同一个地址(复制粘贴忘了改)、定时器DB块没有设置Retain导致断电数据丢失、以及一个死循环风险(WHILE循环退出条件依赖的外部变量永远不会变化)。
两个模型谁更强?
我做了个简单对比,各有千秋。Claude在逻辑分析上略胜一筹,GPT在快速覆盖面上好一些。但两个都有盲区——它们都不太理解S7的OB组织块和执行优先级,所以跨OB的竞态条件一个都没发现。
谨慎三件事
第一,AI看不懂梯形图。至少目前主流大模型对LAD这种图形化语言的解析能力很差。SCL还行,LAD基本不行。所以如果你全是梯形图写的程序,这招没用。
第二,AI不会发现”少写了什么”——它只能分析你给了它什么。你漏了一段逻辑,它不知道。就像审稿人能挑错字但发现不了你该写的那段话没写一样。
第三,不是所有AI说的都对。那3个误报里有个说”这个MOVE指令源和目标大小不一致会丢数据”——我查了西门子手册,S7-1500的MOVE会自动处理长度匹配,不存在这个问题。你不验证就改,反而会引入新bug。
总结一下
AI写代码目前还不太靠谱(之前那兄弟问的就是这个),但AI审代码——你还真别看不起它。它有个人类不太具备的优势:不累。一个3000行的程序,人看两个小时眼睛就花了,AI不会。它每行都能仔细看,不会因为”这行看起来没问题”就跳过去。
我现在养成了个习惯:写完程序,先让AI审一遍,再自己审一遍,最后同事再过一遍。三层把关,效果好很多。特别是那些隐式类型转换、数组越界、变量未初始化这类低级但致命的错误,AI真的比人可靠。
你们有人试过用AI审PLC代码吗?审出了什么奇葩bug?评论区聊聊。