Model Weight Store Upload Planning:Mooncake Reshard 模型权重上传规划机制解析
人工智能大模型模型推理服务后端【免费下载链接】MooncakeMooncake is the serving platform for Kimi, a leading LLM service provided by Moonshot AI.项目地址https://gitcode.com/gh_mirrors/mo/Mooncake点击查看免费下载plan_weight_upload将一份完整的运行时权重放置runtime weight placement转换为不可变的WeightUploadPlan。该计划向 Store 写入端提供规范的StoredWeightManifest、payload 对象位置以及每次上传操作对应的来源证据source evidence。本文基于 Mooncake 仓库中 模型权重存储上传规划设计文档 与 mooncake-reshard 实现源码深入讲解上传规划的输入约束、副本选择算法、计划内容结构、快照写入 API、恢复路径与原生 Store 依赖帮助你理解并复现这套一次完整权重放置 → 一个不可变上传计划的机制。1. 设计动机为什么需要显式的上传规划层在大模型推理/训练场景中权重model weight需要从分布式运行时多机多卡、TP/PP/EP/DP 并行切分迁移到持久化 Store再在任意目标放置下恢复。这个过程有两个天然风险来源不一致运行时权重可能处于 lease 租约期、worker 实例可能变化、多个 DP 副本的 generation 可能不一致若直接按当前内存地址上传容易读到半更新状态。布局信息丢失Store 端保存的只是字节对象若从 Store key 反推模型布局会产生脆弱耦合。Mooncake Reshard 的解法是先由框架适配器framework adapter导出无地址的规范几何信息tensor 全局形状、并行轴切分、片段几何再由 planner 把所有绑定binding与放置placement校验、筛选并固化为一个不可变计划。Store 写入端只消费计划、执行 I/O从不推断模型布局或并行度。2. 输入两份 Manifest 的契约上传规划接受两类输入见 上传规划实现输入作用WeightPlacementManifest描述全局 tensor 几何以及 TP/PP/EP/DP 各并行轴的归属关系ownershipWeightRuntimeBindingManifest提供已填充populated放置参与者的活体来源绑定worker 地址、instance_id、lease_id、generationPlanner 会对每个提供的绑定逐一校验其与放置的一致性pair_manifests配对、tensor 描述符一致性校验等。模型语义如 tensor 如何切分、并行轴含义保持在框架适配器中适配器在调用本 API 之前即导出规范的 tensor 与并行轴元数据。2.1 强制约束上传必须来自复制语义的 DP 张量实现中有一个关键限制_collect_upload_sources会先检查是否存在has_dp_ownership(tensor)即 DP 是否被声明为张量归属轴每个 DP rank 只持有部分数据。若存在这样的 DP-owned 张量直接抛出ValueErrorWeight Store upload requires replicated DP source tensors; DP-owned tensor snapshots are not supported这意味着Store 上传的完整副本语义要求 DP 是复制轴ReplicatedAxis每个 DP rank 都持有完整张量DP 作为所有权轴每个 rank 持有一部分的张量快照不支持直接上传因为无法选择一个完整副本。这也是下面副本选择算法能成立的前提。3. 副本选择Replica Selection只存一份完整来源副本规划器只为每次上传存储一个完整来源副本算法分四步对应_collect_upload_sources与complete_parallel_source_replicas见 ownership.py要求复制语义的 DP 语义 完整逻辑覆盖对每个 DP rank检查该 rank 上的所有非 DP-owned 张量的片段是否无重叠地精确覆盖完整张量boxes_exactly_cover用全局偏移 局部形状做盒子覆盖校验。只有完整覆盖的 DP rank 才成为候选副本。要求该副本内每个选中的来源绑定具有相同 generation对每个候选 DP rank收集其片段所属绑定 manifest 的 generation若集合大小恰为 1才把该 rank 记为generation 一致。全部候选都没有一致 generation 时抛错source manifests have no complete generation-consistent DP replica多个候选副本 generation 不一致时抛complete source DP replicas have inconsistent lease generations。确定性选择最低 DP rankselected_dp min(generations_by_dp)保证同一组输入永远选出同一个副本便于复现与对账。保留每个选中片段的逻辑 TP/PP/EP 归属选中的片段保留其rank.tp/pp/ep与parallel_tensor_owner判定结果Store 侧不需要也不保留运行时地址。最终 manifest 中每个被选中的逻辑来源片段恰好对应一个 stored fragmentDP 副本不会重复 payload 对象一个完整副本只写一份字节。关于筛选细节candidates以(tensor_id, global_offset, local_shape)为几何键分组组内用_runtime_sort_key按dp、pp、ep、tp排名的顺序再按worker_id、fragment_id排序后取第一个随后按(tensor_id, global_offset, local_shape)排序输出。测试 test_upload_planning.py 覆盖了上述全部行为test_upload_plan_selects_one_complete_generation_consistent_dp_replica选中唯一完整且 generation 一致的副本、test_upload_plan_rejects_complete_dp_replicas_at_different_generations跨副本 generation 不一致被拒、test_upload_plan_rejects_incomplete_dp_replica不完整副本被拒、test_upload_plan_rejects_dp_owned_source_tensorDP-owned 张量被拒、test_upload_plan_preserves_tp_pp_and_ep_fragment_ownershipTP/PP/EP 归属被保留。4. 计划内容Plan ContentsWeightUploadPlan的结构WeightUploadPlan是不可变数据类定义见 contracts.py包含manifestStoredWeightManifest其group、manifest、payload key 全部不可变对象创建后不可修改operations每个 stored fragment 对应一个UploadOperationsource_placement_id与source_placement_digest来源放置身份与摘要用于上传时校验来源未漂移transaction_group_id与control_key上传事务组及其决策decision控制键。4.1UploadOperation一份来源证据 目标几何每个UploadOperation携带字段含义source_placement来源PlacementFragment无地址的逻辑几何source_snapshot无所有者的RuntimeFragmentSnapshot由RuntimeFragmentSnapshot.from_attested_pair从放置片段 绑定片段构造source_participant_id/source_instance_id来源参与者与运行时实例 IDsource_lease_id/source_generation来源租约 ID 与 generationtarget目标StoredFragmentSnapshotfragment_id、tensor_id、全局偏移、局部形状、object_key、object_offset0、nbytes、aliases构造期做了大量契约校验来源放置与绑定的 placement_fragment_id 必须一致来源片段与目标片段的 tensor_id/global_offset/local_shape/nbytes 必须完全一致target.object_offset必须为 0source_snapshot.lease_generation必须等于source_generation。4.2 Key 布局与 fragment 摘要plan_weight_upload生成的 key 布局namespace默认default、key_prefix默认weights均校验非空{key_prefix}/{namespace}/{resource_id}/{revision}/{weight_generation} ├── /manifest # StoredWeightManifest 本体 ├── /payload/{transaction_id}/{fragment_id} # 每个片段的字节对象 └── /transactions/{transaction_id} └── /decision # 事务决策控制键其中transaction_id为uuid4().hex每个fragment_id是对{tensor_id}|{global_offset}|{local_shape}做SHA-256 摘要并截取前 24 个十六进制字符_fragment_digest因此几何相同的片段在任何机器、任何代际下得到同一 fragment_id——这是幂等与去重的基础整个StoredWeightManifest还有manifest_digest对to_json()sort_keysTrue、紧凑分隔符的字节流做 SHA-256供manifest_identity使用WeightUploadPlan的__post_init__还会验证transaction group 必须属于 manifest groupcontrol_key必须等于{transaction_group_id}/decisionoperations 的目标集合必须与 manifest fragments 完全一致payload object_key 必须属于本事务。关于 payload 写入端文档指出 The payload writer rebinds this evidence to a fresh runtime manifest and acquires the framework allocation guard before Store I/O。即上传时WeightUploadService.upload会先做一系列新鲜度校验validate_manifest_pair、revision/generation/placement_id/digest 匹配、instance_id 陈旧检测、lease/generation 陈旧检测、same_runtime_snapshot比对必要时通过acquire_weight_binding_token获取新的绑定 token 与 allocation guards再执行batch_put_from批量写入失败时以FAILED_DRAINED终态释放 token见 upload.py。5. 执行边界Execution BoundaryStore 写入端只消费计划Store writer 负责payload 写入、注册registration、事务提交/中止commit/abort、Store 到运行时读取Store-to-runtime reads。Store writer 不负责从 Store key 推断模型布局或并行度模型语义在框架适配器侧。这种边界隔离带来两个好处一是 Store 端逻辑与框架无关可复用于多种框架适配器二是 key 布局、事务结构可以自由演进而不影响模型语义。事务侧由WeightUploadTransactiontransaction.py管理require_writable检查/认领事务可写性、commit把决策写入control_key并发布 manifest、abort_upload清理 payload。注意 writer 的abort()在_commit_decision_may_exist为真时不允许 abort提示retry commit instead——避免在决策边界模糊时误清理已可能提交的数据。6. 快照 APISnapshot APIbegin_weight_snapshot快照入口在 entrypoint.py 与 store.pyMooncakeDistributedStore.begin_weight_snapshot(descriptor, adapter) # - WeightStoreWriter调用流程WeightStoreWriter见 writer.py构造时adapter.export_source(snapshot)一次性导出完整来源放置与活体绑定WeightSnapshotSource并校验resource_id/revision/weight_generation与WeightSnapshotDescriptor一致随即调用weight_store.plan_upload(...)生成内部WeightUploadPlan调用方逐 tensor 写入writer.write_tensor(tensor_id, tensor)——适配器的resolve_fragment_ids(tensor_id, tensor, source)把框架 tensor 映射为规范 placement fragment ID并拒绝空解析、重复解析、跨快照片段、跨 tensor 片段、重复提交某个参与者participant的必需片段全部提交后自动_flush_participant触发该参与者的实际上传WeightUploadService.upload全部片段就绪后writer.commit()才发布StoredWeightManifest——commit 前任何缺失片段都会 abort 并抛错Weight snapshot is missing required fragments支持with上下文管理器正常退出自动 commit异常退出自动 abort除非 commit decision 可能已存在。WeightSnapshotAdapter协议snapshot.py定义了三个方法export_source、resolve_fragment_ids、source_allocation_guards返回框架侧 lifetime guards供上传前绑定。该协议正是模型语义留在框架适配器这一设计落地的载体。6.1 存储策略归属文档明确writer 拥有其不可变 payload 与元数据对象的存储策略逐 tensor 的复制replication、分片partition、upsert 参数在本 API 之外。因此每次提交的快照都有且只有一个显式 manifest 契约one explicit manifest contract不存在同一快照被不同策略部分写入的歧义。7. 恢复路径Restore从StoredWeightManifest出发恢复从StoredWeightManifest开始加载实现见 load.pyload_manifest(manifest_key)store.get(manifest_key)读取 JSON →StoredWeightManifest.from_json严格反序列化拒绝重复字段、非有限数值、字段缺失→ 校验manifest.manifest_key与请求 key 一致loader 依据每个 stored fragment 的tensor_id、全局偏移、局部形状、object key、object offset、字节长度重建来源几何结合目标放置与运行时绑定经plan_stored_transfer_to_target_placementbind_logical_transfer_plan生成WeightLoadPlan其校验保证 transfer 的 resource/revision/generation 与 manifest 一致、来源片段与 manifest fragments 一致最终通过get_into_ranges把对象范围读入目标缓冲StoreBackend.get_into_ranges支持prepare_get_into_ranges_snapshotget_into_ranges_from_snapshot的快照读路径见 backend.py。这条路径不使用 legacyTensorMetadata头也不使用 legacy 并行 tensor 重建元数据——恢复所需的一切几何信息都内联在StoredWeightManifest中。7.1 持久化边界什么进 Store什么留在运行时进 Storemanifest 内逻辑 tensor 描述符TensorDescriptorglobal_shape、dtype、itemsize、layer_id、expert_id、layout_fingerprint、shard_dims、parallel_axes、片段几何fragment_id、global_offset、local_shape、nbytes、aliases、payload key、快照身份namespace、resource_id、revision、weight_generation、group_id、manifest_key、created_at、digest留在活体绑定/守卫路径不进 Store运行时地址address、分配所有者allocation owners、lease、worker 实例。这些是易失的、随进程生命周期变化的Store 保存它们没有意义且会引入陈旧地址风险。8. 原生 Store 要求Native Store RequirementReplicateConfig.group_ids原生 Store 写入端使用group 语义确保 payload、manifest、事务控制对象分别落在其声明 group 中。这依赖 Mooncake wheel 的ReplicateConfig暴露group_ids字段即文档所述 PR #3000 引入的 API。在 structured_object_store.py 中可以看到第 559-581 行getattr(config, group_ids, None)读取group_ids支持字符串或字符串列表若列表长度 1 则抛错要求恰好一个 group然后以该 group_id 生成写配置第 6594-6620 行附近group_ids被纳入已知配置键并提供按物理 key 数量对齐 group 的辅助逻辑normalize_to_list、空列表时置None走非分组路径。适配器在 Store I/O 开始前若检测到旧版绑定无group_ids的ReplicateConfig会直接拒绝The adapter rejects an older binding before Store I/O starts。上传时 payload 写配置通过config_factory([plan.manifest.group_id] * len(batch), payload)统一挂到 manifest group 下upload.py从而保证 payload 与 manifest、事务对象同组隔离、可统一管理。9. 小结一次上传规划的生命周期把全文串起来plan_weight_upload的完整生命周期是框架适配器导出WeightPlacementManifestWeightRuntimeBindingManifest模型语义在此终结planner 校验所有绑定剔除 DP-owned 张量选出完整、generation 一致、最低 DP rank的单一来源副本保留 TP/PP/EP 逻辑归属生成不可变WeightUploadPlan规范 manifest、逐片段UploadOperation含来源证据、来源身份/摘要、事务组与控制键Store writer 按write_tensor→ 参与者级 flush →commit()的顺序在 allocation guard 保护下执行batch_put_from最后在control_key写入决策并发布 manifest恢复端从StoredWeightManifest反序列化几何经plan_stored_transfer_to_target_placementget_into_ranges读回目标运行时。整个设计的关键取舍可以概括为三句话逻辑几何进 Store、运行时地址留内存每快照一份显式 manifest 契约Store 端永远不做布局推断。这套机制使权重上传具备可复现性确定性副本选择、一致性generation/lease/instance 三重新鲜度校验与可审计性digest 决策控制键是 Mooncake Reshard 权重存储链路的核心底座。赞分享人工智能大模型模型推理服务后端【免费下载链接】MooncakeMooncake is the serving platform for Kimi, a leading LLM service provided by Moonshot AI.项目地址https://gitcode.com/gh_mirrors/mo/Mooncake点击查看免费下载相关推荐Mooncake Reshard 设计解析无地址权重重排规划与运行时绑定Mooncake Reshard 设计解析无地址权重重排规划与运行时绑定 mooncake reshard 是 Mooncake 中负责 模型权重在完整资源放人工智能大模型模型推理服务后端Fluxer 附件上传完整指南预上传Presigned Upload四步流程、单/多 part 模式与上传中继Upload Relay机制解析Fluxer 附件上传完整指南预上传Presigned Upload四步流程、单/多 part 模式与上传中继Upload Relay机制解析 本指南模型权重窃取Model Weight Stealing攻防解析AI Red Team 的提取风险评估与防御实践模型权重窃取Model Weight Stealing攻防解析AI Red Team 的提取风险评估与防御实践 本篇技术指南围绕 AI Red Teami文档教程知识库上一篇TypeGraphQL与React集成前端GraphQL类型安全终极指南下一篇DeepSeek-R1-Distill-Qwen-7B70亿参数模型实现推理能力跃升数学编程双突破创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

插件系统开发实战:从plugin.json到加载失败排查与安全隔离

插件系统开发实战:从plugin.json到加载失败排查与安全隔离

1. 从“plugins”这个标题说起:插件系统到底在解决什么问题“plugins”这个词看起来简单到几乎没什么可讲的,但如果你真正动手写过插件系统,或者维护过一个需要支持第三方扩展的工具链,就会知道这里面的水比想象中深得多。我最早接…

2026/10/4 10:45:22 阅读更多 →
AI工程从零到落地:Prompt、RAG与评估体系的实战指南

AI工程从零到落地:Prompt、RAG与评估体系的实战指南

1. 先搞清楚:AI工程到底在“工程”什么很多人一听到“AI工程”四个字,第一反应是“那不就是训练模型吗”或“搞一堆算法调参”。这其实是最大的误区。我做了几年AI落地项目后越发觉得,AI工程的核心根本不是让模型跑起来,而是让模型…

2026/10/4 10:45:22 阅读更多 →
Audiveris 的 .zip 归档:训练样本仓库(samples/images/annotations)的结构、用途与运维

Audiveris 的 .zip 归档:训练样本仓库(samples/images/annotations)的结构、用途与运维

桌面应用计算机视觉图像处理OCR 【免费下载链接】audiveris Latest generation of Audiveris OMR engine 项目地址: https://gitcode.com/gh_mirrors/au/audiveris 点击查看 免费下载 本篇技术指南聚焦 Audiveris OMR 引擎中一类特殊的输出产物——.zip 归档文件。…

2026/10/4 10:45:22 阅读更多 →

最新新闻

冷知识为何让人上头?从“没用的小学生知识”到内容创作与日常应用

冷知识为何让人上头?从“没用的小学生知识”到内容创作与日常应用

"都是没用的小学生知识,建议刷到点不感兴趣"——我对这句话太熟了,因为我自己就是做内容的人,这几年在短视频平台上刷到过不下几百个类似开场白的视频。标题配着这种自嘲语气,内容却是一个让人"哇"一声的冷知…

2026/10/4 13:42:59 阅读更多 →
萌新打招呼总被无视?社交破冰三件套设计思路

萌新打招呼总被无视?社交破冰三件套设计思路

1. "萌新打招呼"这件事,为什么值得单独聊聊很多人可能觉得,"萌新打招呼"不就是进群、进论坛、进游戏时说一句"大家好,我是新人,请多关照"吗?这有什么好写的?但如果你真的在各…

2026/10/4 13:42:59 阅读更多 →
cppcheck argumentSize 检查器:函数定长数组参数与实参尺寸不匹配的静态分析实战

cppcheck argumentSize 检查器:函数定长数组参数与实参尺寸不匹配的静态分析实战

开发工具静态分析代码质量质量保障 【免费下载链接】cppcheck static analysis of C/C code 项目地址: https://gitcode.com/gh_mirrors/cpp/cppcheck 点击查看 免费下载 导读 本文围绕 cppcheck(C/C 静态分析工具)内置的 argumentSize 检查…

2026/10/4 13:42:59 阅读更多 →
XPipe 13.4.4 版本更新解读:KVM/QEMU 虚拟机集成、文件浏览器增强与独立安全更新机制

XPipe 13.4.4 版本更新解读:KVM/QEMU 虚拟机集成、文件浏览器增强与独立安全更新机制

桌面应用开发工具运维 【免费下载链接】xpipe Access your entire server infrastructure from your local desktop 项目地址: https://gitcode.com/GitHub_Trending/xp/xpipe 点击查看 免费下载 本篇基于 XPipe 13.4.4 的官方更新日志(dist/changelog/…

2026/10/4 13:42:59 阅读更多 →
AI Agent时代云架构重构:计算、推理与数据的物理融合

AI Agent时代云架构重构:计算、推理与数据的物理融合

1. 这不是一次技术升级,而是一场云架构的底层重写“AI Agent 时代的云:计算、推理和数据必须重新整合”——这句话乍看像一句行业口号,但如果你在一线做过三年以上AI基础设施搭建、云平台运维或大模型应用交付,就会立刻意识到&…

2026/10/4 13:42:59 阅读更多 →
AI工程化从零到一:模型部署、数据漂移与可复现训练的完整实战路线

AI工程化从零到一:模型部署、数据漂移与可复现训练的完整实战路线

把"跑通一个AI服务"和"工程化落地一个AI服务"彻底分开来看,是我做这套从零整理时最强烈的感受。标题里的ai-engineering-from-scratch,说白了就是希望给那些已经会调模型、会跑notebook,但还没亲手把一个模型变成稳定线上…

2026/10/4 13:41:58 阅读更多 →

日新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/4 1:00:58 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/4 1:00: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/4 11:40:45 阅读更多 →
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/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练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/3 9:42:36 阅读更多 →