当前位置: 首页 > news >正文

Docusaurus技能库插件:数据驱动与组件化集成实战

1. 项目概述:一个为Docusaurus注入灵魂的技能库插件

如果你正在使用Docusaurus构建技术文档、博客或知识库,并且希望站点不仅仅是静态内容的堆砌,而是能动态展示你的技能图谱、项目经验,甚至是一个交互式的个人名片,那么你很可能需要rio225/docusaurus-skill这个项目。这是一个为Docusaurus设计的插件,它允许你在你的静态站点中,轻松地集成一个美观、可定制且数据驱动的“技能”或“能力”展示模块。

简单来说,这个插件解决了一个很实际的需求:如何在一个以文档为核心的静态站点中,优雅地展示动态的、结构化的个人或团队能力数据。传统的做法可能是手动编写一个HTML页面,或者用Markdown表格来罗列技能,但这不仅维护麻烦,而且样式单一,缺乏交互性。docusaurus-skill插件将这部分功能模块化,让你通过简单的配置文件(通常是JSON或YAML)来管理你的技能数据,然后插件会自动将其渲染成卡片、进度条、标签云等丰富的可视化组件,无缝集成到你的Docusaurus主题中。

它非常适合个人开发者构建技术博客简历页、团队用于展示技术栈、开源项目展示核心贡献者技能,或者任何需要清晰呈现能力维度的场景。接下来,我将以一个深度使用者的角度,拆解这个项目的核心设计、如何从零开始集成并深度定制,以及在实际操作中会遇到哪些“坑”和对应的解决技巧。

2. 核心设计思路与架构拆解

2.1 为什么选择插件化方案?

在深入代码之前,理解作者rio225为什么选择开发一个Docusaurus插件,而非一个独立的React组件或页面模板,是把握其设计精髓的关键。Docusaurus的核心哲学是“内容优先”,其插件系统旨在以非侵入式的方式扩展功能。docusaurus-skill作为一个插件,完美遵循了这一原则。

首先,它实现了关注点分离。你的技能数据(skills.json)和站点内容(docs/,blog/)是分开管理的。你可以独立更新技能信息,而无需触碰任何React组件代码。这降低了维护成本,尤其当技能数据需要频繁更新时。

其次,它深度集成Docusaurus生态。插件可以直接利用Docusaurus的构建流程、主题系统、@docusaurus/theme-common组件库(如<ThemeProvider>)以及样式方案(CSS Modules或Infima)。这意味着插件生成的UI在视觉和交互上能与你的站点主题保持高度一致,避免了“拼凑感”。

再者,它提供了开箱即用的约定。通过标准的docusaurus.config.js进行配置,用户无需学习一套新的构建配置。插件会自动处理资源的加载、组件的注册,你只需要在Markdown或JSX中像使用内置组件一样使用它即可,学习曲线非常平缓。

2.2 数据驱动与可配置性设计

docusaurus-skill的核心是一个数据驱动模型。所有展示内容都源于一份结构化的数据文件。通常,这个文件位于项目根目录的data/文件夹下,例如skills.json。其结构设计得非常灵活,以适配不同场景。

一个典型的数据结构可能包含以下几个层级:

  1. 分类(Categories): 如“编程语言”、“前端框架”、“DevOps工具”、“软技能”等。这构成了技能展示的一级导航或分组依据。
  2. 技能项(Skill Items): 每个分类下的具体技能,如“JavaScript”、“React”、“Docker”、“团队协作”。
  3. 技能属性(Attributes): 每个技能项可以附带多种属性,用于控制其展示方式和含义。最核心的属性包括:
    • level: 熟练度,通常用数字(如1-5)、百分比或描述性文本(“入门”、“熟练”、“专家”)表示,用于生成进度条或星级评分。
    • description: 技能的简要说明或关键成就。
    • icon: 技能图标,可以是FontAwesome的类名、一个SVG路径或图片URL,用于视觉增强。
    • tags: 标签,用于进一步筛选或分类,例如“正在学习”、“核心技能”、“已认证”。
    • link: 关联链接,点击技能项可以跳转到更详细的文档、项目或认证页面。

这种数据结构的设计,使得插件不仅能展示一个简单的列表,还能支持过滤(按标签或分类)、排序(按熟练度或名称)、搜索等高级功能,只要插件的前端组件实现了对应的逻辑。

2.3 前端渲染组件的灵活性

插件通常会提供一个或多个React组件,例如<SkillOverview /><SkillCategory /><SkillCard />。这些组件的设计决定了最终的视觉效果和交互体验。

  • <SkillOverview />: 这是一个容器组件,可能负责读取全局技能数据,并渲染出整个技能页面的框架,包括分类导航栏和内容区。
  • <SkillCategory />: 负责渲染单个分类下的所有技能项。它可能会接收一个categoryId作为属性,然后从全局数据中过滤出对应的技能进行渲染。
  • <SkillCard />: 这是最小的渲染单元,负责展示单个技能的所有信息。它的UI是可定制的重点,开发者可以通过传递不同的variant属性(如'compact''detailed''progress')来切换展示样式。

样式定制通常通过CSS Modules或支持Docusaurus主题的CSS变量来实现。插件会提供一套默认样式,但允许用户通过覆盖CSS变量或编写自定义样式表来完全匹配自己站点的设计语言。

3. 从零开始集成与配置实战

假设我们有一个全新的Docusaurus项目(版本^3.0.0),现在需要集成docusaurus-skill插件。以下是详细的步骤和每一步背后的考量。

3.1 环境准备与插件安装

首先,确保你的Docusaurus项目是基于最新稳定版创建的。然后,通过npm或yarn安装插件。

# 使用 npm npm install @rio225/docusaurus-skill # 或使用 yarn yarn add @rio225/docusaurus-skill

注意:务必查看插件README文件中的“Peer Dependencies”部分。该插件可能对Docusaurus核心库、React或某些图标库有特定版本要求。安装时如果出现版本冲突警告,需要根据提示进行升级或降级。一个常见的坑是Docusaurus 2.x和3.x的API有较大变化,确保插件版本与你的Docusaurus主版本兼容。

3.2 准备技能数据文件

在项目根目录下创建一个data文件夹,并在其中创建skills.json文件。这是整个插件的“数据源”。我们设计一个相对完整的数据结构示例:

{ "categories": [ { "id": "frontend", "name": "前端技术", "description": "Web前端开发相关技术与框架" }, { "id": "backend", "name": "后端与数据库", "description": "服务器端、API与数据存储技术" }, { "id": "devops", "name": "运维与工具", "description": "部署、监控、自动化与开发工具链" } ], "skills": [ { "id": "react", "name": "React", "category": "frontend", "level": 4.5, "levelMax": 5, "description": "精通Hooks API及生态(Redux Toolkit, React Router)。有大型SPA项目架构经验。", "icon": "fab fa-react", "tags": ["core", "framework"], "link": "/docs/frontend/react-best-practices" }, { "id": "typescript", "name": "TypeScript", "category": "frontend", "level": 4, "levelMax": 5, "description": "能在项目中严格应用类型系统,设计泛型和工具类型。", "icon": "fas fa-code", "tags": ["core", "language"] }, { "id": "nodejs", "name": "Node.js", "category": "backend", "level": 4, "levelMax": 5, "description": "熟悉Express/Koa框架,有高并发RESTful API及中间件开发经验。", "icon": "fab fa-node-js", "tags": ["runtime", "core"] }, { "id": "docker", "name": "Docker", "category": "devops", "level": 3.5, "levelMax": 5, "description": "熟练编写Dockerfile,使用Docker Compose进行多服务编排。", "icon": "fab fa-docker", "tags": ["container", "ci-cd"] } ] }

数据结构解析:

  • levellevelMax: 这里用数值表示熟练度,levelMax定义了上限(通常是5或10),前端组件可以用这个比例来渲染进度条宽度或计算星级。这种数值化表示比纯文本更利于排序和可视化。
  • icon: 这里使用了FontAwesome的CSS类。你需要确保你的站点已经引入了FontAwesome图标库。如果不想引入额外依赖,插件可能也支持使用SVG字符串或指向本地/网络图片的URL。
  • link: 这里指向了站内文档路径。这很好地体现了与Docusaurus内容体系的融合,点击技能可以深入查看相关技术文档。

3.3 配置docusaurus.config.js

这是将插件激活并连接到数据源的关键步骤。打开docusaurus.config.js文件,在plugins配置项中添加docusaurus-skill

// docusaurus.config.js module.exports = { // ... 其他配置(title, tagline, themeConfig等) plugins: [ [ '@rio225/docusaurus-skill', { // 指定技能数据文件的路径,相对于项目根目录 skillsDataPath: './data/skills.json', // 自定义技能展示页面的路由路径,默认为 '/skills' routePath: '/skills', // 是否在导航栏中自动添加一个指向技能页面的链接 addNavbarLink: true, // 导航栏链接的显示文本 navbarLinkLabel: '技能栈', // 更多样式和行为配置... // 例如,设置默认的展示变体 defaultVariant: 'card', // 是否启用按熟练度排序 sortByLevel: true, }, ], ], };

配置项详解:

  • skillsDataPath: 必须正确配置,否则插件无法找到数据。路径可以是绝对路径,也可以是相对于项目根目录的路径。
  • routePath: 这个配置非常有用。它定义了访问技能页面的URL。如果你希望这个页面是站点的“关于我”或“简历”的一部分,可以设置为/about/skills
  • addNavbarLink&navbarLinkLabel: 对于用户来说非常友好,插件自动在导航栏生成入口,无需手动修改themeConfig.navbar.items。但如果你希望更精细地控制导航栏(比如放在下拉菜单里),可以将其设为false,然后手动配置。
  • defaultVariantsortByLevel: 这些是插件提供的“开关”,让你可以控制默认的展示逻辑,而不需要修改组件代码。

3.4 在页面中使用技能组件

配置完成后,你有两种主要方式来使用技能展示功能。

方式一:访问独立页面。运行npm run start启动开发服务器,然后在浏览器中访问你配置的routePath(例如http://localhost:3000/skills)。插件会自动为你生成一个完整的技能展示页面,其布局和样式由插件内置的页面组件决定。

方式二:在任意页面中嵌入组件。如果你不希望有一个独立的页面,而是想把技能模块嵌入到已有的页面(如首页src/pages/index.js或某个文档docs/intro.md)中,插件通常会导出React组件供你直接使用。

在Markdown文件中,你可能需要使用MDX语法(需要启用@docusaurus/plugin-content-docs的MDX支持):

<!-- docs/resume.md --> # 我的技术栈 这里展示我核心的技术能力: import { SkillCategory } from '@rio225/docusaurus-skill'; ## 前端专长 <SkillCategory categoryId="frontend" variant="progress" /> ## 后端与基础设施 <SkillCategory categoryId="backend" variant="card" /> <SkillCategory categoryId="devops" variant="card" />

在React组件(JSX)中,使用方式类似:

// src/pages/index.js import React from 'react'; import Layout from '@theme/Layout'; import { SkillOverview } from '@rio225/docusaurus-skill'; export default function Home() { return ( <Layout> <main> <h1>欢迎来到我的空间</h1> <p>下面是我的核心技能概览:</p> {/* 渲染整个技能库 */} <SkillOverview showFilter={true} /> </main> </Layout> ); }

关键点:使用import语句引入组件时,务必确认插件导出的具体组件名。查看插件的文档或源码的src/index.js文件来确定可用的导出项。

4. 深度定制:让技能库独一无二

默认的样式和布局可能无法完全满足你的品牌需求。docusaurus-skill作为一款设计良好的插件,通常会提供多种定制途径。

4.1 样式覆盖与主题集成

最常用的定制方法是覆盖CSS变量或编写自定义CSS。

1. 通过CSS变量定制:如果插件使用了Docusaurus的Infima CSS框架或自定义的CSS变量,你可以在项目的src/css/custom.css文件中覆盖它们。

/* src/css/custom.css */ :root { /* 修改技能卡片的背景色和边框 */ --skill-card-bg: var(--ifm-card-background-color); --skill-card-border: 1px solid var(--ifm-color-emphasis-200); --skill-card-border-radius: 12px; /* 修改进度条的颜色 */ --skill-progress-bar-bg: #e0e0e0; --skill-progress-bar-fill: var(--ifm-color-primary); /* 修改分类标签的样式 */ --skill-category-badge-bg: var(--ifm-color-secondary); --skill-category-badge-text: white; } /* 针对暗色模式 */ [data-theme='dark'] { --skill-card-bg: #2d2d2d; --skill-progress-bar-bg: #404040; }

你需要查阅插件的样式文档或直接检查其生成的HTML元素的类名和CSS变量,才能进行有效覆盖。

2. 通过自定义CSS类深度定制:如果CSS变量不够用,你可以直接为插件组件添加自定义类名,然后编写更详细的CSS规则。这通常需要插件支持className属性。

<SkillOverview className="my-custom-skill-overview" />
/* src/css/custom.css */ .my-custom-skill-overview .skill-category { margin-bottom: 3rem; border-left: 4px solid var(--ifm-color-primary); padding-left: 1rem; } .my-custom-skill-overview .skill-card { transition: transform 0.2s ease, box-shadow 0.2s ease; } .my-custom-skill-overview .skill-card:hover { transform: translateY(-4px); box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); }

4.2 组件包装与逻辑扩展

有时,你可能需要修改组件的行为或添加新的功能。这时,“包装”或“组合”是比直接修改插件源码更好的策略。

场景:为每个技能卡片添加一个“了解更多”的按钮,点击后显示模态框。由于直接修改SkillCard组件困难,我们可以创建一个自己的包装组件。

// src/components/EnhancedSkillCard.js import React, { useState } from 'react'; import { SkillCard } from '@rio225/docusaurus-skill'; // 导入原组件 import Modal from '@theme/Modal'; // 使用Docusaurus主题的Modal(如果可用) export default function EnhancedSkillCard({ skill, ...props }) { const [isModalOpen, setIsModalOpen] = useState(false); return ( <> <div style={{ position: 'relative' }}> {/* 渲染原技能卡片 */} <SkillCard skill={skill} {...props} /> {/* 在卡片角落添加一个自定义按钮 */} <button className="button button--outline button--sm" style={{ position: 'absolute', top: '8px', right: '8px' }} onClick={() => setIsModalOpen(true)} aria-label={`了解更多关于${skill.name}`} > <i className="fas fa-info-circle"></i> </button> </div> {/* 自定义模态框 */} {isModalOpen && ( <Modal open={isModalOpen} onClose={() => setIsModalOpen(false)} title={`深入探索:${skill.name}`} > <p>这里可以放更详细的描述、项目案例、学习心得等。</p> <p><strong>熟练度解读:</strong> {skill.level}/{skill.levelMax}</p> {skill.description && <p><strong>概述:</strong> {skill.description}</p>} {/* 可以在这里添加更多自定义内容 */} </Modal> )} </> ); }

然后,在你的页面中,遍历技能数据并使用自定义的EnhancedSkillCard组件。这种方式既保留了插件的所有基础功能,又无缝添加了新的交互,且在未来插件升级时,你的定制化部分更容易维护。

4.3 数据源的扩展与动态化

默认从静态JSON文件读取数据简单可靠,但在某些场景下,你可能希望数据是动态的,例如从Headless CMS(如Strapi)、GitHub API(展示仓库语言统计)或数据库获取。

实现思路:你可以在插件外部构建一个数据获取层。例如,创建一个src/data/fetchSkills.js模块:

// src/data/fetchSkills.js // 示例:从多个来源聚合数据 export async function fetchDynamicSkills() { // 1. 从静态JSON加载基础数据 const baseSkills = await import('../../../data/skills.json'); // 2. 从GitHub API获取动态数据(例如,仓库语言统计) let githubSkills = []; try { const response = await fetch('https://api.github.com/users/yourusername/repos'); const repos = await response.json(); // 分析repos,提取编程语言数据,转换为技能格式 githubSkills = processRepoLanguages(repos); } catch (error) { console.error('Failed to fetch GitHub data:', error); } // 3. 合并数据源 // 注意:这里需要处理去重和合并逻辑,例如同名技能合并level等 const mergedSkills = mergeSkills(baseSkills.skills, githubSkills); return { categories: baseSkills.categories, skills: mergedSkills, }; } function processRepoLanguages(repos) { /* ... */ } function mergeSkills(baseSkills, dynamicSkills) { /* ... */ }

然后,你需要修改使用技能组件的地方,不再直接使用插件提供的绑定静态数据的组件,而是先获取数据,再传递给一个接受skills属性的通用展示组件,或者修改插件源码以支持异步数据加载(这属于高级定制,需谨慎)。

实操心得:动态数据源虽然强大,但引入了异步性和外部依赖,会显著增加构建复杂度和页面加载时间。对于个人博客或文档站,除非技能数据变化极其频繁,否则静态JSON配合GitHub Actions等CI/CD工具定期更新,是更简单、更稳定的方案。

5. 常见问题、排查技巧与性能优化

在实际集成和使用过程中,你可能会遇到一些问题。以下是一些常见情况的排查思路和解决技巧。

5.1 构建与运行时问题

问题1:插件安装后,运行npm run startnpm run build失败,提示Cannot find module '@rio225/docusaurus-skill'

  • 排查:首先确认安装命令是否成功执行,node_modules目录下是否存在该包。然后,检查docusaurus.config.js中插件的名称拼写是否正确。一个极易忽略的坑是:Docusaurus插件在配置时,包名前的@符号有时在配置数组中需要省略,有时不需要。这完全取决于插件作者的导出方式。必须严格参照插件官方文档的示例。
  • 解决:1) 删除node_modulespackage-lock.json,重新运行npm install。2) 仔细对比插件README中的配置示例。如果插件名为docusaurus-plugin-skill,配置时可能是'docusaurus-plugin-skill',也可能是'@rio225/docusaurus-skill'

问题2:技能页面能访问,但显示空白或“No data”。

  • 排查:这是最常见的问题。首先打开浏览器开发者工具(F12),查看“网络”选项卡,确认对skills.json文件的请求是否成功(状态码200)。如果请求失败,检查skillsDataPath配置的路径是否正确,以及文件是否在构建时被正确复制到了输出目录(通常是build文件夹)。其次,查看“控制台”是否有JavaScript错误,可能是数据格式不符合插件预期。
  • 解决:1) 确保skillsDataPath是相对于项目根目录的路径。2) 使用绝对路径path.join(__dirname, './data/skills.json')有时更可靠。3) 检查skills.json的JSON格式是否正确,可以使用JSON验证工具。4) 确认数据中的category字段值与categories数组中的id完全匹配(大小写敏感)。

问题3:样式混乱,与网站主题不匹配。

  • 排查:检查插件组件是否正常加载了Docusaurus的主题上下文。在自定义组件中使用了插件的子组件时,需要确保它们被包裹在<ThemeProvider>内(Docusaurus Layout通常已处理)。另外,检查自定义CSS的优先级,你的规则可能被插件默认样式覆盖。
  • 解决:1) 确保使用插件的页面外层有<Layout>组件。2) 在自定义CSS中,使用更具体的选择器来提高优先级,例如.my-page .skill-card。3) 使用!important声明作为最后的手段(不推荐)。

5.2 数据与展示问题

问题4:技能图标不显示。

  • 排查:确定图标方案。如果使用FontAwesome,检查站点是否引入了对应的FontAwesome CSS库。可以在docusaurus.config.jsheadTagsscripts/stylesheets配置中引入。如果使用SVG,检查SVG路径字符串是否正确。如果使用图片URL,检查链接是否有效。
  • 解决:1) 引入图标库。2) 在插件配置中寻找是否有关图标的配置项,例如iconLibrary: 'fontawesome'。3) 回退方案:在数据中提供一个icon的备选文本,或在组件逻辑中,当图标加载失败时显示技能名称的首字母。

问题5:希望增加新的技能属性,如“最近使用时间”、“自信度”。

  • 解决:这涉及到数据模型和组件渲染的扩展。首先,在skills.json中直接添加新字段即可,JSON是灵活的。关键在于前端组件是否能识别并渲染这个新字段。
    • 如果插件支持“自定义渲染器”或“插槽”:这是最理想的情况,你可以在配置中指定如何渲染新字段。
    • 如果不支持:你需要“fork”或“eject”插件的相关组件。将node_modules中该插件的特定组件代码复制到你的项目src目录下进行修改。然后,修改该组件,从skill对象中读取你的新属性(如skill.lastUsed),并将其渲染到UI上。注意:这会使得未来升级插件变得困难,需要手动合并更改。

5.3 性能与SEO优化

优化1:数据文件过大导致页面加载慢。

  • 技巧:技能数据通常不会很大,但如果包含大量详细描述和图标base64编码,可能会增大文件体积。可以考虑:
    • 将图标资源作为外部链接或使用雪碧图,而非内嵌在JSON中。
    • 对技能描述进行压缩,或在列表中只显示摘要,详情页再展示完整描述。
    • 如果技能项非常多(超过100个),考虑实现分页或虚拟滚动,但这需要修改插件的前端逻辑。

优化2:技能页面缺乏交互性。

  • 技巧:默认的静态卡片可能有些枯燥。可以通过一些轻量级交互提升体验:
    • 悬停效果:用CSS添加阴影、缩放或边框高亮。
    • 筛选与排序:如果插件未提供,可以自己实现一个顶部的筛选栏(按分类、标签筛选)和排序按钮(按名称、熟练度排序)。这需要前端状态管理(如React的useState)。
    • 搜索功能:在技能库顶部添加一个搜索框,实时过滤技能名称和描述。可以使用fuse.js这类轻量级模糊搜索库。

优化3:SEO考虑。

  • 技巧:技能页面通常是重要的个人或项目展示页,有SEO价值。确保:
    • 插件生成的页面有良好的HTML语义化标签(<section>,<article>,<h2>等)。
    • 每个技能项的关键信息(名称、描述)应直接渲染在HTML中,而不是完全由JavaScript动态加载,以便爬虫抓取。
    • 为技能页面在docusaurus.config.jsthemeConfig中设置合适的metadata,如titledescription

集成rio225/docusaurus-skill这类插件,其价值远不止于添加一个功能模块。它更是一种思维模式:将动态内容数据化,通过配置而非代码来驱动展示。这迫使你更好地组织和结构化你的知识资产。在实际操作中,最大的挑战往往不是技术实现,而是如何设计一份清晰、有意义、可持续维护的技能数据模型。花时间思考你的分类体系、熟练度衡量标准,比纠结某个CSS样式更重要。当你的技能库能够随着你的成长而同步演进时,这个插件的价值才真正得以体现。

http://www.jsqmd.com/news/820695/

相关文章:

  • 上海黄金回收今日价格,足金999实时1010-1020元/克 - 奢侈品回收测评
  • 大模型时代红利:小白程序员必收藏的转型指南与高薪赛道解读!
  • JavaScript鼠标手势增强工具:supermouse-js核心原理与自定义实践
  • 蚂蚁灵波开源LingBot-VLA后训练代码!150条示教数据即可适配新机器人
  • 90%的程序员面试,都会问到的编程基础知识点,全在这里
  • Revelation光影包:5分钟打造电影级Minecraft画面的终极指南
  • 2026 年广州黄金回收谁给价高?5 家正规机构报价对比排行 - 奢侈品回收测评
  • 基于大语言模型的塔罗牌AI解读系统:技术架构与实现详解
  • 收藏!AI时代程序员转型指南:5条进阶路径+3个月行动表,小白也能学大模型
  • CircuitPython存储空间优化与社区参与实战指南
  • 盒马鲜生购物卡回收方法,这样操作超划算! - 团团收购物卡回收
  • 大模型应用实战:Stream-Omni框架实现流式与多模态交互
  • Go语言数据结构:数组、切片与MAP
  • 零Token AI工具构建:本地部署开源大模型实战指南
  • C语言实战:从零构建2048游戏,掌握核心算法与图形编程
  • ColorUI:15分钟构建高颜值小程序的完整色彩系统解决方案
  • 深度解析开源小红书采集工具:XHS-Downloader技术架构与实战应用指南
  • 四季青潜规则:金链子结账,比支票更获信任 - 奢侈品回收测评
  • 问: ansible有java的API吗?
  • LizzieYzy:围棋AI分析的终极免费工具,5分钟快速上手
  • OCR识别慢/不准怎么办?5种优化方案实测(附代码)
  • OBS多路推流插件终极指南:5分钟掌握多平台同步直播技术
  • 《“叶”问手册——从零开始学习STM32中文参考手册》01
  • day15 C语言 指针3
  • AI提示词注入绕过工具:一键绕过Codex/Claude安全限制,CTF夺旗与渗透测试必备神器
  • OpenClaw性能优化实战:网络I/O、解析处理与并发控制深度解析
  • 一键安装Cursor AI编辑器:Bash脚本自动化部署实践
  • 从Git历史到数据洞察:构建代码仓库统计分析工具的设计与实践
  • 枣庄 CPPM 证书费用 山东本地 CPPM 报考详解 - 中供国培
  • 基于Kubernetes的MLOps参考架构:从模型开发到生产部署的工程化实践