news 2026/9/24 23:17:10

COCO转YOLOv8训练商店偷窃检测:从标注到部署全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
COCO转YOLOv8训练商店偷窃检测:从标注到部署全指南

简介:面向安防与零售场景的商店偷窃行为识别数据集资源,主要服务于计算机视觉算法工程师、研究人员及安防应用开发者,用于解决监控视频中偷窃行为的自动检测与识别问题。数据集中包含从原始视频中抽取的8395张真实场景图像,统一采用COCO格式进行标注,可直接用于目标检测、姿态估计等任务的模型训练与效果验证,兼顾素材规模与标注质量。压缩包内共2000个文件,以1995张jpg图像为主体,图像来自视频帧截取;另外包含3个json标注文件和2个txt辅助说明文件,用于标签映射、数据划分等用途,包体总大小约455.58MB,结构清晰便于直接接入主流深度学习框架。当前资源已有545人浏览学习,具备一定的应用参考价值。数据整体在商店偷窃行为识别上的平均准确率达到98.6%,说明标注质量与场景覆盖较为可靠。对于需要训练识别模型、验证算法性能或搭建零售安防系统的开发者,这份数据集能够提供扎实的数据基础与标注支撑。

1. 商店偷窃行为识别数据集:8395张COCO标注图,从监控帧到训练闭环

如果你做过监控视频里的行为识别,一定知道最耗时间的不是调模型,而是凑数据。商店偷窃(shoplifting)这类场景尤其难搞:公开数据集少、授权敏感、真实监控画面又往往模糊、遮挡严重。这个数据集把 8395 张原始图片统一标成了 COCO 格式,等于把最脏的活先干完了。宣称的平均准确率 98.6% 听起来很漂亮,但我不建议你直接拿这个数字当交付标准,更值得关注的是它背后的标注结构和训练闭环。适合谁用?想快速验证检测方案、做行为识别落地实验的算法工程师和研究生,以及刚接触目标检测、需要一份干净 COCO 数据练手的入门者。这篇文章会把 COCO 标注拆开、给出训练和评估的完整步骤,再把帧序列、类别不平衡这些坑一个个说清楚。

2. 拆解 COCO 标注:从 JSON 结构到数据质量检查

2.1 COCO 格式核心字段与这个数据集的标注语义

COCO 格式并不是一套“文件夹里有图和 txt”的简化约定,它用单个 JSON 文件承载全部标注信息。标准的 annotations 结构包含 info、licenses、images、annotations、categories 五部分。images 里每一行是一条图片记录,annotations 里每一条对应一个目标框,categories 则定义了类别 ID 到名称的映射。很多从 Roboflow 导出的数据集会在 info 里带上导出时间、版本号,文件名里也会保留来源视频的痕迹,比如 Shoplifting034_x264-mp4_8473_jpg 这种命名,说明这张图是从 id 为 034 的视频第 8473 帧截出来的。理解这一点对后续划分训练集和验证集非常重要,因为同一个视频的相邻帧非常相似,直接随机划分会造成数据泄漏,后面我会专门讲。

这个数据集的核心用途是“商店偷窃行为识别”,但 COCO 格式本身是目标检测的通用格式,所以它做的是“检测”而非“行为分类”。在拿到数据后,第一件事不是急着训练,而是确认 categories 里到底定义了几类。常见的设计有两种:一种只框“偷窃行为发生时的关键物体”(比如顾客手部、商品),另一种会同时标注“人”和“商品”,再结合时序逻辑判断动作。从文件名和标注来源看,它倾向于把视频帧作为独立图片处理,逐帧给出边界框。无论类别设计是哪一种,都要在训练前统一类别 ID,否则后续转 YOLO 格式会乱套。

2.2 写个 Python 脚本检查标注质量:类别分布、框面积和越界框

我一般拿到 COCO 数据集后,不会先看图片,而是先跑一遍全面体检。下面这个脚本可以输出类别数量、每类目标数、边界框面积分布、以及越界框数量。它不依赖任何深度学习框架,只要装了 pycocotools 或者纯 json 解析就能跑。

import json from collections import Counter # 指向数据集里的标注文件,按实际路径改 with open('annotations/instances_train.json', 'r', encoding='utf-8') as f: coco = json.load(f) # 构建 img_id 到图片元数据的映射 id_to_img = {img['id']: img for img in coco['images']} # 构建 category_id 到名称的映射 id_to_cat = {cat['id']: cat['name'] for cat in coco['categories']} cat_counter = Counter() area_list = [] invalid_box = 0 # 越界框计数 for ann in coco['annotations']: cat_id = ann['category_id'] cat_counter[id_to_cat[cat_id]] += 1 x, y, w, h = ann['bbox'] # COCO bbox 格式是 [x, y, width, height] area_list.append(w * h) # 拿到对应图片的宽高,判断框是否超出边界 img_info = id_to_img[ann['image_id']] iw, ih = img_info['width'], img_info['height'] if x < 0 or y < 0 or x + w > iw or y + h > ih: invalid_box += 1 # 每类目标数量 print('类别统计:') for name, cnt in cat_counter.most_common(): print(f' {name}: {cnt}') print(f'平均框面积: {sum(area_list) / len(area_list):.1f} 平方像素') print(f'越界框数量: {invalid_box}')

这段脚本里最值得注意的就是越界框检测。COCO 官方标注严格规定 bbox 不能超出图片边界,但半自动标注工具导出的数据经常出现 x + w 超过图片宽度 1~2 个像素的情况。检测阶段这类框影响不大,训练阶段却会产生错误的 anchor 匹配,尤其使用 YOLO 系列时可能直接报错。另外,面积分布能告诉你这个数据集是“大目标为主”还是“小目标密集”。如果平均框面积只有几百平方像素,而图片是 1280×720 的监控画面,说明后续训练必须加大输入尺寸或者使用 P2 层特征,不能用默认的 640×640。类别统计则直接暴露类别不平衡问题,如果“商品”这类框有 5 万个而“偷窃动作”只有 3000 个,那就需要考虑采样策略。

3. 把 COCO 跑进 YOLOv8:格式转换、数据划分与训练参数

3.1 COCO JSON 转 YOLO txt:坐标归一化与文件路径整理

直接用 YOLOv8 训练通常不喂 COCO JSON,而是用每张图对应一个同名 txt 的格式。转换时要注意三个细节:类别 ID 必须从 0 开始连续编号;边界框要转成归一化的中心点坐标;每个图片名要和 txt 文件完全一致。下面这段脚本可以完成转换,同时帮你按视频 ID 划分训练集和验证集,避免相邻帧泄漏。

import json import os import random from collections import defaultdict with open('annotations/instances_train.json', 'r', encoding='utf-8') as f: coco = json.load(f) # 建立 image_id -> 文件名 的映射 id_to_name = {img['id']: img['file_name'] for img in coco['images']} # 建立 image_id -> 视频编号 的映射,前提是文件名里包含帧来源 id_to_video = {} for img in coco['images']: # 示例:Shoplifting034_x264-mp4_8473_jpg.rf.jpg parts = img['file_name'].split('_') video_id = parts[0] if len(parts) > 0 else 'unknown' id_to_video[img['id']] = video_id # 把标注按图片聚合 anns_by_img = defaultdict(list) for ann in coco['annotations']: anns_by_img[ann['image_id']].append(ann) # 类别 ID 映射为连续编号 cat_ids = sorted({ann['category_id'] for ann in coco['annotations']}) cat_id_map = {old: new for new, old in enumerate(cat_ids)} img_ids = list(anns_by_img.keys()) random.shuffle(img_ids) # 按视频划分:确保同一视频的帧全部进同一侧 video_keys = set(id_to_video[i] for i in img_ids) video_keys = list(video_keys) random.shuffle(video_keys) train_videos = set(video_keys[:int(len(video_keys) * 0.8)]) train_ids = [i for i in img_ids if id_to_video[i] in train_videos] val_ids = [i for i in img_ids if id_to_video[i] not in train_videos] os.makedirs('yolo_dataset/images/train', exist_ok=True) os.makedirs('yolo_dataset/labels/train', exist_ok=True) os.makedirs('yolo_dataset/images/val', exist_ok=True) os.makedirs('yolo_dataset/labels/val', exist_ok=True) def write_yolo(img_ids, split): for img_id in img_ids: fname = id_to_name[img_id] stem = os.path.splitext(fname)[0] out_txt = f'yolo_dataset/labels/{split}/{stem}.txt' img_info = next(img for img in coco['images'] if img['id'] == img_id) iw, ih = img_info['width'], img_info['height'] with open(out_txt, 'w') as w: for ann in anns_by_img[img_id]: x, y, bw, bh = ann['bbox'] # 转归一化中心点坐标 cx = (x + bw / 2) / iw cy = (y + bh / 2) / ih nw = bw / iw nh = bh / ih cls = cat_id_map[ann['category_id']] w.write(f'{cls} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}\n') write_yolo(train_ids, 'train') write_yolo(val_ids, 'val') print(f'train images: {len(train_ids)}, val images: {len(val_ids)}')

这里我没有直接把图片复制进对应目录,而是先只生成标签。实际上 YOLO 训练时需要图片路径正确,所以你应该在转换前就把图片文件按 train/val 组织好,或者在写 txt 的同时执行 shutil.copy。上面这种划分方式的关键是按视频划分,而不是按图片随机划分。商店监控视频的相邻帧往往只差几十毫秒,画面几乎一样,随机划分会让验证集变成训练集的“复读机”,指标虚高得离谱,部署到真实视频流时立刻现原形。类别 ID 重映射也千万别省略,COCO 原始类别 ID 可能是 1、3、5,YOLO 要求从 0 开始,不映射会导致类别错乱且不容易察觉。

3.2 训练参数怎么设:imgsz、epochs、batch 与数据增强

数据集转换好后,训练 YOLOv8 需要一份 data.yaml。下面这份配置对应单类别/多类别的场景,按你的实际类别名修改。

# data.yaml path: ./yolo_dataset train: images/train val: images/val nc: 2 names: 0: person 1: shoplifting

训练命令我用的是 ultralytics 的 Python API,因为它能方便地接入后续评估脚本:

from ultralytics import YOLO # 从 YOLOv8m 预训练权重开始,比从头训练收敛快得多 model = YOLO('yolov8m.pt') model.train( data='data.yaml', imgsz=1280, # 监控画面中小目标多,统一放大输入 epochs=100, batch=16, lr0=0.001, augment=True, mosaic=0.5, # 前 50% epoch 用 mosaic,后面关掉 close_mosaic=10, # 最后 10 个 epoch 关闭 mosaic,稳定收敛 patience=20, seed=42, project='shoplifting_exps', name='run_1280', )

imgsz 是这张数据集的第一个关键参数。如果原图是 1920×1080 的监控抽帧,里面的人体可能只占 80×200 像素,默认 640 输入会让小目标缩到几乎不可见。我一般会先用 960 到 1280 之间的值做一次快速实验,对比验证集 mAP。batch 大小受显存限制,但至少要保证单卡 batch 不小于 8,否则 BatchNorm 统计不稳定。mosaic 增强对这个场景是一把双刃剑:mosaic 能把四张图拼在一起,提高模型对小目标和遮挡的鲁棒性;但商店偷窃动作本身依赖完整的时序上下文,过度拼接会让模型学到“碎片化的局部特征”,所以我把 mosaic 概率降到 0.5,并且最后 10 个 epoch 完全关闭。这也是明显区别于通用目标检测调参的细节。

训练过程中要盯着两个曲线:train/cls_loss 应该平滑下降,val/box_loss 如果先降后升就是过拟合。这个数据集规模不大不小,100 个 epoch 足够。如果训练到 80 epoch 时 val mAP 还在涨,可以考虑加 50 epoch;如果 40 epoch 就不动了,优先检查前面说的数据泄漏,而不是盲目加迭代。

4. 评估与调优:98.6% 准确率怎么验证,mAP 和置信度阈值怎么配合

4.1 准确率不等于 mAP:先搞清楚数据集宣称的 98.6% 从哪来

很多人拿到数据集看到“平均准确率达到 98.6%”就以为模型部署后也有这个效果,这是最大的误解。准确率(Accuracy)在目标检测里并不是一个很自然的指标,因为检测模型输出的是“哪张图里有目标”和“目标在哪个位置”,而不是简单的二分类。98.6% 可能来自图片级的行为分类、单个类别的精确率、或者某个任务上的 top-1 准确率,只有看到评估脚本才能确认。在你没有重新跑测试集之前,这个数字只能作为数据集标注质量的参考信号,而不是模型性能承诺。

目标检测的通用评估指标是 COCO mAP,它综合了 IOU 从 0.5 到 0.95 共 10 个阈值下的平均精度。下面这段代码用训练好的权重在验证集上做评估:

from ultralytics import YOLO model = YOLO('shoplifting_exps/run_1280/weights/best.pt') # 只用 val 集评估,IOU 阈值覆盖 0.5:0.95 metrics = model.val( data='data.yaml', split='val', imgsz=1280, conf=0.001, iou=0.6, ) print('mAP50:', metrics.box.map50) print('mAP50-95:', metrics.box.map) print('每类 AP:', metrics.box.ap)

评估时要注意 conf 参数。推理阶段我们通常把置信度阈值设成 0.3 或 0.5,但评估阶段为了计算完整的 PR 曲线,conf 要设得极低,比如 0.001。这样才能覆盖所有可能被误检的低置信度框,得到的 mAP 才是真实水平。如果你用 conf=0.5 去评估,mAP 会比正常值虚高很多,因为低置信度的正样本全部被提前滤掉了,PR 曲线的起点就不完整。这是很多人复现数据集指标失败的第一原因。

4.2 调优策略:从难例挖掘到损失权重

如果你发现验证集 mAP50 已经到 0.95 以上,但 mAP50-95 只有 0.6,说明框定位精度不够。此时优先做两件事:一是继续提高输入尺寸,1280 不行就试 1536,但要注意显存占用和推理延迟;二是检查验证集里是否存在大量边界框面积小于 32×32 的小目标,YOLOv8 的检测头对这类目标不敏感,需要开启 P2 层或者用 SAHI 做切片推理。

如果发现某一类 AP 特别低,比如“shoplifting”动作类的 AP 只有 40%,但“person”类有 90%,这就是典型类别不平衡。处理方法不是简单复制样本,而是先用 classifier 做难例挖掘。把训练集里被分错的样本筛出来,单独建一个“hard set”,做二次微调。下面这个策略是我常用的流程:第一轮正常训练;第二轮用 best.pt 对训练集做检测,把所有漏检的标注框对应的图片抽出来,加上随机翻转和颜色抖动,重新组成一份微调集,用更小的学习率继续训练 30 epoch。

# 难例挖掘示意:找出漏检的图片 import glob from ultralytics import YOLO model = YOLO('shoplifting_exps/run_1280/weights/best.pt') train_images = glob.glob('yolo_dataset/images/train/*.jpg') hard_set = [] for img_path in train_images: # save_dir=False 只返回结果不落盘,加速 results = model.predict(img_path, conf=0.1, imgsz=1280, save_dir=False) # 需要拿到 gt 做比对,这里省略详细匹配代码 # 如果 gt 框与预测框最大 IOU < 0.5,就加入 hard_set hard_set.append(img_path) # 用 hard_set 上的 yaml 进行二次微调 model.train(data='data_hard.yaml', epochs=30, lr0=0.0001, resume=False)

难例挖掘本质上是让模型把注意力集中在它最容易犯错的地方。我在实际项目中遇到过的典型情况是:模型把所有推购物车的顾客都识别成了 shoplifting,因为购物车本身与行窃动作的空间位置高度重合。这种情况下,光加数据不够,需要在标注层面区分“推车”和“将商品放入包中/口袋”的行为语义,或者干脆把模型输出和行为分类器串联起来,用商品的位移轨迹做二次判断。这个我会在最后一章展开。

5. 避坑指南:帧泄漏、标注错位、类别不平衡的真实翻车记录

5.1 验证集 mAP 虚高,部署后效果断崖式下跌

现象:用这份数据集训练的模型,验证集 mAP50 能达到 0.98,看起来尤其优秀,但一接到真实摄像头视频流,漏检率立刻飙到 30% 以上。

原因:文件命名暴露出的视频抽帧特性没有被处理。直接随机划分训练集和验证集时,同一个视频的相邻帧大量同时出现在训练集和验证集里。相邻帧之间差异极小,模型等于 “背题” 考了高分,一到没见过的新场景就现原形。

解决:严格按视频维度划分数据集。把文件名中的视频 ID 提出来,用视频 ID 做 group split,保证同一个视频的所有帧只在训练集或验证集里出现一次。如果你拿到的是已经划分好的数据集,验证集里仍然混着同一视频的帧,建议按帧间隔重采样:每 10 帧取 1 帧进验证集,最大程度降低帧间相似度。从那以后我每次拿到监控视频数据集,第一件事就是统计“同一视频的帧是否同时出现在 train 和 val 里”,这一步不做,后面都是空中楼阁。

5.2 边界框标注与人体实际位置错位

现象:训练过程中 loss 降到一定程度后不再下降,可视化验证集预测结果时发现模型预测框总是比真实框偏左或偏上,尤其是被货架遮挡的人体。

原因:这个数据集的部分标注可能来自半自动跟踪工具,对运动速度快的目标,标注框滞后于目标实际位置。我曾在文件名里看到来自 MP4 视频的抽帧,这类工具默认按 30fps 抽帧,但对快速弯腰、伸手的动作,相邻两帧的位移可以达到几十像素,微调框跟不上就会产生系统性偏差。

解决:训练前增加一个“框对齐”检查,对同一目标在相邻帧中的位置做平滑拟合,如果某一帧的框偏离拟合轨迹超过阈值,手动修正或直接删除该帧。另一个更省事的做法是用一个先验模型对全部数据做预检测,把检测结果和标注框做比对,自动标出差异大于 20 像素的样本。这样能快速定位出错帧,而不是靠肉眼翻几千张图。标注错位不会直接导致模型不收敛,但会让边界框回归精度长期停在低水平。

5.3 “shoplifting” 类别样本远少于 “person”,模型偏向学习主体类别

现象:训练完查看 per-class AP,person 类 AP 95%,shoplifting 类 AP 只有 65%,整体 mAP 被拉高,但实际需要的行为识别能力不达标。

原因:店铺监控里人的边界框往往每帧都有,而“偷窃行为”相关的标注框只在动作发生时出现,两类数量可能相差 10 倍以上。模型为了降低整体 loss,会偏向学样本量大的类别,导致行为类别的召回率很低。加上 shoplifting 这种动作类目标往往没有稳定的视觉外观,不像“人”有统一的形状特征,学起来更困难。

解决:不要用最简单的 oversample 复制少数类图片,那样容易过拟合。我一般会用两阶段方法:第一阶段只训练 person 检测器,把所有人框出来;第二阶段对每个 person 框做动作分类,输入的裁剪区域包含历史和未来几帧的堆叠。这样就把“在整图中找目标”和“判断动作”两个难度拆开了。如果坚持单阶段检测,需要给 shoplifting 类别更高的 loss 权重,Ultralytics 支持在 loss 层面配置类别权重,实际项目中我一般把少数类权重设为 2~3 倍,同时配合 mosaic 增强。

5.4 图像尺寸不一致导致归一化标注全部偏移

现象:转换 YOLO 格式后训练,前几个 epoch loss 异常高,部分锚框与目标完全没有重叠。

原因:数据集里 8395 张图片不是同一个分辨率,一部分来自 1920×1080 的视频抽帧,另一部分可能是经过 Roboflow 预处理后的 640×480 缩略图。转换脚本里如果用的图片宽度来自 JSON,而实际图片经过外部缩放,坐标归一化后就会出现系统性偏移。

解决:转换前先扫描所有图片的实际尺寸,与 JSON 里的 width/height 逐一对比,不一致的以实际尺寸为准重新计算 bbox。更稳妥的做法是统一 resize 到同一尺寸并保持宽高比填充黑边,然后再生成标签。这一点对监控数据尤其致命,因为不同摄像头的分辨率和画幅比差异很大,模型在训练时看到不同尺度的同一目标,会无法决定应该匹配哪个 anchor。

6. 进阶技巧:把检测输出变成行为判据,用帧间投票稳住误检

到这步,你已经有了一个能稳定框出人和商品的检测模型。但“商店偷窃行为识别”在真实业务里的需求从来不是画框,而是触发告警。直接对每一帧的检测结果做判断,会出现大量抖动:顾客弯腰系鞋带被当成熟人、伸手拿货架高层商品被当成偷窃。我给自己的模型加了一层很简单的后处理,效果立竿见影。

常见做法是维护一个检测结果的滑动窗口队列,对每个目标和它的属性做“N 帧内出现 M 次”的投票。这个逻辑不需要重新训练,只改动推理脚本。下面是一个简化版:

from collections import deque class FrameVoter: def __init__(self, window=15, min_votes=10): self.window = window self.min_votes = min_votes # key: (class_id, normalized_center_x, normalized_center_y) self.history = deque(maxlen=window) def update(self, detections): current_frame = set() for det in detections: # 用归一化中心点作为目标身份近似,实际项目可以加 IoU tracker key = (int(det.boxes.cls[0]), round(float(det.boxes.xyxy[0][0]) / 1280, 2), round(float(det.boxes.xyxy[0][1]) / 720, 2)) current_frame.add(key) self.history.append(current_frame) vote_count = {} for frame_keys in self.history: for key in frame_keys: vote_count[key] = vote_count.get(key, 0) + 1 alert = False for key, cnt in vote_count.items(): if key[0] == 1 and cnt >= self.min_votes: alert = True # 行为类目标连续多帧出现,触发关注 return alert

这段逻辑里,window 是时间窗口长度,按 30fps 算,15 帧就是 0.5 秒。min_votes 设置太高会漏报,太低会误报,我习惯跟客户一起调这两个值。它真正的价值是:检测模型输出的是单帧语义,行为判据依赖的是跨帧一致性。把“出现次数”作为置信度之外的第二个门槛,误报率能压下一个量级。

我在复盘这个数据集的一次测试时发现,很多“偷窃”框实际是顾客的手划过画面边缘,单帧看很像抓取动作,但拉长到 1 秒窗口看,手的位置并没有靠近携带物。从那以后我每次做动作类检测项目,都会强制走一遍“单帧检测 + 滑动窗口投票 + 告警延迟”的链路,先把图像模型的可信度边界摸清,再谈准确率。这个数据集能让你快速跑通前面的所有步骤,真正的业务挑战永远在模型之外。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 23:15:44

图像质量评价核心指标CNR:从数学原理到Python代码实现全解析

做图像质量评价的同行&#xff0c;应该都绕不开CNR这个指标。无论你是做医学影像、工业无损检测还是遥感图像处理&#xff0c;只要涉及“目标在背景里到底清不清楚”这个问题&#xff0c;CNR&#xff08;Contrast-to-Noise Ratio&#xff0c;对比度噪声比&#xff09;都是最常被…

作者头像 李华
网站建设 2026/9/24 23:15:43

PyTorch鸟类识别实战:从环境踩坑到ONNX部署全链路

简介&#xff1a;本资源是一份基于Python与卷积神经网络&#xff08;CNN&#xff09;实现的鸟类图像识别实战项目&#xff0c;面向深度学习初学者、计算机视觉入门者及高校课程设计学生&#xff0c;解决真实场景下的细粒度图像分类问题。压缩包共856个文件&#xff0c;主体为84…

作者头像 李华
网站建设 2026/9/24 23:14:24

安全审计实战:从代码审计到漏洞挖掘的系统性技能指南

刚接手一个紧急任务&#xff1a;一个上线两年的老系统被业务方投诉接口响应异常&#xff0c;让我"顺手看一眼"。结果十分钟内&#xff0c;我在一个导出功能里发现了一个垂直越权漏洞——普通用户只要改一下URL里的ID&#xff0c;就能导出别人的订单数据。那一刻我意识…

作者头像 李华
网站建设 2026/9/24 23:14:23

从Verba看RAG引擎:嵌入、向量搜索与混合检索实战解析

我见过太多团队把 RAG 做成“大模型套壳”&#xff1a;文档一堆进去就开始提问&#xff0c;结果答得天花乱坠&#xff0c;引用来源却驴唇不对马嘴。问题不在大模型&#xff0c;而在检索这条链路。RAG 的全称是 Retrieval-Augmented Generation&#xff0c;检索增强生成&#xf…

作者头像 李华
网站建设 2026/9/24 23:14:21

LLM工具调用实战:从协议设计到容错恢复的工程指南

1. 从一次线上事故说起&#xff1a;工具调用为什么值得单独记一笔去年冬天我接手了一个内部知识助手项目&#xff0c;模型选的是当时口碑不错的一个开源对话模型&#xff0c;业务逻辑也不复杂——用户提问&#xff0c;模型判断是否需要查数据库、查文档、调接口&#xff0c;然后…

作者头像 李华
网站建设 2026/9/24 23:13:30

本地多轮对话客服系统实战:Python+Ollama+Chroma+LangChain全流程

收到&#xff0c;说干就干。这期我们用Python Ollama Chroma LangChain&#xff0c;老老实实从零搭一个本地多轮对话客服系统&#xff0c;跑通全流程。讲真&#xff0c;客服系统是LLM落地最典型的场景之一&#xff0c;但市面上的教程要么只讲单轮对话&#xff0c;要么直接用…

作者头像 李华