TiaLink
把 TIA Portal 接到你的智能体:导入、编译、读回核对、PLCSIM 仿真。本地运行,工程数据不出厂。
打开 TiaLink只读审查一套 18 网络的 LAD+SCL 程序:按 7 类清单找缺陷,分 P0/P1/P2,每条带块/网络证据和复现方法;工程零改动。
学完你能:能只读审查一套 LAD+SCL 程序,产出带证据、分严重级别、可复现的《程序审查报告》,并分清编译能查出、仿真能验证、只能人工确认的三类问题。
前面几课把「敢改」拆开了:读懂老工程(L1)→ 知道改动会波及谁(L2)→ 写块到编译 0/0(L3)→ 让程序在虚拟 PLC 里跑起来(L4)。这一课补上投运前最后一道:这套程序哪里会出事,先修哪条。
程序审查(code review)不是让 AI 说「代码写得怎么样」,而是让它在只读前提下,按一张固定清单找出有失败场景的缺陷,并产出能复核的《程序审查报告》。风格偏好、命名习惯、个人写法,不进入「发现」;没有失败场景的候选,只能进「误报/已排除」或「待确认」。
本课用示例库里的 分拣箱(Factory IO) 当靶子:Main 的 18 个网络 + 1 个 SCL 通信 FC(1 个网络),31 个标签,5 个系统实例 DB。这套开源示例保留了原工程的真实缺陷,正好用来练审查。本次实测找到:
Feed Conveyor 被 3 个网络同时驱动,没箱子也在转,停止不保持;Emitter 只有一个扫描周期(10ms)的脉冲,执行器可能来不及动作;最后一条尤其重要:AI 审查最大的风险不是漏看,而是把「看起来像问题」当成「已确认的缺陷」。 本课会专门做一遍反证,把误报挡在报告外面。
先别看示例页的「常见问题」。本课是盲审:先按接线审一遍,再对照示例页。审完你会发现,示例页原来的右分支描述也不准确——这正是审查要解决的问题(本课审完后已修正示例页,下面保留原来的错误说法作对照)。
口径:AI 是辅助审查,结论必须人工复核;本课不是安全认证,急停/安全功能必须由有资质的人确认。审查阶段工程零改动。
输出 → 写点 表、逐块编译消息、硬件地址;http://localhost:8080/mcp;Main,并新增系统实例 DB;dirty 状态当基线;允许逐块编译,但不保存;在博途那台机器上启动 TiaLink、打开空白工程。页首状态条会自动检测;然后在客户端里加一个 Streamable HTTP MCP 服务:
先在本页顶部点「设置」填一次地址(存在本机,示例库页面也用同一个地址),下面的 URL 会跟着更新,点「复制」贴进客户端配置:
{
"mcpServers": {
"tialink": {
"type": "http",
"url": "http://localhost:8080/mcp",
"headers": { "Authorization": "Bearer <你的 TiaLink API Token>" }
}
}
}看到什么:客户端列出 TiaLink 的工具(名字以 tialink_ 开头,覆盖健康检查、读工程、导出、编译、保存等)。工具数量随版本变化,不必对数字。
在一个空工程里新建 CPU(本课实测用 CPU 1215C DC/DC/DC,S7-1200),按示例的导入顺序导入。没有 1215C 也可以用你现有的 S7-1200/1500 沙盒;本课的逻辑结论与 CPU 型号无关,硬件 I/O 警告会随配置不同。
Default tag table(31 个标签);MHJ-PLC-Lab-Function-S71200;Main(OB1,18 个网络)。导入方式:在示例页点「导入到 TIA」(推荐),或用 TiaLink 的 tialink_import 按上面的顺序逐个导入。推荐用示例页按钮:agent 不需要自己找 XML,也不会去猜文件路径。
导入完成后,把下面这段发给 agent,让它做基线盘点,先不要开始审查:
只做基线盘点,不要审查、不要修改任何逻辑、不要保存工程;可以逐块编译以获取编译结果。
对象:当前工程里的 sorting-boxes 示例(Main + MHJ-PLC-Lab-Function-S71200 + 5 个系统实例 DB + Default tag table)。
请报告:
1. 工程名、设备名、CPU 型号/订货号、软件名;
2. 块清单(块名/类型/编号/语言)、Main 的网络数、点表标签数、系统实例 DB 数;
3. 逐块编译结果:每个对象的错误数/警告数 + 消息原文;
4. 导入前/后的 dirty 状态(如果知道;不知道就写“无法确认”);
5. 与预期不符的地方:缺块、同名覆盖、导入失败、编译错误、硬件 I/O 警告。
不要猜;没有的信息标“无法确认”。不要保存工程。
用自己的工程时:把对象和预期规模换掉,基线项(块/点表/编译/dirty)不变。
看到什么:agent 报告的规模应该对得上:2 个块 + 5 个系统 DB + 1 张点表;Main 18 个网络;逐块编译 0 错误 / 1 警告。基线表如下:
| 对象 | 错误 | 警告 | 说明 |
|---|---|---|---|
MHJ-PLC-Lab-Function-S71200(FC9000) |
0 | 1 | 硬件 I/O 警告 |
Main(OB1) |
0 | 1 | 同一条硬件 I/O 警告 |
| 整个 PLC 软件 | 0 | 1 | 5 个系统 DB 均编译成功 |
注意:编译警告「Inputs or outputs are used that do not exist in the configured hardware」先不要修,也不要忽略——它是审查的候选之一。本课用的 1215C 集成 I/O 不包含示例里的 Q1.2、Q1.3、QW30、QW34,这条警告是真实的硬件配置差异。
同时记下:审查前 dirty 是什么。本课实测从 dirty=false 开始,导入/编译后变 dirty=true,但没有保存。这份基线就是后面审查报告的「范围与基线」段;如果这里已经发现缺块/导入失败,先解决,不要进入审查。
反例:只发一句「帮我 review 一下这段 PLC 程序」。agent 大概率会给你一堆风格建议:命名、注释、网络拆分、变量表规范——听起来都对,但没有一条能证明「会停机」。
正例:把「审什么、怎么算问题、怎么给证据、怎么排除误报」一次说清。下面这段可以直接复制,靶子换成你的工程:
只读审查,不要修改任何对象,也不要保存工程。对象是当前工程的全部 PLC 软件(块、点表、DB)。
目标:找出会导致误动作、停机、无法投运、数据损坏或难以维护的缺陷;不要给纯风格建议。
按 7 类逐项审查:
1) 结构与调用:空网络、未调用块、重复驱动、调用关系、实例 DB;
2) 状态与保持:置位/复位配对、自锁、首扫描、保持性、断电恢复;
3) 时序与扫描:扫描顺序、双线圈、边沿存储、定时器类型(TON/TOF/TP)、单扫描脉冲;
4) 互锁与安全:启停/急停/联锁、冲突输出、故障失效方向;
5) 数据与地址:类型/范围/数组边界、INT/REAL、计数器溢出、I/O 地址与硬件通道;
6) 可维护性:巨型网络、空接口、全局变量、魔法数、命名与注释;
7) 可测试性:手动/仿真模式、场景可注入、诊断与报警。
对每个候选问题输出:
- 证据:块名 + 网络号 + 标签/指令;跨网络问题列出所有写点;
- 失败场景:什么输入/时序/硬件状态下出错,后果是什么;
- 严重级别:P0 停机/安全/数据损坏;P1 功能错误/难恢复;P2 维护/可读性;P3 待确认;
- 置信度:确认(程序内可证)/ 推断(需工艺或硬件确认)/ 无法确认;
- 修复建议:最小改动 + 风险;
- 验证方法:读图/逐块编译/PLCSIM/云仿真/人工;
- 反证:有没有其他网络、外部写入或工艺约束使它不成立。
最后输出《程序审查报告》,按 P0→P1→P2 排序,并单列「误报/已排除」和「无法确认」。
不要编造行号;没有失败场景的候选不要写进报告。
这段任务书有四个关键点:
看到什么:agent 不会立刻给你一份“感觉”,而是先回一个审查计划/范围,例如(示意,实际措辞会变):
收到。只读审查,不修改、不保存。
范围:Main (OB1, LAD, 18 networks) + MHJ-PLC-Lab-Function-S71200 (FC9000, SCL, 1 network)
基线:编译 0 错误 / 1 警告;dirty=true
计划:1) 导出块/点表 2) 建 输出→写点 表 3) 按 7 类扫描 4) 反证/分级 5) 出报告
先扫全;候选会按 P0/P1/P2 + 证据列出,没有失败场景的不进报告。
如果它只回一句“好的”然后开始讲命名/注释,说明任务书没生效:把 7 类清单、证据要求和“没有失败场景不进报告”再发一遍。真正的发现和报告在第四步到第七步;这一步只要确认它按清单扫全、按证据说话。
这一步不需要新的提示词。 第二步的任务书已经包含「证据」「跨网络列出所有写点」「逐块编译」的要求;agent 会自己继续。正常使用不需要你一步步指挥。它会做四件事:
输出 → 写点 表:对每个输出/标志,列出所有写它的网络和指令;看到什么:agent 会先摆出规模(2 个块、18 个网络、31 个标签、5 个系统 DB、编译 0 错误 / 1 警告),再给出 输出 → 写点 表。这张表是审查的核心工具;本课实测得到的关键行:
| 输出 / 标签 | 写它的网络 | 指令 | 备注 |
|---|---|---|---|
Feed Conveyor |
N4 / N6 / N7 | 普通线圈 / 置位 / 复位 | 三个驱动,扫描顺序敏感 |
Chain_Transfer_Right |
N11 / N12 / N13 | 普通线圈 / 置位 / 复位 | N11 与 N12 条件互斥;N11 在 Tag_5=0 时恒真 |
Tag_5 |
N13 | 复位 | 程序内没有置位 |
Tag_9 |
N16 | 普通线圈 | 由 TON 自复位 |
表里只要出现同一输出多个写点,或某个标志只有复位,就进入候选;单看一个网络是看不出来的。
如果 agent 停下来:只回一句「继续,先把 输出 → 写点 表建出来,再按 7 类扫描」,不要重新发整段任务书。
这里有一个容易踩的坑:导出的 SCL 文本里可能出现
511Ret_Val、空GOTO ;这种拼接。先不要把它写成 P0——它是文本反编译的伪影,不是 TIA 编译器的结论。下一步会专门处理。
这一步不需要新的提示词。 第二步的任务书已经要求「跨网络列出所有写点」和「失败场景」;agent 应该从证据包直接进入候选分析。如果它停下来,只回一句「继续,按 7 类给候选,先不要写报告」。
你可能需要回答的:agent 可能会问 Load 是保持信号还是短脉冲、右分拣应该由哪个箱型触发。知道就回答;不知道就说「标推断/待确认」,不要让它猜。
下面两条发现先用离线逐扫描推演确认;你在自己的工程里可以用 PLCSIM 按同一张场景表复现(见 L4)。
先看右分支的接线:
NOT Tag_5 AND Load → Chain_Transfer_Right(普通线圈);Tag_5 AND Load → Chain_Transfer_Right(置位),同时 Tag_5 AND Load → TOF 8s → Right_Conveyor;FALLING(Right Entry) → 复位 Chain_Transfer_Right 和 Tag_5。这是 Main 的实际梯形图(N11/N12/N13 三个网络写同一个 Chain_Transfer_Right):
把三个写点放在一起看,才能发现 N11 的 NOT Tag_5 恒为 1;单看 N12 会以为“Tag_5 置位后才动作”。
Tag_5 在整个程序里只有复位、没有置位(除非 HMI/通信从外部写入,本课未发现)。所以:
NOT Tag_5 恒为 1;Load=1,N11 就把右链条打开,不区分箱型;Tag_5 AND Load 不会成立,Right_Conveyor 也不会转;Tag_2=1(左箱型),N9 也会置位左链条——左右链条同时动作。
逐扫描推演(Load=1):
Tag_2 |
Tag_5 |
左链条 | 右链条 | 右输送机 |
|---|---|---|---|---|
| 0 | 0 | 0 | 1 | 0 |
| 1 | 0 | 1 | 1 | 0 |
级别:P1(功能错误,可能造成机构干涉)。
置信度:确认(静态接线 + 离线逐扫描仿真)。
修复建议:补 Tag_5 的置位条件(另一种箱型),并让 N11/N12 统一用一种驱动方式;或者删掉 N11,只保留按箱型的 N12。
验证:场景表断言「左箱型只允许左链条」「右箱型只允许右链条」。
Feed Conveyor 多驱动,没箱子也进料再看进料输送机:
Tag_1 → Feed Conveyor(普通线圈,每个扫描都写);Tag_1 AND Height_sensor_1 AND NOT Load → Feed Conveyor(置位);Load OR Reset_Button_1 → Feed Conveyor(复位)。这是 Main 的实际梯形图(N4/N6/N7 三个网络写同一个 Feed Conveyor):
注意 N4 同时驱动 Start Light、Remover 1、Remover 2;Feed Conveyor 只是其中一个输出。
OB1 每个扫描按 N4 → N6 → N7 执行。于是:
Tag_1=1、Height_sensor_1=0、Load=0:N4 写 1,N6 不成立,N7 不动作 → 1。没有箱子时进料输送机也在转;N6 的 Height_sensor_1 条件被 N4 完全覆盖。Tag_1=1、Height_sensor_1=1、Load=0:N4 写 1,N6 也写 1,N7 不动 → 1;Load=1:N4 先写 1,N7 再复位 0 → 本扫描结束为 0;Load 变回 0:N4 又写 1,N7 不动作 → 1(重新启动)。也就是说,N7 的「停止」只在 Load=1 的扫描有效,不是保持;而「有箱才进料」的 N6 条件也被 N4 覆盖。如果 Load 是短脉冲,停止只持续一个扫描;如果 Load 是保持信号,输送机在箱子到位时停、箱子一离开又自动重启——这不一定符合工艺意图。
级别:P1(功能错误:没有箱子也进料;且停止不保持)。
置信度:确认(程序内 + 离线逐扫描仿真);工艺意图仍需确认。
修复建议:只保留一个驱动源;若要「有箱才进料、停止并保持」,用置位/复位或自锁,不要让普通线圈每扫描覆盖;或者把 N4 的 Feed Conveyor 拆成独立输出。
验证:Tag_1=1, Height_sensor_1=0, Load=0 → 1(没箱子也转);Height_sensor_1=1, Load=0 → 1;Load=1 → 0;Load=0 → 1(重启)。若要求停止保持,最后一步应为 0。
这一步不需要新的提示词。 第二步的任务书已经覆盖「时序/扫描」和「数据/地址」;agent 会从那套清单继续扫。如果它停下来,只回一句「继续,把时序和地址两类扫完,再对硬件」。
你可能需要回答的:原机 CPU 实际插了哪些 DQ/AQ 模块、Q1.2/Q1.3/QW30/QW34 对应哪些通道;Emitter 是电磁阀还是接触器、10ms 脉冲够不够。知道就回答;不知道就说「标待确认」,不要让它猜。
Emitter 只有一个扫描周期的脉冲N16 是 TON(IN = Tag_1 AND NOT Tag_9, PT = T#10s) → Tag_9,N17 是 Tag_9 → Emitter。Tag_9 自己又是 TON 的「非」条件,所以计时到 10s 后:
Tag_9=1;Tag_9=0,TON 重新计时。这是 Main 的实际梯形图(N16/N17):
Emitter 只得到一个扫描(10ms)的脉冲。如果它是电磁阀/接触器,10ms 可能来不及动作——现场表现就是「出料偶尔不动作」。级别 P2;修复用 TP 保持一个固定脉宽,或用置位/复位 + 定时器复位。
编译 0 错误 / 1 警告。本课沙盒是 CPU 1215C DC/DC/DC,集成 DI14/DQ10 + AI2/AQ2;示例使用 Q1.2、Q1.3、QW30、QW34,不在集成 I/O 范围内。原始工程可能另有 DQ/AQ 模块。
这不是逻辑错误,但不能忽略:TIA 编译不检查「地址有没有物理通道」,下载后这些点可能根本没有接线。审查报告里把它列为 P2「硬件配置待确认」,修复方式是补模块或改地址,验证方式是硬件组态 + 下载后 I/O 检查。
31 个标签里没有 E-stop,程序只有 Start/Reset。这不一定是缺陷:原机可能有硬接线安全回路或安全继电器。审查报告把它列为 P3「无法确认」,需要电气图纸和安全评审;AI 不能做安全认证,也不能用「程序里没有」推出「机器不安全」。
这一步是整节课最值钱的地方。AI 审查最常见的失败不是漏看,而是把可疑当成确认。对每条候选,追问三个问题:
本课实测排除了三条「看起来很吓人」的候选:
| 候选 | 为什么看起来像问题 | 反证结果 | 处理 |
|---|---|---|---|
SCL 里的 511Ret_Val、空 GOTO ; |
像两处语法错误,AI 很容易报 P0 | 真实 TIA 逐块编译 0 错误 / 1 警告,块 consistent=true;重新导出 XML 是结构化的 PEEK/POKE/GOTO token |
误报,排除;修正示例页的「SCL 编译失败」说法 |
| SCL FC 每扫描 120×10 次系统时间读写 | 循环很大,像会拖垮扫描周期 | 没有扫描时间实测;不能从代码结构直接推结论 | 标 P2/P3「推断/需实测」,不进 P1 |
| N2 复位在 N3 置位之前,两个按钮同按 | 像启停竞争 | 两个按钮同时按下时 Start 优先;没有工艺要求证明这是缺陷 | 标 P3「待确认」,不算已确认缺陷 |
重点看第一条。导出文本里确实有:
1#Value:=PEEK(area := 16#82,2 dbNumber := 0,3 byteOffset := 511Ret_Val);4...5 GOTO ;但 tialink_compile 对 MHJ-PLC-Lab-Function-S71200 的真实结果是 0 错误 / 1 警告,tialink_meta 显示 consistent=true。重新 tialink_export 这个 FC,XML 里是结构化的 PEEK / POKE / GOTO token,不是上面那段拼接文本。
结论:511Ret_Val 和空 GOTO ; 是文本反编译/导出拼接伪影,不是程序缺陷。审查时不能用「读导出文本」代替「让 TIA 编译」。 这条误报已经回写修正到示例页:原来写「SCL 编译失败」,现在写「导出文本有拼接伪影,TIA 实际编译 0 错误」。
反证之后,报告里只留下能证实的:
| ID | 级别 | 发现 | 置信度 |
|---|---|---|---|
| P1-01 | P1 | 右分拣不按箱型;左箱型时左右同时动作;N12 不触发 | 确认(静态 + 仿真) |
| P1-02 | P1 | Feed Conveyor 多驱动:没箱子也进料,停止不保持 |
确认(静态 + 仿真);工艺意图待确认 |
| P2-01 | P2 | Emitter 单扫描脉冲(10ms / 10s) |
确认(仿真) |
| P2-02 | P2 | 编译警告:硬件中不存在使用的 I/O | 确认(编译 + 硬件对照) |
| P3-01 | P3 | 程序内无急停/安全逻辑 | 无法确认(需图纸/安全评审) |
报告不需要很长,但每一段都要能复核。先看报告的结构和分级口径:
用这个模板:
# 程序审查报告
### 1. 范围与基线
工程 / CPU / 块 / 网络 / 语言 / 点表 / 系统 DB / 审查前 dirty
### 2. 结论摘要
P0/P1/P2 数量;能不能投运;最危险的 1-2 条
### 3. 发现
#### P1-01 <标题>
- 证据:块名 + 网络号 + 标签/指令(跨网络列出所有写点)
- 失败场景:什么输入/时序/硬件状态下出错,后果是什么
- 影响:停机 / 误动作 / 数据损坏 / 维护风险
- 级别:P0 / P1 / P2
- 置信度:确认 / 推断 / 无法确认
- 修复建议:最小改动 + 风险
- 验证方法:读图 / 逐块编译 / PLCSIM / 云仿真 / 人工
### 4. 误报与排除
候选 → 为什么看起来像问题 → 反证结果 → 处理
### 5. 无法确认
需要工艺 / 硬件 / 安全资料才能判断的项
### 6. 修复顺序与回归计划
P0 → P1 → P2;每条怎么验证;谁确认
### 7. 只读声明
改没改、保存没保存;结束 dirty 状态
完整产物如下(本次运行生成;展示时只做了排版,内容未改):
只读生成 · 2026-10-21 · TiaLink 1.1.0.0 + TIA Portal V19 · L7_Station(CPU 1215C DC/DC/DC)
sorting-boxes(开源示例,MIT)Main(OB1,LAD,18 个网络)+ MHJ-PLC-Lab-Function-S71200(FC9000,SCL,1 个网络)Default tag table,31 个标签;系统实例 DB 5 个dirty=false;审查过程未修改被审查的程序对象,未保存工程Feed Conveyor 多驱动,没箱子也进料,停止不保持)Emitter 单扫描脉冲;硬件 I/O 配置警告)NOT Tag_5 AND Load → Chain_Transfer_Right(普通线圈);N12 Tag_5 AND Load → Chain_Transfer_Right(置位);N13 复位 Chain_Transfer_Right 和 Tag_5,但程序内没有任何 Tag_5 置位。Load=1 且 Tag_5=0 → N11 开右链条;Tag_2=1 时 N9 同时开左链条,左右同时动作。右输送机(N12 的 TOF)不运行,因为程序内 Tag_5 不置位。Tag_5 的置位条件(另一种箱型),N11/N12 统一用一种驱动方式;或删除 N11,只保留按箱型的 N12。Tag_2=1, Tag_5=0, Load=1 → 只允许左链条;Tag_2=0, Tag_5=1, Load=1 → 只允许右链条。Feed Conveyor 多驱动,没箱子也进料,停止不保持Tag_1 → Feed Conveyor(普通线圈);N6 Tag_1 AND Height_sensor_1 AND NOT Load → Feed Conveyor(置位);N7 Load OR Reset_Button_1 → Feed Conveyor(复位)。Tag_1=1、Height_sensor_1=0、Load=0 时,N4 仍把 Feed Conveyor 写成 1——没有箱子也进料;N6 的 Height_sensor_1 条件被完全覆盖。Load=1 时 N7 复位为 0,但 Load 一消失,下一扫描 N4 又写 1,停止不保持。Feed Conveyor 拆成独立输出。Tag_1=1, Height_sensor_1=0, Load=0 → 1(没箱子也转);Height_sensor_1=1, Load=0 → 1;Load=1 → 0;Load=0 → 1(重启);若要求停止保持,最后一步应为 0。Emitter 是单扫描脉冲TON(IN=Tag_1 AND NOT Tag_9, PT=10s).Q → Tag_9;N17 Tag_9 → Emitter。Tag_9 在第 1000 个扫描(10ms 周期)为 1,第 1001 个扫描为 0;Emitter 只得到一个扫描的脉冲。TP 保持固定脉宽,或用置位/复位 + 定时器复位。Tag_9 的脉宽。Q1.2、Q1.3、QW30、QW34。511Ret_Val、空 GOTO ;,看起来像语法错误;真实 TIA 逐块编译 MHJ-PLC-Lab-Function-S71200 为 0 错误 / 1 警告,块 consistent=true。结论:文本导出拼接伪影,不是缺陷;不要用文本导出代替编译器。Load 传感器是保持信号还是短脉冲(影响停止的持续时间;不改变「没箱子也进料」的结论)Tag_5 应该由哪个箱型置位)Tag_5 置位/统一驱动 → 编译 0/0 → 场景表验证左右互斥;Feed Conveyor:单一驱动/保持停止 → 场景表验证「无箱不进料」+「Load 消失后不重启」;Emitter:TP/锁存 → 脉宽测量;审查过程未修改被审查的程序对象,未调用 save;导入/编译只改内存状态;结束 dirty=true,由工程主人关闭不保存。
输出 → 写点 表:多驱动、置位/复位配对、扫描顺序问题一眼可见;dirty,审查后应当没有保存(本课实测 false → true,但从未 save)。Load 是保持还是脉冲、右分拣应该由哪个箱型触发、Feed Conveyor 的停止要不要保持;Q1.2/Q1.3/QW30/QW34 在原机上有哪些模块/通道;dirty 有记录;511Ret_Val、空 GOTO ; 就是典型;真实 TIA 编译 0 错误。编译结论只信编译器。把 TIA Portal 接到你的智能体:导入、编译、读回核对、PLCSIM 仿真。本地运行,工程数据不出厂。
打开 TiaLink