机器学习实战:从数据到模型的八步探险与核心利器

前言

在上一篇《机器学习实战:什么是机器学习》中,我们简单的介绍了一下机器学习当中几个比较常见的算法和学习内容的介绍.但是我们最多只是明白了几个专有名词,对其本质却是一无所知.

所以本文作为本系列的第二篇,我们将踏上从“知道”到“做到”的关键一步。将一起走完一个典型机器学习项目的完整生命周期——从原始数据的获取与清洗,到特征工程、模型训练、评估与调优,直至最终部署前的关键考量。我们将把这趟旅程拆解为清晰的八个步骤,并深入剖析贯穿其中的几大核心“利器”:数据预处理技术、交叉验证策略、过拟合应对方法等。

希望可以为初学者建立起系统性思维结构。准备好了吗?


一. 机器学习项目:从迷茫到精通的八步通关秘籍

核心思想:机器学习之旅的每一步

一个成功的机器学习项目绝非一蹴而就,它是一个结构化、迭代的复杂流程。这个流程旨在将看似杂乱无章的原始数据,转化为能够提供智能洞察或预测能力的强大工具。遵循一套清晰的项目流程,不仅能确保项目的系统性、可控性和高成功率,还能帮助团队在海量数据和复杂模型之间找到一条清晰的路径,有效管理风险,最终交付高质量的机器学习解决方案。

我们将机器学习项目拆解为八个关键步骤,每一步都至关重要:

  1. 放眼大局 (Frame the Problem):这是项目的起点,也是成功的基石。我们需要深入理解业务问题,明确项目的最终目标,定义衡量成功的指标,并确定解决方案的类型(例如,是监督学习还是无监督学习?是分类任务还是回归任务?)。这一步确保了我们的机器学习方案能够真正解决实际问题并创造价值。

  2. 获取数据 (Get the Data):数据是机器学习的“燃料”。在这一阶段,我们将收集、整合、清洗并初步探索原始数据。数据的质量和数量将直接决定模型的性能上限,因此,这一步的重要性不容小觑。

  3. 探索和可视化数据以获得见解 (Explore and Visualize Data):拿到数据后,我们不能急于求成。通过统计分析和可视化技术,我们可以深入理解数据的特征,发现潜在的模式,识别异常值,并预见可能存在的问题。数据探索能帮助我们形成对数据的直观理解,为后续的数据准备和模型选择提供宝贵依据。

  4. 为机器学习算法准备数据 (Prepare the Data):这是机器学习中最耗时但至关重要的一步。原始数据往往无法直接用于模型训练,我们需要对其进行预处理,使其适合机器学习算法的输入。这包括特征工程(创造新的、更有意义的特征)、数据清洗、缺失值处理、数据转换和缩放等。数据准备的质量直接影响模型的训练效率和最终性能。

  5. 选择一个模型并训练它 (Select and Train a Model):在数据准备就绪后,我们将根据问题的类型和数据的特性,选择最合适的机器学习模型,并使用准备好的数据对其进行训练。选择合适的模型和有效的训练策略是构建高性能模型的关键。

  6. 微调模型 (Fine-tune the Model):模型训练完成后,我们还需要对其进行精细的“打磨”。通过调整模型的超参数、运用集成学习等高级方法,我们可以进一步优化模型的性能。微调能够显著提升模型的准确性和泛化能力,使其达到最佳状态。

  7. 展示解决方案 (Present the Solution):一个优秀的模型不仅要性能卓越,还要能被理解和采纳。在这一步,我们将向项目的利益相关者展示模型的性能,解释模型的决策过程,并提供可操作的洞察。有效的沟通和可视化是确保项目成果被理解和采纳的重要环节。

  8. 发布、监控和维护系统 (Launch, Monitor, and Maintain):机器学习模型并非一劳永逸。一旦部署到生产环境,我们需要持续监控其性能,并进行必要的更新和维护。这是因为数据可能会随着时间发生“漂移”,模型也可能“老化”,持续的监控和维护是确保模型长期稳定运行的关键。

完成了这八步,我们的机器学习项目才算真正落地。然而,在整个流程中,数据处理和模型优化是贯穿始终的重中之重。当然,作为一篇博客我们主要是探讨如何高效地处理数据,以及如何科学地评估和优化我们的模型。这些内容是我们在学习阶段最有能力去实现的了.

二. 数据流水线:构建机器学习的“自动化工厂”

核心思想:自动化生产线

在机器学习项目中,我们经常需要处理海量数据,并且这些数据往往需要经过多步复杂的转换才能用于模型训练。手动处理这些步骤不仅效率低下,而且容易出错。这时,机器学习流水线(Data Pipeline)就显得尤为重要了。

实现思路: 机器学习流水线就像一条自动化生产线,将数据处理的各个环节串联起来,让数据从“原材料”高效地转化为“成品”,每个环节独立运作又紧密协作。

流水线机制的引入,使得复杂的数据处理过程得以模块化和自动化,极大地提高了效率、可维护性和鲁棒性。它在各种机器学习场景中都得到了广泛应用,尤其是在需要处理大量数据、进行多阶段数据转换以及团队协作开发的项目中。

  • 组件化:流水线由多个独立的组件构成,每个组件都专注于完成特定的数据处理任务,例如数据清洗、特征提取或模型训练。这种模块化的设计使得开发和维护变得更加简单。
  • 异步运行:流水线中的组件通常是异步运行的。每个组件从上游拉取数据,处理完毕后将结果输出到下一个数据存储器,供下游组件使用。这种松耦合的设计提高了系统的并行处理能力。
  • 数据存储接口:组件之间通过数据存储接口进行交互,这使得整个系统易于理解和管理。不同的团队可以专注于不同组件的开发和维护,提高了协作效率。
  • 鲁棒性:流水线设计的一大优势在于其健壮性。即使某个组件发生故障,下游组件通常仍可以继续使用该组件的最后输出,从而避免了整个系统的崩溃。
  • 监控:为了确保流水线的顺畅运行,实施适当的监控机制至关重要。我们需要实时监控所有组件的运行状态,及时发现并解决问题,避免因组件故障导致数据陈旧或系统性能下降。

通过构建高效的数据流水线,我们能够确保数据处理的自动化和标准化,为后续的模型训练和部署提供坚实的基础。接下来,我们将探讨如何科学地评估这些经过精心处理的数据所训练出的模型。

三. 模型评估:如何给你的AI“打分”?

核心思想:想要比较出来不同的模型的好坏,我们必须要对模型进行评分

当我们训练好一个机器学习模型后,如何判断它的“真功夫”呢?这就需要借助模型评估指标了。这些指标是量化模型性能的标准,它们帮助我们衡量模型在特定任务上的表现,并指导我们进行模型选择和优化。

实现思路: 评估指标就像考试分数,用来衡量机器学习模型表现好坏,不同的“考试”有不同的“评分标准”,比如预测数值的准确度(RMSE、MAE)或分类的精确度。

选择合适的评估指标至关重要,因为它直接影响我们对模型优劣的判断以及模型的优化方向。不同的问题类型(例如,回归问题和分类问题)和业务目标需要采用不同的评估指标。评估指标贯穿于模型训练、微调和部署的各个阶段,是指导我们决策的关键。让我们来看看回归问题中常用的几个评估指标:

  • 均方根误差 (Root Mean Square Error, RMSE)

    • 公式RMSE=1m∑i=1m(y(i)−y^(i))2RMSE = \sqrt{\frac{1}{m}\sum_{i=1}^{m}(y^{(i)} - \hat{y}^{(i)})^2}RMSE=m1i=1m(y(i)y^(i))2
    • 特点:RMSE对应于欧几里得范数(ℓ2ℓ_22 范数),它衡量的是预测值与真实值之间距离的平方和的根。由于误差被平方,RMSE对异常值(outliers)非常敏感,大的误差会被显著放大。当异常值呈指数级减少时(如钟形曲线分布),RMSE通常是首选的评估指标。
  • 平均绝对误差 (Mean Absolute Error, MAE)

    • 公式MAE=1m∑i=1m∣y(i)−y^(i)∣MAE = \frac{1}{m}\sum_{i=1}^{m}|y^{(i)} - \hat{y}^{(i)}|MAE=m1i=1my(i)y^(i)
    • 特点:MAE对应于曼哈顿范数(ℓ1ℓ_11 范数),它衡量的是预测值与真实值之间距离的绝对值之和的平均值。与RMSE不同,MAE对异常值不那么敏感,因为它不平方误差。因此,MAE更适用于存在较多异常值的场景。

在理解这些指标时,我们不得不提一下“范数”这个概念。范数是衡量向量大小的一种方式,而不同的范数对误差的敏感度也不同。例如,ℓkℓ_kk 范数定义为 ∣∣v∣∣k=(∑i=1n∣vi∣k)1/k||v||_k = (\sum_{i=1}^{n}|v_i|^k)^{1/k}∣∣vk=(i=1nvik)1/k。其中,ℓ0ℓ_00 范数给出向量中非零元素的数量,ℓ∞ℓ_∞ 范数给出向量中的最大绝对值。范数指数越高,它就越关注大值而忽略小值,这也是RMSE比MAE对异常值更敏感的根本原因。

了解了如何评估模型,下一步就是如何让我们的数据变得更“听话”,更适合模型的学习。这正是数据处理的艺术所在。

四. 数据预处理:让原始数据“焕然新生”的魔法

核心思想:对于模型的原材料进行加工

原始数据往往是“脏乱差”的,它们可能包含缺失值、异常值,不同特征的数值范围可能天差地别,甚至数据分布也不符合模型的要求。大多数机器学习算法无法直接处理这样的原始数据。因此,机器学习数据处理就显得尤为重要了。

实现思路: 数据处理就像给“原材料”做精细加工,包括去除杂质(缺失值)、调整形态(特征缩放)和提炼精华(特征工程),让它们更适合“模型”消化吸收。

有效的数据处理能够显著提高模型的训练效率、准确性和泛化能力。它是连接原始数据与高性能模型的桥梁,在任何机器学习项目的“数据准备”阶段都不可或缺。那么,我们通常会进行哪些数据处理操作呢?

1. 缺失值处理 (Handling Missing Values)

  • 问题:数据集中常常存在缺失的特征值,而大多数机器学习算法无法直接处理它们。
  • 解决方案
    • 删除对应实例:最简单粗暴的方法是直接去掉包含缺失值的行。
    • 删除整个属性:如果某个特征的缺失值过多,以至于该特征的价值不大,可以考虑直接删除该列。
    • 缺失值归责 (Imputation):这是最常用的方法,即用某个特定值(如零、均值、中位数、众数)来填充缺失值。更高级的方法包括:
      • sklearn.impute.KNNImputer:它会用该特征的 kkk 近邻的平均值来替换每个缺失值,距离的计算基于所有可用特征。
      • sklearn.impute.IterativeImputer:这种方法会为每个特征训练一个回归模型,根据所有其他可用特征来预测缺失值,并迭代地改进填充效果。

2. 类别特征编码 (Encoding Categorical Features)

  • 问题:机器学习算法通常需要数值输入,但我们的数据中常常包含文本或离散的类别特征。
  • 挑战:直接将类别映射为数值可能会导致算法错误地假设数值之间存在距离关系(例如,将“红”编码为1,“绿”编码为2,“蓝”编码为3,算法可能会认为“红”和“绿”比“红”和“蓝”更相似,这显然是错误的)。
  • 解决方案
    • 独热编码 (One-Hot Encoding):这是最常用的方法。它将每个类别转换为一个二进制(0或1)特征。例如,如果有一个颜色特征包含“红”、“绿”、“蓝”三个类别,独热编码会创建三个新列:颜色_红颜色_绿颜色_蓝。如果原始实例的颜色是“红”,那么颜色_红列为1,其他两列为0。值得注意的是,独热编码后常常会产生大量的零,这时稀疏矩阵就派上用场了,它能高效地存储这些“空荡荡”的数据。

3. 特征缩放 (Feature Scaling)

  • 问题:不同特征的数值范围可能差异巨大,例如,一个特征的取值范围是0到1,而另一个特征的取值范围是1000到100000。这可能导致模型训练不稳定或收敛缓慢,因为某些算法对特征的尺度非常敏感。
  • 解决方案
    • 最小-最大缩放 (Min-Max Scaling / Normalization):这种方法会将每个特征的值移动和重新缩放,使其最终值落在0到1之间。它通过减去最小值并除以最大值和最小值之间的差值来实现。这种方法简单直观,但容易受异常值影响。
    • 标准化 (Standardization):标准化首先减去特征的平均值(使均值为零),然后将结果除以标准差(使标准差为1)。这种方法不会将值限制在特定范围内,但受异常值的影响小得多,因此在实践中更为常用。

4. 处理重尾分布 (Handling Heavy-tailed Distributions)

  • 问题:当特征的分布有一个“重尾”(即远离平均值的值不是指数级稀有)时,最小-最大缩放和标准化可能会将大多数值压缩到一个小范围内,而机器学习模型通常不喜欢这种分布。
  • 解决方案
    • 数学变换:通过对特征进行数学变换来改变其分布,使其更接近正态分布,例如:
      • 平方根:用特征的平方根替换特征。
      • 幂变换:将特征提升到0到1之间的幂。
      • 对数变换:如果特征具有幂律分布(如人口数量),用对数替换该特征会非常有帮助。
    • 特征分桶 (Feature Bucketizing):将特征的分布分成大致相等大小的桶,并用它所属的桶的索引替换每个特征值。这能产生几乎均匀分布的特征,无需进一步缩放。对于具有多峰分布的特征(如房屋中位数年龄),将其分桶也很有帮助,但这次将桶的ID视为类别,并使用独热编码。
    • 径向基函数 (Radial Basis Function, RBF):为每个模式添加一个特征,表示房屋年龄中位数与该特定模式之间的相似性。相似性通常使用高斯RBF计算,其输出值随着输入值远离固定点而呈指数衰减。例如,exp(-γ(x-35)^2),其中 γ 决定衰减速度。Scikit-Learnrbf_kernel() 函数可用于创建新的高斯RBF特征。

数据处理是机器学习的基石,它直接决定了模型的“上限”。而如何让模型在现有基础上发挥出最大的潜力,则需要我们掌握模型优化的策略。

五. 模型优化:让你的AI“更上一层楼”的秘密武器

核心思想:对于我们的模型进行的一场特训

即使我们已经精心处理了数据并选择了合适的模型,初始训练出的模型也可能并非最佳。它可能存在欠拟合(模型过于简单,无法捕捉数据中的模式)或过拟合(模型过于复杂,过度学习了训练数据中的噪声,导致泛化能力差)的问题。

实现思路: 模型优化就像给运动员做特训,通过调整训练方法(超参数调优)和引入更强大的技术(交叉验证、集成学习),让模型在比赛中(预测任务)表现更出色。

机器学习模型优化,正是指在模型训练完成后,通过一系列技术和策略,进一步提升模型性能、解决这些问题,并找到最佳模型配置的过程。这个过程在机器学习项目的“微调模型”阶段至关重要,是提升模型在实际应用中表现的关键。

1. 解决欠拟合 (Addressing Underfitting)

  • 问题:当模型太简单,无法学习数据的底层结构时,它在训练数据和新数据上的表现都会很差。
  • 解决方案
    • 选择更强大的模型:尝试使用具有更多参数或更复杂结构的机器学习模型。
    • 提供更好的特征:通过深入的特征工程,为学习算法提供更具信息量的特征。
    • 减少模型约束:例如,通过减少正则化超参数来放松对模型的限制,让模型有更大的自由度去学习数据。

2. 超参数调优 (Hyperparameter Tuning)

  • 是什么:超参数是学习算法的参数,它们必须在模型训练前设置,并在训练期间保持不变。超参数调优就是寻找这些超参数最佳组合的过程。
  • 方法
    • 手动调整:这是一种耗时且效率低下的方法,尤其当超参数组合众多时。
    • 网格搜索 (Grid Search)Scikit-LearnGridSearchCV 类是实现网格搜索的强大工具。我们告诉它希望实验哪些超参数以及要尝试哪些值,它会使用交叉验证来评估所有可能的超参数值组合。当超参数组合相对较少时,网格搜索效果良好。
    • 随机搜索 (Randomized Search)Scikit-LearnRandomizedSearchCV 类则提供了随机搜索的功能。它会评估固定数量的组合,在每次迭代中为每个超参数选择一个随机值。随机搜索的优点在于,对于连续或离散但值较多的超参数,它能探索更多不同的值。即使超参数数量和可能值很多,我们也能通过控制迭代次数来控制计算成本。因此,当超参数搜索空间较大时,随机搜索通常是更优的选择。

3. 交叉验证 (Cross-validation)

  • 是什么:交叉验证是一种更可靠的模型评估方法,它通过将训练数据分成多个折叠(folds),轮流将其中一个折叠作为验证集,其余作为训练集进行训练和评估。Scikit-Learn 提供了强大的 k 折交叉验证功能。
  • 示例:我们可以将训练集随机拆分为10个不重叠的子集(折叠),然后对模型进行10次训练和评估,每次选择不同的折叠进行评估,并使用其他9次折叠进行训练。最终,我们会得到一个包含10个评估分数的列表。
  • 优点:交叉验证提供了更准确的模型性能衡量,减少了对特定数据划分的依赖,并有助于避免数据窥探偏差(Data Snooping Bias)。

在模型优化的过程中,我们必须时刻警惕一个隐形的“陷阱”——数据窥探偏差。它可能让我们的模型看起来很棒,但在实际应用中却大打折扣。那么,什么是数据窥探偏差,又该如何避免呢?

六. 数据窥探偏差:机器学习中的“开卷考试作弊”

核心思想:考试前偷看试卷

数据窥探偏差(Data Snooping Bias)是机器学习中一个非常隐蔽且危险的“陷阱”。它指的是在模型开发过程中,我们无意中使用了测试集的信息来指导模型选择或超参数调优,从而导致对模型泛化能力的估计过于乐观。

实现思路: 数据窥探偏差就像考试前偷看了试卷,虽然能让你这次考的好,但实际能力并没有提升,下次遇到新题还是会“露馅”。

测试集是用来模拟模型在真实世界中未见过的数据上的表现的。如果测试集的信息在训练或调优阶段被“泄露”给模型,模型就会对测试集产生“记忆”,从而在测试集上表现出虚高的性能,而实际部署时性能会大打折扣。这种偏差在任何机器学习项目中都可能发生,尤其是在数据划分不当或评估流程不严谨时。为了确保我们对模型泛化能力的评估是真实可靠的,我们必须采取严格的策略来避免数据窥探偏差。

避免数据窥探偏差的策略:

  1. 严格划分数据集:这是最基本的原则。我们需要将数据集严格划分为三个部分:

    • 训练集 (Training Set):专门用于模型的训练。
    • 验证集 (Validation Set):用于模型选择和超参数调优。我们可以在验证集上反复试验,找到最佳的模型配置。
    • 测试集 (Test Set):仅用于最终评估模型的泛化能力。在整个开发过程中,测试集必须保持独立和不可见,绝不能在训练或调优阶段接触到它。
  2. 稳定训练/测试拆分

    • 问题:如果我们每次运行程序时都随机拆分数据集,可能会生成不同的测试集,导致模型“看到”更多数据,从而产生偏差。
    • 解决方案
      • 保存测试集:在第一次运行时就将测试集保存下来,并在后续运行中始终加载使用同一个测试集。
      • 设置随机种子:在调用随机数生成器之前设置一个固定的随机种子(例如,np.random.seed(42)),以确保每次生成相同的混淆索引,从而保证数据集拆分的一致性。
      • 基于实例标识符的哈希:对于那些需要频繁更新数据集,但又要求稳定拆分的场景,我们可以使用每个实例的唯一且不可变的标识符来决定其是否进入测试集。例如,计算每个实例标识符的哈希值,并根据哈希值决定其归属(如哈希值低于最大哈希值的20%则放入测试集)。这种方法确保了测试集在多次运行和数据集刷新后都能保持一致。

避免数据窥探偏差是构建健壮、可靠机器学习模型的关键一步。而为了更高效、更自动化、更规范地进行数据处理,我们还需要掌握数据转换函数的构建。

七. 数据转换函数:打造你的专属“数据处理工具箱”

核心思想:标准化的工具箱

像我们提到的在机器学习项目中,数据处理往往涉及多个步骤,例如清洗、转换、特征工程等。手动执行这些操作不仅效率低下,而且容易出错,难以复现和维护。这时,将这些操作封装成数据转换函数就显得尤为重要了。一次成本,永久复用.

实现思路: 数据转换函数就像一套标准化的“工具箱”,把数据处理的每一步都封装起来,让你可以随时随地、高效准确地对数据进行“加工”,确保数据处理的质量和一致性。

数据转换函数是将原始数据或中间数据进行清洗、转换、特征工程等操作的封装代码块,旨在实现数据处理过程的模块化和自动化。将数据处理操作封装成函数,可以显著提高代码的可重用性、可维护性和可测试性,从而确保数据处理的一致性和准确性。它在机器学习项目的“数据准备”阶段得到了广泛应用,尤其是在需要对数据进行复杂、多步骤处理的场景中。

那么,编写数据转换函数具体有哪些好处呢?

  1. 可重现性 (Reproducibility):一旦数据转换逻辑被封装成函数,你就可以在任何数据集上轻松地重现这些转换。例如,当你获取新的数据集时,只需调用相同的函数即可,确保了数据处理过程的一致性。
  2. 可复用性 (Reusability):你可以逐步构建一个可在未来项目中重复使用的转换函数库,这将极大地提高开发效率,避免重复造轮子。
  3. 实时系统集成 (Real-time System Integration):在实际部署中,你可以在实时系统中使用这些函数来转换新数据,再将其提供给你的算法。这确保了线上线下数据处理逻辑的一致性,避免了模型在生产环境中表现不佳的问题。
  4. 实验性 (Experimentation):通过封装数据转换函数,你可以轻松尝试各种转换组合,并快速查看哪种组合效果最好,从而加速模型优化过程。

数据转换函数是构建高效、可维护机器学习系统的重要组成部分。
在数据处理中,我们还会遇到一种特殊的数据结构——稀疏矩阵,它在处理某些类型的数据时具有独特的优势。

八. 稀疏矩阵:高效管理“空荡荡”数据的智慧

核心思想:空的太多了,我们选择不记录了

在许多机器学习应用中,尤其是在处理独热编码后的类别特征时,我们经常会遇到一种特殊的数据结构——稀疏矩阵。这种矩阵的特点是包含了大量的零元素。如果直接存储这些矩阵,会浪费大量的内存和计算资源。

实现思路: 稀疏矩阵就像一个“聪明”的仓库管理员,对于大部分都是空的货架(零元素),它只记录有货的货架(非零元素)在哪里和有什么,大大节省了空间和查找时间。

稀疏矩阵就是一种特殊的数据结构,用于高效存储和操作包含大量零元素的矩阵。它只存储非零元素的值及其位置,而忽略了大量的零元素。稀疏矩阵通过只存储有效信息,显著提高了存储和计算效率。它广泛应用于自然语言处理(如词袋模型)、推荐系统、图像处理和独热编码等领域。任何产生大量零元素的场景都可能受益于稀疏矩阵。

那么,稀疏矩阵具体有哪些优势呢?

  1. 内存效率:稀疏矩阵在内部仅存储非零值及其位置,而不是存储所有元素,从而节省了大量的内存。例如,当一个类别属性有成百上千个类别时,独热编码会产生一个非常大的矩阵,除了每行一个1之外,其他元素几乎全是0。在这种情况下,稀疏矩阵是最佳选择。
  2. 计算速度:由于只处理非零元素,许多矩阵运算(如乘法、加法)在稀疏矩阵上会更快,这对于大规模数据处理来说至关重要。

在Python中,SciPy 库提供了多种稀疏矩阵格式及其操作,例如 scipy.sparse.csr_matrixscipy.sparse.csc_matrix,它们分别适用于不同的操作场景。

🏁 总结与思考

至此,我们已经完成了机器学习从数据到模型的八步探险,并深入探讨了支撑这一旅程的几大核心利器:从项目流程的宏观把控,到数据流水线的自动化构建;从模型评估的科学标尺,到数据预处理的精妙艺术;从模型优化的策略,到数据窥探偏差的规避;再到数据转换函数的模块化,以及稀疏矩阵的巧妙应用。这些知识点共同构成了机器学习实践的基石,帮助我们更高效、更准确地构建和部署机器学习模型。

机器学习的魅力在于其不断演进的特性。每一次数据处理的优化,每一次模型参数的微调,都可能带来性能的显著提升。记住,机器学习不仅仅是算法和代码,更是一门将数据转化为价值的艺术。希望本文能为您在机器学习的道路上提供一份清晰的指引,助您在未来的AI探索中乘风破浪,创造更多可能!

那么,我们到底该如何在一个机器学习项目中运用这些“秘密武器”呢,来解决一个现实世界中的挑战呢?

敬请期待,我们下一讲见!

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐