Windows部署Diffy:接口差异测试与回归验证完整指南
做微服务重构或者依赖升级的时候我最怕的事情不是代码编译不过而是“上线没问题但行为悄悄变了”。接口还是那个接口字段类型、边界条件、异常消息却可能被人为调整过这种回归问题靠人眼很难发现。这次在Windows上部署了一次Diffy做差异测试把新旧版本服务同时挂在一个代理后面用真实请求对比响应差异整个过程踩了一些坑也把原理和参数理解得更透彻了。这篇文章就把完整流程写出来从环境准备到启动脚本再到常见问题的排查思路希望对准备在Windows上做类似验证的同学有帮助。Diffy是一个开源的差异测试工具核心思路很直接让同一个请求同时打到老版本和新版本然后比较返回结果。它特别适合“行为是否发生变化”这类回归验证。整个部署依赖Java环境Windows本身没有特殊限制但官方脚本默认面向Linux和macOS所以我们需要用命令直接启动额外处理端口、防火墙这些细节。文章里我会尽量把每个步骤说清楚也会解释为什么这样做。1. 这个工具到底是干嘛的1.1 先搞清楚“差异测试”解决什么问题传统接口回归测试通常是提前准备一组用例跑完后对比预期结果。但真实世界里请求参数是千变万化的覆盖率永远有限尤其是老服务重构、第三方SDK升级、数据库迁移这种场景你很难确定“所有行为都保持一致”。差异测试的思路反过来了它不预设预期值而是把同一个请求同时发到新老两个版本上直接比较两边返回是否一致。只要有差异就说明行为已经变了至于这个变化是不是有意的由人再去判断。Diffy就是专门做这件事的工具。它作为一个代理层接收外部发来的请求然后转给三个后端实例做对比。它不关心你的业务逻辑只关心HTTP响应、异常、响应体内容是否对得上。这里面有一个很关键的设计参与对比的“老版本”有两个实例而不是一个。原因很简单很多服务本身就有不确定性比如接口返回里带时间戳、随机数、TraceID如果拿一个老版本和一个新版本比即使完全没改动也会因为随机字段的不同而产生一堆误报。有两个老版本实例时Diffy可以先看两个老版本之间是否不一致如果它们自己都不一致那这个差异就被判定为“噪音”不在最终结果里当成问题。1.2 三个实例的对比逻辑在Diffy的配置里有三个角色master.primary、master.secondary和candidate。前两个通常指向稳定生产版本的两个副本candidate指向待验证的新版本。每次请求进来Diffy会以一定策略选择目的版本组合然后比较三份响应。比较的时候最终会产生三类结果一类是“相同”指候选版本和两个基础版本都没有明显差异一类是“差异”指两个基础版本一致但候选版本和它们不同这就是需要人重点关注的回归点还有一类是“错误”一般指请求异常、超时、后端不可用等。整个过程中Diffy会把请求和响应都记录下来方便之后在Web界面里逐个查看。我举个实际例子帮助理解。假设你的老接口返回{name:demo,ts:1690000000}由于ts是个动态时间戳两个老版本自身返回的ts就不一样。Diffy会把这部分差异过滤掉。但如果新版本把字段名从name改成了userName两个老版本返回都是name只有候选版本返回userNameDiffy就会把这个差异标记出来。这样你就不用浪费精力去处理那些因为随机因素造成的假告警直接盯着有效差异看就行。1.3 适合用在哪不适合用在哪就我的实际经验而言Diffy最合适的场景有三类接口重构或内部实现替换需要验证新旧行为完全一致。第三方依赖、基础组件升级担心暗改行为。数据迁移或缓存引入后确认逻辑没有出现偏差。它不适合做性能压测因为一次原始请求会被放大成三次后端请求。也不适合对强一致要求非常高的场景因为Diffy本身是采样对比不一定覆盖全部流量。它更偏向“开发阶段的验证工具”而不是生产环境的实时监控。理解了这个边界你后面部署配置参数时就不会有过高预期。2. Windows部署前的准备2.1 Windows上部署的麻烦点Diffy官方发布包里的启动脚本是shell脚本默认给Linux和macOS用的Windows下直接运行会报错。这不是说Diffy不支持Windows而是它默认没提供Windows的批处理脚本。解决办法也简单不用官方脚本用java -jar直接启动核心jar包所有配置通过命令行参数传进去。你要具备的基础只有两点会打开命令提示符或PowerShell知道JAVA_HOME怎么配。另一个麻烦点是Windows的防火墙。默认情况下Java进程监听端口后外部设备不一定能访问你需要手动放行。如果只是本机浏览器访问一般没问题但如果要把Diffy地址给同事联调就必须处理防火墙规则不然会白白折腾很久。2.2 装好JDK并确认版本Diffy是基于JVM的Scala应用对JDK版本比较敏感。我的实测经验是JDK 8最稳妥。它的底层依赖是在JDK 8时代构建的用JDK 11或者17启动有可能遇到模块系统限制或者反射访问报错。虽然在某些版本下高版本也能跑起来但没必要在环境上给自己挖坑。安装步骤不复杂下载JDK 8安装包完成安装后在系统环境变量里增加JAVA_HOME指向安装目录再把%JAVA_HOME%\bin加到Path变量里。打开新的命令提示符执行java -version看到类似java version 1.8.x的输出就说明环境没问题。注意如果电脑上已经有多个JDK一定要确认当前命令窗口用的是哪个版本。可以在CMD里执行where java看看解析到的路径是不是你期望的JDK目录。Windows不会自动帮你切换先后顺序和Path配置会直接影响运行结果。2.3 拿到Diffy包下载还是自己编译Diffy官方在开源代码托管平台上有发布构建产物如果你只是想在Windows上快速用起来直接下载编译好的压缩包就好。解压后你会发现目录里有bin、lib等文件夹。bin里主要是给Linux和macOS的脚本Windows下不用管它。lib里放着Diffy的server jar包我们后面命令直接引用这个jar。如果你想自己从源码构建需要先装好sbt和Scala工具链命令大致是sbt assembly。但在Windows上构建Scala项目偶尔会遇到编码、权限、依赖下载慢的问题而且构建产物和官方下载的其实没有本质区别。所以我的建议是不是想改源码的话别自己编译浪费时间。下载后建议把压缩包解压到一个路径不包含中文和空格的目录比如C:\diffy。避免后面命令里出现路径解析的问题省心很多。2.4 准备演示用的三个本地服务在正式接业务服务之前最好先准备三个本地HTTP服务把Diffy跑通一次理解界面上的概念后再接真实项目。最方便的方式是用Python内置的HTTP服务。Windows上如果已安装Python 3可以省掉写代码的过程直接创建目录和文件。我建议建一个演示目录结构大致如下C:\diffy-demo ├── master1 │ └── data.json ├── master2 │ └── data.json └── candidate └── data.json三个目录里的data.json故意写不同的内容。master1和master2作为老版本内容应该基本一致但可以包含一个不同的随机字段用来演示噪音过滤candidate作为新版本可以故意改掉一个业务字段。这样启动之后Diffy就能呈现出“有效差异”和“忽略差异”两种效果非常直观。3. 一步一步在Windows上启动Diffy3.1 启动三个版本服务打开三个独立的命令提示符窗口分别执行三条命令。第一条python -m http.server 8882 --directory C:\diffy-demo\master1第二条python -m http.server 8883 --directory C:\diffy-demo\master2第三条python -m http.server 8881 --directory C:\diffy-demo\candidate这里我把master1放在8882端口master2放在8883端口candidate放在8881端口。先启动它们是为了让Diffy启动时就能连到后端避免后面排查时区分不清“Diffy没起来”和“后端没起来”。如果Python版本比较老没有--directory参数可以先cd到对应目录再执行python -m SimpleHTTPServer 8882。三种服务启动后分别用浏览器访问一下这几个端口能正常看到目录列表或data.json内容即可。3.2 编写启动脚本直接使用Diffy的jar包启动时命令比较长而且参数多。我建议在C:\diffy目录下新建一个start_diffy.bat文件内容如下echo off set JAVA_HOMEC:\Program Files\Java\jdk1.8.0_202 set PATH%JAVA_HOME%\bin;%PATH% cd /d C:\diffy java -Xms256m -Xmx512m -jar C:\diffy\lib\diffy-server.jar ^ -candidatelocalhost:8881 ^ -master.primarylocalhost:8882 ^ -master.secondarylocalhost:8883 ^ -service.protocolhttp ^ -serviceNamediffy-demo ^ -proxy.port8880 ^ -admin.port8884命令里^是Windows CMD里的换行符号注意它后面不能有空格否则会被当成普通字符。如果你的JAVA_HOME设置已经配到了系统环境变量里脚本前两行可以直接去掉。有一点需要特别说明diffy-server.jar的具体文件名以你实际解压后的lib目录为准可能带有版本号或其他前缀。写脚本前先看一眼直接把文件名替换成真实名称。3.3 第一次启动并观察日志双击或者执行start_diffy.bat后控制台会滚动输出日志。正常情况下会出现端口监听、配置加载之类的信息。由于Diffy本身日志量比较大我第一次跑的时候看到一堆INFO日志还以为报错了其实只要进程不退出、没有明显堆栈异常就是正常的。启动完成后可以测试两个端口8880Diffy代理端口也提供Web界面浏览器访问http://localhost:8880应该能看到界面。8884管理端口访问http://localhost:8884/admin之类的路径可以看到一些运行状态信息。如果页面直接打不开先用netstat -ano | findstr :8880确认端口是否被监听。找不到监听项说明Java进程没起来回看日志找具体错误。3.4 用Web界面看差异现在开始完整请求。打开浏览器访问http://localhost:8880/data.json意思是让Diffy代理转发一次对data.json的请求。执行几次之后回到Diffy首页就能看到请求列表和差异状态。在这个demo里master1和master2的data.json内容可以故意保持大体一致只让某个字段值不同candidate里把另一个核心字段改成不同值。Diffy会先判定master1和master2之间的差异是“非确定性噪音”然后只把candidate和它们的有效差异展示出来。你可以在界面上展开请求看到三个版本的响应详情也可以筛选只看“差异”类型。这一步跑通基本上就说明Diffy在Windows上已经部署成功。后面接真实服务时只需要把candidate和master指向实际地址路径按你自己的接口路径访问。4. 关键参数和运行原理4.1 参数逐个拆解配置Diffy的一大堆参数里最核心的是下面几个参数作用示例candidate待验证的新版本服务地址localhost:8881master.primary基准服务主实例地址localhost:8882master.secondary基准服务次实例地址localhost:8883service.protocol后端服务协议httpserviceNameDiffy内部的服务标记diffy-demoproxy.portDiffy对外代理和Web界面端口8880admin.port管理端口用于查看运行状态8884其中candidate、master.primary、master.secondary这三个是必须配置的。serviceName可以按项目名自己定义作用是在Diffy内部区分不同服务也会在日志和界面上展示。proxy.port是外界访问Diffy的唯一入口所有测试请求都走这个端口。有同学可能会问为什么同时有proxy.port和admin.port不能用一个端口因为Diffy把“转发代理”和“管理信息”两个职责分开了。proxy端口给业务方使用admin端口给运维和调试人员使用互不干扰。Windows防火墙放行的时候两个端口最好都放行。4.2 一次请求在Diffy内部怎么走当你的Windows上的服务A发起一个请求到http://localhost:8880/data.json时Diffy并不是简单地把请求原样转发给三个后端。它会按照内部策略把请求组合发送。常规组合是一个请求发给candidate一个请求发给master.primary一个请求发给master.secondary。然后根据三个响应来判断分类。如果master.primary和master.secondary返回的响应本身不一致说明这两个老版本之间存在不确定因素Diffy会把这个差异标记出来但不会当作候选版本的问题。如果master两个实例返回一致而candidate返回不一样这才算真正值得关注的差异。这种设计本质上是给“基准”这一侧也加了对照实验用两份老版本来捕获老版本自身的不稳定输出。真实生产服务里经常有随机数、时间戳、动态请求ID没有这一步差异测试基本没法用因为会满屏都是假阳性。4.3 差异结果是怎么算出来的Diffy比较的不只是HTTP状态码还会看响应头、响应体、异常信息等。当然了它默认不会对响应体的每个字节都做严格一致性校验而会更偏重内容层面的差异。这个需要在实际使用中多积累经验。比如响应体里有一段动态生成的Token每次请求都会变。如果两个master返回的Token不一样Diffy会认为这是噪音。但如果候选版本比老版本多了一个字段两个master都没有该字段Diffy就会给出一个有效差异。从使用角度来说只要看到界面里“Difference”类型的记录就说明候选版本和基准版本的行为有出入。至于出入可不可以接受需要你自己进入详情页看完整响应体甚至对比线上日志再做判断。Diffy只负责“找出不同”不负责“判断对错”。5. 常见问题排查实录5.1 端口起不来怎么办最典型的问题是8880端口被占用或者候选版本端口没启动。排查分两步先用netstat -ano | findstr :8880看端口占用PID再通过tasklist | findstr 老PID确认是哪个进程占用的。如果是Diffy自己占的但页面打不开可能是进程状态不对。如果被其他程序占了可以改proxy.port或者结束占用进程。taskkill /PID 1234 /F这个命令在管理员权限下执行比较可靠。分不清占用进程是否重要时建议不要乱杀进程直接换一个端口更安全。5.2 版本不兼容的报错最常见的错误之一是UnsupportedClassVersionError这通常是因为你用了JDK 17或更高版本而Diffy的部分类库是旧版本构建的字节码版本不被支持。解决办法是切回JDK 8然后确认Java命令确实指向JDK 8。另一种错误是类似NoSuchMethodError或ClassNotFoundException多发生在自己源码构建、但构建环境依赖没对齐的时候。直接改用官方下载包通常能绕开。5.3 外部访问不了本机能访问但别的电脑通过http://你的IP:8880访问不了百分之九十是防火墙拦截。Windows防火墙默认会阻止Java进程的入站请求。可以手动加一条入站规则允许TCP端口8880和8884。netsh advfirewall firewall add rule nameDiffy Allow dirin actionallow protocolTCP localport8880,8884这条命令需要在管理员权限的CMD里执行。如果公司网络或虚拟机网络还有更上层防火墙那就不归Windows管了需要联系网络负责人。5.4 界面一直No dataWeb界面能打开但请求之后一直是No data说明Diffy并没有收到任何请求或者收到了但没被完整记录。优先检查发起请求时是不是用对了端口有没有直接访问了三个后端端口。三个后端是否都启动Diffy是否在启动日志里成功连上它们。请求路径是否在服务上真实存在比如服务端只有/data.json你却请求了根路径/。我调试的时候犯过一个错三个Python HTTP服务都开了但启动Diffy时参数里的localhost写法不对结果Diffy没法连接master。把参数改成完整localhost:8882后就好了。5.5 更多避坑Diffy会把一次请求放大到三次后端请求所以如果你在Windows上用本地服务做验证尽量避免在Diffy后端的服务里写很多日志或者做耗时操作否则整个流程会感觉非常卡。然后Windows的命令行窗口默认编码经常是GBKDiffy日志里如果包含中文内容可能显示乱码。可以在CMD里先执行chcp 65001切到UTF-8或者在PowerShell里启动脚本。这个不影响Diffy功能但排查问题时能减少干扰。最后一个容易被忽略的点路径空格。Java命令在Windows解析时如果jar包路径在C:\Program Files下面命令行参数里可能需要用引号包住。最简单的办法是解压到C:\diffy这类路径下省掉引号转义的折腾。结尾就聊几句把Diffy在Windows上跑通之后你会发现它真正的作用不是部署本身而是帮你把“版本行为是否一致”这件抽象事变成了可视化、可对比、可筛选的具体证据。我更推荐的做法是先在本地用模拟服务把Diffy的界面和差异分类看明白再接入真实项目。原因是真服务的响应体更复杂一旦出现海量差异如果没有提前建立对Diffy输出形式的直觉会很快迷失在数据里。Windows环境完全足够作为开发调试环境生产环境想长期跑再去考虑Linux容器化。最后提醒一件事接手别人的部署脚本时先确认JDK版本和端口参数这两个地方踩坑概率最高也是我自己花时间最多的地方。

相关新闻

Qt5兼容QFtp库:零修改迁移FTP功能的实战方案

Qt5兼容QFtp库:零修改迁移FTP功能的实战方案

简介:本资源是面向Qt5开发者(尤其是从Qt4迁移或需兼容旧FTP功能的中高级工程师)的技术适配方案,解决Qt5.9中QFtp被移除后仍需使用传统FTP协议进行文件上传、下载与目录管理的实际问题。压缩包共9个文件,包含2个核心头文…

2026/10/14 22:54:32 阅读更多 →
大模型Token消耗优化实战:从输入压缩到模型选型的全链路降本指南

大模型Token消耗优化实战:从输入压缩到模型选型的全链路降本指南

1. 调用大模型时,Token到底花在了哪里很多人第一次认真看大模型账单的时候,都会愣一下:明明感觉没问几个问题,怎么费用就上去了。我刚开始接大模型接口那会儿也一样,总觉得“按量计费”应该很便宜,结果一个…

2026/10/14 22:53:29 阅读更多 →
TokenRouter:从请求级到Token级的推理路由优化实践

TokenRouter:从请求级到Token级的推理路由优化实践

1. 从一次推理延迟抖动说起:为什么要做 token 级路由 去年帮一个做智能客服的朋友排查线上问题,现象很怪:同一台推理服务器,白天响应稳定在 200ms 左右,一到晚上高峰期就飙到 1.5s,GPU 利用率却只有 40% 上…

2026/10/14 22:53:29 阅读更多 →

最新新闻

从1500词到8000词:我用分级读物把阅读词汇量真正滚起来的三年

从1500词到8000词:我用分级读物把阅读词汇量真正滚起来的三年

三年前我刚开始系统学英语的时候,遇到过一个特别尴尬的场景。一本号称"适合中级学习者"的读物,我翻了三页就合上了——满页生词,查完一句忘一句,读完第一章已经过去两个小时,脑子里只剩下一片混乱。后来我才…

2026/10/15 0:27:20 阅读更多 →
DMAD:对抗式知识蒸馏实现高质量快速图像生成

DMAD:对抗式知识蒸馏实现高质量快速图像生成

1. 这不是GAN,也不是Diffusion:DMAD到底在解决什么真问题?最近翻论文时看到“DMAD: Distribution Matching as Adversarial Distillation for Fast Visual Generation”这个标题,第一反应是——又一个缩写套娃?但细读下…

2026/10/15 0:27:20 阅读更多 →
从被替代到人机协作:AI时代的职业转型与不可替代性修炼

从被替代到人机协作:AI时代的职业转型与不可替代性修炼

1. 2026,AI 碾过来的那个冬天1.1 先说说我怎么被"碾碎"的如果你第一次刷到这篇,我简单交代一下前情:我是做内容创作的,写了将近十年的行业稿子、人物故事和产品文案。2026年以前,我一直觉得 AI 就是个高级一…

2026/10/15 0:27:20 阅读更多 →
Gmapping参数全解析:从激光匹配到粒子滤波的调参指南

Gmapping参数全解析:从激光匹配到粒子滤波的调参指南

写这篇Gmapping参数说明的念头,是我在建图调试被同一个问题绕晕的时候冒出来的。当时用的是某开源机器人平台,激光数据正常、里程计输出也正常,Gmapping画出来的地图却总是歪的。我翻了网上很多配置,发现大家贴的参数几乎一模一样…

2026/10/15 0:27:20 阅读更多 →
superpowers:让Claude Code和Codex CLI真正长出‘手脚‘的智能体技能框架

superpowers:让Claude Code和Codex CLI真正长出‘手脚‘的智能体技能框架

1. 从“superpowers”说起:一个让 AI 编程助手真正长出“手脚”的技能框架第一次看到 “superpowers” 这个词,是在几个做 AI 辅助开发的群里。有人甩出一张截图,说自己的 Claude Code 突然会“自己规划任务、自己写测试、自己跑命令、自己修…

2026/10/15 0:27:20 阅读更多 →
ponytail 实践指南:用轻量封装收束散乱操作与插件技能

ponytail 实践指南:用轻量封装收束散乱操作与插件技能

1. 从“ponytail”这个热词说起:它到底指什么第一次看到“ponytail”被当成一个技术热词来搜,我其实愣了一下。这个词本意是“马尾辫”,一个再日常不过的发型词,怎么就跟“skill”“插件”“如何使用”这些词绑在一起了&#xff1…

2026/10/15 0:26:20 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →