首页/新闻资讯/正文详情

PaddleNLP 词法分析实战:基于 GRU-CRF 的中文分词与词性标注完整训练流程

发布时间:2026/9/25 17:43:22 来源:云帆数科 栏目:资讯中心
PaddleNLP 词法分析实战:基于 GRU-CRF 的中文分词与词性标注完整训练流程
人工智能大模型预训练微调LoRARLHF强化学习分布式训练【免费下载链接】PaddleNLPEasy-to-use and powerful LLM and SLM library with awesome model zoo.项目地址https://gitcode.com/gh_mirrors/pa/PaddleNLP点击查看免费下载本文围绕 PaddleNLP 仓库中的词法分析示例slm/examples/lexical_analysis/README.md系统讲解基于「双层双向 GRU CRF」序列标注模型的完整工作流数据组织与 IOB2 标注体系、单卡/多卡训练、模型评估、静态图导出与部署预测以及通过 Taskflow 一键调用 LAC 分词任务。读完本文你可以从零复现 LAC 类词法分析模型的训练与部署理解每个命令行参数背后的源码实现。1. 任务与模型结构词法分析任务的输入是一个字符串文档中称为「句子」输出是句子中的词边界和词性、实体类别。序列标注是词法分析的经典建模方式该示例使用基于 GRU 的网络结构学习特征并将学习到的特征接入 CRF 解码层完成序列标注。模型由四部分构成输入层采用 one-hot 方式表示每个字以一个 id 表示Embedding 层one-hot 序列通过字表转换为实向量表示的字向量序列特征层字向量序列作为两层堆叠的双向 GRU的输入学习输入序列的特征表示堆叠两层以增加学习能力解码层CRF 以 GRU 学习到的特征为输入以标记序列为监督信号实现序列标注。对应到源码整个网络在 model.py 中由BiGruCrf类实现与上述四个步骤一一对应class BiGruCrf(nn.Layer): def __init__(self, word_emb_dim, hidden_size, vocab_size, num_labels, emb_lr2.0, crf_lr0.2, with_start_stop_tagTrue): # one-hot id - 实向量 self.word_embedding nn.Embedding( num_embeddingsself.vocab_size, embedding_dimself.word_emb_dim, ...) # 两层双向 GRU self.gru nn.GRU( input_sizeself.word_emb_dim, hidden_sizeself.hidden_size, num_layers2, directionbidirectional, ...) # 发射分数 self.fc nn.Linear(in_featuresself.hidden_size * 2, out_featuresself.num_labels 2 if with_start_stop_tag else self.num_labels, ...) # CRF 解码 self.crf LinearChainCrf(self.num_labels, self.crf_lr, with_start_stop_tag) self.crf_loss LinearChainCrfLoss(self.crf) self.viterbi_decoder ViterbiDecoder(self.crf.transitions, with_start_stop_tag)forward的行为取决于是否有标签训练时传入labels经crf_loss计算负对数似然损失推理时无标签则走viterbi_decoder输出最优标签序列。从源码结构看这里体现了「同一网络、两种前向路径」的典型序列标注写法——CRF 训练时用全局损失监督解码时用 Viterbi 算法保证全局最优路径。另外两个设计细节值得注意分组学习率Embedding 层的学习率缩放为emb_lr2.0CRF 转移层为crf_lr0.2网络其余部分使用基础学习率。这源于 LAC 原始设计思路embedding 参数多、需要学得快CRF 转移矩阵只依赖标签组合、收敛快用较小学习率避免振荡。参数初始化与正则所有权重采用Uniform(-0.1, 0.1)初始化并对 GRU/线性层权重加L2Decay(coeff1e-4)正则。CRF 相关组件来自 paddlenlp/layers/crf.pyViterbiDecoder优先从paddle.text导入不存在时回退到 PaddleNLP 自带实现见 model.py。2. 数据准备2.1 下载示例数据集仓库提供了少数样本用于示例输入数据格式执行以下命令下载并解压示例数据集lexical_analysis_dataset_tinypython download.py --data_dir ./其实现见 download.py通过paddle.utils.download.get_path_from_url从百度 BOS 下载并解压数据集压缩包。2.2 数据格式训练数据需要用户按应用场景自行组织。格式规定如下文件第一行是固定的表头text_a\tlabel之后每行数据由两列组成以制表符\t分隔第一列是 utf-8 编码的中文文本字与字之间用\002分隔第二列是每个字对应的标注同样以\002分隔采用IOB2 标注体系X-B表示类型为 X 的词的开始X-I表示类型为 X 的词的持续O表示不关注的字在词性、专名联合标注中实际上不存在 O。示例摘自原文档除\002了\002他\002续\002任\002十\002二\002届\002政\002协\002委\002员\002,\002马\002化\002腾\002,\002雷\002军\002,\002李\002彦\002宏\002也\002被\002推\002选\002为\002新\002一\002届\002全\002国\002人\002大\002代\002表\002或\002全\002国\002政\002协\002委\002员 p-B\002p-I\002r-B\002v-B\002v-I\002m-B\002m-I\002m-I\002ORG-B\002ORG-I\002n-B\002n-I\002w-B\002PER-B\002PER-I\002PER-I\002w-B\002PER-B\002PER-I\002w-B\002PER-B\002PER-I\002PER-I\002d-B\002p-B\002v-B\002v-I\002v-B\002a-B\002m-B\002m-I\002ORG-B\002ORG-I\002ORG-I\002ORG-I\002n-B\002n-I\002c-B\002n-B\002n-I\002ORG-B\002ORG-I\002n-B\002n-I解析逻辑在 data.py 的load_dataset中逐行读取后用\t切分两列再用CHAR_DELIMITER \002切分字与标签并通过assert len(words) len(labels)校验字与标签是否一一对应。文件名中含infer的文件会被当作无标签推理数据只取文本列。2.3 标签体系标签集合包含24 个词性标签小写字母和4 个专名类别标签大写字母完整定义如下标签含义标签含义标签含义标签含义n普通名词f方位名词s处所名词t时间nr人名ns地名nt机构名nw作品名nz其他专名v普通动词vd动副词vn名动词a形容词ad副形词an名形词d副词m数量词q量词r代词p介词c连词u助词xc其他虚词w标点符号PER人名LOC地名ORG机构名TIME时间需要特别注意的是人名、地名、机构名和时间四个类别存在两套标签PER / LOC / ORG / TIME 与 nr / ns / nt / t。被标注为第二套小写标签的词是模型判断为低置信度的人名、地名、机构名和时间词。开发者可以基于这两套标签在四个类别的准确率与召回率之间做出自己的权衡——例如严格场景下只信任大写专名标签高召回场景下合并两套标签。2.4 词表文件数据集目录中除train.tsv、test.tsv、infer.tsv外还包含三个词表文件在 train.py 中被加载word.dic字词表OOV 字统一映射到OOV词元tag.dic标签表OOV 标签回退为O见 data.py 中convert_tokens_to_ids的oov_replace_token参数q2b.dic全角转半角DBC→SBC归一化词表训练、评估、预测前都会先经过normalize_token做文本归一化。convert_example还会将序列截断到max_seq_len默认 64 字并输出(token_ids, length, label_ids)三元组由Pad/Stack/Tuple完成批组装word_ids按[PAD]索引填充、length堆叠、label_ids按O标签索引填充见 train.py。3. 模型训练3.1 单卡训练python train.py \ --data_dir ./lexical_analysis_dataset_tiny \ --model_save_dir ./save_dir \ --epochs 10 \ --batch_size 32 \ --device gpu \ # --init_checkpoint ./save_dir/final文档说明的六个核心参数如下参数释义data_dir数据集所在文件夹路径model_save_dir训练期间模型保存路径epochs模型训练迭代轮数batch_size每次迭代每张卡上的样本数目device训练使用的设备gpu表示使用 GPUcpu表示使用 CPU文档中另提及xpu表示百度昆仑卡见 3.3 节关于当前源码取值范围的说明init_checkpoint模型加载路径通过设置它可以启动增量训练3.2 源码中的完整参数表train.py 的argparse定义中还有一组文档未逐一展开、但对复现实验很关键的模型超参与训练控制参数参数默认值释义max_seq_len64单句最长字数超长截断base_lr0.001影响整个网络的基础学习率Adam 优化器crf_lr0.2CRF 层学习率缩放系数透传给BiGruCrfemb_dim128字嵌入维度hidden_size128GRU 隐层节点数logging_steps10每 X 个 step 打印一次训练日志save_steps100每 X 个 step 保存一次 checkpointdo_evalTrue保存 checkpoint 时是否顺带评估3.3 训练循环的源码细节从 train.py 的主循环可以看到几处实操要点checkpoint 命名每save_steps步保存为model_global_step.pdparams这也是评估/导出命令中model_100.pdparams这类路径的由来best 模型自动选择每次保存 checkpoint 后若do_evalTrue会立即在测试集上跑evaluateF1 高于历史最佳时额外保存一份best_model.pdparams增量训练--init_checkpoint指向的目录若存在paddle.load后model.load_dict加载参数实现断点续训指标计算使用paddlenlp.metrics.ChunkEvaluator(label_listlabel_vocab.keys(), suffixTrue)以「词」为最小评测单位计算 precision / recall / F1——suffixTrue即 IOB2 的 B/I 后缀约定。设备取值范围当前 train.py 中--device的choices为[cpu, gpu]README 中提及的xpu属于文档层面的说明直接传xpu会被参数校验拒绝跨平台部署时需注意这一前提。多卡训练时通过paddle.distributed.get_world_size()判断卡数多于 1 卡则init_parallel_env并使用DistributedBatchSampler保证各卡数据不重叠。3.4 多卡训练python -m paddle.distributed.launch --gpus 0,1 train.py \ --data_dir ./lexical_analysis_dataset_tiny \ --model_save_dir ./save_dir \ --epochs 10 \ --batch_size 32 \ --device gpu \ # --init_checkpoint ./save_dir/final多卡模式下batch_size表示每张卡的批大小全局批大小 batch_size × 卡数调参时需注意等效学习率的影响。4. 模型评估加载训练保存的参数文件在测试集上验证python eval.py --data_dir ./lexical_analysis_dataset_tiny \ --init_checkpoint ./save_dir/model_100.pdparams \ --batch_size 32 \ --device gpu其中./save_dir/model_100.pdparams是训练过程中保存的参数文件请更换为实际得到的训练保存路径也可使用自动保存的best_model.pdparams。eval.py 的流程与训练中的evaluate一致重新构建BiGruCrf网络emb_dim、hidden_size默认各 128必须与训练一致→paddle.load加载权重 → 遍历测试集每批调用model(token_ids, length)得到 Viterbi 解码标签 → 用ChunkEvaluator累加后输出eval precision: %f, recall: %f, f1: %f注意评估、预测、导出脚本各自独立解析参数因此--emb_dim、--hidden_size、--max_seq_len的默认值必须与训练时保持对齐否则网络结构与权重形状不匹配。5. 模型导出动态图训练结束之后可以将动态图参数导出为静态图参数具体代码见 export_model.py。静态图参数保存在output_path指定路径中运行方式python export_model.py --data_dir./lexical_analysis_dataset_tiny \ --params_path./save_dir/model_100.pdparams \ --output_path./infer_model/static_graph_params参数说明params_path动态图训练保存的参数路径output_path静态图参数导出路径。从源码看导出过程是标准的paddle.jit动态转静态流程见 export_model.pymodel paddle.jit.to_static( model, input_spec[ InputSpec(shape[None, None], dtypeint64, nametoken_ids), InputSpec(shape[None], dtypeint64, namelength), ], ) paddle.jit.save(model, args.output_path)两个输入token_ids[None, None]动态 batch 与动态句长和length[None]的名称与形状会在推理侧被固定复用这正是部署脚本按token_ids/length两个 input handle 喂数的依据。注意导出时模型以无标签模式运行静态图中固化的是 Viterbi 解码路径。6. 静态图部署预测导出模型后用于部署deploy/predict.py 提供了基于paddle.inference的 Python 部署预测示例。运行方式分两种情况开启 PIRPaddlePaddle 3.0.0 默认python deploy/predict.py --model_fileinfer_model/static_graph_params.json \ --params_fileinfer_model/static_graph_params.pdiparams \ --data_dir lexical_analysis_dataset_tiny未开启 PIRpython deploy/predict.py --model_fileinfer_model/static_graph_params.pdmodel \ --params_fileinfer_model/static_graph_params.pdiparams \ --data_dir lexical_analysis_dataset_tinydeploy/predict.py中Predictor类的关键实现值得部署时参考通过paddle.inference.Config(model_file, params_file)创建配置GPU 场景调用config.enable_use_gpu(100, 0)CPU 场景调用config.disable_gpu()可再按需开启 MKL-DNN、设置线程数switch_use_feed_fetch_ops(False)关闭默认 feed/fetch 算子改用get_input_handle/get_output_handle直接拷贝数据copy_from_cpu输入token_ids与lengthpredictor.run()后从输出 handle 取出标签预处理与训练侧完全一致convert_example中同样执行全角转半角归一化、OOV 替换、max_seq_len截断再经parse_result把字级 B/I 标签解析成词与词性对最终以Text: ... / Result: [(词, 词性), ...]的形式打印并在结尾统计总预测耗时脚本内置--epochs参数用于多轮 benchmark。7. 动态图模型预测对无标签数据可以直接用动态图权重预测不需要先导出python predict.py --data_dir ./lexical_analysis_dataset_tiny \ --init_checkpoint ./save_dir/model_100.pdparams \ --batch_size 32 \ --device gpu得到类似以下输出完整结果写入当前目录results.txt(大学, n)(学籍, n)(证明, n)(怎么, r)(开, v) (电车, n)(的, u)(英文, nz) (什么, r)(是, v)(司法, n)(鉴定人, vn)predict.py 读取的是data_dir下的infer.tsv无标签文件data.py 中load_dataset对infer文件只取文本列并跳过首行表头。输出格式的拼接逻辑在parse_result中遍历字级标签遇到-B后缀或前一非 O 标签后出现 O即把累积的部分词落盘取tag.split(-)[0]得到词性最终zip(sent, tags)组成(词, 词性)序列。这套解析逻辑在动态图预测与静态图部署预测中是共用的。8. Taskflow 一键预测如果不想自己走完整训练部署流程可以直接使用 PaddleNLP 提供的 Taskflow 工具对输入文本进行一键分词from paddlenlp import Taskflow lac Taskflow(lexical_analysis) lac(LAC是个优秀的分词工具) [{text: LAC是个优秀的分词工具, segs: [LAC, 是, 个, 优秀, 的, 分词, 工具], tags: [nz, v, q, a, u, n, n]}] lac([LAC是个优秀的分词工具, 三亚是一个美丽的城市]) [{text: LAC是个优秀的分词工具, segs: [LAC, 是, 个, 优秀, 的, 分词, 工具], tags: [nz, v, q, a, u, n, n]}, {text: 三亚是一个美丽的城市, segs: [三亚, 是, 一个, 美丽, 的, 城市], tags: [LOC, v, m, a, u, n]}] 任务的默认路径为$HOME/.paddlenlp/taskflow/lexical_analysis/lac/默认路径下包含执行该任务需要的所有文件。从源码 paddlenlp/taskflow/lexical_analysis.py 看LacTask声明了四个资源文件——model_state.pdparams、tag.dic、q2b.dic、word.dic首次使用时按内置 URL 与 MD5 校验下载到默认路径这与第 2.4 节训练数据目录中的词表文件一一对应说明 Taskflow 内置模型与本训练流程属于同一模型体系。如果希望得到定制化的分词及标注结果也可以通过 Taskflow 加载自定义的词法分析模型。通过task_pathmodel_path指定用户自定义路径自定义路径下的文件需要和默认路径的文件一致custom_task_path/ ├── model.pdparams ├── word.dic ├── tag.dic └── q2b.dic加载自定义模型进行一键预测from paddlenlp import Taskflow my_lac Taskflow(lexical_analysis, model_path./custom_task_path/)此外LacTask还支持传入user_dict用户自定义词典见 lexical_analysis.py用于业务领域专有词的强制干预适合行业语料上的定制化部署。更多使用方法请参考 Taskflow 文档。9. 预训练模型如果希望直接使用预训练好的 LAC 模型完成词法分析任务而不用从示例数据训练可参考仓库指向的 LAC 官方模型与 PaddleHub 分词模型下载渠道README 中给出外链以官方渠道发布的权重与词表为准。使用预训练模型时word.dic、tag.dic、q2b.dic必须与模型配套版本一致——因为 embedding 维度、标签数量直接决定了网络形状词表不匹配会在paddle.load/load_dict阶段报错。10. 小结从示例脚本到生产部署的路径阶段入口文件输入输出数据下载download.py—lexical_analysis_dataset_tiny/训练train.pytrain.tsv/test.tsv 三个词表save_dir/model_*.pdparams、best_model.pdparams评估eval.pytest.tsv checkpointprecision/recall/F1动态图预测predict.pyinfer.tsv checkpointresults.txt、(词, 词性)序列静态图导出export_model.py动态图参数static_graph_params.*部署预测deploy/predict.py静态图模型低延迟推理结果一键调用Taskflow(lexical_analysis)文本text/segs/tags结构整体来看这套示例完整覆盖了「数据 → 训练 → 评估 → 导出 → 部署」的典型 Paddle 序列标注工程链路核心模型只有百余行model.py但围绕它的参数分组学习率、IOB2 标签解析parse_result、全角半角归一化、Chunk 级指标等细节都是复现和迁移到其他序列标注任务NER、POS 等时可以直接借鉴的工程实践。赞分享人工智能大模型预训练微调LoRARLHF强化学习分布式训练【免费下载链接】PaddleNLPEasy-to-use and powerful LLM and SLM library with awesome model zoo.项目地址https://gitcode.com/gh_mirrors/pa/PaddleNLP点击查看免费下载相关推荐PaddleFormers 词法分析实战指南基于 PaddleHub 的 LAC 与 jieba_paddle 中文分词、词性标注与专名识别PaddleFormers 词法分析实战指南基于 PaddleHub 的 LAC 与 jieba_paddle 中文分词、词性标注与专名识别 导读 中文自然语人工智能大模型微调模型推理服务PaddleNLP RoFormerTokenizer 源码级解析基于 jieba 预分词与 WordPiece 的中文分词实践PaddleNLP RoFormerTokenizer 源码级解析基于 jieba 预分词与 WordPiece 的中文分词实践 导读 RoFormerRo人工智能大模型预训练微调LoRARLHF强化学习分布式训练模型推理服务推理引擎模型量化模型压缩本地部署NLPPaddleNLP RoFormerv2Tokenizer 深度解析基于 WordPiece 的中文预训练分词器使用与实现PaddleNLP RoFormerv2Tokenizer 深度解析基于 WordPiece 的中文预训练分词器使用与实现 RoFormerv2RoForm人工智能大模型预训练微调LoRARLHF强化学习分布式训练模型推理服务推理引擎模型量化模型压缩本地部署NLP上一篇LLM-as-a-Judge 智能体的 Web Search 工具设计指南从 Zod 模式契约到研究管线落地Agent-Skills-for-Context-Engineering 实战下一篇DB-GPT 快速上手指南从克隆仓库到完成首次对话的 5 步最小配置方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

GitHub 热榜项目 - 日榜(2026-02-16):用 TaoToken 统一 Key 跑通榜单项目配置
GitHub 热榜项目 - 日榜(2026-02-16):用 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/9/25 17:43:22

Ubuntu22.04.5 安装 Visual Studio Code 开发环境:TaoToken 统一 Key 配置与验证
Ubuntu22.04.5 安装 Visual Studio Code 开发环境: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/9/25 17:43:16

基于 ANTLR v4 的 Apache Thrift IDL 文法解析:从 .thrift 源文件到语法树
基于 ANTLR v4 的 Apache Thrift IDL 文法解析:从 .thrift 源文件到语法树

编程语言编译器开发工具 【免费下载链接】grammars-v4 Grammars written for ANTLR v4; expectation that the grammars are free of actions. 项目地址: https://gitcode.com/gh_mirrors/gr/grammars-v4 点击查看 免费下载 本指南以 grammars-v4 仓库中的 thrift/… · 2026/9/25 17:43:10

【Maven系列2】生命周期与插件
【Maven系列2】生命周期与插件

讲解Maven的生命周期和插件,以及常用的命令。Maven生命周期三套生命周期Maven 的生命周期并不是一个整体,Maven 拥有三套相互独立的生命周期:clean:项目清理的处理default(或 build):项目部署的处理site:项… · 2026/9/25 18:27:53

Apereo CAS 作为 OAuth 2.0 服务端:协议端点、配置属性与授权流实战指南
Apereo CAS 作为 OAuth 2.0 服务端:协议端点、配置属性与授权流实战指南

后端认证鉴权单点登录 【免费下载链接】cas Apereo CAS - Identity & Single Sign On for all earthlings and beyond. 项目地址: https://gitcode.com/gh_mirrors/ca/cas 点击查看 免费下载 本文以 Apereo CAS 官方文档为骨架,系统讲解如何将 CAS … · 2026/9/25 18:27:47

色弱色盲色彩校正:Daltonization 算法在前端看板中的实战
色弱色盲色彩校正:Daltonization 算法在前端看板中的实战

色弱色盲色彩校正:Daltonization 算法在前端看板中的实战在全人类人口结构中,有超过 $8%$ 的男性与 $0.5%$ 的女性(全球近 3 亿人) 患有不同程度的先天性色觉障碍(Color Vision Deficiency, CVD / 俗称色弱与色盲&… · 2026/9/25 18:27:29

大模型辅助的 ARIA 角色与状态图谱自动标注流水线
大模型辅助的 ARIA 角色与状态图谱自动标注流水线

大模型辅助的 ARIA 角色与状态图谱自动标注流水线在复杂的企业级前端富交互组件(如多层嵌套树形控件 TreeView、复合分段选项卡 Tabs、无级滑动滑块 Slider、以及网格数据表格 DataGrid)开发中,无障碍 ARIA 角色(Roles&#xff09… · 2026/9/25 18:27:23

【论文笔记Rapidly Handling Constrained Multi-objective Optimization Problems with Hypervolume Gradient01】
【论文笔记Rapidly Handling Constrained Multi-objective Optimization Problems with Hypervolume Gradient01】

《Rapidly Handling Constrained Multi-objective Optimization Problems with Hypervolume Gradient Subspace Approximation》Kenneth M. Zhang, Angel E. Rodriguez-Fernandez, Ke Shang, Senior Member, IEEE, Hisao Ishibuchi, Fellow, IEEE, and Oliver Schutze提出了一种… · 2026/9/25 18:27:17

万能文件分析师Skill:以后收到几十页PDF,别再从第一页开始硬看了!
万能文件分析师Skill:以后收到几十页PDF,别再从第一页开始硬看了!

工作里最容易被低估的一件事,就是“看文件”到底有多耗时间。领导突然丢来一份80页的PDF,让你下午给结论;群里一次发来5个方案,让你说说区别;同事传来几十页制度文件,让你找出跟某个项目有关的条款。过去我… · 2026/9/25 18:26:59

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

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

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

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

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

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

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码