AI可复现性挑战:固定随机种子、锁定环境,让训练结果稳定复现
1. 从一次“幽灵复现失败”说起到底什么是AI的可复现性挑战前阵子我把一台GPU服务器上的旧训练任务重新跑了一遍用的确实是当时的代码、当时的数据文件、当时的依赖环境结果AUC从0.713变成了0.704。当时我的第一反应不是“代码写错了”而是心里咯噔一下这个问题我已经不是第一次遇见了。行业里面对这类现象有一个专门的说法就是AI的可复现性挑战。所谓可复现性挑战说白了就是同一个AI模型实验从数据准备、模型训练、调参到最终评估很难在脱离原始环境之后被精确重演。你可能只是在另一台机器上重跑或者把依赖升了个版本甚至仅仅换了一张不同型号的GPU最后拿到的Loss曲线和评估指标就变了。这听起来不像“Bug”那么刺眼但它比Bug更棘手因为它并不总是导致程序崩溃而是让结果变得“似是而非”。这篇文章我想把这五个字拆开讲清楚可复现性到底卡在哪个环节哪些随机源最容易坑人以及我这些年在一线训练和团队协作里是怎么一步步把“跑一次”变成“跑多少次都一样”的。无论你是刚接触深度学习的算法新人还是要给团队定实验规范的负责人下面这些内容都很实用。1.1 我碰到的那次“指标蒸发”事件那次出问题的任务本身不复杂是一个点击率预估方向的模型。第一次训练跑了将近三十个小时最后验证集AUC是0.713我当时把权重、日志和代码都存了下来。两个星期以后我用同一份训练数据、同一个commit的代码在另一台机器上重新训练出来的AUC却变成了0.704。这个变化听起来只有零点零几可放在线上A/B实验里足以让一个本来“预期正向”的策略变得不可判断。我花了大半天时间排查先把概率比较大的嫌疑排除了一遍没有改数据、没有改预处理、没有改模型结构。后来我把两个实验的日志放到一起逐行对比才发现两个运行在第三个epoch之后Loss曲线就出现了肉眼可见的分离而且分离方向完全随机不是谁高谁低而是两边开始各走各的。类似的经历我相信很多跑过深度学习的同行都遇到过。问题不在于某个人的代码写得不好而是整个训练链路里天然存在很多“随机变量”它们平时不动声色一旦环境变了就会一起发作。可复现性挑战真正难的地方就在这里一堆微小的差异叠加起来最后变成你完全认不出的结果。1.2 “跑通了”其实有三个层次运行、复现、追溯在团队里我经常听到有人说“这个模型我跑通了”。“跑通”这个词的歧义太大了。我习惯把实验结果分成三个层次层次含义典型表现能运行程序不崩溃有输出训练脚本能出Loss能保存模型可复现外部条件一致时结果一致相同代码、相同环境、相同数据跑出相同指标可追溯不但能重来还能说清差异来源重新实验时能定位哪一步引入偏差很多项目和论文停在第一层也就是“能运行”。模型训练完指标记录在Excel里代码可能还在某个人的本地分支上依赖没锁。等到换人、换机、换季度再想还原当初那个结果基本只能靠运气。第二层“可复现”是绝大多数工业团队应该追求的下限把随机种子固定好、依赖锁好、数据版本固定至少自己隔三个月还能跑出接近的结果。第三层“可追溯”更难它要求每一个实验都有完整的上下文包括代码版本、数据版本、环境摘要、随机种子、甚至还包含CPU/GPU型号。只有到了这一层你才敢在跨团队协作、审计、线上回滚的时候说一句“这事经得起问”。我个人的判断是AI的可复现性挑战真正挑战的不是“重跑一次”而是“重跑十次都说得清楚”。前者是工程纪律后者是系统设计。2. 三座随机性暗礁种子、数据次序与GPU算子要跟可复现性打交道首先得知道“鬼”藏在哪。我排查过很多次复现失败最后发现大部分问题都能归到三个随机源上。这三样东西几乎出现在每一次训练里却极少被人认真对待。2.1 随机数固定种子不是“做做样子”深度学习里的随机数几乎无处不在。模型参数初始化用的是随机数Dropout要随机丢弃神经元数据加载要随机打乱顺序很多优化器也有内部的随机状态。你可以粗暴地理解成整个训练过程就是一场大型随机实验如果不把随机源锁住每次实验都是不同宇宙里的平行事件。最常见的做法是设一个固定种子比如这样import random import numpy as np import torch seed 20240512 random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed)这几行代码要在任何数据读取、模型构建之前执行因为随机状态一旦被消费后面再怎么设种子都晚了。我见过不少人把种子设置在导入PyTorch之后、却在数据增强模块里用到了NumPy的随机数于是模型本身的种子固定了但数据增强还在随机抖动最后照样复现不了。这里还有一个很多人忽略的点固定了Python、NumPy和PyTorch的种子不等于把全世界的随机源都锁住了。有些扩展库会维护自己的随机状态多进程数据加载里每个worker的随机状态也需要单独处理。所以固定随机种子是必要不充分条件它能把大头稳住但小头不解决结果还是会有细微波动。2.2 数据加载次序多线程Shuffle里藏着状态问题第二个随机源是数据加载顺序。同一个训练集你按顺序喂给模型和打乱后喂给模型训练出来的模型是完全不同的。这一点很好理解可真正容易踩坑的是你以为你设置了全局随机种子数据顺序就一定固定然而DataLoader里的多进程一开事情就变了。PyTorch的DataLoader在num_workers 0时每个worker进程的随机状态和主进程并不完全同步。如果你只设了全局种子然后直接shuffleTrue那么每次启动训练时数据打乱的顺序仍然可能不同。更稳妥的做法是给DataLoader单独传一个Generatorg torch.Generator() g.manual_seed(seed) train_loader DataLoader( dataset, shuffleTrue, generatorg, num_workers4, )这个Generator本质上就是数据加载器的专属随机源跟主进程的随机状态分开管理。这样你设置种子之后打乱顺序的随机行为至少在同一个PyTorch版本里是确定的。如果你是做分布式训练还要注意每个rank拿到的数据分片是否一致因为分布式Sampler通常会重新划分数据划分逻辑和shuffle的种子同样需要被固定和记录。2.3 GPU算子里藏着的“非确定性缝隙”这一条可能是最容易被忽略的。很多人把代码环境都固定好了随机种子也都设了结果跑两次还是差一点点这时候八成是GPU算子的非确定性在作祟。GPU上很多计算是并行的比如矩阵乘法和卷积底层会把一个大计算拆成很多小块并行执行。小块之间的计算顺序偶尔会不一样浮点数加法的顺序一变结果在最后几位上就有差异。这种差异本身极小但会随着训练步数累积最后在指标上表现出零点几甚至一个百分点的差距。我一般会在训练代码里补上这两个设置torch.backends.cudnn.benchmark False torch.backends.cudnn.deterministic True这里面的逻辑是benchmark默认会为了性能去自动挑选卷积算法挑的过程本身就是非确定的关掉它再强制使用确定性算法能减少不少波动。但你也别指望这两个开关一开就万事大吉不同型号的GPU、不同驱动版本的底层实现仍然可能存在差异尤其是有Tensor Core参与的低精度计算跨硬件完全复现的难度更高。可以说GPU层面的非确定性是“可以被抑制但很难被根除”的。3. 环境漂移版本号背后的版本才是复现失败的第二主谋随机性只解释“同一环境跑两次为什么不一样”。可复现性挑战还有另一半换个环境跑为什么结果差那么多这一半的答案通常写在环境依赖里。3.1 版本号不能担保行为一致很多人认为把requirements.txt里的版本号写清楚了环境就锁定了。这个认知在简单场景下成立在真实项目里却很危险。依赖不是孤立的你的Python包会依赖别的包那些包又依赖更底层的库。版本号只能说明“装了哪个版本”不能说明“这个版本在当前环境里表现如何”。举个很常见的例子NumPy版本变了某些随机数生成算法在不同版本里的实现可能不同你用旧版本生成了一组数据增强的随机序列队友用新版本跑数据分布就微妙地变了。PyTorch或CUDA版本更新之后某些算子的默认实现也可能调整同样代码跑出来的数值就有偏差。版本号只能说明“装了哪个版本”不能说明“这个版本在当前环境里表现如何”。更麻烦的是同一份代码可能在不同的Python版本、不同的操作系统、不同的GPU驱动下表现各异。一个在Python 3.8下跑得好好的训练脚本到了Python 3.11环境里没准连随机数序列都变了。所以可复现性的环境问题本质上不是“版本对不对”而是“环境是否被完整定格”。3.2 用依赖锁定和容器把环境变成“可搬运的现场”我处理环境问题一般分两步走。第一步锁定直接依赖和间接依赖。pip freeze能把当前环境里所有安装的包和版本导出来我通常保存成分requirements.lock.txt而不是手写一个宽松的requirements.txt。关键区别在于手写的版本列表往往只写了顶层依赖比如torch2.3.0可torch依赖的几十个底层包版本没有被固定。pip freeze会把整棵依赖树都记录下来别人拿到手才能重建一个差不多的环境。第二步用容器把整个环境连同基础镜像一起打包。我常用的做法是用Dockerfile固定训练环境而且不是只固定镜像Tag还会尽量固定镜像的摘要值# 一个可复现训练镜像的简化示例 FROM train-base:py310-cu121sha256:2a459e5f8c4e1a... WORKDIR /workspace COPY requirements.lock.txt . RUN pip install --no-cache-dir -r requirements.lock.txt COPY code/ ./code/ CMD [python, -m, train]这样做的好处是别人拿到的不是一个模糊的“基于某个镜像”的承诺而是一串可以校验的哈希值。镜像本身一旦被构建出来只要Digest不变里面所有二进制、系统库、Python包就都一致。环境从“玄学”变成了“可以搬走的现场”。3.3 我推荐的低成本环境快照三件套说句实话并不是所有团队都有精力维护一套复杂的镜像发布流水线。如果你从小团队起步我推荐先做这三件低成本的事情每次训练跑起来之前导出一份requirements.lock.txt跟代码一起提交写一个简单的Dockerfile至少保证“给我这台机器我能重建环境”把GPU驱动版本、CUDA版本、机器型号一行字写进实验记录里。这三件事花不了半小时却能解决大部分环境漂移问题。我在自己的项目里早期就是靠这三招才把“换了机器没法复现”的频率从每周两三次降到了几乎为零。4. 把实验追溯变成工程习惯从单个Notebook到多人团队如果说固定种子和锁定环境是“防意外”那实验追溯就是“查真相”。一个可复现的AI项目必须有足够的上下文信息让任何人在任何时候都能回答三个问题这个结果是什么时候产生的用什么代码和数据产生的当时的运行环境是什么4.1 每一次训练都要有“身世档案”我之前也走过弯路喜欢在训练脚本里随手改参数每次跑完就在终端里瞄一眼指标然后转头去写下一个版本。这种做法在当时很爽可一旦要回头对比就完全抓瞎。后来我养成一个习惯每次训练启动前生成一个实验卡片文件连同训练日志一起保存。这个卡片不需要很复杂有下面这些字段就够了{ project: ctr_model_0426, git_commit: f7b2c3e9a1d4, dataset_version: recsys_v320240512, seed: 20240512, data_sha256: a3f2d93b1c..., environment: train-base:py310-cu121sha256:2a459e5f8c4e1a..., cuda_version: 12.1, gpu_type: A100-40G }我自己会把这段JSON放在训练日志的第一行这样即使模型文件散落各地只要还有人留着日志就能找到训练时的完整上下文。工程上更规范的做法是接入开源实验管理框架把指标、参数、代码commit、环境信息自动记录成一条实验记录。两者不冲突手动写卡片是最低保障自动记录是锦上添花。4.2 数据版本和模型注册缺了哪一块都会被坑很多人做实验追溯时只盯着代码和环境却把数据版本这一环漏了。数据集文件在磁盘上的路径可能没变但内容早被人悄悄换过一版。我现在要求团队里所有数据变更都要带版本标识训练前先计算数据文件的SHA256跟实验卡片里的值比对不一致就直接中断训练。这听起来有点“矫枉过正”但数据文件被覆盖导致实验结果莫名变化的事我见得太多了。模型层面也一样。一个项目跑上几个月磁盘里会有几十个checkpoint如果只靠文件名区分你根本分不清哪个对应哪个实验、哪个是最终采用版本。我建议给模型注册增加最少四项元数据模型版本号、训练代码commit、训练数据版本、关键评估指标。这样当你需要回溯“线上那个模型是怎么训出来的”时就不用在硬盘里大海捞针了。4.3 一次团队协作复现排查的真实过程之前在某团队合作一个推荐模型项目A同学和B同学分别独立复现同一个训练流程结果A的验证集指标比B高了接近0.02。两人代码版本一致、环境镜像一致、随机种子一致看起来什么都对得上。最后我让他们把数据文件的哈希值列出来一查才发现A机器上数据集是5月12号的版本B机器上数据集的路径名虽然完全一样但文件其实在5月20号被覆盖过。数据版本不一致其他再对齐也没用。这件事之后我们把数据校验从“靠人自觉”变成了“训练入口强制校验”没有通过哈希校验的训练任务直接不给跑。排查过程本身不算复杂但它说明一个道理可复现性不是某一个环节的事而是数据、代码、环境、随机状态四者的合力结果。少记录任何一块排查时都要多花好几倍时间。5. 可复现不等于“每次一分不差”我们要复现的是边界不是玄学聊到这里你可能会有个疑问是不是把所有种子、环境、代码都固定了模型训练就必须每次都给出完全一样的数字从理论上讲在一个完全确定的单机环境里可以做到高度一致但在真实工程里我建议你换个目标把结果稳定在可接受的容差范围内而不是追求逐位相同。5.1 什么时候可以接受微小的波动单机单卡训练通常能做到接近确定只要算子没有太强的非确定性、依赖版本没有变化两次训练结果往往能对齐到小数点后三四位。但一旦进入多卡并行或分布式训练情况就不一样了。多卡训练中梯度在不同设备之间做归并通信顺序、数值精度都会带来细微差异这种差异在累积之后可能变成零点几个百分点的指标浮动。所以我做实验对比时会把“可复现”定义成一个区间两次训练同一模型的指标差不超过某个阈值比如相对误差0.5%就认为可复现超过阈值则视为异常必须停下来排查。这个阈值不是拍脑袋定的而是要结合你任务本身的波动来设。如果模型在固定数据上本身就有较大的随机波动你硬要要求0.1%以内那大概率是折腾自己。核心思想是要复现的是“实验结论”而不是“浮点数本身”。5.2 把“可复现”变成持续回归测试可复现性如果只在新实验启动时被想起来那它永远是被动的。更好的做法是把它做成一类自动化回归测试定期用同一份测试数据、同一个训练配置把当前模型和上一版本的模型都跑一遍对比评估指标。我自己的习惯是每次模型结构或数据处理逻辑有变动时先跑一个“对照实验”新代码、旧代码在相同数据子集上各训一个小规模版本看指标差异方向是否与预期一致。如果新代码引入了不该有的变化这个小规模对照实验能很快暴露出来不需要等到完整训练结束才发现问题。组件化分析、事故复盘、抽查抽查都是这里持续安装的场景。这样做的成本很低收益却很高可复现性从“临时救火”变成了“日常体检”。5.3 我日常训练前常用的检查清单这里分享一份我每次启动训练前都会在脑子里过一遍的清单你可以直接抄走随机种子是否在数据加载和模型构建之前固定DataLoader是否单独指定了GeneratorcuDNN的确定性开关是否打开依赖是否通过锁文件固定并记录在实验卡片里数据版本是否经过SHA256校验代码commit和当前工作区是否干净GPU型号和CUDA版本是否写进了训练日志这套清单不复杂但它能把“可复现”从一句口号变成每天重复的动作。我大部分踩过的坑最后回头都能对应上清单里的某一行。6. 回头看“可复现性挑战”我自己的坚持做了几年训练和模型迭代之后我看代码的眼光变了。拿到一份训练代码我最先看的不是它的网络结构有多精巧而是它敢不敢把随机种子、数据版本、环境指纹这些“出身信息”摆在明面上。敢摆出来的实验至少经得起别人问一句“换台机器还行吗”不敢摆的哪怕指标再好看我心里也会打个问号。我不敢说我现在的每个实验都做到了百分之百可复现但我至少养成了一些小习惯每次训练前多写一行种子每次跑完多导出一份环境锁文件每次对比实验多记录一下数据版本的哈希值。这些动作单独看都不起眼积累起来却能让整个项目的可复现性上一个台阶。最后再多说一句AI的可复现性挑战不是一个“一次就能解决”的问题它更像是一个持续维护的实验纪律。你只要稍微松懈一点那些隐藏的随机源和环境漂移就会悄悄回来。好在应对手段并不神秘——固定种子、锁定环境、记录上下文、设置合理容差然后把它们变成日常惯性。做到这些你会在某一天突然发现那些曾经让你抓狂的“幽灵差异”已经很久没有出现过了。

相关新闻

从零构建计算机网络知识体系:分层、封装与核心概念详解

从零构建计算机网络知识体系:分层、封装与核心概念详解

1. 为什么我要从零写一个计算机网络专栏做开发这些年,被问得最多的问题里,“怎么学计算机网络”绝对排得进前三。每次有新人问我该看什么书、该刷什么题,我都想起自己当年抱着那本厚得能当枕头的经典教材,从物理层啃到应用层&…

2026/10/20 3:25:24 阅读更多 →
Vue3——第 2 篇:开发环境搭建与第一个 Vue 应用

Vue3——第 2 篇:开发环境搭建与第一个 Vue 应用

本篇定位:在理解 Vue 的基本概念之后,我们需要真正"把代码跑起来"。本篇将带你从零开始,一步步搭建 Vue 3 开发环境,创建并运行你的第一个 Vue 应用,并深入理解项目目录结构。读完本篇,你将拥有一…

2026/10/20 3:26:22 阅读更多 →
Vue3——第 3 篇:模板语法——从插值到指令的全面掌握

Vue3——第 3 篇:模板语法——从插值到指令的全面掌握

本篇定位:模板语法是 Vue 的"视图层语言",是你每天编写 Vue 代码时打交道最多的部分。本篇将系统讲解 Vue 模板中的所有语法规则——从简单的文本插值到强大的指令系统,让你彻底掌握"如何把数据变成用户看到的界面"。读完…

2026/10/20 3:26:23 阅读更多 →

最新新闻

PS自带字体设计商标侵权风险高,安全用字流程详解

PS自带字体设计商标侵权风险高,安全用字流程详解

前几天有个做电商的朋友发了个文件给我,说是新做的品牌字标,急着要提交商标注册。我打开一看,他用PS里的自带字体拉了四个字,又加了个描边,觉得很稳。我第一句话就问:这字体你拿到商用授权了吗?…

2026/10/20 5:54:19 阅读更多 →
鸿蒙应用开发中的手势冲突排查与解决实战指南

鸿蒙应用开发中的手势冲突排查与解决实战指南

先讲个我实际踩过的坑。上次做一个卡片瀑布流页面,每张卡片本身支持左右滑动来切换操作按钮,页面本身又是一个可上下滚动的长列表。写完之后第一轮自测就翻车了:手指在卡片上左右滑,列表纹丝不动;上下滑,卡…

2026/10/20 5:54:19 阅读更多 →
P2P_SDK集成指南:NAT穿透与音视频传输避坑实践

P2P_SDK集成指南:NAT穿透与音视频传输避坑实践

简介:这份TUTK IoTC官方SDK压缩包为开发者在Android、iOS、Windows及macOS平台快速构建摄像头P2P监控系统提供完整工具链,面向物联网或音视频领域的工程人员。压缩包内共1187个文件,整体约56.15MB,其中既包含Java、C源码及头文件&…

2026/10/20 5:54:19 阅读更多 →
App Inventor 集成 MQTT:用 UrsAI2Paho 扩展实现物联网实时通信

App Inventor 集成 MQTT:用 UrsAI2Paho 扩展实现物联网实时通信

简介:面向App Inventor开发者的UrsAI2Paho扩展包,是一个基于Eclipse Paho客户端库的MQTT插件,目标是让没有网络编程经验的用户也能通过拖拽积木完成连接服务器、发布/订阅主题和接收消息等物联网通信任务;内置心跳维持与QoS消息等…

2026/10/20 5:54:19 阅读更多 →
Eplan许可证管理优化:从部署到维护的完整排查指南

Eplan许可证管理优化:从部署到维护的完整排查指南

在电气设计团队里,Eplan 的许可证管理几乎每个管理员都绕不过去。日常最常听到的抱怨就是"明明采购了足够的授权,图纸高峰期却提示许可不足",或者"墙边工位那台电脑连着的是我们团队的许可证,但那人已经出差两周了…

2026/10/20 5:54:19 阅读更多 →
PPT工程化实战:用ppt-master实现演示文稿批量生成与自动化

PPT工程化实战:用ppt-master实现演示文稿批量生成与自动化

1. 项目缘起与核心定位第一次看到“ppt-master”这个标题,我脑子里蹦出来的不是某个具体工具,而是一类非常典型的工程需求:把演示文稿从“手工活”变成“可编程、可复用、可批量”的流水线。过去几年里,我参与过不少内部汇报、产品…

2026/10/20 5:53:19 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

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

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

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

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

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

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 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/19 2:54:50 阅读更多 →
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/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练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/18 12:16:16 阅读更多 →