跳到正文
Learn-LAD
PLC AI 实战/把整套工程变成一张会回答问题的图

把整套工程变成一张会回答问题的图

给整个 TIA 工程建一张知识图谱,用调用/读写/实例化关系和未解析引用回答「谁用谁、改它波及谁、哪里缺东西」,每条结论都带文件与行号。

进阶 第 6 课 30 分钟 TiaLink

学完你能:能对一个陌生工程做一次图谱问答,产出「对象 + 关系 + 风险」三张表,并知道哪些结论可以直接当证据、哪些必须回 TIA 复核。

概述

上一课《改一个 IO 地址,会影响谁?》是一处一处地查;这一课换一种问法:先让 agent 给整套工程建一张图,然后直接问这张图。

一句话区别:搜索给你候选,图谱给你带行号的证据。

图里有三样东西,必须一起看:

组成 含义 用来回答
节点 工程里的对象:块、网络、接口成员、标签、触点/线圈/盒子、SCL 语句 "工程里有什么"
边 对象之间的关系 + 出处:调用、实例化、类型、读、写、连线 "谁调用谁、谁写这个标签"
未解析引用 建立了引用、但工程里找不到对应对象的名字(不建边,避免污染结论) "哪里缺东西"——接手/迁移前最值钱的一张清单

本课用同一套开源工程 PLC_SCADA_HMI(MIT)实测,全程只读:你只需要说清要问什么,建图和查询都是 agent 自己完成的。

本课按一步一问组织:每步给出可复制的「你说」和对应的「它回」,先看输出再问下一步;一次要全套报告的提示词放在最后,作为熟练后的选项。

指标 本课实测(2026-10-27,TIA Portal V19 + TiaLink 1.4.0.0)
设备 S7-1500/ET200MP station_1,CPU 1513F-1 PN(6ES7 513-1FL02-0AB0,V2.9)
建图 一句话,1–3 秒(本机从零开始实测 1.2 s)
图 227 个对象节点 / 517 条关系 / 8 条未解析引用
工程规模 OB1(4 网络)、2 个 FB、2 个实例 DB、2 张点表、51 个标签

核心观点三句话:

  1. 图谱不是 AI 猜的,是从工程里解析出来的结构索引;每条关系都能回到文件与行号,所以能当证据。
  2. 结论要分"能当证据"和"要复核":调用/读写/实例化是硬事实;"这个引用了不存在的东西"要么是真缺失,要么是外部库,必须判定。
  3. 未解析引用往往比正例更有用:本工程 8 条 IEC_Timer_0_DB* 全是找不到对应对象的引用——这类问题编译不一定报,靠搜也很难发现。

你将学会

  • 让 agent 给整个工程建一张图,并确认这张图是你现在打开的这个工程、是刚建的;
  • 一次拿到对象清单:块的类型/编号/语言/网络数、实例 DB 关系、点表、UDT、CPU 型号与订货号、有没有同名对象;
  • 让 agent 找对象时说清"结果有没有被截断"——只看前几条就下结论是这类分析最常见的错;
  • 让 agent 拆开一个块:接口、每个网络、它调了谁、它读写哪些标签;
  • 问出"谁调用 / 谁写了这个标签",并让每条结论带上出处和行号;
  • 做影响面分析:"改它/删它,波及几层、经过什么关系",以及为什么"它属于哪个块"要单独问;
  • 产出幽灵引用清单,并把每条判定成"真缺失 / 外部库 / 待补"。

前置条件

  • Windows 机器,已安装 TIA Portal V19(TiaLink 当前基于 V19 与 Openness 构建);
  • TiaLink:在 TiaLink 页面 下载并启动,打开要分析的工程(图谱建的是"当前打开的工程",空工程会被直接拒绝,见常见坑);
  • 一个支持 Streamable HTTP MCP 的客户端(Claude Code、Cursor、VS Code 等),MCP 端点为 http://localhost:8080/mcp;
  • 图谱能力需要授权:未授权的安装会被拒绝(403);如果 TiaLink 启动时禁用了图谱,同样用不了;
  • 练习对象:你自己的工程,或本课同款开源工程 PLC_SCADA_HMI(MIT;工程文件是仓库里的 PLC/PLC_SCADA_HMI.zap19),也可以用示例库里的多块示例 SCL 训练:存储功能块 练手;
  • 两条纪律:分析阶段只读(本课不导入、不改块、不保存);工程本来 dirty 不影响建图,但要记下基线。

步骤

本课按一步一问组织:每步只问一件事,先看输出再问下一步。后面的分析步骤都有「你说」和对应的「它回」,输入和输出对得上;熟练后想一次拿全套报告,再看文末的「熟练后:一次要全套报告」。

第一步:配好 TiaLink 与 MCP

在博途那台机器上启动 TiaLink、打开工程。页首状态条会自动检测;然后在客户端里加一个 Streamable HTTP MCP 服务:

MCP
{
  "mcpServers": {
    "tialink": {
      "type": "http",
      "url": "http://localhost:8080/mcp",
      "headers": { "Authorization": "Bearer <你的 TiaLink API Token>" }
    }
  }
}

看到什么:客户端连上了 TiaLink,你可以直接用中文让它读工程。用不着记工具名,也不用背命令——下面每一步都只是"你说话,它去做"。

第二步:建图,并确认建的是"现在这个工程"

你说(一句话就行):

只读。先给当前打开的工程建一张工程图,然后告诉我图的基本情况:工程名、CPU 型号、图里有多少对象和关系、有多少条未解析引用、一共花了多久。

它回(本机实测):

它会告诉你 实测值
工程 PLC_SCADA_HMI
设备 / CPU S7-1500/ET200MP station_1 / CPU 1513F-1 PN
图里有多少东西 对象节点 227、关系 517
缺口 未解析引用 8 条
建图用时 约 1 秒(这一次从零开始 1.2 s)

一条命令建图,之后全是只读查询
建图约 1 秒;建完之后所有提问都不再碰工程,工程零改动

这里要盯的不是数字大小,而是三条确认,它们决定后面的结论能不能信:

  1. 工程名对不对——图上挂的是不是你正在分析的那个工程(本课是 PLC_SCADA_HMI);
  2. 是不是刚建的——让它报建图时间;工程改过却不重建,图还是旧的,而且它不会自动提醒你;
  3. 是从"当前打开的工程"建的,还是沿用了以前某次留下的旧图——旧图看着一切正常,却可能整块整块地过期。

这三条任何一条说不清,先重建一次,再往下问。

第三步:一步一问,输入和输出对得上

不用一次写一大段。后面每一步只问一件事:盘家底、找对象、看一个块、问关系、问影响、抓缺口。每次问完先看两件事:

  • 结果有没有被截断("还有更多");
  • 每条结论有没有出处(块名 + 网络号 / 文件 + 行号 / 关系出处)。

分开问的好处很直接:输入小、输出短,哪一步不对当场就能发现;一次问六件事,某一段被截断你很难察觉。下面的每一步都给出可以直接复制的「你说」和本次实测的「它回」。

想一次拿到整套报告?那是熟练后的用法,见文末「熟练后:一次要全套报告」。

第四步:agent 盘家底

你说:

只读。列出这个工程里有什么:块(类型、编号、语言、网络数)、实例 DB、点表、UDT、CPU 型号与订货号;同名对象单独列,没有的对象写 0。

它回:一次问清,比逐块读快,也不容易漏。本次清单:

项 实测
CPU / 订货号 / 固件 CPU 1513F-1 PN / 6ES7 513-1FL02-0AB0 / V2.9
块 OB1::Main(OB 1,LAD,4 网络)、FB::Auto_mode(FB 2,LAD,1 网络)、FB::Manu_mode(FB 3,LAD,1 网络)
实例 DB InstanceDB::Block_1_DB(12)、InstanceDB::Manu_mode_DB(13)
点表 / UDT Main_variables、additional_variables / 0 个
同名对象 0
  • 签名带编号与语言(FB 2 [LAD]),可以直接和 TIA 项目树对照;
  • CPU 订货号是很多"这套程序到底能不能下到现场那台 CPU"问题的第一步;
  • 同名对象不是"重复代码",而是同一个名字在多处被定义(多版本工程、复制粘贴的工程很常见)。本工程是 0;一旦不为 0,后面按名字问会得到"有歧义"的答案,必须让 agent 指定是哪一个——否则你看到的读写清单可能来自另一个副本。

第五步:agent 找对象

你说:

只读。找 Auto_mode(换成 CV-101 或 Conveyor 也可以):按精确名 → 前缀 → 注释里的词 → 包含逐级放宽,告诉我命中的是哪一档,以及结果有没有被截断。

它回:它会按"精确名 → 前缀 → 注释里的词 → 包含"逐级放宽,并告诉你命中的是哪一档:

你问 命中 靠什么命中
Auto_mode 4 条:FB::Auto_mode、调用点 Main::N1::I1、它的文件、它的网络 精确名 + 前缀
CV-101 1 条:Main_variables.CV-101(Bool %Q4.0,注释 "Conveyor") 精确名
Conveyor 3 条 注释里的词(不是名字)

看到什么,两句要盯:

  • 命中里出现调用点,说明这个名字也被用在调用上——这正是"谁在调它"的入口;
  • 结果是否被截断。本课问 Auto_mode 时就是"还有更多",如果你不问一句"看全了吗",就会把前 4 条当全部。

第六步:agent 看一个块

你说(主程序):

只读。把 OB1::Main 一次拆开:接口、每个网络、它调用了谁、读写清单、块内缺失引用;哪一部分被截断就说明。

你说(另一个 FB):

只读。再看 FB::Auto_mode:接口、网络、读写清单、块内缺失引用。

它回:一个块一次拿全:接口、每个网络、聚合后的调用目标与读写清单、块内缺失的引用。

OB1::Main(本工程主程序)本次结果:

项 实测
块 OB 1 [LAD],4 个网络(N1/N2 各有内容,N3/N4 是空网络)
调用了谁 FB::Auto_mode、FB::Manu_mode
读 / 写 10 处读 / 0 处写
块内缺失引用 0

FB::Auto_mode(1 个网络)则是另一种画像:接口是空的(输入/输出/静态等分节都没成员),网络里却有 22 处读、17 处写、5 条找不到对象的引用——这是本工程真实的样子(不是解析出错),它直接解释了第九步的 8 条幽灵引用(另一个 FB Manu_mode 是 21 读 / 16 写 / 3 条)。

看到什么:如果结果里写着"只给了一部分",说明这个块比给你看的多(网络数或读写条数被截断);要么让它继续要,要么缩小问题范围,别拿一页当全部。

第七步:agent 问关系

这是这套图存在的理由。问法只有两种:"谁用它"和"它用了谁"。

你说(标签读写):

只读。additional_variables.tag3 被谁读、被谁写?读写分开,每条给出块名 + 网络号 + 行号 + 出处。

你说(调用点):

只读。Main::N1::I1 属于谁、谁连到它、它调了谁?每条给出出处。

它回:先看关系形状(示例子图),再看两张关系表。

关系图:谁用它、它用了谁
关系图:主程序网络 N1 的第 1 个调用点调用了 FB::Auto_mode;同一个标签被 2 个触点读、2 个线圈写,每条边都能回到行号。绿=调用,蓝=读,橙=写,灰虚线=包含 / 导线,紫虚线=点表包含。(示例子图;完整图是 227 个对象节点 / 517 条关系。)

读和写分开看:同一个 tag3 有 2 条蓝色读边、2 条橙色写边,说明改动会碰到 4 个 LAD 位置;灰虚线是结构包含,紫虚线是点表包含。

问"这个标签被谁读、被谁写"(additional_variables.tag3),本次结果一条不漏:

关系 来自 行 出处
属于点表 additional_variables — 点表包含
读 Auto_mode::N1::L13(触点) 152 按操作数解析
写 Auto_mode::N1::L26(线圈) 217 按操作数解析
读 Auto_mode::N1::L27(触点) 222 按操作数解析
写 Auto_mode::N1::L35(线圈) 262 按操作数解析

同一个调用点,问"它属于谁、谁连到它、它调了谁":

关系 从 到 出处
属于 Main::N1(网络) Main::N1::I1(调用点) 结构包含
连线 Main::N1::L11(LAD 零件) Main::N1::I1 LAD 导线
调用 Main::N1::I1 FB::Auto_mode 按调用解析
  • "出处"就是可信度标签:按调用解析、按操作数解析、结构包含、点表包含……它告诉你这条关系是怎么来的;没有出处的结论不要当证据;
  • 同一个标签既有读也有写,方向必须分开看:本例 2 读 2 写就是"改动影响"的全部软件面(4 个位置,行号落在 152–262);
  • 行号能回源:拿行号回到工程文件,就能看到那条指令,这是抽查的方法。

第八步:agent 问影响面

"改它会波及谁"和"谁用它"不是一回事:前者会沿关系反着走多层,每一条命中都告诉你走了几层、经过什么关系。

你说(默认关系):

只读。如果改或删 FB::Auto_mode,波及哪些对象?按层数列,标明经过什么关系。

你说(加上「包含」):

只读。再把「包含」也算上,多走几层,看它属于哪个块。

它回:下面先看关系形状,再看默认关系和加「包含」两组结果。

影响面:改 FB::Auto_mode 会波及谁
影响面:改这个 FB,谁会跟着动。调用 / 实例化是默认关系集合能答的;①–④ 是额外把「包含」算上才出现的第 1–4 层。(示例子图,只画这条影响链。)

图里把两层画在一起:调用 / 实例化是默认问法能答的部分;①–④ 是额外把「包含」算上才出现的层级链。箭头按正常的「包含」方向画(外层的源文件 → 块 → 网络 → 内层文件);影响面是反着走这些箭头,所以离 FB::Auto_mode 最近的是第 1 层。

它回(默认关系):

层数 经过 命中
1 调用 调用点 Main::N1::I1
1 实例化 实例 DB InstanceDB::Block_1_DB

可以直接写成一句人话:"Auto_mode 被主程序第 1 个网络调用,实例 DB 是 Block_1_DB;改它的接口要同时看这两处。"

但默认的关系集合里没有"包含",所以"它属于哪个块"不会出现。把"包含"也算上,并多走几层,才会沿层级往上走:

它回(加上「包含」):

层数 经过 命中
1 包含 它的源文件
2 包含 它所在的网络 Main::N1
3 包含 OB1::Main(包含它的块)
4 包含 主程序的源文件

这条差异值得记住:默认问的是"谁会受影响"(调用/读写/实例化),加了"包含"才回答"它长在谁身上"。

第九步:agent 抓幽灵引用

你说:

只读。列出所有未解析引用,每条给文件与行号,标「待定 / 外部」,并判定「真缺失 / 外部库 / 待补」;不能确认的不要猜。

它回:引用了、但工程里找不到对象的名字,不会被硬凑成关系,而是进这张清单——接手/迁移前最该看的东西。本工程 8 条:

状态 引用(被写入) 文件 行
待定 IEC_Timer_0_DB_3 blocks/Auto_mode.xml 332
待定 IEC_Timer_0_DB_4 blocks/Auto_mode.xml 337
待定 IEC_Timer_0_DB_1 blocks/Auto_mode.xml 483
待定 IEC_Timer_0_DB_2 blocks/Auto_mode.xml 488
待定 IEC_Timer_0_DB_3 blocks/Manu_mode.xml 232
待定 IEC_Timer_0_DB_4 blocks/Manu_mode.xml 237
待定 IEC_Timer_0_DB_2 blocks/Manu_mode.xml 323
外部 IEC_Timer_0_DB blocks/Auto_mode.xml 493

怎么读这张表(本课最值得带走的方法):

  1. 先看状态:"待定" = 可能是还没进这份工程的对象;"外部" = 这个名字任何本工程文件都不可能定义,多半来自别的项目/库;
  2. 再对照来源:这 8 条全是定时器线圈写实例——而这两个 FB 的接口确实没有成员,工程里也没有同名的全局 DB。所以它们不是"解析漏了",而是块里用了不存在的背景 DB 名字;
  3. 最后定性:真缺失(要补对象)/ 外部库(要引库)/ 待补(下次建图就齐)。这一刀只有人能拍,agent 只负责把证据摆齐。

交叉验证(可选但建议):让 agent 顺手编译一遍,本次结果是一句 No block was compiled. All blocks are up-to-date.("没有块被编译")。注意:这句话意味着这次"成功"不能当成"逻辑没问题"的证据,只能当成"当前没有待编译改动"。幽灵引用到底会不会炸,仍然要按上面三步人工判定。

第十步:你得到什么

你说:

只读。把前面的结果整理成三张表:对象表、关系表、风险表;每条结论带出处或行号,不能确认的标注「无法确认」。

它回:

  • 三张表:对象表(类型/编号/语言/网络数/实例 DB 关系)、关系表(调用/读写/实例化,带调用点与行号)、风险表(未解析引用 + 定性 + 复核动作);
  • 一份能贴进评审的记录:每条结论都有出处或行号,别人可以抽查;
  • 工程零改动:只建图与查询,没导入、没改块、没保存;dirty 与开始时一致。

完整产物如下(本次运行生成;展示时只做了排版,内容未改):

展开《工程图谱报告》全文(对象表、关系表、风险表、复核动作)

工程图谱报告:PLC_SCADA_HMI

只读生成 · 2026-10-27 · TiaLink 1.4.0.0 + TIA Portal V19

1. 图的基本情况

字段 值
来源 当前打开的工程(不是旧图)
设备 / CPU S7-1500/ET200MP station_1 / CPU 1513F-1 PN(6ES7 513-1FL02-0AB0,V2.9)
图规模 227 个对象节点 / 517 条关系(包含 220 / 调用 2 / 实例化 2 / 读 87 / 写 52 / 连线 154)
未解析 8(待定 7 / 外部 1)
同名对象 0
建图时间 2026-10-27T17:42:33Z

2. 对象表

对象 类型 签名 说明
OB1::Main OB OB 1 [LAD] 4 网络;N1/N2 有内容,N3/N4 为空网络
FB::Auto_mode FB FB 2 [LAD] 1 网络 / 79 个网络元素;22 读 17 写;接口无成员;未解析 5
FB::Manu_mode FB FB 3 [LAD] 1 网络;21 读 16 写;未解析 3
InstanceDB::Block_1_DB 实例 DB InstanceDB 12 [DB] Auto_mode 的实例
InstanceDB::Manu_mode_DB 实例 DB InstanceDB 13 [DB] Manu_mode 的实例
Main_variables 点表 — 含 CV-101(Bool %Q4.0,注释 Conveyor)等
additional_variables 点表 — 含 HMI/MATLAB 握手与 tag3
UDT — — 本工程 0 个

3. 关系表(节选)

关系 源 目标 出处
调用 Main::N1::I1 FB::Auto_mode 按调用解析
实例化 InstanceDB::Block_1_DB FB::Auto_mode 按实例解析
写 Auto_mode::N1::L26(线圈,行 217) additional_variables.tag3 按操作数解析
写 Auto_mode::N1::L35(线圈,行 262) additional_variables.tag3 按操作数解析
连线 Main::N1::L11 Main::N1::I1 LAD 导线

4. 风险表

# 风险 证据 定性 复核动作
1 8 条 IEC_Timer_0_DB* 引用无对应对象 未解析清单,行号见上表 待人工定性(疑真缺失) 在 TIA 里查这 4 个定时器实例是否存在;不存在则补或改块
2 两个 FB 接口无成员,但网络里读写大量标签 接口分节为空;Auto_mode 22 读/17 写,Manu_mode 21 读/16 写 结构性风险(可编译、可运行,但不可参数化复用) 与工程主人确认为什么不用接口变量
3 空网络 N3/N4 网络里没有元素 信息 确认是有意留白还是漏写
4 编译状态不可当验收 编译报告:No block was compiled 盲区 改完必须真正改一个块再编译,才能验证

5. 只读声明

本报告生成过程未修改工程:只建图与查询,未导入、未改块、未保存;工程 dirty 与开始时一致。

需要你动手的地方(很少)

  • 幽灵引用的定性:是"真缺失"还是"外部库",只有人和工程主人能拍;
  • 工程语义:为什么接口是空的、为什么有空的 OB 网络——图只能告诉你"是这样",不能告诉你"该不该这样";
  • 复核抽样:按报告里的行号回工程文件抽查 2–3 条,确认 agent 没有把"猜测"写成"事实";
  • 保存纪律:本课不需要保存;如果后续要改工程,导入 ≠ 保存,保存必须由工程主人确认。

熟练后:一次要全套报告(可选)

分步问适合第一次做图谱分析:每步都能核对,出错容易定位。熟悉之后,可以把下面这段一次发出去,让它按顺序做完并给出三张表。代价是输出很长,必须逐段检查有没有「还有更多」。

只读,不要修改任何对象,也不要保存工程。请给这个工程建一张图,然后回答:

  1. 工程里有什么:块(类型、编号、语言、网络数)、实例 DB、点表、UDT、CPU 型号与订货号;同名对象单独列;
  2. 调用结构:主程序调了谁、每个调用点在哪个网络;
  3. 读写关系:关键 DB/标签被哪些块、哪些网络读、哪些网络写,读写分开;
  4. 影响面:如果我改或删掉某个 FB/DB,波及哪些对象、经过什么关系;
  5. 缺口:有没有引用了工程里不存在对象的名字(幽灵引用),每条给出文件与行号,并判定是「真缺失 / 外部库 / 待补」;
  6. 每条结论给出依据(块名 + 网络号 / 文件 + 行号 / 关系的出处),只能推断的标注「推断」,无法确认的标注「无法确认」。

最后给三张表:对象表、关系表、风险表。不要猜。

第一次做,建议还是按上面的步骤分开问;这套一次性提示词适合你已经知道该看哪些结果、只需要它跑完整套的时候。

验证清单

  • 每一步的「你说」和「它回」对得上:问清单回清单、问读写回读写、问影响回层级,没有用一份大报告代替逐步核对;
  • 图是从当前打开的工程建的,建图时间是刚才,工程名就是要分析的那个;
  • 对象数和工程对得上(本课 227 个节点),没有建失败的对象;
  • 对象清单与 TIA 项目树一致;没有某种对象也要明确写 0(本课 UDT = 0);
  • 至少 3 条结论抽样回源:按关系给的行号回到工程文件、或在 TIA 里核对网络号,确认一致;
  • 读写结论区分读/写,调用结论带调用点,不是"某块里可能用到";
  • 未解析引用每条都有状态与定性(真缺失 / 外部库 / 待补),没有含糊的"可能有问题";
  • 编译状态记录在案,并明确它不是本课的验收结论(本课是 No block was compiled);
  • 被截断的结果都注明"未看全",没有拿一页当全部;
  • 工程零改动:dirty 与开始时一致,未保存。

常见坑

  • 同名对象当成一个:多版本/复制粘贴的工程里,同一个名字可能来自两个文件。按名字问会得到"有歧义",必须让 agent 指定是哪一个,否则你看到的读写清单可能来自另一个副本。
  • 空结果读成"没有依赖":没建图就提问是"还没有图";建出来的图若是空的会被直接拒绝(并保留上一张图);删图之后再问又回到"还没有图"。三种都不是"没有依赖"。
  • 不建图就相信旧图:工程改完不重建,图还是旧的,而且它不会自己提醒你;换工程/换设备后更不能用旧图。
  • 沿用旧图却以为是当前工程:只确认了"有图",没确认"这张图是什么时候、对哪个工程建的"。先问建图时间和工程名。
  • 把"编译通过"当验收:本课编译报告就是"没有块被编译",等于什么都没验证。要验证,必须真正改一个块再编译。
  • 未解析 ≠ 编译错误:"待定"可能只是对象还没进这份工程,"外部"才是本工程不可能定义;反过来,编译通过也不代表没有幽灵引用。
  • 把结果上限当全量:查询有上限,超了会告诉你"还有更多";结论要写"未看全",或者换更精确的问法(限定块、限定标签、限定关系类型)。
  • 一次问太多:一条提示词塞进六件事,输出很长,中间某段被截断很难发现;按本课的「一步一问」走,每步先核对再继续。
  • 建错了图:让它删图重建;删之前先让它报告会删什么,确认删的是图谱而不是工程对象。
  • 大工程一次全建:对象特别多时,可以让 agent 先只建某一部分(例如只建程序块,或只建某个分组),再逐步扩大。
  • 版本差异导致"结果对不上":这套能力在持续修正中。排错第一步先确认 TiaLink 的版本与构建号(页首状态条和健康检查里都有),把版本写进报告,别让"版本不同"伪装成"结论不同"。

下一步

本课工具

TiaLink

把 TIA Portal 接到你的智能体:导入、编译、读回核对、PLCSIM 仿真。本地运行,工程数据不出厂。

打开 TiaLink