Aligning the Objective of LLM-based Program Repair

基本信息

2025ICSE(2025年5月2日)

博客贡献人

页禾七

作者

Junjielong Xu(香港中文大学(深圳)),Ying Fu(重庆大学)

Shin Hwei Tan(Concordia University(加拿大)),Pinjia He(香港中文大学)

摘要

大语言模型( LLMs )在自动程序修复(APR )方面取得了不错的效果。然而,仅使用解码器的LLMs (例如, GPT-4 )的下一个令牌预测训练目标(the next token prediction training objective)与当前填充式(infilling-style)方法的掩码跨度预测目标(the masked span prediction objective)不一致,这阻碍了LLMs充分利用预训练知识进行程序修复。此外,虽然一些LLM可以利用相关组件(artifacts)(例如,测试用例)来定位和修复某些函数中的bug,但现有的方法仍然依赖于语句级的错误定位方法来提供一个bug hunk列表来进行修复。这种限制阻碍了LLMs探索超出给定位置的潜在修复。

在本文中,我们研究了一种新的方法来适应LLM进行程序修复。我们的核心见解是,LLM的APR能力可以通过简单地将输出与它们的训练目标对齐,并允许它们在不首先识别错误语句的情况下对整个程序进行优化来大大提高。基于这一认识,我们设计了D4C——一个直接了当的APR提示框架。D4C可以正确修复Defects4J中的180个缺陷,每个补丁只需采样10次。该方法优于直接使用完美错误定位的SOTA APR方法10 %,并减少了90 %的补丁采样数量。我们的研究结果表明:( 1 )目标对齐对于充分挖掘LLM的预训练能力至关重要;( 2 )对于基于LLM的APR方法,用直接调试(debugging)代替传统的localize - buggy - hunks - then - repair 工作流更有效。因此,我们相信本文为APR中LLMs的应用引入了一种新的思路。

1 介绍

程序修复是软件周期的重要组织部分,因此研究人员开始探索自动程序修复。根据补丁的生成方式,APR方法可以分为:基于启发式的,基于约束的,基于模板的,基于学习的。其中传统方法依赖于预先定义的模式来解决特定的bug类型,基于学习的方法通常使用大规模,高质量的数据集训练神经机器翻译(NMT),近几年开始利用LLMs来进行APR。

然而,由于两个原因,现在的LLMs不能很好地适应APR。

  • the inference objective of current approaches is misaligned with LLM’s training objective.

    LLMs可以分为encoder-only,encoder-decoder和decoder-only三种,其中前两种通常被训练用于预测掩码tokens(比如infilling或者denosing),而第三个被训练用来预测下一个token(比如completion)。现有的基于LLM的方法在推理过程中一般采用infilling的方法在被掩码的错误代码处预测修复代码,早期这种方法确实取得了不错的效果,因为使用的模型也是通过infilling训练的。但是最近像GPT4这样decoder-only的LLMs,人们也试图直接用于infilling-style APR,效果提升就并不大。我们假设这是因为decoder-only的LLMs在训练的时候,训练目标是completion,而不是infilling。

  • the current workflow limits LLM from fully exploiting its pre-trained capability.

    现有的方法一般遵循先用语句级定位工具获取潜在buggy hunks的评分排序列表,再使用APR方法在这些hunks处修复程序的工作流程。然而,LLMs通过引入不同的组件(比如编译器或者虚拟机的错误报告),已经具备了独立修复其生成代码中琐碎语法错误的能力,也就是在没有给定bug hunks的情况下识别bug的能力。而且考虑到LLMs优越的代码理解能力,目前的错误定位工具可能无法提供正确的buggy hunks,如果让大模型在这些提供的buggy hunks中去修复可能反而阻碍他们探索更广阔的潜在补丁空间。并且最近还有一项研究表明,LLMs不能很好利用给定的buggy line,并且会过度依赖它们,因此传统的localize - buggy - hunks - then - repair 工作流可能对基于LLMs的APR方法无效。

本文探索了一种新颖的使用LLM进行程序修复的方法。我们提出:
1)将填充离散hunks的输出对齐到完成整个函数可以更好地达到训练目标

aligning the output from infilling discrete hunks to completing entire functions can better attain the training objective.

2)允许LLM以类似人类的方式定位和修复带有组件的buggy hunks,可以进一步提高其APR性能。

allowing LLM to locate and repair buggy hunks with artifacts in a humanlike manner can further improve its APR performance.

基于这两点见解,本文提出了D4C(Direct Debug Drives Decent Code),一种无需复杂提示和额外训练的APR方法。

我们对Defects4J和DebugBench中single-function bugs相关的共计1207个Bug进行了实验,D4C修复了Defects4J中437个单函数缺陷中的180个,比目前的SOTA 方法在基于完美语句级FL情况下提高了10 %。同时,D4C在每个patch上仅采样10次,仅为目前SOTA方法的10%。

综上,本文贡献:

1)问题重构:将infilling-style的修复问题重构为program refinement问题。我们的实验表面,要求LLMs生成一个完整的refined函数可以与decoder-only的预训练目标一致。

2)新的工作流:允许LLMs以人类的方式使用不同类型的组件(例如,失败的测试用例,错误消息,代码注释等)来定位和修复Buggy hunks可以进一步提高其APR性能。

3)实验和评估:在两个数据集上评估了本文提出的D4C以说明其有效性。

2 背景和动机

2.1 大模型体系结构和训练目标
背景

在这里插入图片描述

LLMs可以分为encoder-only,encoder-decoder和decoder-only三种。

  • Encoder-only LLMs

    • 代表:BERT以及他的变体(CodeBert)
    • 结构:具有双向Transformer编码器结构
    • 训练目标:通常在掩码语言建模目标(masked language modeling objective,MLM)上进行训练,旨在通过理解周围上下文来对掩码token进行去噪和重建
    • 损失函数:在已知所有未掩码token的情况下,生成掩码token的条件概率的对数和
      在这里插入图片描述
      其中M为掩码token的总数量
  • Decoder-only LLMs

    • 代表:GPT系列以及LLaMA系列

    • 结构:具有自回归transformer解码器结构

    • 训练目标:主要在因果语言建模目标(causal language modeling objective,CLM)上进行训练,旨在通过遵循前文来预测下一个token

    • 损失函数:在已知所有前面tokens的情况下,生成下一个token‘的条件概率的对数和
      在这里插入图片描述

      ​ 其中N为输入tokens的数量

  • Encoder-Decoder LLMs

    • 代表:T5及其变体(比如CodeT5)
    • 结构:拥有完整的transformer结构(使用编码器将输入文本嵌入到向量表示,使用解码器在输入提示后因果地生成新的token)
    • 训练目标(以T5为例):通常在去噪目标(denoising objective)上进行训练,旨在根据prompt中被掩码的位置,生成对应的原始片段spans(span是相邻的token序列)
    • 损失函数:在已知所有输入tokens的情况下,生成掩码token的条件概率的对数和
      在这里插入图片描述
      ​ 其中M是被掩码的token数量和
动机

encoder-only 和 encoder-decoder(尤其是T5)在训练过程中都包含损坏(corruption)和去噪(denoising)阶段——将输入文本中的一系列token替换为掩码token,并从掩码token中重构这些token。基于这种方式,Xia等人提出了infilling-style的APR,目标是用一个掩码token替换bug hunk,并提示模型进行直接推断,将固定的hunk从掩码中恢复过来。infilling-sytle的APR在不同模型中有不同的实现方式:在CodeBERT中从被掩码的hunks中恢复正确代码,而其他token保存不变;在CodeT5中,只输出从被掩码的hunks中恢复的正确代码。

decoder-only的LLMs在预训练过程不包含去噪过程,因此从被掩码的token中学习固定的hunk的生成变得有挑战性。这种目标不对齐会严重影响LLM在特定任务的性能,比如文本分类和知识问答。因此我们有以下见解:

将decoder-only的LLMs的输出从固定的Hunks修改为整个精化程序,可以更好地将推理目标与训练目标对齐,从而显著增强APR性能。

Modifying decoder-only LLMs’ output from fixed hunks to the entire refined program can better align the inference objective to the training objective, thus significantly enhancing APR performance.

2.2 APR技术和工作流
背景

在这里插入图片描述
如图2所示,ARP工作流程通常包括三个步骤:1)错误定位 2)补丁生成 3)补丁验证。其中APR的研究主要集中在补丁生成上面。

根据补丁的生成方式,分为基于启发的,基于约束的,基于模板的,基于学习的。

基于非学习的方法通常受限于有限的程序变换集合,导致大量无效补丁的生成。为了确定应用这些转换的位置,目前的策略是首先使用语句级错误定位工具生成可疑的bug hunks的评分列表,然后使用APR工具依次为每个提供的hunk生成补丁,最后使用给定的测试用例对生成的每个补丁进行验证。

基于NMT的APR工具通过在没有专门设计的补丁模板和搜索启发式的大型bug - fix并行训练语料上学习代码语义,优于传统方法,但NMT模型一般具有有限的参数规模,因此其训练成本和推理效率是可控的。因此,它们非常适合于传统的APR工作流。

动机

近年来,人们使用LLMs来进行APR。但是研究人员通常遵循当前的APR工作流程,将LLM当作一个新的补丁生成器,以取代以前的NMT模型。然而,在当前的工作流中,将LLM直接用于补丁生成步骤对其预训练知识的利用不足,因为这些模型表现出独立定位和修复缺陷程序bug的能力。

在这里插入图片描述

如图3所示,由于语句级的FL工具可能并不总是提供对buggy hunks的完美预测,限制LLM对提供的hunks进行修复可能会导致在错误位置验证补丁的时间浪费。此外,由于LLM的推理开销和时间成本远远高于传统的APR工具,使用LLM为所有给定的hunks生成补丁可能会造成巨大的资源浪费。因此,我们有以下见解:

使用含有缺陷程序和相应组件对LLMs提示,可以使其在没有语句级FL的情况下同时定位和修复缺陷程序,从而进一步提升APR性能。

Prompting LLMs with buggy programs and corresponding artifacts can enable them to locate and repair buggy hunks simultaneously without statementlevel FL, thus further improving APR performance.

3 D4C: DIRECT DEBUG DRIVES DECENT CODE

在这里插入图片描述

基于上述两点见解,我们提出了D4C框架。

当输入一个buggy程序,D4C使用相关的组件,包括文档,失败的测试信息来构造Bug报告。然后,D4C使用该报告来指导模型生成buggy程序的精化版本(refined version)。为了使LLM的推理目标与其预训练的完成目标保持一致,我们采用了一次性提示策略:在prompt中的目标buggy程序之前前缀一个固定的buggy程序及其精化版本,使得LLM能够推断它们的输入输出关系,并最终生成期望格式的目标程序的精化版本。D4C不需要任何额外的微调。它只改变输出格式以与预训练目标对齐。

3.1 问题定义

我们将APR问题建模为一个完成(completion)任务,该任务旨在基于buggy程序和相关组件生成一个精化程序。

D4C的优化目标:

在这里插入图片描述

现有的infilling-style APR的优化目标:

在这里插入图片描述

其中,t表示token,θ是LLMs的可训练参数。

3.2 模型选择

选择了最先进的LLMs——GPT4。然而,由于GPT4是一个黑盒模型,其CLM目标不可知,因此我们另外选了一个白盒模型——Mixtral-MoE来验证生成一个整体的精化函数是否能更好地对齐训练目标。

3.3 组件提取

提取

1)描述函数的通用目的及其输入输出数据类型的文档或注释

2)失败测试用例的输入和期望输出

3)执行这些失败测试用例的错误信息

如果某些函数没有函数级的注释,D4C可以替代使用相关的README文档。此外,如果某些组件在某些场景中不可用(例如,online judgment的测试用例是未知的),D4C将用占位符语句替换表中的工件,如"此程序不具有任何已知的测试用例"。

3.4 Prompt构建

在这里插入图片描述

role-play system instruction:You are an AI debugger …

a fixed example:手工编写的Bug报告和它的精化程序

我们的潜在目标是激发LLM的语境学习( ICL )能力,即类比提示语中的报告-修复对以进一步理解指令。这种一次性的ICL还允许我们将LLM的输出格式限制为一个精化的函数,而不是与APR (例如,单位diff补丁)相关的其他常见输出格式。此外,这种受限的输出格式有助于我们从LLM响应中自动提取校正后的函数进行自动化的补丁验证,如图5所示。由于我们的目标是使用D4C来显示我们的洞察力的有效性,而不是像RAG那样使用复杂的提示策略来开发强大的方法,因此我们只使用一个固定的例子来使LLMs遵循输出格式。

3.5 补丁生成

在LLM推理阶段对整个程序进行精化。此外,本文没有引入一个额外的补丁排序方法,这是因为D4C在解码时最多只需要生成10个补丁,明显少于现有方法的采样数(超过数百次的采样)。因此,D4C可以随后验证所有10个补丁,而不会在错误的补丁上花费大量的精力(5分钟内完成),而不是经历一个耗时的验证数百个补丁的过程(长达5小时)。

此外,虽然D4C可以通过比较补丁的自然度(naturalness)(用困惑度perplexity或熵entropy来量化) 对补丁进行排序,但是先前的研究表明,使用自然度来识别程序的正确性是不准确的。因此,我们不使用任何重排序策略来节省计算成本。

简单来说就是D4C 生成的候选补丁很少,可以直接全部验证,而不必进行复杂排序。并且已有研究表明使用自然性来判断程序正确性不准确。

根据以前基于LLM的方法级生成工作,我们假设能提供buggy function给D4C,D4C可以选择函数中的行进行修改。在真实世界的场景中,通过分析失败测试的执行结果,现有的方法级FL工具可以提供buggy function。

3.6 补丁验证

将D4C提取的精化程序替换原源代码中的buggy程序,然后,D4C运行相应的测试套件,找到编译成功的补丁并通过所有测试。

然而,由于基准程序存在潜在的测试覆盖不完全问题,APR方法往往会产生不完全满足开发人员预期功能而通过所有测试的补丁,从而不能真正修复缺陷。这些补丁被称为似真补丁(plausible patches)。

理想情况下,开发人员验证是有帮助的,但是Defects4J中的缺陷是历史固定(historically fixed)和过时的,使得开发人员的反馈不切实际。为了确保实验的严谨性,我们遵循现有的APR论文,通过在自动评估后为每个可能的补丁添加手动验证,以识别与人类书写的补丁相同或语义等价的正确补丁。

4 实验验证

RQ1)D4C与其他基于LLM的APR方法比较

RQ2)驱动D4C设计的两个见解的有效性

RQ3)不同的组件和参数如何影响D4C

4.1 实验设置

1)环境和实现:

关键词:调用OpenAI APIs,8xA100 NVIDIA GPU服务器,黑盒模型GPT - 4 - 0613,白盒模型mixtral - 8x7b - instruct - v0.1,python=3.9,Ubuntu 20.04.5 LTS,随机性超参数温度(temperature)设置为1.0(OpenAI默认值),每个补丁设置1分钟的超时阈值,采样数设置为10。

2)数据集:

1027个逻辑单功能错误bug(590个来自DebugBench,437个来自Defects4J)

DebugBench是针对数据泄露而设计的一个新的调试基准,它包含了来自LeetCode的Java,C + +和Python3的共计4253个错误。然而,由于在新基准上重现当前基线的复杂性,我们没有将其用于D4C和基线之间的比较;

Defects4J是一个广泛使用的APR基准测试程序,它包含了来自17个开源仓库的835个真实缺陷。在前期工作的基础上,我们将Defects4J的单功能缺陷分离为v1.2 (203个缺陷)和v2.0 (234个缺陷)。由于其包含了大部分代码模型已经训练过的开源项目的先前版本的数据,因此面临着数据泄露的威胁。

3)评价指标:

总的来说就是正确补丁的数量。

具体来说:

对于Defects4J数据集,如果生成的补丁通过了所有测试用例,那么就判断为似真补丁,再进一步通过人工来判断是不是正确补丁;

对于DebugBench数据集,只要生成的补丁能通过LeetCode的所有测试用例,就是正确补丁。同时,为了区别于人工检查的正确补丁,我们将能够通过LeetCode验证的补丁称为已验证补丁(verified patches)。

4)基线:

在RQ1中,选择了几种最先进的基于LLM的APR方法作为基准,包括AlphaRepair,FitRepair,ChatRepair,RAP-Gen和Repilot,所有这些基线都采用infilling目标;

在RQ2中,选择了不同的输入和输出格式进行比较,以显示对齐输出格式和在输入中提供组件的优越性。我们还选择了添加或删除不同信息(例如,function comments)的提示作为基线,以调查不同信息对APR的贡献。

4.2 RQ1: 与其他基于LLM的APR比较

结果见表2
在这里插入图片描述

表2分析:
设置:完美定位条件(即对于其他基线,都提供正确的bug hunks);

结果:D4C的性能超过现有的infilling-style方法,超过最新的ChatRepair约10%,且每个bug的采样数只有10,比最有效的基准采样次数减少了90%

ChatRepair模型的原理是使用GPT4在给定buggy hunks下进行多轮对话

为了说明其在真实世界场景中的有效性,我们进一步使用现有的统计FL工具进行了D4C和基线的实验,结果见表3。

在这里插入图片描述

表3分析:

设置:基线使用语句级的FL工具(比如Tarantula),D4C使用方法级的定位工具(比如:FLUCCS)

选择这两个方法以及只在Defects4J数据集比较的原因:1)只有这两个方法的论文中给出了非完美定位的数据结果;2)FLUCCS只支持Defects4J数据集

结果:与完美定位相比,D4C的修复数量只下降了4.8%,明显低于infilling-style的APR基线(至少下降30%)

4.3 RQ2:两个见解的有效性
  • 见解1验证

在白盒模型(Mixtral - MoE)上计算不同输出格式的平均困惑度,即CLM目标(方程2)的推理损失。测量困惑度是评估生成的内容是否与训练语料的分布一致的最直接的方法,因为LLMs的训练是为了最小化CLM目标。因此,较低的困惑度值表明模型在预测给定序列时更有信心。具体来说,我们采用了两种输出格式,包括使用固定hunk patch的填充式APR (记为Hunk)和使用整个函数输出的D4C ( Func )。图6给出了实例:

在这里插入图片描述

实验结果见表4。

在这里插入图片描述

表4分析:

设置:第一列是不同输入输出格式的组合,第二列是困惑度,第三列是白盒模型生成的已验证补丁的分布,第四列是黑盒模型生成的已验证补丁的分布

困惑度越低,代表模型越“熟悉”或越容易生成这种输出。

结果:

1)当模型输出的是完整函数(entire function)时,其困惑度(perplexity)显著低于输出为固定代码块(fixed hunks)的情况,而且这个结果不受输入形式的影响,说明了以完整函数作为输出,更符合大语言模型的训练目标。

2)输出完整函数不仅生成了更多的已验证补丁,而且这些补丁的困惑度也更低,比输出离散代码块(discrete hunks)更有效。

3)当仅生成固定代码块时,模型的输出困惑度远高于它在“完整输入+输出”条件下计算的困惑度

  • 见解2验证

从表4中可以看出:Report-Func的组合表现最好,超过了 Mask-Hunk这个常见的“infilling-style APR”方案,这一现象与前面在 Defects4J 数据集上的评估结果(RQ1)是一致的。但是在RQ1的实验中,D4C 的有效性既来自bug 报告的设计,也来自输出与语言模型训练目标的对齐(objective alignment),而在本次实验中即使输出格式相同,使用bug 报告作为输入仍然比使用掩盖错误代码的程序(Mask)表现更好, 这说明:bug 报告不仅有助于定位 bug 的位置,还能提供更多语义信息来帮助生成更高质量的补丁。 因此,这个现象验证了作者提出的第二个见解。

4.4 RQ3 消融实验和敏感性分析

w/o Document:Prompt中不包括程序文档或方法注释

w/o Test:Prompt中不包含失败测试用例的输入和期望输出;

w/o Message:Prompt中不包含失败测试的错误信息;

- Mask:D4C使用masks来识别缺陷,不包含任何组件(Mask-Func)

- Pure:D4C不包含任何指导,既没有mask,也没用组件

实验结果如表5所示。

在这里插入图片描述

5 讨论

5.1 有效性威胁

外部威胁:数据泄露问题,无法推广到这两个数据集中以外的编程语言

内部威胁:Defects4J的测试覆盖不完全问题

5.2 似真补丁的定性分析

表5显示D4C共生成了210个似真补丁,但是有30个是不正确的,图7给出了一个错误补丁的例子。

在这里插入图片描述

由于失败测试中包含”src“标签作为输入,因此LLM会自然地生成只通过包含”src“测试的补丁,而没有考虑鲁棒性。(本质是过拟合)

图8给出了一个不受bug hunks约束情况下生成的正确修复的例子。

在这里插入图片描述

开发人员的补丁是修改了两个if条件,然而,D4C只需要插入一条语句,就产生了和开发者补丁语义等价的正确补丁。如果要GPT4在这两个hunks处生成补丁,GPT-4只能写出两个Exception语句,反而无法通过测试用例。

5.3 Token成本和补丁生成价格

对于Defects4J:

token数量:

  • 输入prompt:1386.84tokens(已成功修复:1325.68;未成功修复:369.72)
  • 输出:314.39tokens(已成功修复:285.98;未成功修复:325.80)

考虑到OpenAI的定价:

  • 输入 token:$0.01 / 1,000 tokens
  • 输出 token:$0.03 / 1,000 tokens

因此,平均每个补丁的生成成本:$0.023(已成功修复:$0.021;未成功修复:$0.024)

每个bug生成10个补丁,所以总成本为**$0.23 / 每个 bug**。

又D4C 能在Defects4J上修复 180 个 bug,而且平均来说,正确补丁排在第 4.29 个(std = 1.74),如果我们在发现正确 patch 后就提前停止生成,则:

  • 平均每个 bug 只需要生成 4.29 个 patch
  • 每个bug的平均成本将降低到** $0.18 / 每个 bug **
5.4 补丁验证中的额外代价

因为很多项目的测试用例并不完备,所以不能只依赖测试结果,还需要人工审查。

D4C :

  • 每个 bug 平均会生成 5.80 个 test-passing 的 patch;
  • 其中平均每 2.06 个(即前两个左右)就有一个是真正的正确 patch。

传统的 infilling-style APR 方法:

  • 带有 patch 排序机制时,需要验证 400 多个似真补丁才能找到正确的;
  • 没有排序时甚至要验证 600 多个

所以D4C大幅降低人工验证的工作量,更“人性化”。

就算是最差情况(最多生成 10 个 patch),用户最多也只需要审查 10 个补丁,这也远比之前的方法少得多。

处理人工验证,还有一个隐形成本:自动化运行测试用例所花的时间

D4C:

  • 每个 patch 最多测试 1 分钟

  • 每个 bug 最多跑 10 分钟的测试

其他方法:

  • 测试一个 bug 有时需要长达 5 小时的搜索和验证

6 结论

本文提出了一种新的方法来使LLM适应自动程序修复。我们的关键见解是,基于LLM的APR的有效性可以通过

1)使输出与他们的训练目标保持一致;

2)允许他们在没有给定buggy hunks的情况下优化整个程序来提高;

基于这一认识,我们设计了基于LLM的APR提示框架D4C。我们的评估表明,在已知准确 bug 位置的前提下,D4C比SOTA APR方法修复能力高出10%。我们的研究结果呼吁为未来基于LLM的APR方法采用新的范式和调试工作流程。

启发

1)本文提到的训练目标对齐,这一观点同样适用于学生程序的修复,在设计prompt的时候可以参考本文图6中的Report-Func范式;

2)在本文中通过利用不同的组件,能够让LLM自己去理解程序,从而减少了错误定位环节,这种方式同样可以迁移到学生程序中来——直接利用LLM进行程序修复,跳过错误定位。并且对于学生程序来说,程序的背景(编程题目),失败的测试用例都是较为轻易获取的,也不存在缺失情况;

3)利用LLM进行学生程序修复具有很大的潜力。本文采用的DebugBench数据集来自Leetcode,比较符合学生程序的特点,而在本文的实验中,DebugBench的590个bug有521个能够正确修复(成功率达到88%)。而对于编程初学者的错误代码,代码的复杂度还要低一点(基本上不涉及到算法,更多的是对相关语法的掌握程度),因此直接采用本文的方式应该能达到与DebugBench数据集上同等甚至以上的效果。

BibTeX

@misc{xu2025aligningobjectivellmbasedprogram,
title={Aligning the Objective of LLM-based Program Repair},
author={Junjielong Xu and Ying Fu and Shin Hwei Tan and Pinjia He},
year={2025},
eprint={2404.08877},
archivePrefix={arXiv},
primaryClass={cs.SE},
url={https://arxiv.org/abs/2404.08877},
}

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐