news 2026/10/10 20:43:38

基于yolo11的血液细胞检测实战:BCCD数据集从训练到部署

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于yolo11的血液细胞检测实战:BCCD数据集从训练到部署

简介:面向医学影像分析与目标检测开发者的YOLO11血液细胞图像检测资源包,聚焦血涂片中的血小板、红细胞与白细胞识别,辅助血液疾病诊断。包内整合三百六十四张已标注的血液细胞图像,提供文本标签与可扩展标记语言标签两套格式,并预先划分训练集、验证集与测试集,同时包含配套的配置文件,可直接用于多个版本目标检测算法的训练。资源中还提供训练好的模型权重、基于Python的脚本以及使用教程文档,覆盖数据准备、模型训练、推理评估等主要环节,便于快速复现工作或迁移至自定义数据集。压缩包共一千八百五十四个文件,以教程文档、样本图像、标签文件、脚本、配置与权重等类型为主,整体大小约六十四兆字节,目录结构清晰,方便按需检索。目前已有九十三人学习,适合具备一定Python基础的医学影像初学者或目标检测研究者直接上手。

1. 用 ultralytics-yolo11 拆一套血液细胞检测:364 张图的 BCCD 才是真正要解决的问题

血液细胞图像的目标检测,过去总被当成“数据不够就玩不动”的典型,但这套 ultralytics-yolo11 检测和分析血液细胞图像资源里,BCCD 数据集只有 364 张标注图,却能把血小板、红细胞、白细胞三类目标完整跑通。真正难的不是模型,是数据集格式、类别不平衡和部署路径三段。这个压缩包同时给了 YOLO txt 和 VOC xml 两种标签,划分好了 train/val/test,附 data.yaml 和训练好的权重,适合的目标很明确:想用 yolo11 做细胞检测、又不想花两周整理标注格式的从业者或新手。它是医工交叉检测一个很低的入门门槛,检测结果也能为辅助血液疾病诊断里的细胞计数统计提供前端支撑。

2. 先拆 BCCD 数据集:两种标注格式、data.yaml 和目录划分

2.1 拿到压缩包后第一件事:把目录铺开

这个包解压以后,建议先别急着装 ultralytics,而是把数据目录完整看一遍。BCCD 是血液细胞检测里很常用的公开基准集,资源作者已经帮你做了最繁琐的工作:图像统一放 images,YOLO 标签按 txt 格式放 labels,VOC 标签按 xml 格式放 annotations,train/val/test 三个划分也已经切好。压缩包里还有 inference.cpp、main.cc 这样的 C++ 部署入口文件,以及训练时自动生成的 labels.cache,后者在第 5 章会专门讲它的坑。

我一般会先跑一次目录树,把脑中的地图建起来:

BCCD/ ├── images/ │ ├── train/ # 约 250 张 │ ├── val/ # 约 60 张 │ └── test/ # 约 50 张 ├── labels/ │ ├── train/ # 与 images/train 同名同前缀的 txt │ ├── val/ │ └── test/ ├── annotations/ # VOC 格式 xml,v5/v8/v11 训练时不直接读 ├── data.yaml # 训练入口配置 └── labels.cache # 训练时自动生成的标签缓存

这段结构的意义在于:images 和 labels 的目录名、图片名前缀必须严格一致,YOLO 训练时是靠“同名不同后缀”去找标签的。如果两者对不上,训练会直接报 File not found 或者 image 无标签警告。

2.2 三种细胞的检测任务差异

BCCD 的类别不多,只有三类,但检测难度差别很大。先看看这三类在实际检测里分别难在哪:

类别英文名标签下标检测难点
血小板Platelets0尺寸小,很容易漏检
红细胞RBC1密度高,细胞之间粘连严重
白细胞WBC2数量少,样本极度不均衡

这三类在辅助血液疾病诊断场景里的作用也不一样:血小板数量异常和凝血功能相关,红细胞数量对应贫血方向,白细胞则和感染、炎症相关。但注意一点,目标检测只负责“框出来 + 数出来”,不是直接下诊断结论,做工程落地时这个边界要拎清。

可以用几行 Python 快速统计训练集里每个类别的目标数,确认数据分布:

from pathlib import Path from collections import Counter names = ["Platelets", "RBC", "WBC"] counter = Counter() for txt in Path("BCCD/labels/train").glob("*.txt"): for line in txt.read_text().strip().splitlines(): if not line.strip(): continue cls = int(float(line.split()[0])) counter[names[cls]] += 1 print(counter)

这段代码读的是 YOLO txt 标签的第一列类别编号,逐文件统计后你会发现 WBC 的数量可能只有 RBC 的十分之一甚至更少。训练策略就得针对这个不均衡做调整,否则模型会倾向于把一切深色、有核的细胞都判成 RBC。

2.3 看清 txt 和 xml 的对应关系

YOLO 训练直接读 txt,每行五个数字:类别、归一化中心点 x、归一化中心点 y、归一化宽、归一化高。全部是 0 到 1 之间的比例值,不是像素坐标。

label_path = Path("BCCD/labels/train/BloodImage_00001.txt") for line in label_path.read_text().strip().splitlines(): cls, cx, cy, w, h = map(float, line.split()) print(f"class={int(cls)} cx={cx:.4f} cy={cy:.4f} w={w:.4f} h={h:.4f}")

这里 cx 是相对图像宽度的比例,cy 是相对图像高度的比例。比如 cx=0.5 代表目标中心在图像水平正中间,和图像尺寸无关,这是 YOLO 格式最核心的设计。VOC xml 则记录的是绝对像素坐标,bndbox 节点下面 xmin、ymin、xmax、ymax 四个值直接对应原图坐标。

解析 xml 的常见做法:

import xml.etree.ElementTree as ET xml_path = "BCCD/annotations/BloodImage_00001.xml" root = ET.parse(xml_path).getroot() img_w = float(root.find("size/width").text) img_h = float(root.find("size/height").text) for obj in root.findall("object"): name = obj.find("name").text box = obj.find("bndbox") xmin = float(box.find("xmin").text) ymin = float(box.find("ymin").text) xmax = float(box.find("xmax").text) ymax = float(box.find("ymax").text) cx = (xmin + xmax) / 2 / img_w cy = (ymin + ymax) / 2 / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h print(name, f"yolo: {cx:.4f} {cy:.4f} {w:.4f} {h:.4f}")

如果你后续要往 VOC 格式迁移,反推公式就是:xmin = (cx - w/2) * img_w,其余同理。这个小脚本值得留着,因为不少公开数据集只给一种格式,跨格式迁移时它就是后悔药。

2.4 data.yaml 里必须检查的两个字段

data.yaml 是整个训练链路的入口配置,压缩包里已经给了一份,但直接拿去训练大概率会因为路径问题翻车。YOLO11 的 data.yaml 推荐写法是带 path 根目录:

# data.yaml path: D:/datasets/BCCD # 改成你自己的绝对路径 train: images/train val: images/val test: images/test nc: 3 names: 0: Platelets 1: RBC 2: WBC

这里最容易踩的坑是 path 没改。很多人解压到某个目录后直接 yolo train,结果 YOLO 在默认工作目录下找不到 images 目录。我一般会直接把 path 写成绝对路径,train/val 保持相对路径,这样不管从哪个目录启动训练都不会出错。

nc 和 names 的顺序也要核对。BCCD 的标签 txt 是按 0=Platelets、1=RBC、2=WBC 编的,data.yaml 里的 names 顺序必须完全一致。一旦错位,比如把 RBC 写成下标 0,训练不会报错,但模型学的东西全是错的,而且你很难从 loss 曲线看出来。

3. ultralytics 环境与训练参数:从 yolo11n 起步的可复现配置

3.1 安装 ultralytics 的正确姿势

如果你之前用 yolov8 训练过自己的数据集,对 ultralytics 这套接口应该很熟。BCCD 这套标签格式对 v5/v8/v9/v10/v11/v12 通吃,但既然手头是 yolo11 资源,我建议直接用 ultralytics 最新版。安装之前先建独立虚拟环境,这是最快减少环境冲突的办法:

conda create -n yolo11 python=3.10 -y conda activate yolo11 # GPU 用户先装对应版本的 torch,以 CUDA 12.1 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 # 再装 ultralytics pip install ultralytics -i https://pypi.tuna.tsinghua.edu.cn/simple

注意 Python 版本必须落在 3.8 到 3.12 之间,超过 3.12 很容易出现第 5 章要讲的 could not find a version 报错。装完先跑一次官方预训练权重验证环境:

yolo predict model=yolo11n.pt source=https://ultralytics.com/images/bus.jpg

能输出一张带框的 bus.jpg,说明环境就绪。这一步五分钟值得花,避免把环境问题误判成数据和代码问题。

3.2 为什么从 yolo11n 起步,而不是直接上 yolo11s 或 x

BCCD 只有 364 张图,属于典型的小数据目标检测场景。模型容量越大,过拟合风险越高。yolo11n 参数量最小、训练最快,适合先把数据链路跑通,确认 loss 能正常下降。yolo11s 可以作为第二轮实验,专门看 WBC 召回率有没有提升。

模型参数量级适用判断
yolo11n最小首选,跑通流程、确认收敛
yolo11s中等WBC 召回不足时升级
yolo11m/x较大数据量撑不住,不建议直接用

这套取舍逻辑也适用于其他目标检测数据集。先小模型验证“数据没问题、标签没问题、训练能收敛”,再用大模型刷精度,比一上来就大模型跑三天划算得多。

3.3 训练命令和关键参数含义

环境就绪后,用下面的命令启动训练:

yolo detect train \ model=yolo11n.pt \ data=D:/datasets/BCCD/data.yaml \ epochs=120 \ imgsz=640 \ batch=16 \ device=0 \ workers=4 \ cache=True \ project=runs/bccd \ name=yolo11n_bccd

model=yolo11n.pt 表示加载 COCO 预训练权重做迁移学习。BCCD 和 COCO 差距很大,但迁移学习仍然能显著加速收敛,这是目标检测小数据集的标准做法,比从随机权重训练稳得多。

参数值理由
epochs120BCCD 很小,训练很快;配合早停不会浪费
imgsz640默认值;若 RBC 密集尺度漏检,可升 960
batch168GB 显存的保守值,OOM 就降到 8
cacheTrue把标签缓存进内存,提速明显
workers4Windows 下如果报 DataLoader 错误,改成 2 或 0

训练过程中看 runs/bccd/yolo11n_bccd/results.png 里的 box_loss 和 cls_loss,正常情况两条曲线都在前 20 个 epoch 快速下降,之后缓慢收敛。如果 loss 全程不动,优先检查 data.yaml 的 path 和 label 目录名。

3.4 权重选择:best.pt 还是 last.pt

训练结束后,weights 目录下有两个权重:best.pt 和 last.pt。best.pt 是验证集 mAP 最高的一轮,last.pt 是最后一轮。绝大多数场景直接用 best.pt,但有一个例外:如果你打算接着用更多数据继续训练,last.pt 更适合作为起点,因为 best.pt 可能对应较早的 epoch,学习率状态不太连续。

微调时我一般会在 best.pt 基础上继续训,但关闭预训练权重加载,避免学习率跳变:

yolo detect train \ model=runs/bccd/yolo11n_bccd/weights/best.pt \ data=D:/datasets/BCCD/data.yaml \ epochs=60 \ imgsz=960 \ batch=8

这张命令本质是把 imgsz 从 640 提到 960,专门应对小尺寸血小板漏检问题。图像分辨率提升后,小目标在特征图上的像素占比变大,漏检率通常会明显下降。

4. 拿到 best.pt 之后:Python 推理、导出 ONNX 与 C++ 部署入口

4.1 Python 端推理和细胞计数

训练好的权重可以直接用 ultralytics 的 Python API 跑推理,这是最快看到效果的方式:

from ultralytics import YOLO import numpy as np model = YOLO("runs/bccd/yolo11n_bccd/weights/best.pt") results = model.predict( source="D:/datasets/BCCD/images/test", conf=0.25, iou=0.45, imgsz=640, save=True, save_txt=True, project="runs/bccd/predict", name="test", ) for r in results: if r.boxes is None: continue clss = r.boxes.cls.cpu().numpy().astype(int) counts = np.bincount(clss, minlength=3) print(f"{r.path}: Platelets={counts[0]} RBC={counts[1]} WBC={counts[2]}")

conf=0.25 是置信度阈值,低于这个值的框会被过滤。在这套细胞数据上,血小板置信度通常偏低,我一般会单独把血小板场景的 conf 降到 0.2 再对比一轮,用召回率换误检率。iou=0.45 是 NMS 的 IoU 阈值,细胞粘连程度高时可以把 iou 提到 0.5,减少重叠框被误删的概率。

这个计数循环可以直接输出每张图三类细胞的数量,正是辅助血液疾病诊断里最需要的“统计”环节。

4.2 导出 ONNX:部署前的关键一步

要把模型从 Python 搬走,第一步是导出 ONNX:

yolo export \ model=runs/bccd/yolo11n_bccd/weights/best.pt \ format=onnx \ imgsz=640 \ opset=12 \ simplify=True

opset=12 对 onnxruntime 的兼容性比较稳,simplify=True 会调用 onnxsim 去掉一些冗余计算。导出成功后,模型文件从 .pt 变成 .onnx,之后就可以脱离 PyTorch 环境部署。

4.3 C++ 推理骨架:inference.cc 到底在做什么

压缩包里带了 inference.cpp、main.cc、config 这样的文件,说明作者预留了 C++ 部署入口。常见做法是拿 ONNX Runtime 加载模型,整个流程分三步:预处理、推理、后处理。C++ 端最容易写错的就是预处理,这里给出骨架:

#include <onnxruntime_cxx_api.h> #include <opencv2/opencv.hpp> cv::Mat letterbox(const cv::Mat& src, int target = 640) { float scale = std::min((float)target / src.cols, (float)target / src.rows); cv::Mat resized, canvas(target, target, CV_8UC3, cv::Scalar(114, 114, 114)); cv::resize(src, resized, cv::Size(), scale, scale, cv::INTER_LINEAR); resized.copyTo(canvas(cv::Rect((target - resized.cols) / 2, (target - resized.rows) / 2, resized.cols, resized.rows))); return canvas; }

letterbox 的核心是保持宽高比缩放,四周用 114 灰度填充到 640×640。这里 114 是 YOLO 系列模型训练时的填充默认值,和 Python 端的预处理必须完全一致。后处理时把输出坐标减去 padding,再除以 scale,才能还原到原图坐标。

YOLO11 的 ONNX 输出形状是 1×(4+nc)×8400,nc=3 时就是 1×7×8400。8400 来自 80×80、40×40、20×20 三个特征图相加。每一列代表一个候选框,前 4 行是 cx、cy、w、h,后 3 行是三个类别的得分,没有单独的 objectness 分数,这点和 YOLOv5 不同。

4.4 快速验证:直接用 val 命令看底数

如果暂时不写代码,只想确认训练好的模型质量,直接跑验证命令:

yolo detect val \ model=runs/bccd/yolo11n_bccd/weights/best.pt \ data=D:/datasets/BCCD/data.yaml \ split=test \ conf=0.25 \ iou=0.5

命令执行完会输出 mAP50、mAP50-95 和各类别 AP,并生成混淆矩阵图。先看 mAP50 是否达到可接受水平,再看 WBC 那一行的召回率。WBC 作为少数类,如果 AP 明显低于 RBC,训练阶段的类别不均衡就体现在这里了。

5. BCCD 实战避坑:五个我翻过车的地方

5.1 pip install ultralytics 报 could not find a version that satisfies the requirement

现象:在某个 Python 环境里执行 pip install ultralytics,提示 ERROR: Could not find a version that satisfies the requirement ultralytics,后面还跟着 from versions: none。

原因:ultralytics 对 Python 版本有要求,通常是 Python 3.8 到 3.12。如果当前环境是 Python 3.13 及以上,或者 pip 版本太老,PyPI 上找不到匹配 wheel,就会报这个错。

解决:先升级 pip,再看 Python 版本:

python -m pip install --upgrade pip python --version

版本不对就重建虚拟环境,用 conda 固定 Python 3.10,再装 torch 和 ultralytics。装完用 yolo predict 验证一次,确认 import 级正常。

5.2 训练时 File not found 或 image 无标签警告

现象:启动训练后报错找不到 data.yaml,或者大量输出 WARNING 提示某张图片没有标签,但 labels 目录里文件明明存在。

原因:data.yaml 里的 path 是相对路径,而实际工作目录不在数据集根目录;或者 images 和 labels 目录名不匹配,YOLO 只认 images 同级目录下的 labels。

解决:把 data.yaml 的 path 改成绝对路径,并确认 train 的值是 images/train 而不是 label 路径。标签缺失的图直接从数据集里删掉,不要留着,否则训练时会反复警告并拖慢速度。

5.3 labels.cache corrupted 导致训练中断

现象:第一次训练正常,第二次改动数据集后启动训练,报 CACHE 文件 corrupted 或者 cache 与标签不一致。

原因:YOLO 会把标签校验结果缓存到 labels.cache 文件里,下次训练直接加载缓存跳过校验。但数据集内容变了,旧缓存没有同步失效。

解决:找到数据集根目录下的 labels.cache 删掉,重新训练会自动重建。我现在的习惯是,每次增删图片或修改 txt 标签,直接先删缓存再启动训练,提前规避。

5.4 WBC 样本太少,训练完 WBC 的召回率特别低

现象:混淆矩阵里 RBC 的 AP 很高,WBC 的召回率只有 RBC 的一半甚至更低,测试集上 WBC 漏检严重。

原因:BCCD 里 WBC 数量远少于 RBC,模型在训练时对 WBC 的特征学习不足。这是数据不均衡导致的,不是模型 bug。

解决:常见做法是分三步走。第一步,把 imgsz 提到 960,让白细胞核的纹理更容易被提取。第二步,对 WBC 标注做重复采样,把 WBC 样本复制几份放进训练集,但注意要配合随机增强,否则只是重复记忆。第三步,使用 mixup 增强,让模型在混合样本里学习判别特征。数据增强参数可以这样加:

yolo detect train \ model=runs/bccd/yolo11n_bccd/weights/best.pt \ data=D:/datasets/BCCD/data.yaml \ epochs=60 \ imgsz=960 \ batch=8 \ mixup=0.3 \ fliplr=0.5

mixup=0.3 表示有 30% 的概率对两张图做混合,比单纯复制样本更抗过拟合。WBC 召回率上来了,再看 RBC 有没有被误伤,动态调整 mixup 比例。

5.5 C++ 推理和 Python 结果不一致

现象:同一张测试图,Python 端检测出 15 个目标,C++ 端只输出 8 个,或者框的位置整体偏移。

原因:两端预处理不一致。常见差异包括 letterbox 填充值不是 114、缩放插值方式不同、图像通道顺序 RGB/BGR 反了、归一化时用 255 还是 1.0,以及推理后的 dequantize 类型不对。

解决:用一张固定测试图,把两端的输出全部 dump 成 numpy 或者 txt 逐列比对。先对比第一层的输入 tensor 是否数值一致,再对比输出 tensor 是否一致。输入差 0.001 就能导致输出差好几个框。C++ 端我一般固定用 OpenCV 读图 BGR、letterbox 填充 114、除以 255 转 float32,和 Python 端保持同一套公式,不再各自调参。

6. 收尾验证:用 val 指标和 ONNX 对比拦住部署翻车

6.1 三个必须看的指标

模型训练完,不要只看 loss 曲线就说“训好了”。我每次都会跑一遍完整评估,重点盯三个数字:mAP@0.5、mAP@0.5:0.95、以及每个类别的召回率。

from ultralytics import YOLO model = YOLO("runs/bccd/yolo11n_bccd/weights/best.pt") m = model.val(split="test", conf=0.25, iou=0.5, plots=True) print("mAP@0.5:", m.box.map50) print("mAP@0.5:0.95:", m.box.map) print("per-class:", m.box.ap_class_index, m.box.ap)

plots=True 会在验证目录生成 confusion_matrix.png 和 PR 曲线。看混淆矩阵时重点看 WBC 这一行,被误判成 RBC 的样本越多,说明类别不均衡问题越严重。这三个数字会成为你后续调参的基准线,每次改动只允许一个指标变差,否则回滚。

6.2 导出前后的 golden 对比:一张图拦住 90% 的部署翻车

C++ 端部署最大的风险是“练好的模型到了 C++ 端就变了个模型”。我的习惯是导出 ONNX 前后,拿固定的一张测试图做一次输出对比。先用 Python 记录 ONNX Runtime 的输出,作为基准,再让 C++ 端输出同一张图的同一维度结果做数值比较。

import onnxruntime as ort import cv2 import numpy as np def make_blob(img, target=640): h, w = img.shape[:2] scale = min(target / w, target / h) nw, nh = int(w * scale), int(h * scale) resized = cv2.resize(img, (nw, nh), interpolation=cv2.INTER_LINEAR) canvas = np.full((target, target, 3), 114, dtype=np.uint8) top = (target - nh) // 2 left = (target - nw) // 2 canvas[top:top+nh, left:left+nw] = resized blob = canvas.transpose(2, 0, 1)[None].astype(np.float32) / 255.0 return canvas, scale, left, top img = cv2.imread("demo.jpg") canvas, scale, left, top = make_blob(img) sess = ort.InferenceSession("best.onnx", providers=["CPUExecutionProvider"]) input_name = sess.get_inputs()[0].name out = sess.run(None, {input_name: blob})[0] print("output shape:", out.shape) print("first column:", out[0, :, 0])

这段代码里 letterbox 的 left、top 偏移被显式记录,后处理时直接用它们还原坐标。C++ 端同样存这两个值,就能保证两端的坐标还原逻辑一致。第一列的 7 个数字是第一个候选框的 cx、cy、w、h 和三个类别得分,直接对比这 7 个数字是否一致,比看最终框更底层、更可靠。

从那以后,我每次做检测类项目都强制走一遍固定流程:先统计类别分布,再核 data.yaml,然后小模型跑通收敛,最后导出前后做一次 golden 对比。这四个动作能拦住九成以上的翻车现场。希望帮到你。

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

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

手写语法分析器:从LL(1)文法到可执行解析器

简介&#xff1a;本资源是一份面向计算机专业本科生及编译原理初学者的语法分析实践教学材料&#xff0c;聚焦编译器核心环节——语法分析的原理理解与代码实现。内容覆盖上下文无关文法定义、LL/LR分析对比、递归下降与Yacc/Bison工具应用、抽象语法树构建及语法错误处理等关键…

作者头像 李华
网站建设 2026/10/10 20:42:31

MATLAB实现SAO雪消融优化算法优化SVR回归预测模型全流程

做预测的朋友应该都有同感&#xff1a;支持向量机回归&#xff08;SVR&#xff09;虽然好用&#xff0c;但C、gamma、epsilon这三个参数真的要调到血压升高。最近我在MATLAB里把雪消融优化算法&#xff08;SAO&#xff09;和SVR结合了一把&#xff0c;做了一套可以直接跑起来的…

作者头像 李华
网站建设 2026/10/10 20:39:11

基于PJ85718DM与STM32F031C6的双温度监测方案设计与实现

1. 从一颗传感器和一颗MCU说起&#xff1a;这个组合到底在解决什么问题温度监测这件事&#xff0c;听起来简单&#xff0c;做起来全是细节。尤其是当你需要同时盯着本地机箱内的温度和几十米外某个房间的温度时&#xff0c;问题就来了&#xff1a;用同一个传感器&#xff1f;信…

作者头像 李华
网站建设 2026/10/10 20:37:39

MiniMax 白送 3000 积分:0 元上手 H3 文生视频全流程

MiniMax 白送 3000 积分&#xff1a;0 元上手 H3 文生视频全流程 【免费下载链接】MiniMax-H3 MiniMax H3 是一个通用的全模态生成系统。它支持对由文本、图像、视频和音频组成的多模态上下文进行统一理解&#xff0c;并能生成分辨率高达 2K、时长可达 15 秒的带原生立体声音频…

作者头像 李华
网站建设 2026/10/10 20:34:30

动态规划序列问题实战:从最长公共子序列到最大子序和

2. 动态规划入门&#xff1a;从最长公共子序列到最大子序和1. 内容整体设计与思路拆解刷到第43天&#xff0c;动态规划已经进入“序列问题”的核心区域。今天这四道题放在一起&#xff0c;其实有很清晰的递进关系&#xff1a;1143最长公共子序列是基础母题&#xff0c;1035不相…

作者头像 李华
网站建设 2026/10/10 20:31:03

OpenRouter 平替实操:LiteLLM 把成本与链路透明度拿回来

OpenRouter 平替实操&#xff1a;LiteLLM 把成本与链路透明度拿回来 【免费下载链接】litellm The fastest, litest AI Gateway. Rust core with Python SDK. Call 100 LLM APIs in OpenAI (or native) format with cost tracking, guardrails, load balancing, and logging [B…

作者头像 李华