news 2026/9/25 3:00:04

knowledge-catalog 语义模型保真度指南:push / pull 各环节保留了什么、丢掉了什么

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
knowledge-catalog 语义模型保真度指南:push / pull 各环节保留了什么、丢掉了什么
  • 数据目录
  • AI Agent
  • 人工智能
  • 知识管理
  • 示例工程

【免费下载链接】knowledge-catalog

Google Cloud Knowledge Catalog Tools and Samples

项目地址:https://gitcode.com/gh_mirrors/kn/knowledge-catalog
点击查看免费下载

本文是 toolbox/mdcode/docs/semantic-model/fidelity.md 的深度解读与扩展。核心主题是:在kcmd(本仓库toolbox/mdcode中的语义模型命令行工具)中,一份语义模型文档被kcmd push推送到 Knowledge Catalog 与 BigQuery / Spanner 属性图、再由kcmd pull拉回时,每个方向分别保留什么、丢弃什么、规范化什么。读完本文,你将掌握往返矩阵(round-trip matrix)的每一格含义、BigQuery 与 Spanner 两个后端的差异、pull返回的"规范化视图"为何不等于你的原始文件,以及如何围绕这些保真度限制组织你的工作流——结论是:始终以你亲手编写的模型文档为唯一事实来源(source of truth)。

kcmd是语义模型(Semantic Model)的部署工具:它以一份 YAML 文档描述业务的实体、字段、关系、度量,把模型一次性部署到两类目的地——Knowledge Catalog(治理与检索元数据)和属性图(BigQuery Graph 或 Spanner Graph,供查询)。"推"与"拉"都不是无损的:目录只保存元数据,图只保存它可查询的部分,而pull只能返回目录当初被给予的内容。本文档就是一张"每个方向存活什么"的权威对照图。

一、先理解:三个目的地各自的"内存"

在逐格分析前,先明确三个目的地的本质差异,这是理解整个保真度矩阵的前提:

  • Knowledge Catalog:持有元数据而非模型全量拷贝。它用一组系统类型(dataplex-types/global下的内置类型)记录模型的条目、方面(aspect)与链接。唯一的例外是自定义类型semantic-action与semantic-constraint,由kcmd init预置(见 Reference → What gets created in Knowledge Catalog)。push 只引用这些类型,从不创建它们。
  • BigQuery Graph:部署一个CREATE OR REPLACE PROPERTY GRAPH,实体→节点表(NODE TABLE)、关系→边表(EDGE TABLE)、度量→MEASURE;描述性元数据写入每个元素的OPTIONS(...)(可用--print查看生成的 DDL)。
  • Spanner Graph:同样的CREATE OR REPLACE PROPERTY GRAPH,但没有MEASURE、没有OPTIONS元数据——只保留可查询的结构(节点表、边表、LABEL层次)。

哪个后端接收 push,不由命令行标志决定,而是由模型的deployment target(或所选绑定 profile)决定。详见 部署指南 与 binding profiles。

二、往返矩阵(round-trip matrix):一图看懂每个要素的宿命

行是你编写(authored)的模型要素,列是它在每个方向上的结局:✓= 按原样返回;—= 在该目的地不存在。BigQuery 与 Spanner 各占一列;两者在所有结构性行上一致,仅在有 Spanner 目标无MEASURE、无OPTIONS元数据之处不同。

编写的要素→ Knowledge Catalogpull恢复→ BigQuery→ Spanner
实体(name、source)semantic-entity条目¹⁰✓NODE TABLENODE TABLE
字段schema方面列✓(类型收缩²)节点表上的列¹节点表上的列¹
字段labelschema逐字段注解✓并入OPTIONS(description)— 丢弃
字段表达式(规范 SQL)仅--emit-expressions仅当随表达式推送生成 DDL生成 DDL
字段维度角色(is_time)仅--emit-expressions³仅当随表达式推送³记入OPTIONS(description)— 丢弃
主键schema.primaryKey✓节点表KEY(...)节点表KEY(...)
唯一键schema.uniqueConstraints✓— 丢弃(只发主键)— 丢弃(只发主键)
度量semantic-metric条目name、entity、description、instructions、type⁵MEASURE⁴— 丢弃(无MEASURE)
关系(1:1 / 1:N)schema-join链接✓(名称规范化⁶)EDGE TABLEEDGE TABLE
关系(M:N /association)— 不存储—EDGE TABLE(经 junction 表)EDGE TABLE(经 junction 表)
实体extends— 未建模—LABEL子句 + 字段展平LABEL子句 + 字段展平
动作(Action)semantic-action条目¹²✓¹²— 不部署¹²— 不部署¹²
约束(Constraint)semantic-constraint条目¹³✓¹³— 不部署¹³— 不部署¹³
description(实体/度量/字段/关系)条目描述 / 方面✓OPTIONS(description)— 丢弃
ai_context.synonyms— 不存储—OPTIONS(synonyms=[...])— 丢弃
ai_context.instructionsguidelines方面⁷✓⁷并入OPTIONS(description)— 丢弃
ai_context.examples— 不存储—并入OPTIONS(description)(Examples:行)— 丢弃
模型级description/instructions模型条目上✓⁸— 丢弃⁸— 丢弃⁸
模型级ai_context.synonyms/examples— 不存储—— 丢弃— 丢弃
部署目标记录在模型条目上✓命名图命名图
绑定 profile(备选物理绑定)— 只记录被选中的那个¹⁴—¹⁴每个 BigQuery 绑定的 profile 一张图每个 Spanner 绑定的 profile 一张图
厂商方言expression变体(非规范的dialects[]条目)¹¹— 不存储—回退——仅当无规范expression时用于生成 DDL回退——仅当无规范expression时用于生成 DDL
custom_extensions(超出部署目标)— 不存储—⁹— 不在图中— 不在图中

脚注详解:单元格背后的细微差别

  1. 字段类型来源。图使用源列(source column)自身的类型;字段编写的datatype不会被携带。也就是说,字段类型在图中由物理列决定,而不是由逻辑声明决定。
  2. 字段类型收缩(collapses)。字段类型基本可往返,仅有两处收缩:无类型 →Opaque,以及String→ 无类型。两者在目录中都存为dataType STRING,靠metadataType区分(OTHER→ 读回Opaque;STRING→ 读回无类型)——这正是它们能以不同方式往返的原因。这一点在源码中有直接印证:knowledge_catalog.ts 的 schemaAspectData 中,无类型字段发布为Opaque(STRING +metadataType OTHER,显式的"类型未知"标记),使 pull 恢复为Opaque而非丢弃类型;编写的String映射为 STRING。测试夹具 actions_place_order.knowledge_catalog.golden.json 与 actions_place_order.pull.golden.yaml 分别展示了这一发布与恢复形态。
  3. 维度角色。默认推送省略逐字段的semantics块,因此维度角色只有在--emit-expressions下才会写入——且回来后只是一个裸dimension: {}标记(不带is_time等细节)。默认推送则完全丢弃该标记。
  4. 度量形态。一个度量必须解析到恰好一个实体(否则 push 被拒绝),并且归约到一个受支持的聚合——SUM/AVG/COUNT/MIN/MAX——作用于单个操作数(否则以警告跳过)。
  5. 度量类型。度量的表达式受--emit-expressions门控;其数据类型仅在为具体类型(如Decimal)时可往返——无类型、String或Opaque度量回来时无类型。(原因在源码中可见:metricAspectData 的注释说明,度量方面模板只携带dataType而没有metadataType,所以Opaque序列化为 STRING,pull 将度量恢复为无类型。)
  6. 关系名称。关系名称回来时被小写化/连字符化(Places Order→places-order)——目录只在链接 id 中保存名称。见下文"Writer-side follow-up"。
  7. guidelines 方面。guidelines方面只存在于模型、实体和度量上——字段与关系没有。因此字段级、关系级的ai_context.instructions在 Knowledge Catalog 中没有归宿(关系的 instructions 仍会到达 BigQuery,折入边的OPTIONS(description))。源码印证见 guidelinesAspectData:只有ai_context.instructions被路由进该方面,synonyms/examples在该方面没有位置。
  8. 模型级元数据。两个图都没有语句级元数据的归宿——BigQuery 静默丢弃图语句的OPTIONS,Spanner 完全没有OPTIONS——所以模型的description与ai_context.instructions改由 Knowledge Catalog 承载。
  9. 其他自定义扩展。在香草0.2.0.dev0profile 下,custom_extensions块(GOOGLE 部署目标之外的)是厂商元数据的唯一载体;它在 push 时惰性、不持久化到 Knowledge Catalog,因此pull永远不会恢复它。pull还发出扩展的0.2.0.dev0/googleprofile,它没有custom_extensions载体,所以这样的块也不会被重新序列化——保留你的编写文件。OWL 导入器不发出任何此类块:它只导入(见 导入 OWL 本体)。
  10. 逻辑(未绑定)模型。无绑定的模型仍然发布到 Knowledge Catalog:每个实体的source记录为空(resources: []),因为背后没有表;不带连接列的关系以警告跳过。当同一次 push 还部署了图时,目录条目首先被裁剪为图所绑定的部分——见下文"To Knowledge Catalog"。
  11. 厂商方言回退。你编写的是expression.dialects[]列表;图从规范(BigQuery/ANSI)变体构建。importedExpression/importedDialect不是编写键——loader 从非规范方言条目(例如度量导入自的 MAQL 或 Snowflake 形式)推导它们,并在无规范变体时逐字用作回退。见 Model spec §2.5。
  12. 动作(Actions)。动作只到达 Knowledge Catalog——作为模型条目下的一个semantic-action条目,pull从该条目读回。其他每个 push 目标都不为它部署任何东西并警告一次。其guards以约束名存储,并逐字往返。名称所引用的约束若在一次 pull 中缺失,会被保留而非丢弃,因此部分 pull 绝不会静默改写作者的模型;pull 对保留的名称发出警告,push 在约束回归前拒绝该模型。名称被方面重复是唯一例外——会被丢弃到单一出现,因为 loader 拒绝重复且文档必须保持可加载。其affects以同样方式往返,对重复的 concept-and-operation 对也遵循同样的例外。见 Modeling write operations。
  13. 约束(Constraints)。约束只到达 Knowledge Catalog——作为模型条目下的一个semantic-constraint条目,pull读回它。其他每个 push 目标都不为它部署任何东西并警告一次。发布是 push 对约束所做的全部;"解决它"的是运行(run),而应用所嵌入的运行时是在写入前把每个 guard 交给 judge 的东西。
  14. 绑定 profiles。一个模型可以定义多个物理实现,每个绑定 profile 一个。--all-profiles为每个声明了部署目标的 profile 部署一张图,各自部署到其目标命名的后端;没有目标的 profile 被跳过,两个 profile 声称同一张图则在任何部署前被拒绝。Knowledge Catalog 仍只记录一个绑定——--profile命名的那个,否则是默认绑定——而--all-profiles运行总是记录默认绑定,两个标志互斥。见 Binding profiles。

三、To Knowledge Catalog:目录记录什么、以什么为条件

目录保存元数据而非模型的完整拷贝。它使用的每个资源类型都是dataplex-types/global下的内置系统类型,唯有kcmd init预置的自定义semantic-action/semantic-constraint类型对除外。push 引用这些类型,从不创建它们。

记录什么取决于 push 的类型:

  • 仅目录的 push(--no-profile),或无绑定的纯逻辑模型,记录整个模型:文档声明的每个实体、度量和关系。
  • 同时部署图的 push先把模型裁剪为图所绑定的部分,因此未绑定字段——以及任何依赖它的实体、度量或关系——也一并被排除在目录条目之外。对这类 push 的 pull 返回的是绑定视图而非完整编写模型。
  • 逻辑模型仍产生完整条目:每个实体的source记录为空(resources: []),因为背后没有表;不带连接列的关系以警告跳过。这一行为在源码中有明确注释与实现:deploy_knowledge_catalog.ts 中对source.resources的处理(空列表是诚实的"尚无绑定"),测试 deploy_knowledge_catalog.test.ts 验证了逻辑模型的发布形态。

一次绑定,而非全部绑定。模型可定义多个物理实现——比如一个面向 BigQuery 的分析绑定和一个面向 Spanner 的操作绑定——kcmd push --all-profiles为每个部署一张图。目录这条腿不随之扇出:它只运行一次,针对--profile命名的 profile,否则针对默认绑定。因此裸kcmd push与kcmd push --all-profiles写入相同的条目,区别仅在于部署了多少张图。

连续 push 不会累积。条目 id 只从逻辑名推导——模型、实体、度量——不带 profile 成分,所以推送第二个 profile 会把目录调和到那个绑定,而不是叠加到第一个写的内容上:共享元素把source换成新 profile 的表;在部署图(因此会裁剪)的 push 上,新绑定无法回答的实体或度量被删除而非遗留。目录因此一次只描述一个物理实现:它记录该绑定的部署目标和表,但从不记录 profile 的名字,也从不记录其他 profile 存在。pull返回最后写入的那个。保留 profile 文件——目录不是它们的仓库。

默认不存 SQL 表达式。已发布的系统类型模板尚未携带逐字段semantics块或semantic-metric.expression字段,因此默认 push 省略它们。传入--emit-expressions可在模板获得这些字段后写入规范的 GoogleSQL/ANSI 表达式。该门控在源码中明确实现:knowledge_catalog.ts 第 125 行const emitExpr = opts.emitExpressions ?? false;,并在 schemaAspectData 与 metricAspectData 中据以决定是否发出semantics/expression键;KcGenerateOptions.emitExpressions的声明见 deploy_knowledge_catalog.ts。

目录从不存储:ai_context.synonyms/examples、字段级ai_context(只有模型、实体、度量的instructions在guidelines方面有归宿)、以及原始厂商 SQL(importedExpression——例如度量导入自的 MAQL 或 Snowflake 形式)。这些留在你的编写文档中;厂商 SQL 与表达式在生成图 SQL 时仍会被使用。

动作(Actions)在目录中的往返

每个动作遵循与其他一切相同的"每条目一元素"规则:各自成为模型条目下的一个semantic-action条目,在semantic-action方面携带其 executor、类型化参数、guards与affects。它们通过pull无损往返(名称、描述、executor、类型化参数、guards、affects、instructions)。

  • 从字段投影的参数以其编写时的投影形式往返:方面存储concept与field,连同解析出的标量type;pull 把投影写回时不带类型,因此重新加载时从同一字段解析、得到同一参数。
  • 两样东西不随投影往返:其label与ai_context被丢弃——方面没有地方放它们——所以 pull 恢复的是参数的description而非这两者。且 pull 恢复的措辞以参数自身的面目出现:loader 在模型加载时把继承的description解析进参数,下游无法区分其与作者手写的差别,所以 pull 出的文档把它写在原作者留白的位置。重新加载得到同一参数,但字段与参数如今各持一份副本,改字段不再联动。
  • 投影字段不在 pull 文档中(裁剪丢弃了无绑定可达的实体)时,参数以声明参数出现并携带解析出的type——因为发出一个解析不到任何东西的concept/field对会写出无法加载的文档。
  • sqlexecutor随其余内容往返其statements:它们是写入本身,不是关于写入的注释,因此丢弃它们的目录会描述一个无人能重新部署的动作。
  • 条目类型是自定义的,所以kcmd init创建它;不声明任何动作的模型永远不需要它。

affects作为事实而非原文往返。两种编写形态——裸名称与记录——在模型中是同一形态,所以只携带 concept 的记录(- concept: Account)回来时是裸Account,说的是同一件事。首遍之后逐字节稳定。affects只存储作者所写的内容,这正是它能在部分 pull 下完好存活的原因。一个concept是实体还是边不记录,所以没有任何东西需要重新解析——也就不会有东西变陈旧。这对多对多关系最重要:它根本到不了目录;pull 从 schema-join 条目链接恢复关系,而链接只携带外键边,因此命名 M:N 边的 concept 在一个完全良构的模型上会显得无法解析——它却原样返回。

约束(Constraints)在目录中的往返

每个约束以同样方式发布:各自成为模型条目下的一个semantic-constraint条目,规则与任何instructions放在semantic-constraint方面,description作为条目自身的摘要。名称、描述、on_violation、severity、instructions,以及声明规则的任一体——expression或judgment——通过pull无损往返。声明了两种路由词的约束会原样返回(不填充默认值)。方面还携带一个派生的evaluation字段(deterministic或judged),pull 从规则体重新计算而非读取它,因此它永远不会与旁边的规则不一致;它不会写入编写文档,因为编写文件中的派生值是会变陈旧的值。同时声明两种规则体(或都不声明)的条目以警告跳过,而不是被 pull 成一个自己 push 时会失败的模型。该条目类型也是自定义的,不声明任何约束的模型永远不需要它。

四、To BigQuery:结构与描述元数据的分流

push 同时保留可查询的结构与附着其上的描述性元数据。结构变成节点表、边表与度量;描述性元数据写入图中每个元素的OPTIONS(...)(用--print可见)。

BigQuery 图的OPTIONS给元素一个description字符串与一个synonyms数组。synonyms是唯一拥有专属选项的部分,因此它结构性地、作为自己的数组携带过去。其余部分——description、instructions、examples和字段的label——共享单一的description字符串,因此被合并进它(examples 以Examples: …行呈现)。它们的内容被保留;它们的独立结构没有。

模型自身的语句级元数据无处可去:BigQuery 静默丢弃图语句的OPTIONS,所以模型的description/ai_context不在图中——description与ai_context.instructions改由 Knowledge Catalog 承载。主键之外的唯一键也被丢弃(只发主键)。导入的厂商 SQL 不作为独立形式携带:图在规范expression存在时从中构建,仅当模型从未被转译成规范形式时才逐字回退到导入的厂商 SQL。

extends层次在 BigQuery 端以LABEL子句 + 字段展平呈现,一个实体可extends: [Parent, …],push 把超类型字段展平到每个子类,子类表携带自己的KEY与全部继承属性的列绑定——具体规则与 SQL 示例见 Reference → Class hierarchies 与 Modeling class hierarchies。

五、To Spanner:只保留可查询的结构

Spanner 目标保留可查询的结构,丢弃描述性元数据。节点表、边表与LABEL(含extends层次,字段展平)与 BigQuery 完全一致地部署,但使用裸的表名与图名。两样东西按设计不上船:

  • 度量(Metrics)。Spanner 没有MEASURE,所以每个模型级度量都以警告丢弃。BigQuery 独有的"度量必须解析到单个实体"规则在此不适用。照常编写你的度量——BigQuery 目标仍会发出它们,Knowledge Catalog 仍记录每个semantic-metric条目——它们只是不在 Spanner 图中。
  • OPTIONS元数据。Spanner 不携带逐元素OPTIONS,所以description、synonyms、instructions、examples与字段label不写入 Spanner DDL。它们在同一次 push 中仍到达 Knowledge Catalog(模型/实体/度量的描述与instructions落在条目与guidelines方面上),因此描述层活在目录中而非 Spanner 图中。这镜像了 BigQuery 丢弃图语句OPTIONS而保留逐元素OPTIONS的方式。

其余一切——键、关系、标签层次——与上文的→ BigQuery列一致。动作与约束不到达任一图;它们发布到 Knowledge Catalog,各为一个semantic-action/semantic-constraint条目,并通过pull无损往返。

Spanner 端还使用异步 DDL:语句经 Spanner AdminupdateDatabaseDdl长时运行操作应用并轮询完成(BigQuery 经jobs.query运行其 DDL)。见 Reference → What gets created in Spanner。

六、What pull recovers:返回的是"规范化视图"

pull返回 push 写入的内容——上文pull恢复列即摘要。当 push 部署了图时,push 写入的已被裁剪为绑定视图,所以 pull 返回该视图。关于它如何回来,有两类:

规范化(Normalized)——内容幸存,形式改变:

  • 关系名称回来时被小写化/连字符化(Places Order→places-order);目录只在链接 id 中存名称。测试验证了这一 id 形态:deploy_knowledge_catalog.test.ts 断言直接外键关系写为一条schema-join链接、链接 id 为sales-orders-to-customer;action_affects.test.ts 与 actions.test.ts 则确认 pull 仅从schema-join条目链接重建关系。见下文"Writer-side follow-up"。
  • 字段类型往返,除两处收缩:无类型字段回来为Opaque,String字段回来为无类型(两者都存dataType STRING,靠字段的metadataType区分——见脚注²)。度量的数据类型仅在具体类型(如Decimal)下往返;无类型、String或Opaque度量回来为无类型,因为度量方面存数据类型但不存标记其为Opaque的元数据类型。
  • 字段的维度角色(仅当以--emit-expressions推送时存在)回来为裸dimension: {}标记,不带其细节(is_time等)。
  • 顺序:每个实体内的字段顺序被保留,但实体与度量的顺序不保留——它们按目录自己的顺序回来,而非编写顺序。原 YAML 中的注释不被保留。

因此,push 后接 pull 不会返回你的原始文件。把 pull 出的文档视为目录元数据的忠实副本,而非编写模型的副本,并把编写文档保留为事实来源。

七、Writer-side follow-up:当前 push 写入侧的已知限制

上文有一处缩减是 push 当前写入的限制,而非 pull 能恢复的极限。它在此记录为写入侧后续事项;读者(pull)已返回目录持有的全部内容。

  • 关系名称。schema-join方面类型的metadataTemplate没有关系名称的字段,因此 push 无法存储它,pull 从链接 id 恢复它——而链接 id 被小写化与连字符化(条目链接 id 格式禁止原始大小写/下划线)。逐字返回名称需要在 Knowledge Catalog(服务端)为内置schema-join方面类型添加名称字段,之后客户端写/读是小事;这与门控--emit-expressions的semantics字段属于同一类缺口。

(非规范的部署目标不是pull 缺口:push 在任何一条腿运行前就在验证门拒绝它,因此它永远不会被写入——见 Validation。)

八、实操建议:围绕保真度组织工作流

把上面的矩阵落到日常操作,几条可执行的结论:

  1. 把编写文档当唯一事实来源。目录是元数据视图、图是可查询视图、pull 是目录视图——三者都非你的 YAML。pull适合恢复工作区、查看目录实际持有内容、或确认别人部署的模型,但不适合作为编辑主副本。删除模型文档不会自动清目录条目;跨模型删除需要--force-remove(见 README → Updating and removing models)。
  2. 需要表达式与维度角色进目录时,用--emit-expressions。默认关闭;开启后规范表达式与semantics角色随条目发布并可被 pull 恢复。kcmd push --print与--validate-only可在写任何东西前预览生成的 DDL 与条目计划。
  3. 区分后端能力。Spanner 目标丢弃度量与全部OPTIONS描述层(描述活在目录中);BigQuery 目标把描述合并进OPTIONS(description)但丢弃图语句级元数据与唯一键。为查询性选后端时,先对照本文矩阵确认你依赖的要素在目标后端有归宿。
  4. 绑定 profile 与目录的关系是"一次一个"。--all-profiles部署多张图,但目录只记录一个绑定(默认绑定);连续推送不同 profile 会调和(替换source、删除新绑定无法回答的元素)而非累积。保留 profile 文件——目录不是它们的仓库。
  5. 动作与约束只活在目录。它们不到达任一图;依赖目录的semantic-action/semantic-constraint条目做治理与发现,别指望图 DDL 中出现它们。kcmd init --semantic-model会预置这两个自定义类型对。

九、相关文档与源码指引

  • fidelity.md(本文来源,原文档)
  • Deploying a semantic model(部署总览)
  • Model specification(格式规范,§2.5 表达式、§6 扩展机制、§7 绑定层)
  • Binding profiles(一个逻辑模型、多个物理绑定)
  • Reference(CLI 标志、各目的地创建物、验证、权限)
  • Modeling write operations(动作与约束的完整建模指南)
  • 源码实现:knowledge_catalog.ts(目录条目/方面生成)、deploy_knowledge_catalog.ts(目录推送选项)、deploy_bigquery.ts 与 deploy_spanner.ts(图 DDL 生成)、pull_kc.ts(pull 重建)
  • 测试验证:deploy_knowledge_catalog.test.ts、actions.test.ts、action_affects.test.ts,以及 golden 夹具(如 actions_place_order.knowledge_catalog.golden.json)
  • 数据目录
  • AI Agent
  • 人工智能
  • 知识管理
  • 示例工程

【免费下载链接】knowledge-catalog

Google Cloud Knowledge Catalog Tools and Samples

项目地址:https://gitcode.com/gh_mirrors/kn/knowledge-catalog
点击查看免费下载

相关推荐

上一篇:5分钟生成IDA脚本:iblessing的Objective-C方法交叉引用可视化方案
下一篇:前端性能分析终极指南:如何快速提升Lighthouse评分到90+

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 2:58:28

Multisim 14.0安装教程:环境准备、授权激活与常见报错排查

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

作者头像 李华