YOLO模型对比与LLM集成:构建鲁棒疲劳驾驶识别系统实践指南
在实际的智能驾驶和工业安全监控场景中,疲劳驾驶识别是一个典型且关键的计算机视觉应用。单纯依赖单一的目标检测模型,往往难以应对复杂多变的真实环境,例如光照变化、驾驶员姿态多样、遮挡以及模型对不同疲劳特征(如闭眼、打哈欠、低头)的敏感度差异。因此,对比和集成多个先进的YOLO模型(如v8、v10、v11、v12),并结合大语言模型(LLM)进行逻辑判断与报告生成,构成了一个更鲁棒、更智能的全栈解决方案。本文面向有一定Python和深度学习基础的开发者,旨在提供一个从模型选型、环境搭建、数据集处理、多模型训练与评估,到集成LLM进行后处理分析的完整实践指南。通过本文,你将能够构建一个可本地部署、具备模型对比能力和智能分析功能的疲劳驾驶识别原型系统。
1. 理解疲劳驾驶识别的技术栈与模型选型
疲劳驾驶识别本质上是一个多目标检测与行为分析任务。其技术栈通常分为三层:感知层、分析层和应用层。感知层负责从图像或视频流中定位出人脸、眼睛、嘴巴等关键区域;分析层则基于这些区域的特征(如眼睛闭合时间、嘴巴张开频率、头部姿态)判断疲劳状态;应用层负责告警、日志记录或与上层系统交互。
1.1 为什么选择YOLO系列模型作为感知层核心
YOLO(You Only Look Once)系列因其在速度与精度间的出色平衡,成为实时目标检测的首选。对于疲劳驾驶识别,我们需要快速、准确地检测出“人脸”、“左眼”、“右眼”、“嘴巴”等小目标。不同版本的YOLO在骨干网络、检测头、训练策略上各有优化:
- YOLOv8: 提供了成熟的分类、检测、分割任务支持,社区生态丰富,文档和预训练模型齐全,是快速验证和部署的稳妥起点。
- YOLOv10: 官方宣称在延迟和精度上做了进一步优化,可能引入了更高效的网络架构或训练技巧,适合对推理速度有极致要求的边缘设备。
- YOLOv11: 作为社区驱动的改进版本,可能集成了多种有效的trick,如新的注意力机制、损失函数或数据增强方法,适合追求更高精度的场景。
- YOLOv12: 通常代表该系列的最新进展,可能包含前述版本优点的集大成以及一些前沿探索,但稳定性和社区支持可能尚在完善中。
在项目初期,同时对比多个模型版本的表现(如mAP、推理速度、资源占用)是做出正确技术选型的关键,而不是盲目追求最新版本。
1.2 大语言模型在分析层的角色:从检测到理解
传统的疲劳判定算法基于硬编码规则,例如PERCLOS(眼睑闭合时间占特定周期的百分比)。这种方式缺乏灵活性和上下文理解能力。集成大语言模型(如Qwen、DeepSeek)可以带来以下提升:
- 多特征融合推理:LLM可以接收一段时间内多个检测目标(眼睛状态、嘴巴状态、头部角度)的序列数据,综合判断疲劳程度,模拟更接近人类的推理过程。
- 生成式报告:不仅输出“疲劳”或“正常”的标签,还能生成自然语言描述,如“驾驶员在过去30秒内频繁闭眼,且伴有3次打哈欠动作,建议立即休息”。
- 处理不确定性:当检测结果存在冲突或噪声时(如部分遮挡导致一只眼睛检测失败),LLM可以基于历史信息和常识进行合理推断。
在本实践中,我们将使用量化后的轻量级LLM进行本地部署,确保系统在无网络环境下也能运行,并保护数据隐私。
2. 环境准备与依赖配置
一个清晰、隔离的环境是复现复杂项目的基础。我们将使用Conda管理Python环境,并明确所有核心依赖的版本。
2.1 创建并激活Conda环境
# 创建名为 fatigue-detection 的Python 3.9环境 conda create -n fatigue-detection python=3.9 -y conda activate fatigue-detection选择Python 3.9是因为它在稳定性与对新库的支持上取得了较好的平衡,与主流深度学习框架兼容性好。
2.2 安装核心深度学习框架与工具
# 安装PyTorch(请根据你的CUDA版本访问官网获取对应命令) # 例如,对于CUDA 11.8 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # 安装Ultralytics YOLO库,这是管理YOLOv8/v10/v11等模型的核心 pip install ultralytics # 安装OpenCV用于图像处理 pip install opencv-python-headless # 安装Transformers库用于加载和使用大语言模型 pip install transformers # 安装其他工具库 pip install pandas matplotlib seaborn scikit-learn注意:PyTorch的安装命令必须与你的显卡驱动和CUDA版本匹配。可以通过
nvidia-smi命令查看CUDA版本。如果使用CPU,则安装CPU版本的PyTorch。
2.3 项目目录结构规划
一个良好的目录结构有助于管理代码、数据、模型和实验结果。
fatigue_detection_project/ ├── data/ │ ├── raw/ # 原始视频或图片 │ ├── images/ # 处理后的图像(训练/验证/测试集) │ ├── labels/ # 对应的YOLO格式标签 │ └── dataset.yaml # YOLO数据集配置文件 ├── models/ │ ├── yolov8n.pt # 预训练的YOLOv8模型 │ ├── yolov10n.pt # 预训练的YOLOv10模型 │ └── llm/ # 本地大语言模型文件 ├── scripts/ │ ├── prepare_dataset.py # 数据集预处理脚本 │ ├── train.py # 模型训练脚本 │ ├── evaluate.py # 模型评估与对比脚本 │ └── inference_llm.py # 集成LLM的推理脚本 ├── outputs/ │ ├── train/ # 各模型训练日志和权重 │ │ ├── yolov8/ │ │ ├── yolov10/ │ │ └── ... │ └── evaluation/ # 评估结果、图表 ├── configs/ # 各模型的配置文件(如yolov10的yaml) └── README.md3. 数据集准备与YOLO格式转换
疲劳驾驶识别需要标注好的数据集。公开数据集如NTHU-DDD、YawDD等可供研究使用。这里我们以自制数据集流程为例。
3.1 数据标注与YOLO格式
YOLO格式的标签文件(.txt)与图像文件同名,每行代表一个标注对象,格式为:<class_id> <x_center> <y_center> <width> <height>坐标和宽高均进行了归一化(除以图像宽度和高度)。
假设我们的类别定义为:
0: face 1: left_eye 2: right_eye 3: mouth3.2 创建dataset.yaml配置文件
在data/dataset.yaml中定义数据集路径和类别。
# 数据集配置文件 path: ../data # 数据集根目录 train: images/train # 训练集图像相对路径 val: images/val # 验证集图像相对路径 test: images/test # 测试集图像相对路径(可选) # 类别数量与名称 nc: 4 names: ['face', 'left_eye', 'right_eye', 'mouth']3.3 使用脚本划分数据集
编写scripts/prepare_dataset.py来随机划分训练集、验证集和测试集,并生成对应的路径列表。
import os import random import shutil from pathlib import Path def split_dataset(image_dir, label_dir, train_ratio=0.7, val_ratio=0.2, test_ratio=0.1): """ 划分YOLO格式的数据集 """ image_paths = list(Path(image_dir).glob('*.jpg')) + list(Path(image_dir).glob('*.png')) random.shuffle(image_paths) total = len(image_paths) train_end = int(total * train_ratio) val_end = train_end + int(total * val_ratio) train_images = image_paths[:train_end] val_images = image_paths[train_end:val_end] test_images = image_paths[val_end:] # 创建目标目录 splits = {'train': train_images, 'val': val_images, 'test': test_images} for split_name, imgs in splits.items(): (Path(image_dir) / split_name).mkdir(parents=True, exist_ok=True) (Path(label_dir) / split_name).mkdir(parents=True, exist_ok=True) for img_path in imgs: # 移动图片 shutil.copy(img_path, Path(image_dir) / split_name / img_path.name) # 移动对应标签 label_path = Path(label_dir) / (img_path.stem + '.txt') if label_path.exists(): shutil.copy(label_path, Path(label_dir) / split_name / label_path.name) print(f"数据集划分完成:训练集 {len(train_images)},验证集 {len(val_images)},测试集 {len(test_images)}") if __name__ == '__main__': split_dataset('data/raw/images', 'data/raw/labels')4. 多版本YOLO模型训练与深度对比
我们将使用Ultralytics框架统一训练YOLOv8和YOLOv10。对于YOLOv11/v12,可能需要从其官方仓库克隆代码并适配。
4.1 训练YOLOv8模型
Ultralytics提供了非常简洁的API进行训练。
# scripts/train_yolov8.py from ultralytics import YOLO def train_yolov8(): # 加载预训练模型(例如yolov8n.pt) model = YOLO('models/yolov8n.pt') # 开始训练 results = model.train( data='data/dataset.yaml', epochs=100, imgsz=640, batch=16, workers=4, project='outputs/train', name='yolov8n_fatigue', save=True, save_period=10, pretrained=True ) if __name__ == '__main__': train_yolov8()4.2 训练YOLOv10模型
YOLOv10的训练方式与v8类似,但需要指定正确的模型文件。
# scripts/train_yolov10.py from ultralytics import YOLO def train_yolov10(): # 注意:需要先下载YOLOv10的预训练权重,例如yolov10n.pt model = YOLO('models/yolov10n.pt') results = model.train( data='data/dataset.yaml', epochs=100, imgsz=640, batch=16, project='outputs/train', name='yolov10n_fatigue', # YOLOv10可能有其特定的参数,需参考其官方文档 ) if __name__ == '__main__': train_yolov10()4.3 关键训练参数解析与常见调整
训练过程中的参数调整直接影响模型性能。下表列出了核心参数及其影响:
| 参数 | 含义 | 常见值/调整建议 | 对训练的影响 |
|---|---|---|---|
epochs | 训练轮数 | 50-300 | 轮数太少欠拟合,太多可能过拟合。监控训练/验证损失曲线决定。 |
imgsz | 输入图像尺寸 | 640, 1280 | 尺寸越大,精度可能越高,但显存消耗和速度越慢。需与数据集原始分辨率匹配。 |
batch | 批次大小 | 8, 16, 32 | 受显存限制。较大的batch通常使训练更稳定,但可能降低泛化能力。 |
workers | 数据加载线程数 | 4, 8 | 提高CPU利用率,加速数据加载。但过多可能导致内存问题。 |
lr0 | 初始学习率 | 0.01, 0.001 | 最重要的超参数之一。太大导致震荡不收敛,太小收敛慢。通常从默认值开始。 |
weight_decay | 权重衰减 | 0.0005 | 防止过拟合的正则化项。 |
cos_lr | 使用余弦退火学习率 | True/False | 启用后,学习率按余弦曲线下降,有助于模型跳出局部最优。 |
label_smoothing | 标签平滑 | 0.0-0.1 | 减轻过拟合,提高模型校准度。 |
4.4 模型评估与对比分析
训练完成后,需要在独立的测试集上评估各模型性能。Ultralytics提供了val方法。
# scripts/evaluate_models.py from ultralytics import YOLO import pandas as pd import matplotlib.pyplot as plt def evaluate_model(model_path, data_yaml): model = YOLO(model_path) metrics = model.val(data=data_yaml, split='test', save_json=True) # 保存JSON结果以便分析 # metrics是一个对象,包含mAP50, mAP50-95, precision, recall等 return { 'model': model_path.stem, 'mAP50': metrics.box.map50, 'mAP50-95': metrics.box.map, 'precision': metrics.box.p, 'recall': metrics.box.r, 'inference_time(ms)': metrics.speed['inference'] } if __name__ == '__main__': model_paths = [ Path('outputs/train/yolov8n_fatigue/weights/best.pt'), Path('outputs/train/yolov10n_fatigue/weights/best.pt'), # 添加v11, v12的路径 ] results = [] for mp in model_paths: if mp.exists(): results.append(evaluate_model(mp, 'data/dataset.yaml')) # 将结果转为DataFrame并保存 df_results = pd.DataFrame(results) df_results.to_csv('outputs/evaluation/model_comparison.csv', index=False) print(df_results) # 绘制对比柱状图 df_results.plot(x='model', y=['mAP50', 'mAP50-95'], kind='bar') plt.title('Model Performance Comparison (mAP)') plt.tight_layout() plt.savefig('outputs/evaluation/mAP_comparison.png')评估指标解读:
- mAP50: 在IoU阈值为0.5时的平均精度均值,是衡量检测准确性的核心指标。
- mAP50-95: 在IoU阈值从0.5到0.95(步长0.05)的平均mAP,更严格,衡量定位精度。
- Precision (精确率): 模型预测为正的样本中,真正为正的比例。
TP / (TP + FP)。 - Recall (召回率): 所有真实为正的样本中,被模型正确预测为正的比例。
TP / (TP + FN)。 - 推理时间: 单张图片的平均推理耗时,决定实时性。
5. 集成大语言模型进行疲劳状态分析与报告生成
在获得高精度的检测结果后,我们需要将连续的检测帧序列转化为疲劳状态判断。这里我们使用本地部署的轻量级LLM(以Qwen1.5-1.8B-Chat为例)来完成时序推理。
5.1 准备本地大语言模型
使用Hugging Face的Transformers库加载量化后的模型,以节省显存。
# scripts/load_llm.py from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline import torch def load_local_llm(model_path="Qwen/Qwen1.5-1.8B-Chat-GPTQ-Int4"): """ 加载本地或下载的量化LLM。 model_path可以是Hugging Face模型ID,也可以是本地路径。 """ tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) # 对于量化模型,可能需要指定device_map和量化配置 model = AutoModelForCausalLM.from_pretrained( model_path, device_map="auto", # 自动分配设备(CPU/GPU) torch_dtype=torch.float16, # 使用半精度 trust_remote_code=True ) # 创建文本生成管道 pipe = pipeline( "text-generation", model=model, tokenizer=tokenizer, max_new_tokens=512, temperature=0.1, # 低温度使输出更确定 do_sample=True ) return pipe llm_pipe = load_local_llm()5.2 构建时序特征并生成LLM提示词
我们需要从一段连续的视频帧(例如10秒,30fps共300帧)的YOLO检测结果中,提取时序特征。
# scripts/inference_llm.py import json from collections import deque class FatigueAnalyzer: def __init__(self, llm_pipe, window_size=300): # 10秒窗口 self.llm = llm_pipe self.window_size = window_size self.detection_history = deque(maxlen=window_size) # 存储历史检测结果 def update_detection(self, frame_results): """ frame_results: 单帧的检测结果列表,每个元素为 [class_id, confidence, x1, y1, x2, y2] """ # 简化处理:记录每帧中每个类别的最高置信度检测结果(或是否存在) frame_summary = { 'face': any(r[0]==0 for r in frame_results), 'left_eye_open': any(r[0]==1 and r[1]>0.5 for r in frame_results), # 置信度>0.5认为睁眼 'right_eye_open': any(r[0]==2 and r[1]>0.5 for r in frame_results), 'mouth_open': any(r[0]==3 and r[1]>0.7 for r in frame_results), # 嘴巴张开阈值可调 } self.detection_history.append(frame_summary) def analyze_fatigue(self): if len(self.detection_history) < self.window_size: return "Insufficient data for analysis." # 计算窗口内的统计特征 history_list = list(self.detection_history) eye_close_ratio = 1.0 - (sum([f['left_eye_open'] and f['right_eye_open'] for f in history_list]) / len(history_list)) yawn_count = sum([f['mouth_open'] for f in history_list]) # 可以加入头部姿态估计的低头频率等 # 构建LLM提示词 prompt = f""" 你是一个专业的驾驶员状态分析系统。请根据以下传感器数据判断驾驶员是否疲劳,并给出简要报告。 数据窗口:最近10秒(300帧)。 特征统计: - 双眼同时闭合的帧数比例:{eye_close_ratio:.2%} (PERCLOS近似值)。 - 打哈欠(嘴巴张开)次数:{yawn_count}。 - 面部持续可检测:{'是' if all(f['face'] for f in history_list) else '否'}。 请按以下格式输出JSON: {{ "fatigue_level": "low/medium/high", // 疲劳等级 "reason": "分析原因,例如:PERCLOS值较高,且伴有频繁哈欠。", "suggestion": "具体建议,例如:建议立即停车休息。" }} 只输出JSON,不要有其他文字。 """ # 调用LLM生成分析 response = self.llm(prompt)[0]['generated_text'] # 尝试从响应中提取JSON try: # 清理响应,找到第一个'{'和最后一个'}' start = response.find('{') end = response.rfind('}') + 1 json_str = response[start:end] analysis = json.loads(json_str) except (json.JSONDecodeError, ValueError) as e: analysis = {"error": f"Failed to parse LLM response: {e}", "raw_response": response} return analysis # 使用示例 analyzer = FatigueAnalyzer(llm_pipe) # 模拟连续检测更新 for frame_idx in range(500): # 假设detect_frame是调用YOLO模型检测单帧的函数 # frame_dets = detect_frame(frame) # analyzer.update_detection(frame_dets) if frame_idx % 300 == 299: # 每10秒分析一次 result = analyzer.analyze_fatigue() print(f"Frame {frame_idx}: {result}")5.3 系统集成与可视化
将YOLO检测流水线与LLM分析器结合,并利用OpenCV实现实时视频流处理与可视化。
# scripts/real_time_detection.py import cv2 from ultralytics import YOLO from inference_llm import FatigueAnalyzer, load_local_llm def main(): # 1. 加载最佳YOLO模型 detector = YOLO('outputs/train/yolov8n_fatigue/weights/best.pt') # 2. 加载LLM分析器 llm_pipe = load_local_llm() analyzer = FatigueAnalyzer(llm_pipe, window_size=150) # 使用5秒窗口提高实时性 # 3. 打开摄像头或视频文件 cap = cv2.VideoCapture(0) # 0为默认摄像头,或替换为视频文件路径 while cap.isOpened(): ret, frame = cap.read() if not ret: break # 4. YOLO检测 results = detector(frame, verbose=False)[0] # 单张图片推理 detections = [] for box in results.boxes: cls_id = int(box.cls[0]) conf = float(box.conf[0]) xyxy = box.xyxy[0].tolist() detections.append([cls_id, conf] + xyxy) # 在图像上画框 label = f"{results.names[cls_id]} {conf:.2f}" cv2.rectangle(frame, (int(xyxy[0]), int(xyxy[1])), (int(xyxy[2]), int(xyxy[3])), (0,255,0), 2) cv2.putText(frame, label, (int(xyxy[0]), int(xyxy[1])-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 2) # 5. 更新分析器 analyzer.update_detection(detections) # 6. 定期分析并显示结果(例如每秒一次) # 这里简化处理,实际可按帧数或时间触发 current_time = cv2.getTickCount() / cv2.getTickFrequency() if hasattr(main, 'last_analysis_time'): if current_time - main.last_analysis_time > 1.0: # 每秒分析一次 analysis = analyzer.analyze_fatigue() if 'fatigue_level' in analysis: fatigue_text = f"Fatigue: {analysis['fatigue_level']}" cv2.putText(frame, fatigue_text, (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2) main.last_analysis_time = current_time else: main.last_analysis_time = current_time # 7. 显示画面 cv2.imshow('Fatigue Detection', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows() if __name__ == '__main__': main()6. 常见问题排查与性能优化
在实践过程中,你可能会遇到以下典型问题。
6.1 模型训练与评估阶段问题
| 问题现象 | 可能原因 | 检查与解决思路 |
|---|---|---|
| 训练损失不下降或为NaN | 学习率过高;数据标注错误;数据未归一化;批次大小太大导致梯度爆炸。 | 1. 降低学习率(如从0.01降至0.001)。 2. 检查数据集yaml文件路径是否正确。 3. 可视化部分标注,确认边界框是否合理。 4. 减小批次大小,或使用梯度裁剪。 |
| 验证集mAP很低,但训练集损失正常 | 严重过拟合;验证集与训练集分布差异大;数据泄露(验证集参与了训练)。 | 1. 增加数据增强(如mosaic, mixup)。 2. 使用更小的模型或增加正则化(weight_decay, dropout)。 3. 确保训练/验证集划分是随机的,且无交集。 4. 检查验证集图片是否损坏或格式异常。 |
| 推理速度慢 | 模型过大(如用了YOLOv8x);输入图像尺寸过大;未使用GPU或GPU驱动有问题。 | 1. 换用更小的模型(如YOLOv8n, YOLOv10n)。 2. 减小推理时的 imgsz参数(如从640降至320)。3. 确认 torch.cuda.is_available()为True,并使用model.to('cuda')。 |
| 某个类别(如“左眼”)检测精度极差 | 该类别样本数量严重不足;标注质量差;目标尺寸太小。 | 1. 检查数据集中该类别的实例数量,进行数据增强或收集更多数据。 2. 使用更小的锚框(Anchor)或专门针对小目标的检测头改进。 3. 尝试在损失函数中为该类别增加权重。 |
6.2 LLM集成与系统运行问题
| 问题现象 | 可能原因 | 检查与解决思路 |
|---|---|---|
| LLM加载失败或显存不足 | 模型文件损坏;量化版本不兼容;显存不够。 | 1. 重新下载模型文件,或尝试不同的量化版本(如Int8, GPTQ)。 2. 使用CPU运行LLM( device_map='cpu'),但速度会慢很多。3. 使用更小的LLM(如Qwen1.5-0.5B)。 |
| LLM响应格式不符合预期 | 提示词(Prompt)设计不清晰;模型未进行指令微调。 | 1. 在提示词中明确要求输出格式(如JSON),并给出示例。 2. 对输出进行后处理,使用正则表达式提取JSON部分。 3. 考虑使用支持工具调用的LLM,或进行简单的微调。 |
| 系统延迟高,无法实时 | YOLO和LLM串行运行,LLM推理耗时过长;视频解码消耗CPU资源。 | 1. 将LLM分析改为异步进行,例如每N帧或每间隔一段时间分析一次,不阻塞主检测线程。 2. 使用多进程或线程,将视频I/O、检测、分析分离。 3. 考虑使用C++或TensorRT加速YOLO推理。 |
| 疲劳判断不准 | YOLO检测框抖动导致时序特征噪声大;LLM提示词中的特征统计方法不合理。 | 1. 对YOLO检测结果进行简单的轨迹平滑(如卡尔曼滤波)。 2. 调整特征统计的窗口大小和阈值(如眼睛闭合的置信度阈值)。 3. 在提示词中加入更详细的领域知识,或收集数据对LLM进行微调。 |
6.3 生产环境部署考量
当系统从原型走向实际部署时,需要关注以下方面:
- 模型服务化:将YOLO检测模型和LLM封装为独立的API服务(如使用FastAPI),便于水平扩展和版本管理。
- 资源监控:监控GPU显存、CPU使用率、推理延迟等指标,设置告警阈值。
- 日志与追溯:记录每一帧的检测结果、分析结论和原始图像(可脱敏),便于问题回溯和模型迭代。
- 模型更新:设计一套流程,能够安全地更新YOLO或LLM模型,并进行A/B测试。
- 数据隐私:确保所有处理在本地或私有云完成,敏感视频数据不出域。
7. 扩展方向与最佳实践
基于当前系统,可以从以下几个方向进行深化和优化:
- 引入更多模态数据:除了视觉信息,可以集成方向盘握力、车辆轨迹、心率等传感器数据,输入LLM进行多模态融合判断,提高准确性。
- 自定义LLM微调:收集高质量的“检测特征序列-疲劳等级”配对数据,对轻量级LLM进行监督微调(SFT),使其更擅长疲劳判断任务。
- 模型蒸馏与量化:将大型YOLO模型(如v8x)的知识蒸馏到更小的模型(如v8n),或对LLM进行更激进的量化(如AWQ, GGUF),以适配资源受限的边缘设备(如Jetson Orin, RK3588)。
- 设计更鲁棒的特征工程:PERCLOS是经典指标,但可以结合眨眼频率、眨眼持续时间、目光游离度等更精细的特征,构建更强大的特征向量再输入LLM。
- 实现端到端训练探索:这是一个更前沿的方向,尝试将目标检测网络与一个轻量级时序推理网络(如LSTM+Attention)进行端到端联合训练,可能获得比两阶段流水线更好的性能。
在实践过程中,一个核心的最佳实践是持续迭代和验证。不要期望第一个版本的模型和规则就是最优的。建立一套从数据收集、标注、训练、评估到在线测试的完整闭环,用实际场景的数据不断驱动系统优化。先从一个小而精的数据集和简单的规则+LLM分析开始,验证流程跑通,再逐步增加数据复杂度和模型复杂度。
