当你想用 YOLOv8 或 YOLOv5 做一套 PCB 印制板缺陷检测系统时,通常会先兴奋地把模型训练出来,然后在封装界面的环节被 PySide6 卡住。这个体感我见过很多次:模型在 notebook 里跑得挺漂亮,框也画出来了,但一旦要把它交给产线同事或客户用,问题就暴露了——没有界面、没有批量导入、没有结果记录,别人根本不知道怎么操作。基于 YOLOv8/YOLOv5 + PySide6 的 PCB 印制板缺陷检测异常识别,看起来像是一个目标检测项目,实际上它是目标检测和桌面软件工程的交叉项目。真正值得投入时间的,不只是把 mAP 调高一点,而是把一次实验变成一套可重复使用的检测工具。
如果只是把 YOLO 权重加载进来,然后用 PySide6 画几个按钮,这当然不算难。难的是整个链路都要稳定:数据标注是否可靠、训练过程是否收敛、导出后的模型推理是否正常、批量检测时会不会卡死、日志有没有记录、交给别人后能不能双击打开。这篇文章会把这条链路拆开,讲清楚每一步的关键点、容易踩的坑,以及我建议的最小落地路径。
1. 为什么这个项目不是“用 YOLO 跑个模型”那么简单
1.1 从模型到桌面应用:真正的工程链路
训练好的 YOLO 模型,只是整套系统里的一个推理引擎。一个可用的 PCB 缺陷检测桌面工具,至少包含下面这些环节:
- 数据准备:收集 PCB 缺陷图像、标注、划分训练集和验证集。
- 模型迭代:选择合适的 YOLO 版本,训练、验证、调参,产出 best.pt。
- 模型导出:为了部署稳定,常需要把 PyTorch 权重导出成 ONNX 等格式。
- 推理接口:封装一个接收图片路径、返回检测框和类别的函数。
- 桌面界面:用 PySide6 搭建主窗口、预览区域、结果表格和日志。
- 线程管理:把推理放到子线程,避免界面卡死。
- 批量任务:支持文件夹批量检测,并记录每张图的结果。
- 打包发布:用 PyInstaller 或类似工具打包成可执行文件。
这个链条里,模型训练只是第一步。很多人做完第一步就停了,结果项目只能停留在自己的电脑里,没法交付。如果说训练模型是炒出一盘菜,那封装桌面应用就是开一个能稳定出餐的餐厅。后者需要考虑配方、备菜、出餐顺序、异常处理和顾客体验。
“基于 YOLOv8/YOLOv5 + PySide6”这个组合的核心价值,不是某个模型有多强,而是它把深度学习和软件工程衔接起来了。你能在一个桌面应用里完成图片选择、模型推理、结果展示和记录,这个闭环才真正解决了“模型怎么用起来”的问题。
1.2 模型选择:YOLOv8 还是 YOLOv5?
很多人在项目一开始就纠结版本。我的看法是:如果没有历史包袱,优先选 YOLOv8;如果团队已经维护了一套 YOLOv5 的代码和部署流程,就没必要强行迁移。
YOLOv5 最明显的优势是社区积累深。很多在工业检测场景中遇到的问题,搜索时都能找到对应的 issue 和解决方案。配套的部署工具、格式转换脚本、量化方案也非常成熟。它适合那种“求稳”的项目,尤其是团队里已经有熟悉 YOLOv5 的工程师。
YOLOv8 的优势在于 ultralytics 官方统一了训练和推理 API,用起来更简洁。你只需要写几行代码就能完成数据加载、训练、验证和导出。它的模块化程度更高,后续如果要替换主干网络或者引入注意力机制,操作路径也会更清晰。
至于 YOLO11,作为更新版本自然有新的改进,但公开可参考的项目案例和部署经验相对少一些。对 PCB 缺陷检测这类需要长期维护的工业项目来说,我建议把 YOLOv8 作为基线模型。你可以用下面这个表格来辅助判断:
| 维度 | YOLOv5 | YOLOv8 | YOLO11 |
|---|---|---|---|
| 资料成熟度 | 很高 | 高 | 中等 |
| 训练 API | 相对分散 | 统一简洁 | 统一简洁 |
| 部署案例 | 很丰富 | 较丰富 | 还在积累 |
| 适合场景 | 求稳的已有流程 | 新项目、快速迭代 | 愿意尝鲜的实验项目 |
这不是说 YOLOv8 一定比 YOLOv5 好。如果你的训练脚本、标注工具、后端推理都围绕 YOLOv5 搭好了,重写一遍反而会增加风险。项目成功的关键不是选一个“最新”的模型,而是选一个团队能长期维护的模型。
1.3 这个方案的适用与不适用场景
要明确一点:基于 PySide6 做的桌面检测工具,不等于产线级 AOI 系统。它适合下面这些场景:
- PCB 样品复检或者抽检:人工拿放大镜看太累,用桌面工具辅助判断。
- 离线批量检测:把需要复检的图片放到一个文件夹,跑一遍,输出结果表。
- 实验室验证:验证新的检测算法在 PCB 数据上是否有效。
- 教学演示:向同事或者学生展示深度学习在工业检测里如何落地。
不适合的场景也很明确:高速产线实时检测。真正的工业 AOI 系统还需要光源控制、工业相机触发、运动控制、PLC 通信、MES 数据上报,甚至温度漂移补偿和误报率控制。这些不是 PySide6 和 YOLO 能直接覆盖的。如果项目方要求“像 AOI 设备一样在线检测”,那这套桌面方案只能作为前期的算法验证,不能替代整套产线系统。
把适用范围写清楚,项目才不会越做越偏。我见过不少同学用一个目标检测项目去回答所有问题,最后被现场环境里的光影、震动和节拍拖垮。桌面工具先服务好“人工复检”这个环节,已经是很大的价值。
2. 先把检测模型跑通:数据集、训练和导出
2.1 数据集准备:PCB 缺陷类型与标注
PCB 缺陷种类很多,常见的有短路、断路、毛刺、缺口、孔洞、桥连、异物等。不同项目定义的缺陷类别不一样,有的只分“有缺陷”和“无缺陷”,有的要细分到具体类型。标注之前要和生产现场的复检标准对齐,不然模型学到的边界可能和实际需求不一致。
数据集目录结构建议使用 YOLO 风格:
datasets/pcb/ ├── images │ ├── train │ └── val └── labels ├── train └── val每一张图片对应一个同名的 txt 标注文件,格式是:
class_id x_center y_center width height这几个数值都是归一化到 0-1 的相对坐标。标注工具可以用 LabelImg、LabelStudio 或者 CVAT,选一个团队习惯的就行。
这里有一个非常容易踩的坑:类别数量少时,很容易出现类别不平衡。比如“短路”样本很多,“孔洞”样本只有几十张,模型就会整体偏向样本多的类别。解决思路是先把数据清单列出来,统计每个类别的数量,再决定是否做数据增强、过采样或者先合并粗分类。
增量训练是另一个常见需求。PCB 缺陷数据往往只有几百张,从零训练很难收敛,更实际的做法是加载预训练权重,继续在自有数据集上微调。比如你已经有一个 YOLOv8 模型,想在新的缺陷类别上继续训练,这属于增量训练。需要特别注意配置文件的类别数和权重保持一致,或者使用同样类别数量的预训练权重。
2.2 用预训练权重做微调
我建议先用 YOLOv8n 或 YOLOv8s 跑通链路,再考虑更大的模型。如果你用的是 GTX 1660 Ti 这种 6GB 显存显卡,YOLOv8n 和 YOLOv8s 都是可以跑的,但 batch 和 imgsz 不要同时拉满。
定义一个 pcb.yaml:
path: datasets/pcb train: images/train val: images/val names: 0: short 1: open 2: burr 3: hole 4: bridge训练命令可以写成:
yolo detect train data=pcb.yaml model=yolov8n.pt epochs=100 imgsz=640 batch=16 device=0如果显存不够,可以把 batch 降到 8 或者 4。这里的关键不是一次训够 100 轮,而是先用少量轮次确认数据路径、标签格式和训练流程没问题。
增量训练的一大优势是收敛快。即便你的缺陷样本不多,模型也能从预训练权重里继承通用视觉特征。相比随机初始化,微调需要的 epoch 通常更少,也更加稳定。
2.3 训练参数和损失曲线验证
训练时不要只盯着 loss。更常见的问题是你看到 loss 在下降,但验证集 mAP 却波动很大,这大概率是过拟合或者数据集划分不合理。
训练完成后,ultralytics 会在 run 目录下生成 results.png,里面包含损失曲线、精度、召回率、mAP 等曲线图。你可以根据 loss 曲线判断:
- 如果 train loss 和 val loss 都在下降,说明训练正常。
- 如果 train loss 下降但 val loss 不再下降,说明模型开始过拟合。
- 如果验证集 mAP 一直很低,先检查数据和标签,不要急着改网络。
这里可以加一个早停策略,比如训练命令里设置patience=20,模型连续 20 个 epoch 没有提升就会自动停止,避免跑太久浪费时间。
不少同学会直接跳到“改进网络结构”,比如替换主干网络为 ConvNeXt V2,或者引入多头注意力机制 MHSA。这些手段确实可能提升精度,但前提是基线模型已经跑通,并且你清楚改动带来的显存和推理代价。如果数据量只有几百张,盲目改大网络反而容易过拟合。
2.4 导出模型:为桌面应用准备推理文件
训练得到 best.pt 后,如果打算在 PySide6 应用里直接调用,可以用 ultralytics 提供的 API。但如果考虑部署稳定性和体积,我建议导出为 ONNX:
yolo export model=best.pt format=onnx imgsz=640导出后你会得到一个 .onnx 文件。这样在桌面应用里可以只依赖 onnxruntime,不一定要装完整的 PyTorch。如果要在 CPU 上跑,还可以考虑转成 OpenVINO 格式,推理速度会更快。
导出后要做一个验证。比如用 onnxruntime 加载模型,输入一张测试图,确认输出维度是否符合预期。YOLOv8 的检测输出通常是一个一维数组,需要经过后处理转成边界框和类别。直接用 ultralytics 的 Python API 可以省掉这些后处理,但如果你想换成 onnxruntime,就要自己写后处理逻辑。
第一次做这个项目,建议先用 ultralytics 的模型对象做推理,等整体流程稳定后,再考虑换 ONNX 后端优化性能。这样能减少变量。
3. 用 PySide6 把检测能力封装成桌面应用
3.1 PySide6 环境准备
PySide6 是 Qt 的官方 Python 绑定,用来做桌面界面很合适。安装前建议单独创建一个虚拟环境,避免和系统里的包冲突。
python -m venv venv # Windows venv\Scripts\activate # Linux/macOS source venv/bin/activate pip install pyside6 ultralytics onnxruntime opencv-python一个最简单的窗口如下:
import sys from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("PCB缺陷检测工具") self.resize(1000, 700) self.button = QPushButton("选择图片", self) self.button.clicked.connect(self.select_image) def select_image(self): pass if __name__ == "__main__": app = QApplication(sys.argv) win = MainWindow() win.show() sys.exit(app.exec())这个窗口还不具备检测能力,但它已经可以运行。后续在这个基础上逐步增加图片预览、结果列表和日志框。
环境准备阶段最常见的问题不是代码,而是版本依赖。PySide6、Torch、OpenCV、NumPy 这些库之间有时会有兼容性差异。如果桌面应用启动时直接崩溃,先看是不是某个库版本太新导致对不上。建议把主要依赖版本写进 requirements.txt,以后换电脑也能复现。
3.2 界面布局:先满足核心操作流程
做界面最忌讳一上来就堆功能。对一个 PCB 缺陷检测工具来说,用户真正关心的是“选一张图,点检测,看到结果”。所以主界面可以先切成四个区域:
- 左侧操作区:选择图片、选择文件夹、置信度阈值、检测按钮。
- 中间预览区:显示原始图片和检测框。
- 右侧结果表格:列出每个检测框的类别、置信度、坐标。
- 底部日志区:记录操作和异常信息。
把核心路径跑通之后,再考虑摄像头实时预览、批量导出报告等高级功能。这个顺序能让你更快得到一个可以演示的版本,而不是开发了两周还停留在界面布局。
在 PySide6 里,可以用 QLabel 显示图片,用 QTableWidget 显示结果,用 QPlainTextEdit 显示日志。布局方面,水平布局加垂直布局足够用了。
3.3 关键点:把模型推理放到 QThread 里
这是整个桌面应用最容易出问题的地方。如果直接在按钮的槽函数里调用模型推理,点击检测后界面会卡住,因为推理是阻塞操作,GUI 事件循环被占用。解决办法是启动一个 QThread 去执行推理,通过信号把结果传回主线程。
一个简单的检测线程结构如下:
from PySide6.QtCore import QThread, Signal class DetectThread(QThread): finished_one = Signal(str, list) error = Signal(str) def __init__(self, image_path, model, conf=0.25): super().__init__() self.image_path = image_path self.model = model self.conf = conf def run(self): try: results = self.model.predict(self.image_path, conf=self.conf) boxes = results[0].boxes.data.cpu().numpy().tolist() if results[0].boxes is not None else [] self.finished_one.emit(self.image_path, boxes) except Exception as e: self.error.emit(str(e))注意 model 最好在创建这个线程之前就加载好,不要在 run() 里每次重新加载模型。否则每检测一张图都会重新读权重,速度慢而且显存可能反复分配。
信号finished_one会把图片路径和检测结果传回主线程,主线程里更新预览和表格。这样界面就不会卡死。如果你要连续检测多张图,可以用循环点击按钮,也可以把图片路径队列传给线程,在 run() 里逐个处理。
3.4 输入校验:QLineEdit 等控件的处理
很多人搜过“pyside6 qlineedit 是否输入”,这是因为用户输入不可信。比如一个 QLineEdit 用来输入图片路径,可能为空、可能路径不存在、可能后缀不对。如果不在检测前校验,程序会在某个隐蔽的地方抛异常。
可以写一个简单的校验函数:
from pathlib import Path def validate_image_path(text): if not text.strip(): return False, "输入为空" p = Path(text.strip()) if not p.exists(): return False, "路径不存在" if p.suffix.lower() not in (".jpg", ".jpeg", ".png", ".bmp"): return False, "图片格式不支持" return True, ""在点击检测按钮或对话框确定时,先调用这个函数。如果校验失败,用 QMessageBox 提示,而不是直接往下跑。除了路径,置信度阈值、批量文件夹、导出目录等输入也应该做类似校验。这不难,但能明显提升工具的可靠度。
3.5 结果可视化与简单报告
检测结果可以直接在 OpenCV 或者 PIL 中画框,然后转成 QImage 显示。也可以在 PySide6 中自绘。我更建议用 OpenCV 画框,逻辑简单,代码也少。
结果表格里至少要有图片名、类别、置信度、左上角坐标和宽高。如果一次检测没有缺陷,也要在表格中显示“无缺陷”或者留空,否则用户会以为是程序没有跑。
报告导出可以先做 CSV 格式,比如:
filename, class, confidence, x1, y1, x2, y2 pcb_001.jpg, short, 0.87, 100, 120, 160, 180 pcb_002.jpg, open, 0.65, 40, 50, 90, 120CSV 生成简单,Excel 能直接打开,后续要接入 MES 或者其他系统也容易解析。更进一步可以输出带有标注图的 PDF 报告,但这属于后期增强,不是第一版必须做的事。
4. 从单张检测到批量任务:工程化的关键拼图
4.1 批量检测策略:先跑通文件夹遍历
批量检测的核心是把“检测单张图”扩展成“遍历文件夹里所有图片”。这里建议不要一次性把所有图片读进内存,而是先用列表收集文件路径,再逐个处理。每处理完一张,就把结果显示到界面或者写入结果列表。
一个常见做法:
from pathlib import Path def collect_images(folder): exts = (".jpg", ".jpeg", ".png", ".bmp") return [p for p in Path(folder).iterdir() if p.suffix.lower() in exts]拿到文件列表后,可以在 QThread 里循环处理,每处理一张发一个信号,主线程刷新进度条或日志。如果在批量过程中用户点击取消,需要设置一个线程标志位来跳出循环。
不建议第一版就做多线程并发检测。显存有限,多个线程同时调用模型推理容易导致显存不足。单线程循环在大多数桌面应用场景里已经够用,尤其是图片数量在几百张以内时,重点是把流程跑稳,而不是追求速度。
4.2 日志与异常处理
桌面工具里到处是 print 会让问题极难定位。建议使用 Python 的 logging 模块,把日志同时输出到控制台和文件。
import logging logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s", handlers=[ logging.FileHandler("pcb_detector.log", encoding="utf-8"), logging.StreamHandler() ] )日志里建议记录:时间、图片路径、检测框数量、耗时、具体异常内容。这样如果同事跑了一百张图后出现一次错误,你还能从日志里找到是哪一张图导致的。
批量处理时,单个图片解码失败、读取权限不足、推理返回空结果,这些异常都不应该中断整个任务。更合理的做法是在循环里捕获异常,记录日志后继续处理下一张:
for img_path in image_list: try: detect_and_save(img_path) except Exception as e: logging.error(f"处理 {img_path} 失败: {e}") continue这样用户能看到整体进度,而不是因为一张坏图导致后面全部停掉。
4.3 性能优化:显存、速度和硬件选择
如果你的开发机是 GTX 1660 Ti 这种 6GB 显存显卡,跑 YOLOv8n 或者 YOLOv8s 是现实的。但要注意别把 batch 和 imgsz 同时拉高。有一类问题很典型:模型能跑,导出的 ONNX 也能跑,但一放进 QThread 批量检测就显存溢出,这通常是因为推理时每次加载新图片都保留了旧结果。
推理循环里要及时释放中间变量。使用 ultralytics 预测时,结果对象会持有处理后的图像数据,处理完后尽快清理或者在循环外统一管理。如果显存还是吃紧,可以降低 imgsz,或者从 YOLOv8s 换成 YOLOv8n。
如果目标是 CPU 推理,建议把模型导出为 OpenVINO 格式。CPU 上跑 ONNX Runtime 已经比纯 PyTorch 快,但 OpenVINO 在 Intel CPU 上通常更有优势。这里需要根据你的部署环境测试,不要听别人说“一定快”就盲目切换。
性能调优有一个顺序:先保证结果正确,再考虑速度;先单张验证,再批量测试;先测 CPU 推理,再考虑 GPU 加速。倒过来会很难排查问题。
4.4 打包分发:把应用交给同事
PySide6 应用通常可以用 PyInstaller 打包成 exe 或者 Linux 可执行文件。打包思路如下:
pip install pyinstaller pyinstaller -D main.py建议先生成目录模式,不要一上来就--onefile。目录模式启动更快,也更容易排查缺失的资源文件。把训练好的模型文件放在资源目录里,打包时通过--add-data带进去。
常见打包坑包括:
- ultralytics 或 onnxruntime 被漏掉,运行时报 ModuleNotFoundError。
- 模型资源文件路径写死,导致换电脑后找不到。
- 打包后的路径包含中文,可能导致 OpenCV 无法读取文件。
- 杀毒软件误报。
这些问题没有统一的完美解,只能根据报错逐项排查。我的建议是不要追求一次打包成功,先打一个最小 demo,确认主窗口能打开,再逐步加入模型推理和批量检测。
5. 常见问题排查:从报错到不稳定输出
5.1 先看现象,再看输入
桌面检测工具出问题时,容易一上来就怀疑模型。实际上很多问题出在输入环节。排查顺序应该是这样:
- 复现问题:用同一张图、同一个参数,确认是稳定问题还是偶发问题。
- 检查输入:图片路径是否存在,格式是否支持,文件是否损坏。
- 检查环境:Python 版本、依赖版本、CUDA 是否可用。
- 检查参数:置信度阈值、图像尺寸、batch 是否合理。
- 检查工具边界:模型是否匹配当前界面代码,导出格式是否兼容。
举个例子,如果所有图片都检测不到框,先不要急着提高置信度阈值或者重训模型,先用命令行单独调用模型,确认模型本身能输出结果。如果命令行正常,那问题大概率在界面传参或者图像读取环节。
5.2 环境与依赖版本冲突
你可能会遇到 torch 和 ultralytics 版本不匹配、opencv-python 和 opencv-contrib-python 同时安装导致的崩溃、PySide6 和 NumPy 版本冲突等问题。解决办法是使用独立虚拟环境,并锁住主要依赖版本。
出现环境相关报错时,第一时间看完整堆栈。很多时候错误信息里已经写明是某个库的 API 不存在或者 DLL 加载失败。如果某个库升级后出现异常,可以回退到项目初期记录的版本。
5.3 推理结果异常:无框、低置信度、错检
推理结果异常通常分三种:
- 完全没有检测框:检查 conf 阈值是否太高,或输入图片尺寸偏离训练尺寸太多。
- 置信度普遍很低:可能是数据分布不一致,比如训练数据都是板面朝上,实际检测时有旋转和反光。
- 检测框位置正确但类别混淆:先检查类别 ID 是否对应,再检查训练样本是否平衡。
遇到这种情况,我会把异常图片收集到一个 badcase 文件夹,然后重新跑一遍模型,导出每张图的置信度和坐标,再人工分析。不要靠肉眼猜,要拿数据说话。
如果只想提高模型精度,可以考虑网络结构改进,比如替换主干网络或引入多头注意力机制。但这类操作更适合在有标注数据充足、基线稳定之后再做。从经验看,多数精度问题不是网络不够强,而是标注噪声和数据量太少。
5.4 界面卡死与崩溃
如果点击检测后窗口直接无响应,基本可以确定推理跑在了 GUI 线程。解决办法就是把推理移到 QThread。另一种情况是界面卡一下然后恢复,可能是图像转 QImage 或显示逻辑太慢,这时要检查是不是把大图直接塞给 QLabel,没做缩放。
程序崩溃时,先看日志和系统事件。如果是在 GPU 推理时崩溃,先看显存占用。很多时候显存不足不会立刻报错,而是在某次分配显存时崩溃。降低 batch、缩小 imgsz,或者改用 CPU 推理,都能缓解。
5.5 一个排查表
| 现象 | 优先排查项 |
|---|---|
| 界面无响应 | 推理是否在 QThread 中执行 |
| 点击检测无输出 | 图片路径、模型文件路径、conf 阈值 |
| 批量处理中断 | 某张图片损坏、日志是否捕获异常 |
| 打包后启动失败 | 资源路径、缺模块、Python 版本 |
| 推理很慢 | 是否用 GPU、模型是否过大、是否导出 ONNX |
排查问题不一定要按表格顺序执行,但至少要有一个清晰的定位思路。最怕的是东改一个参数、西改一个依赖,最后问题依旧。
6. 把一次项目沉淀成可复用能力
6.1 一个可复用的工程流程框架
结合前面的内容,我总结了一个适合 PCB 缺陷检测桌面工具的五步流程:
- 数据盘点:明确缺陷类型、样本数量、标注格式。
- 基线训练:用 YOLOv8n/YOLOv5s 训练一个可用的模型,确认 loss 和 mAP 正常。
- 接口封装:写一个独立于界面的推理接口,输入图片,输出检测结果。
- 桌面集成:用 PySide6 封装界面,把推理放到子线程,支持单图和文件夹。
- 打包验证:打包后在一台干净电脑上测试,确认资源文件、日志和异常处理正常。
每一步都有一个完成标准。比如“接口封装”这步,标准是命令行调用能够稳定输出一张图的结果;桌面集成这步,标准是点击检测不会卡死。没有完成标准就进入下一步,后面返工成本会很高。
6.2 从个人工具到产线工具的边界
这套方案再完善,也只是把模型和界面做成了一个桌面工具。真正进入产线后,你还需要考虑光源亮度、相机曝光、触发信号、传送带速度、PLC 联动、数据上报和报警机制。那些问题已经不是“模型”范畴,而是“系统集成”范畴。
所以不要承诺“可以替代 AOI”。更合适的说法是:这套工具可以作为 AOI 的辅助复检,或者作为算法验证平台。把边界说清楚,不仅是对项目负责,也是对自己的劳动成果负责。
6.3 下一步:先做最小可用版本
如果你正准备开始做这类项目,我的建议是先从“选择一张图片,点击检测,看到检测框”开始。不要第一版就想着摄像头实时检测、多线程并发、批量导出 PDF 报告。先把最小闭环跑通,再逐步增加功能。
反过来,如果你已经训练好了模型,只是还没做界面,那现在最该做的是先写一个 QThread 推理示例,把单张图检测跑通。这个稳定以后,批量检测只是加一个循环,打包分发只是加一个配置。真正决定项目成败的,是基础链路是否可靠。
这个项目的价值不在于某一项技术有多厉害,而在于它把“YOLO 检测模型”和“桌面软件工具”连接了起来。一旦连接成立,后续每次模型迭代、数据扩充、界面优化,都能在一个可复现的流程里进行。先跑通一张图,再谈其他。