
CANN HCCL Tuner Plugin 实战指南用外部 .so 插件改写 cost table 干预算法选择【免费下载链接】hccl集合通信库Huawei Collective Communication Library简称HCCL是基于昇腾AI处理器的高性能集合通信库为计算集群提供高性能、高可靠的通信方案项目地址: https://gitcode.com/cann/hccl导读HCCLHuawei Collective Communication Library的算法选择器Selector通常依据内置 CostModel 在 cost table 中挑选最小代价算法但特定拓扑与数据量下模型预估未必是最优。本文围绕仓库 examples/07_tuner_plugin 目录下的参考实现讲解如何通过一个外部.so插件读取 JSON 配置、修改 cost table从而精确影响 Selector 的算法选择并介绍配套的「采集性能数据 → 生成最优配置 → 加载生效」三步工作流。读完本文你将掌握 Tuner Plugin 的接口契约、JSON 规则格式、配置查找优先级以及两个 Python 脚本的完整用法能够针对自己的集群拓扑生成并落地定制化的算法选择策略。1. Tuner Plugin 是什么在 HCCL 中每次集合通信算子执行前SelectorEngine会生成一张 cost table每个候选算法一个 cost 条目随后通过SelectMinCost选出 cost 最小的算法执行。默认情况下cost 值由内置 CostModel 依据算子、数据量、拓扑等因素计算得出但对特定机型、特定拓扑而言模型预估并不总是与真实性能一致。Tuner Plugin 正是为解决这一问题而设计的开放扩展点HCCL 核心通过dlsym加载外部插件插件在算子调度前拿到本次集合通信的上下文算子类型、数据量、数据类型、通信域拓扑等与整张 cost table按用户配置的规则改写其中某些算法的 cost 值从而影响 Selector 的最终选择。仓库中的 examples/07_tuner_plugin 提供了完整的参考实现演示了「读取 JSON 配置 → 修改 cost table → 影响 Selector 算法选择」的完整链路。从源码结构看该扩展点由三部分构成接口头文件 hccl_tuner_plugin.h定义插件需导出的符号与数据结构核心加载器 tuner_setup.cc负责dlopen/dlsym、环境变量解析、慢调用防护调用点 selector_engine.cc在 Selector 运行链路中 Enrich cost table 并回调插件。2. 插件接口契约与核心加载链路2.1 插件导出的唯一符号插件必须以 C 链接方式导出一个名为hcclTunerPlugin_v1的全局变量类型为hcclTunerFuncs_v1_t其中包含init与getCollInfo两个函数指针见 hccl_tuner_plugin.htypedef struct { hcclTunerInit_t init; /* 通信域初始化时回调一次 */ hcclTunerGetCollInfo_t getCollInfo; /* 每次集合通信算子调度前回调 */ uint32_t structSize; /* HCCL 设值plugin 据此判断缓冲区大小ABI 兼容 */ } hcclTunerFuncs_v1_t;init在通信域comm建立时被调用一次入参为通信域信息hcclTunerCommInfo_trank 数、每服务器 NPU 数、服务器数、Pod 数、超节点数、通信域名、buffer 大小以及宿主函数表hcclTunerHostFunctions_tctxCreate/ctxGet/ctxDestroy/logFunction。插件通常在此读取并解析 JSON 配置把规则表持久化到通信域 host 内存。getCollInfo每次算子调度前被调用入参为本次调用信息hcclTunerCollInfo_t算子类型、字节数、数据类型与命名 cost tablehcclTunerAlgoEntry_t[]。插件逐条匹配规则命中则改写目标条目的cost字段并将*matched置 1。hcclTunerAlgoEntry_t中的engineName/executorName/templateName由 HCCL 核心在 Enrich 阶段填充插件只读cost是唯一可修改字段其语义为0表示禁用、0表示偏好最优、0表示覆盖为指定值、不改则沿用 CostModel 计算值。2.2 HCCL 核心的加载与调用流程核心加载器位于 tuner_setup.cc关键路径如下首次加载HcclTunerInit持互斥锁调用LoadPluginLocked读取环境变量HCCL_TUNER_PLUGIN为空或为none时不加载随后dlopen(path, RTLD_NOW | RTLD_LOCAL)并通过dlsym(handle, hcclTunerPlugin_v1)取得函数表校验init/getCollInfo非空后记入全局单例。填充通信域信息BuildCommInfo从拓扑信息TopoInfoWithNetLayerDetails中提取 rank 数、服务器数、每服务器 NPU 数、Pod/超节点数并通过HcclGetCommName与HcclGetHcclBuffer取得通信域名与 buffer 大小。回调插件在 selector_engine.cc 的TunerEnrichCostTable中先生成 cost table调用AlgoNameMapper::Global()-Enrich填充算法条目的三维名字engine/executor/template再调用HcclTunerCallGetCollInfo让插件改写 cost最终SelectMinCost从 cost table 中取最小值确定算法。慢调用防护核心对getCollInfo调用计时若单次超过 100ms 阈值且连续达到 3 次TUNER_SLOW_CALL_LIMIT会将插件状态置为LOAD_FAILED并回退 CostModel避免插件性能问题拖垮算子调度init慢调用5s只告警不禁用。生命周期HcclTunerDestroy递减引用计数但.so故意不dlclose以避免与在途getCollInfo产生竞争。环境变量HCCL_TUNER_PLUGIN与HCCL_TUNER_CONFIG_FILE均在核心/插件侧生效前者由核心读取决定是否加载插件后者由示例插件自身读取决定配置文件位置。3. 编译构建示例目录的 Makefile 将 plugin.cpp 编译为共享库hccl_tuner_example.sosource /usr/local/Ascend/cann/set_env.sh make产物hccl_tuner_example.so。构建细节编译选项-fPIC -shared -O2 -stdc14头文件路径包含$ASCEND_HOME_PATH默认/usr/local/Ascend/ascend-toolkit/latest可用ASCEND_HOME_PATH变量覆盖与仓库内的 hccl_tuner_plugin.hPLUGIN_INCLUDE指向../../src/ops/op_common/selector/inc。首次构建会自动下载 nlohmann/jsonheader-onlyv3.11.3到third_party/离线场景可手动预放third_party/nlohmann/json.hppMakefile 检测到即跳过下载。插件实现依赖securec.hsnprintf_s/memset_s等安全函数编译时通过$ASCEND_HOME_PATH/include系列路径引入。4. 快速使用设置两个环境变量后正常运行业务即可export HCCL_TUNER_PLUGIN/path/to/hccl_tuner_example.so export HCCL_TUNER_CONFIG_FILE/path/to/hccl_tuner_config.json插件按以下顺序查找配置文件找到第一个可读的即加载$HCCL_TUNER_CONFIG_FILE未设置时跳过./hccl_tuner_config.json进程当前工作目录/etc/hccl/hccl_tuner_config.json系统级兜底。仓库提供了一个可直接运行的示例配置 hccl_tuner_config.json其中对 allreduce 配置了三条规则8~16 ranks 小数据量走sole{nhr}、8 ranks 中大数据量走sole{meshoneshot}、16 ranks 走sequence{meshconcur,nhr,nhr}对 allgather 配置了一条全量规则sole{mesh}所有命中条目的 cost 均置0.0表示最优偏好。5. 三步工作流数据采集与配置生成手工编写 JSON 配置难以猜中各拓扑下的最优算法因此示例目录提供两个 Python 脚本把「为我的拓扑选最优算法」变成三步5.1 第一步采集性能数据prof_test.pyprof_test.py 在环境里逐个算法拉起mpirun hccl_test可执行文件映射见脚本内OP_TO_EXE如 allreduce →all_reduce_test解析 stdout 输出的性能表格把各算法在每个数据量下的带宽和时延写入 CSV。运行前请确认Python 3.8脚本仅使用标准库mpirun在 PATH 中MPICH 或 Open MPI 均可脚本通过OMPI_COMM_WORLD_RANK环境变量自动探测并适配两种命令格式已 source CANN 环境变量$ASCEND_HOME_PATH已设置hccl_test 可执行文件位于$ASCEND_HOME_PATH/tools/hccl_test/bin/也可通过--bin-dir指定其他位置脚本要在 mpirun 会话外运行登录节点普通 shell。如果检测到自己在 MPI 会话里PMI_SIZE/OMPI_COMM_WORLD_SIZE 1脚本会直接报错退出避免嵌套拉起导致采集进程数被放大。典型命令python3 prof_test.py --op-types allreduce,allgather --engines aicpu --np-total 16 --npus 8 \ --hostfile hostfile --minbytes 1K --maxbytes 2G --stepfactor 2 \ --data-types fp32 --output hccl_prof.csv参数说明参数默认值说明--op-types必填采集的算子逗号分隔支持all8 种白名单allreduce/allgather/broadcast/reduce/reduce_scatter/scatter/alltoall/alltoallv--np-total必填总 rank 数即mpirun -n的值--npus未指定每台服务器的 NPU 数透传给 hccl_test-p--hostfile未指定多机 hostfile 文件单机不用传。每行写一条IP:NPU数如10.10.130.22:8#开头的注释行和空行忽略服务器数按有效行数统计--minbytes/--maxbytes未指定数据量区间对应-b/-e两者必须同时给。单位纯数字按字节K/M/G后缀按 1024 进制1K1024B1M1024K支持小数如1.5K--stepbytes未指定线性步进字节正整数对应-i与--stepfactor互斥两者都不传时由 hccl_test 按默认序列扫点--stepfactor未指定等比步进因子对应-f浮点典型值 2即 1K→2K→4K…与--stepbytes互斥--data-typesfp32数据类型逗号分隔脚本支持 16 种int8/uint8/int16/uint16/int32/uint32/int64/uint64/fp16/fp32/fp64/bfp16/fp8e5m2/fp8e4m3/fp8e8m0/hif8对应-d--reduce-opsumreduce 操作类型sum/prod/max/min仅对 reduce 类算子下发-o--enginesall采集引擎支持aicpu/aiv/dpuall展开全部三种见下方说明--algos全量显式指定算法串HCCL_ALGO语义如sole{mesh};parallel{mesh,nhr}--executors/--templates全量按执行器 × 模板展开组合--algos存在时忽略--warmup-iters10预热次数对应-w--iters20迭代次数对应-n--run-timeout600单轮超时秒数超时杀掉整轮进程树按失败继续--pods0Pod 数0 表示未指定生成的配置不约束该维度--super-pods0超节点数同上--outputhccl_prof.csvCSV 输出路径--bin-dirtools/hccl_test/binhccl_test 目录相对$ASCEND_HOME_PATH或绝对路径采集行为说明对应脚本内的关键实现引擎范围当前支持aicpu/aiv/dpuall展开全部三种。dpu不下发-a参数ENGINE_TO_ACCEL表中无 dpu 映射由拓扑绑定决定。暂不支持ccums/ccusched传入会直接报错当前 hccl 不支持 ccu_sched_only / ccu_ms_only 模式配了 ccu 算法也可能回退到 aicpu 算法执行测出的耗时不准会污染选优结果。算法黑名单执行器带 concur 的算法、模板带 multilink / meshconcurrent 的算法不采集meshconcurrent 为 meshclos 方阵组网专属executor 仍是 sole故单独拉黑。这类算法在老选择逻辑下的选中条件很苛刻特定机型、特定拓扑、特定数据量普通环境下就算配了实际可能静默回退选中其他算法导致测出的耗时张冠李戴。拓扑层数剪枝脚本按--hostfile行数、--pods、--super-pods估算拓扑层数单机1 层跨机/跨 Pod2 层跨超节点3 层只采集层数匹配的算法。注意这只是估算下限跨超节点环境务必显式传--super-pods多 Pod 环境要传--pods否则对应层的专属算法会被误剪。指定--algos时层数不匹配的算法会被跳过并在结果里标注。超时容错每轮默认 600 秒超时到点杀掉整个进程组POSIX 下mpirun独立进程组该轮记为失败并继续后续采集。失败或没解析出数据的轮次会在 CSV 里落一行check_resultfailed/noresult的审计记录原始输出追加到output.raw文件里供排查缺 so、dlopen 失败等原因都能在里面找到。增量采集CSV 是追加写的。文件已存在且表头固定 17 字段一致就接着写表头不一致会拒绝追加生成配置时按时间戳去重同一个点只取最新一轮的结果。追加前还会检查文件末字节防止上一轮进程被强杀导致最后一行未完整落盘。5.2 第二步生成最优配置optimize_config.pypython3 optimize_config.py --input hccl_prof.csv --output hccl_tuner_config.jsonoptimize_config.py 的处理流程按算子、数据类型、reduce 类型、拓扑 5 字段分组 → 在每个数据量点上跨 engine/executor/template 挑带宽最高的算法带宽相同比时延→ 相邻数据点同算法的合并成区间区间之间的缝隙划给右边的区间 → 输出插件格式的 JSON。过滤与去重按顺序为filter_failed丢弃 failed/noresult 行→normalize_bytes口径换算→dedup_latest按 timestamp 去重保留最新一轮。两处口径换算需要注意allgather 系按每 rank 口径换算hccl_test 采集的 size 是每个 rank 收到的总量而插件运行时匹配的是每个 rank 发出的量。生成规则前会自动除以 rank 数向上取整CSV 里的原始数值不受影响scatter 按总发出量换算hccl_test 采集的 size 是每个 rank 收到的量而插件运行时匹配的是 root 总发出量。生成规则前会自动乘以 rank 数CSV 里的原始数值不受影响dpu 规则强制min_servers2原因见下文「engine 可选值」一节。此外生成前还有一道白名单硬校验validate_winner胜者算法必须落在插件白名单内op_type / data_type / engine / executor / template 逐一校验。校验不通过的行直接丢弃并在日志里给出计数和原因不会让一条坏数据导致整份配置失效——因为插件侧只要有一条非法 rule就会导致整份配置在 Schema 校验阶段被整体拒绝。5.3 第三步加载生效export HCCL_TUNER_PLUGIN/path/to/hccl_tuner_example.so export HCCL_TUNER_CONFIG_FILE/path/to/hccl_tuner_config.json之后正常运行业务即可插件会按配置改写 cost table。配置格式见下一节。5.4 目录下其他文件tuner_common.py是两个脚本共用的常量表CSV 字段、算法注册表、拓扑层数约束表、黑名单等被两边直接引用不需要单独运行。有两点维护上的事需要知道算法注册表是人工维护的_RAW_VALID_ALGOS每算子合法engine:executor{tpl1,tpl2}组合表与_TOPO_LEVEL_CONSTRAINTS拓扑层数约束表从 HCCL 源码的算法注册宏归纳而来如aicpu:sole{meshoneshot}、aicpu:sequence{meshconcur,nhr,nhr}等不会随 HCCL 版本自动更新。升级 HCCL 后如果新增了算法需要手动同步这两张表否则新算法采不了按未注册组合被跳过。黑名单可以放开排除逻辑集中在tuner_common.py的is_blacklistedconcur 拦截在函数里写死multilink/meshconcurrent 走ALGO_BLACKLIST_KEYWORDS关键词表想采集这些算法时改这里。6. JSON 配置格式插件读取的配置是以下结构{ version: 1, op_types: { allreduce: { rules: [ { match: { min_ranks: 8, max_ranks: 8, min_bytes: 0, max_bytes: 65536, data_type: fp16 }, engine: aicpu, executor: sole, template: nhr, cost: 0.0 } ] } } }6.1 顶层字段字段类型必填说明versionint是配置格式版本目前必须为1op_typesobject是按算子类型组织的规则集6.2 match 条件全部 ANDfirst-match-wins字段类型必填说明min_ranks/max_ranksuint32是通信域 rank 数范围min_bytes/max_bytessize_t是数据量范围字节data_typestring否数据类型int8/int16/int32/int64/uint8/uint16/uint32/uint64/fp16/float16/fp32/float32/fp64/float64/bfp16/bfloat16fp16与float16等价见 plugin.cpp 中g_dataTypeMapcomm_namestring否通信域名子串匹配实现为strstrmin_npus_per_server/max_npus_per_serveruint32否每服务器 NPU 数范围min_servers/max_serversuint32否服务器数范围min_pods/max_podsuint32否Pod 数范围min_super_pods/max_super_podsuint32否超节点数范围buffer_sizeuint64否通信域 buffer 大小精确匹配规则匹配采用first-match-winsgetCollInfo按算子命中op_types下的规则集后从第一条规则开始逐条匹配所有已配置条件全部满足才算命中首条命中的规则即生效后续规则不再尝试。因此规则顺序很重要应将更精确/更优先的规则放在前面。6.3 命中行为engine/executor/template必填指定 cost table 中的目标位置template对单级算法是单 template 名如mesh对多级算法是 executor 后剩余串小写化的拼接如meshconcurnhrnhrcost必填设置该位置的 cost 值0.0表示最优Selector 从 cost table 中选最小值确定算法SelectMinCost。命中后plugin.cpp 的ApplyRule会遍历 cost table 中所有engineName/executorName/templateName与规则一致的条目并改写 cost若目标条目当前cost 0已被禁用插件会跳过不改写SelectMinCost中 cost0 视为 filtered 不参与选择。6.4 engine 可选值aicpu/ccums/ccusched/aiv/dpu注意dpu与前 4 个 device 引擎拓扑互斥、非同台竞争。dpu 算法注册isHostDpuOnlytrue仅 hostdpu 拓扑多 server 且末层 CLOS 全连通可选普通环境 dpu 算法全部被 topo 过滤hostdpu 环境 device 算法全部被过滤。因此 optimize_config 为 dpu rule 强制min_servers2单机采集的 dpu 数据测得的是静默回退的其他算法耗时属无效数据。6.5 executor 可选值sole/sequence/parallel/pipeline/concur/strictordered注意插件侧的g_validExecutors校验表见 plugin.cpp不含strictordered写入会触发 SchemaError 导致整份配置失效因此tuner_common.py的PLUGIN_EXECUTORS已将其排除采集结果中该类算法的行会被 optimize_config 校验丢弃。6.6 template 可选值template不做枚举校验单级是单 template 名多级是 executor 后剩余串小写化的拼接串rule 是否生效由 cost 表 templateName 匹配决定Enrich 按 algName 派生拼写错误匹配不到条目、靠运行时 warning 兜底rule matched but no entry modified。单级mesh/mesh2die/meshoneshot/meshtwoshot/meshconcur/meshmultilink/meshchunk/meshchunktwoshot/nhr/nhrmultilink/nhraicpureduce/nhrsinglechannel/meshconcurrent多级拼接串取 algName 中 executor 后的剩余串小写化如AicpuAllReduceSequenceMeshConcurNHRNHR→meshconcurnhrnhr。{ engine: aicpu, executor: sequence, template: meshconcurnhrnhr, cost: 0.0 }技巧采集 CSV 中多级模板是带逗号的语义串如meshconcur,nhr,nhr与HCCL_ALGO语法一致写入 JSON 前须去掉逗号变成插件拼接串——这正是tuner_common.py中templates_to_plugin_name函数str.replace(,, )的用途。6.7 支持的 op_typeallreduce/allgather/broadcast/reduce/reduce_scatter/scatter/alltoall/alltoallv以上 engine / executor / template / op_type 的可选值与 HCCL 算法选择器的维度定义一致校验表来源注释表明与 alg_parse.cc 相邻的 alg_parse 中ENGINE_TYPES/EXECUTOR_TYPES/ALGO_TYPESkey 保持一致。v 系列算子allgatherv / reduce_scatterv / alltoallvc不在白名单中。7. CSV 列格式hccl_prof.csv每行一个采集点列固定为 17 个供自行后处理参考列含义op_type/data_type/reduce_type采集维度reduce 类之外的算子reduce_type为NAsize_bytes数据量字节engine采集引擎algorithm.executor_type/algorithm.template_type算法多级模板为逗号分隔串如meshconcur,nhr,nhrHCCL_BUFFSIZE采集时的HCCL_BUFFSIZE环境变量值ranks.ranks/ranks.npus_per_server/ranks.servers/ranks.pods/ranks.super_pods拓扑 5 字段未指定的 pods/super_pods 记 0check_result结果校验状态success表示算法结果比对通过failed/noresult表示该轮执行失败或未产出数据仅供参考不参与选优alg_bandwidth(GB/s)/alg_latency(us)性能数据optimize_config 以带宽选优timestamp(ms)毫秒时间戳增量采集去重依据8. 测试Python 单测覆盖两个脚本的全部纯函数如parse_bytes、parse_algos、estimate_topo_levels、merge_intervals等python3 test_l0.pyC 插件测试test/test_plugin.cpp 通过#define HCCL_TUNER_TESTING#include ../plugin.cpp直接测试插件内部逻辑mock 了 hostFuncs 的ctxCreate/ctxGet/ctxDestroy/logFunction与算法条目cd test make ./test_plugin9. 运行示例以下为./test_plugin的典型输出展示插件的各种行为日志前缀[TunerDFX]来自插件自身的logFunction输出。9.1 命中规则并覆盖 costAllReduce 8 ranks、4096B、fp32 匹配规则将目标算法 cost 从 100.0 改为 0.0最优偏好Selector 会选这个算法[TunerDFX] rule hit: opType2 nBytes4096 dataType3 ruleIdx0/2 engineaicpu executorsole templatemeshoneshot cost0.000000 [TunerDFX] modify: algNameAicpuAllReduceSoleMeshOneShot cost 100.000000 - 0.000000多级算法同样支持template为 executor 后剩余串小写化拼接[TunerDFX] rule hit: opType2 nBytes4096 dataType3 ruleIdx0/1 engineaicpu executorsequence templatemeshconcurnhrnhr cost0.000000 [TunerDFX] modify: algNameAicpuAllReduceSequenceMeshConcurNHRNHR cost 5.000000 - 0.0000009.2 不匹配时不干预4 ranks 不在规则要求的 8~16 范围内无规则命中cost table 保持 CostModel 原值[TunerDFX] no rule matched: opType2 nBytes4096 dataType39.3 目标算法已禁用cost0时跳过目标条目 cost-1已被禁用插件不改它SelectMinCost中 cost0 视为 filtered 不参与选择[TunerDFX] rule hit: opType2 nBytes4096 dataType3 ruleIdx0/2 engineaicpu executorsole templatemeshoneshot cost0.000000 [TunerDFX] skip disabled: algNameAicpuAllReduceSoleMeshOneShot cost-1.000000 [TunerDFX] rule matched but no entry modified9.4 Schema 校验失败时整体不干预配置有拼写错误、缺失必填字段、枚举非法等任意 schema error 时插件完全不干预安全降级。这一设计在 plugin.cpp 中体现为init阶段统计schema.errors若大于 0 则把configValid置 0后续getCollInfo直接返回不干预Schema: unknown field mtach in rule, skipping Schema: rule missing required field match Schema: invalid engine invalid_engine Schema: min_ranks(16) max_ranks(8) tuner config loaded, schemaErrors4 Schema validation failed (4 errors), plugin will not intervene10. 注意事项与最佳实践失败安全插件在任何异常路径配置未找到、JSON 解析失败、Schema 校验失败、ctxCreate失败、插件 init 失败下都会静默回退 CostModel不会阻断业务算子执行核心侧还有慢调用熔断兜底。可以放心在生产环境试点。规则顺序match 采用 first-match-wins精确规则放前面、兜底规则放后面规则区间应尽量覆盖完整min/max 都写避免出现匹配不到的缝隙。口径一致性手工编写配置时min_bytes/max_bytes必须按插件运行时口径allgather 每 rank 发出量、scatter root 总发出量填写与 hccl_test 的采集口径不同使用 optimize_config.py 生成可自动完成换算。配置规模限制示例插件内置了MAX_OP_TYPES8、MAX_TOTAL_RULES5000、MAX_RULES_PER_OP2000、MAX_FILE_SIZE4MB等上限超大配置会被拒绝加载。升级维护算法注册表与拓扑层数约束表是人工维护的升级 HCCL 后如有新增算法需同步更新tuner_common.py中的_RAW_VALID_ALGOS与_TOPO_LEVEL_CONSTRAINTS。参考资料Tuner Plugin 示例 README本文的主体来源含完整的中英文对照细节插件接口头文件hcclTunerFuncs_v1_t/hcclTunerCommInfo_t/hcclTunerCollInfo_t/hcclTunerAlgoEntry_t等结构定义核心加载器实现dlopen/dlsym加载、慢调用熔断、通信域信息填充Selector 调用点Enrich 命名 插件回调 SelectMinCost的完整链路示例插件实现JSON 解析、Schema 校验、规则匹配与 cost 改写示例配置可直接参考的规则写法公共常量表算法注册表、拓扑层数约束、黑名单采集脚本 与 配置生成脚本三步工作流的实现C 插件测试插件行为验证与本文运行示例的来源。【免费下载链接】hccl集合通信库Huawei Collective Communication Library简称HCCL是基于昇腾AI处理器的高性能集合通信库为计算集群提供高性能、高可靠的通信方案项目地址: https://gitcode.com/cann/hccl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考