异常检测实战:从孤立森林到动态阈值,构建高可用监控系统
1. 异常检测到底在解决什么问题异常检测这四个字听起来像是学术论文里的术语但如果你做过任何跟数据打交道的项目大概率已经跟它打过照面了。比如服务器CPU突然飙到95%、某条产线的传感器读数偏离历史区间、一批订单里混进了几张明显不合理的退款单——这些场景背后要回答的核心问题只有一个在大量正常数据中怎么把那一小撮“不对劲”的东西揪出来。我最早接触异常检测是在一个设备监控项目里。当时手头有几百台设备的运行日志每台设备每隔几秒上报一次温度、转速、功耗等指标。业务方的需求很朴素“能不能在设备真正坏掉之前提前告诉我哪台可能有问题”这个问题翻译成技术语言就是给定一条时间序列判断当前时刻的数据点是否偏离了正常模式。异常检测的难点不在于“检测”而在于“异常”这个词本身就没有统一定义。不同场景下异常的含义完全不同在金融风控里异常是一笔与用户历史行为严重不符的交易在工业质检里异常是产品表面一个肉眼可见的划痕在运维监控里异常是某个指标突然突破了历史波动范围在医疗健康领域异常是某项生理指标偏离了正常参考区间。所以做异常检测项目第一步永远不是选模型而是跟业务方把“什么算异常”这件事掰扯清楚。我见过太多团队一上来就套孤立森林、Autoencoder结果跑出来的结果业务方根本不认因为双方对“异常”的理解压根不在一个频道上。这篇文章适合谁看如果你正在做跟监控、风控、质检、运维相关的项目需要从数据里找出“少数派”那这篇内容可以直接拿去参考。我会从整体设计思路讲到具体实操包括工具选型、参数计算、踩过的坑尽量把每个决策背后的逻辑说透。2. 整体方案设计与技术选型思路2.1 先搞清楚你的异常属于哪一类异常检测的方法论可以粗略分成三大类选哪一类取决于你手头的数据长什么样。第一类有标签的监督学习。如果你手里已经有一批标注好的“正常/异常”样本那本质上就是一个二分类问题。但现实是异常样本通常极少正负样本比例可能达到1000:1甚至更极端。这种情况下直接用分类模型会面临严重的类别不平衡问题需要配合过采样、代价敏感学习等策略。第二类无监督学习。大多数异常检测项目属于这一类——你只有一堆正常数据或者连哪些是正常哪些是异常都不清楚。这时候的思路是让模型学习“正常长什么样”然后把偏离正常模式的点判为异常。孤立森林、One-Class SVM、Autoencoder都属于这个范畴。第三类半监督学习。你有一批确认正常的样本但异常样本很少或者没有。模型只在正常数据上训练然后根据重构误差或密度估计来判断新样本是否异常。我个人的经验是如果业务方能给出明确的异常定义和少量标注样本优先考虑半监督方案如果完全没有标签那就从无监督方法入手先跑出一个基线结果再让业务方去标注Top-N的可疑样本迭代几轮之后逐步转向半监督。2.2 工具选型为什么我最终选了这套组合在工具层面我试过不少方案最终在一个中等规模的监控项目里稳定下来的组合是这样的环节工具选择选型理由数据处理Pandas NumPy生态成熟调试方便中小规模数据完全够用特征工程Tsfresh 自定义滑窗自动提取时序特征减少手工设计成本基线模型Isolation Forest无需标签对高维数据友好训练速度快进阶模型AutoencoderPyTorch能捕捉非线性模式重构误差可解释性强阈值确定极值理论EVT比固定分位数更稳健适应数据分布变化可视化Plotly Grafana交互式排查方便跟业务方对齐这里重点说一下为什么基线模型选孤立森林而不是One-Class SVM。孤立森林的核心思想是用随机切分的方式把数据点孤立出来异常点因为“离群”所以更容易被少数几次切分就孤立。它的优势在于训练复杂度是线性的不需要计算距离矩阵对高维数据不会像One-Class SVM那样容易过拟合。实测下来在几十万条数据、几十个特征的场景下孤立森林几分钟就能跑完而One-Class SVM可能要跑几个小时。至于阈值确定很多人习惯直接用“超过99%分位数就算异常”但这个方法有个致命问题它假设异常比例是固定的。实际上异常比例会随时间段变化比如大促期间交易异常率天然就比平时高。用极值理论EVT的好处是它通过对尾部分布建模来动态确定阈值能更好地适应数据分布的变化。2.3 整体架构从数据到告警的完整链路一个完整的异常检测系统通常包含以下几个环节数据采集与清洗从各个数据源拉取原始数据处理缺失值、重复值、时间对齐等问题。特征工程把原始时序数据转换成模型能吃的特征向量包括统计特征、频域特征、滑窗特征等。模型训练与推理在历史数据上训练模型对新到来的数据实时打分。阈值判定与告警根据异常分数和动态阈值决定是否触发告警。反馈闭环业务方对告警进行确认或否认标注结果回流到训练集持续优化模型。这个链路里最容易出问题的环节是特征工程和阈值判定。特征工程决定了模型能看到什么信息阈值判定决定了告警的准确率和召回率如何平衡。后面我会分别展开讲。3. 核心细节解析与实操要点3.1 数据预处理别急着上模型先把数据洗干净异常检测对数据质量极其敏感。一个缺失值填充不当可能就会制造出一批“假异常”。我在项目里踩过的一个坑是某台设备因为网络抖动连续几分钟上报的数据都是同一个值。如果直接拿去做检测这段平坦的曲线会被模型判为异常但实际上它只是数据采集出了问题。数据预处理阶段我通常会做这几件事缺失值处理对于时序数据优先用线性插值或前向填充如果缺失比例超过30%考虑直接丢弃该时间段。去重与时间对齐确保每个时间点只有一条记录多条记录需要按业务规则聚合。异常值清洗注意这里说的是“清洗明显的数据错误”比如温度传感器报了-999度这种是采集错误而非业务异常需要先剔除。归一化/标准化不同特征的量纲差异很大需要统一到相近的尺度。对于时序数据我倾向于用RobustScaler而不是StandardScaler因为前者对异常值更鲁棒。注意归一化的时候一定要用训练集的统计量去变换测试集不能把训练集和测试集混在一起算均值和方差否则会造成数据泄露。3.2 特征工程模型的上限由特征决定异常检测项目里特征工程的重要性怎么强调都不过分。原始时序数据直接喂给模型效果通常很差因为模型很难从原始数值里自动学到“波动变大”“趋势改变”这类模式。我常用的特征提取方式包括统计特征均值、标准差、最大值、最小值、中位数、偏度、峰度、四分位距。这些特征能刻画一个时间窗口内的数据分布形态。滑窗特征用固定大小的窗口在时间轴上滑动计算每个窗口内的统计量。窗口大小的选择很关键——太小会引入噪声太大会平滑掉异常。我的经验是窗口大小至少覆盖2-3个完整的业务周期。比如监控日活数据窗口至少设成7天。差分特征一阶差分、二阶差分、同比、环比。这些特征能捕捉趋势变化和突变。频域特征对窗口内的数据做FFT提取主频、频谱能量等。这个在设备振动分析里特别有用。自定义业务特征比如交易场景里的“距上次交易时间间隔”、运维场景里的“距上次重启时间”等。这里分享一个实操技巧用Tsfresh自动提取特征后一定要做特征筛选。Tsfresh默认会生成几百甚至上千个特征其中很多是冗余的。我通常用基于树模型的特征重要性排序保留Top 30-50个特征既能保证效果又能控制计算成本。3.3 模型训练从基线到进阶的迭代路径模型训练我一般分两步走第一步用孤立森林跑基线。孤立森林的参数不多核心是n_estimators树的数量和max_samples每棵树的采样数。我的经验值是n_estimators100、max_samples256在大多数场景下都能给出一个可用的基线。如果数据量特别大可以适当增加树的数量但超过200之后收益递减明显。第二步用Autoencoder做进阶。Autoencoder的思路是让模型学习正常数据的压缩表示然后通过重构误差来判断异常——正常数据重构误差小异常数据重构误差大。网络结构上我通常用3-5层的全连接网络编码器和解码器对称中间瓶颈层的维度设为输入维度的1/4到1/2。训练Autoencoder时有几个关键点损失函数用MSE还是MAE如果数据里噪声比较多MAE更鲁棒如果追求对微小异常的敏感度MSE更合适。早停策略在验证集上监控重构误差如果连续几轮不下降就停止训练防止过拟合。学习率调度用余弦退火或ReduceLROnPlateau避免训练后期震荡。3.4 阈值确定动态阈值比固定阈值靠谱得多阈值确定是异常检测里最容易被忽视但影响最大的环节。固定阈值的问题在于它无法适应数据分布的漂移。比如一个电商平台平时的订单量在几千到几万之间波动大促期间可能冲到几十万。如果用固定阈值大促期间会疯狂告警平时又可能漏报。我目前用的方法是基于极值理论的动态阈值。具体做法是对历史异常分数拟合广义帕累托分布GPD根据目标误报率计算对应的阈值每隔一段时间用新数据重新拟合更新阈值。这个方法的数学细节这里不展开核心思想是只对分布的尾部建模而不是对整个分布做假设。实测下来相比固定分位数阈值动态阈值能把误报率降低30%以上。4. 完整实操流程与关键环节实现4.1 环境准备与依赖安装先说一下我用的环境。Python 3.9以上主要依赖如下pip install pandas numpy scikit-learn pyod pytorch tsfresh plotly这里重点说几个包的用途pyod是一个专门做异常检测的库里面集成了孤立森林、One-Class SVM、LOF等常用算法接口统一非常适合快速实验tsfresh用于自动特征提取pytorch用来搭Autoencoder。4.2 数据加载与预处理实操假设我们有一份设备监控数据包含时间戳、设备ID、温度、转速、功耗五个字段。加载和预处理的代码如下import pandas as pd import numpy as np from sklearn.preprocessing import RobustScaler # 加载数据 df pd.read_csv(device_monitor.csv, parse_dates[timestamp]) df df.sort_values([device_id, timestamp]).reset_index(dropTrue) # 处理缺失值按设备分组做线性插值 df[temperature] df.groupby(device_id)[temperature].transform( lambda x: x.interpolate(methodlinear, limit5) ) # 剔除明显的数据错误 df df[(df[temperature] -50) (df[temperature] 200)] # 归一化 feature_cols [temperature, rotation, power] scaler RobustScaler() df[feature_cols] scaler.fit_transform(df[feature_cols])这段代码里有几个细节值得注意interpolate的limit5表示最多连续插值5个点超过5个点的缺失就保留为NaN后续要么丢弃要么用其他方式处理RobustScaler用中位数和四分位距做缩放比均值和标准差更不容易被异常值带偏。4.3 特征提取与滑窗构造接下来构造滑窗特征。我通常用1小时作为窗口大小步长为10分钟def create_sliding_window_features(df, window_size1h, step10min): features [] for device_id, group in df.groupby(device_id): group group.set_index(timestamp) for start in pd.date_range(group.index.min(), group.index.max(), freqstep): end start pd.Timedelta(window_size) window group.loc[start:end] if len(window) 10: continue feat { device_id: device_id, window_start: start, temp_mean: window[temperature].mean(), temp_std: window[temperature].std(), temp_max: window[temperature].max(), temp_min: window[temperature].min(), temp_range: window[temperature].max() - window[temperature].min(), rotation_mean: window[rotation].mean(), rotation_std: window[rotation].std(), power_mean: window[power].mean(), power_std: window[power].std(), } features.append(feat) return pd.DataFrame(features)窗口大小的选择需要结合业务节奏。如果是设备监控1小时窗口通常够用如果是交易风控可能需要缩短到5分钟甚至更短。步长决定了检测的实时性步长越小检测越及时但计算量也越大。4.4 模型训练与异常打分先用孤立森林跑一个基线from pyod.models.iforest import IForest feature_cols [temp_mean, temp_std, temp_max, temp_min, temp_range, rotation_mean, rotation_std, power_mean, power_std] X features[feature_cols].values # 训练孤立森林 clf IForest( n_estimators100, max_samples256, contamination0.05, # 预估异常比例 random_state42 ) clf.fit(X) # 对新数据打分 scores clf.decision_function(X) features[anomaly_score] scorescontamination参数表示你预估的异常比例这个值不需要很精确它主要影响阈值的初始位置。如果完全不知道异常比例可以先设成0.05后续根据业务反馈调整。4.5 动态阈值计算与告警触发用极值理论计算动态阈值from scipy.stats import genpareto def dynamic_threshold(scores, target_fpr0.01): # 取尾部数据拟合GPD threshold_init np.percentile(scores, 95) tail scores[scores threshold_init] - threshold_init if len(tail) 20: return np.percentile(scores, 100 * (1 - target_fpr)) # 拟合广义帕累托分布 params genpareto.fit(tail, floc0) # 根据目标误报率计算阈值 n len(scores) n_tail len(tail) p target_fpr * n / n_tail threshold threshold_init genpareto.ppf(1 - p, *params) return threshold threshold dynamic_threshold(scores, target_fpr0.01) features[is_anomaly] features[anomaly_score] threshold这段代码的核心逻辑是先用95%分位数把数据分成“主体”和“尾部”然后只对尾部拟合GPD最后根据目标误报率反推阈值。这样做的好处是阈值会随着数据分布的变化自动调整。5. 常见问题与排查技巧实录5.1 告警太多怎么办误报率高的排查思路误报率高是异常检测项目最常见的问题。我遇到过的原因大致有这么几类问题现象可能原因排查方法解决方案每天大量告警阈值设得太低统计告警数量与业务异常数量的比例提高阈值或改用动态阈值某段时间集中告警数据分布漂移对比该时段与历史数据的统计量重新训练模型或加入时间特征特定设备频繁告警设备个体差异大按设备分组统计异常分数分布按设备分别建模或用设备ID做特征告警集中在某些特征特征量纲不一致检查各特征的分布范围重新做归一化或调整特征权重我的经验是误报率控制在5%以内是可以接受的因为异常检测本质上是一个高召回优先的任务。漏报的代价通常比误报大得多——漏掉一个真正的故障可能导致业务中断而多几条误报只是增加一些人工确认成本。5.2 漏报怎么办召回率低的优化方向漏报率高通常意味着模型没有学到真正的异常模式。可以从这几个方向优化增加特征维度模型看不到的信息它永远学不会。检查是否遗漏了关键业务特征。调整窗口大小如果异常表现为短时突变大窗口会把它平滑掉如果异常表现为长期趋势偏移小窗口又捕捉不到。换模型孤立森林对局部异常敏感但对全局趋势变化不敏感。如果异常表现为趋势偏移可以试试Autoencoder或基于预测的残差方法。降低阈值这是最直接的方法但会牺牲误报率需要权衡。5.3 模型上线后效果下降数据漂移的应对策略数据漂移是异常检测系统绕不开的问题。业务在变、用户在变、设备在老化今天正常的模式明天可能就不正常了。我通常用这几个手段来应对定期重训练每周或每月用最新数据重新训练模型。重训练频率取决于业务变化速度变化快的场景可能需要每天重训。在线学习对于流式数据可以用增量学习的方式更新模型。孤立森林不支持增量学习但Autoencoder可以通过在线梯度下降来更新。监控模型指标持续监控异常分数分布、告警数量、业务方确认率等指标一旦发现明显偏移就触发重训练。保留人工反馈通道让业务方能够方便地标记“这条告警是误报”或“这条漏报了”这些反馈是最宝贵的训练数据。5.4 实操避坑清单最后整理一份我在项目里踩过的坑供参考不要用未来数据做特征。滑窗特征只能使用当前时刻之前的数据否则会造成数据泄露离线指标很好看但上线就崩。不要忽略时间对齐。多个数据源的时间戳可能有偏差需要先做时间对齐再合并。不要用全量数据拟合归一化参数。训练集和测试集必须用同一套参数否则分布不一致。不要只用一个模型。孤立森林和Autoencoder的异常打分可以加权融合通常比单模型效果好。不要忘记业务验证。模型说异常不算异常业务方说异常才算异常。上线前一定要让业务方看一批样本确认双方对异常的理解一致。不要设了阈值就不管了。阈值需要定期回顾和调整尤其是在业务节奏发生变化的时期。6. 异常检测项目的扩展方向异常检测做完基线之后还有不少可以深挖的方向。比如多变量异常检测当异常涉及多个指标的联合偏离时单变量方法会失效需要用到图神经网络或Transformer来建模指标之间的关联。再比如可解释性业务方不仅想知道“哪里异常”还想知道“为什么异常”这时候可以用SHAP值或注意力权重来解释模型的判断依据。还有一个方向是异常检测与根因分析的结合。检测到异常只是第一步更重要的是定位异常的原因。我最近在尝试的方法是把异常分数按特征维度分解看看是哪个特征的偏离贡献最大这样能给运维人员提供更直接的排查线索。另外少样本异常检测也是一个值得关注的方向。很多场景下异常样本极少甚至连正常样本都不够。这时候可以用元学习或对比学习的方法让模型从少量样本中快速适应新的异常模式。这些方向我还在陆续实践后续有新的心得再整理出来分享。异常检测这个领域没有银弹每个场景都需要根据数据特点和业务需求来定制方案多试、多调、多跟业务方对齐才是把项目做好的关键。

相关新闻

PyTorch从零实现逻辑回归:深入理解分类与神经网络底层原理

PyTorch从零实现逻辑回归:深入理解分类与神经网络底层原理

逻辑回归这玩意儿,别看名字里带个"回归",它干的其实是分类的活儿。我刚开始学深度学习那会儿,也被这个命名坑过,以为它跟线性回归是亲兄弟,结果发现它是个披着回归外衣的分类器。这次我打算用PyTorch从头到尾…

2026/10/15 20:33:09 阅读更多 →
数据资产管理:核心框架与实践指南

数据资产管理:核心框架与实践指南

1. 数据资产管理的基本概念与挑战在大数据时代,数据已经成为企业最核心的资产之一。每天,全球产生的数据量以惊人的速度增长,从TB级到PB级,甚至EB级。面对如此庞大的数据量,如何有效管理这些数据资产,使其发…

2026/10/15 20:33:09 阅读更多 →
MFC动态实时曲线绘制:双缓冲与环形缓冲区实战

MFC动态实时曲线绘制:双缓冲与环形缓冲区实战

简介:这份资源面向具备一定VC基础的Windows开发者与数据可视化学习者,聚焦MFC框架下动态实时曲线的绘制实现。内容围绕自定义视图类、GDI绘图、数据库交互与多线程同步等核心知识点展开,可用于监控系统、数据采集界面等需要实时刷新图表的场景…

2026/10/15 20:33:09 阅读更多 →

最新新闻

MySQL零基础入门:从安装到增删改查实战教程

MySQL零基础入门:从安装到增删改查实战教程

写这篇教程的初衷很简单——我见过太多人一上来就啃官方文档,结果被术语劝退;也见过不少人背了一堆命令,却连数据库都没装好。MySQL作为最流行的开源关系型数据库,它其实没有传说中那么难,难的是没人告诉你第一步该干嘛…

2026/10/15 21:18:29 阅读更多 →
让AI Agent写出正确代码:自我验证闭环实战指南

让AI Agent写出正确代码:自我验证闭环实战指南

过去大半年,我一直在折腾 AI Agent 写真实业务代码。最头疼的不是它写不出来,而是它写出来的东西你不敢信:代码结构完整、命名也规范、注释还齐,结果一跑测试,边界条件炸了一地。后来听到一位在开发者工具领域深耕多年…

2026/10/15 21:18:29 阅读更多 →
大麦抢票脚本怎么用:Python 自动化抢票从登录到下单的完整指南

大麦抢票脚本怎么用:Python 自动化抢票从登录到下单的完整指南

大麦抢票脚本怎么用:Python 自动化抢票从登录到下单的完整指南 【免费下载链接】Automatic_ticket_purchase 大麦网抢票脚本 项目地址: https://gitcode.com/GitHub_Trending/au/Automatic_ticket_purchase 想让热门演出大麦抢票不再拼手速,靠的不…

2026/10/15 21:18:29 阅读更多 →
LoRA:大语言模型的低秩适应

LoRA:大语言模型的低秩适应

研究问题 预训练模型通常需要下游任务数据来继续训练模型,全参数微调更新全部参数:模型越大,梯度、优化器状态和任务专属模型副本的开销越高。 问题:能否只训练少量参数,获得接近全参数微调的效果,同时减少…

2026/10/15 21:18:29 阅读更多 →
华为OD机考100题含答案:从刷题到考场稳定发挥的完整指南

华为OD机考100题含答案:从刷题到考场稳定发挥的完整指南

简介:这份华为OD机考100题(含答案)docx文档,面向具备一定编程基础、正在准备华为OD机考或同类技术认证的开发者,帮助其系统熟悉机考题型与考察重点。文档精选100道经典真题,涵盖【5键键盘的输出】【N进制减…

2026/10/15 21:18:29 阅读更多 →
参考资源章节如何从“链接堆砌”变成文档导航页

参考资源章节如何从“链接堆砌”变成文档导航页

1. 第32章参考资源放在最后,却是读者最先翻的章节做技术文档这么多年,我越来越觉得“参考资源”是被误解最深的一章。大多数人以为它就是把链接堆在结尾,让读者自己去看,但实际上它决定了一本手册、一个项目文档能不能真正被人用起…

2026/10/15 21:17:27 阅读更多 →

日新闻

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/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

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

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

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

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

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

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 9:49:14 阅读更多 →