开源机器人 AI 框架 LeRobot 入门与实践

在这里插入图片描述

主题:从经典到前沿:具身智能 VLA 入门和实践分享
预约连接:https://m.bilibili.com/opus/1156503743617826868?bsource=dynamic_reserve

分享大纲(总时长:30-45 分钟)

模块 1:机器人抓取经典方法简单疏通
核心内容:梳理机器人抓取经典技术栈 —— 规划控制、视觉方法、模仿学习、强化学习、端到端,通俗讲解核心逻辑,快速建立技术认知

模块 2:具身智能 VLA 解析
核心内容:ppt讲解 ,概念介绍 + 技术路线简析 + 前沿综述汇总 + 前景与挑战分析,兼顾理论基础与行业视角

模块 3:开源机器人 AI 框架 LeRobot 入门与实践
核心内容: LeRobot 介绍使用,SO101 硬件实物介绍 ,仿真实战教学

0 LeRobot框架介绍

相关解读:LeRobot框架设计与架构深度剖析:从入门到精通

相关解读: 解构LeRobot:机器人领域的"Transformers" - 知乎

官方教程 LeRobot

LeRobot 是一个由 Hugging Face 团队主导开发的、基于 PyTorch 的开源机器人学习框架。集成了数据集管理、策略训练、仿真环境交互、以及物理机器人控制等多个关键模块的综合性平台。聚焦「真实世界机器人」的 AI 能力落地。主打模仿学习和强化学习

  • 支持端到端的机器人学习:从数据收集、处理、模型训练、仿真评估到真实机器人部署,LeRobot 提供了全链路的支持。
  • 与Hugging Face生态系统的深度集成:可以方便地从Hugging Face Hub加载预训练模型和标准数据集,加速研究进程。
  • 强大的数据集管理系统:LeRobotDataset 类支持复杂的多模态数据(如视频、图像、状态、动作序列),并提供高效的数据加载和预处理机制。
  • 灵活的环境接口:支持多种流行的机器人仿真环境(如Aloha, PushT, XArm),并易于扩展到新的环境。
  • 模块化与可扩展设计:统一的机器人接口、数据集格式,快速扩展新硬件 / 数据集。
  • 完善的文档与社区支持:提供详细的文档和教程,并依托Hugging Face社区,为用户提供交流和支持的平台。

在这里插入图片描述

支持的环境: LeRobot通过Gymnasium接口支持多个模拟环境:

环境 描述 特点
Aloha 双手机器人操作任务 专注于双手协调操作,如倒咖啡、开瓶盖等
PushT 物体推动操作任务 专注于推动物体到目标位置的任务
XArm XArm机器人操作任务 基于现实世界XArm机器人的模拟环境

支持的硬件: SO101、LeKiwi、Koch、HopeJR、OMX、EarthRover、Reachy2、游戏手柄、键盘、手机、OpenARM、Unitree G1。

支持的策略:

类别 模型
模仿学习 ACTpolicy_diffusionVQ-BeT
强化学习 HIL-SERLTDMPC 和 QC-FQL(即将推出)
VLA模型 Pi0,Pi0.5,GR00T N1.5,SmolVLA,XVLA

1 SO-ARM100/101 介绍 与 在LeRobot中使用

低成本开源机械臂, SO-ARM100/101 作为 LeRobot 生态的核心硬件,通过 “领导臂手动操作 + 从动臂执行任务” 的模式,可快速实现数据采集、模型训练与自主抓取等功能。

易懂的介绍视频 : 为什么毫无精度却爆火?千元级开源AI机械臂原理解析。_哔哩哔哩_bilibili

在这里插入图片描述

每条臂有 6 个自由度 (DOF): 由于每个关节都是独立驱动的,因此每只手臂都可以执行高级动作和复杂操作。可以在官方文档和 GitHub 存储库中找到 详细的组装说明、3D 打印文件、完整的组件列表和校准教程

!!!下面的教程需要 实物,没有实物可以过一眼了解一下框架和流程,流程经过简化了,想要尝试仿真可以跳过

1.1安装

conda create -n lerobot python=3.10.18 ffmpeg=7.1.1 -c conda-forge

然后,将库安装为可编辑模式

git clone https://github.com/huggingface/lerobot.git
cd lerobot
pip install -e .

SO100/SO101/Moss 安装 Feetech SDK,LeRobot采用模块化设计,许多特定功能(如对特定仿真环境或硬件的支持)的依赖是可选的,可以根据需要安装。这有助于保持核心库的轻量化

pip install -e ".[feetech]" 

1.2 校准

lerobot-calibrate --robot.type=so101_follower --robot.port=COM24 --robot.id=my_awesome_follower_arm
lerobot-calibrate --teleop.type=so101_leader --teleop.port=COM22 --teleop.id=my_awesome_leader_arm

需要将机器人所有关节都移动到机械臂关节中间位置,然后一个个活动到他们最大的范围

在这里插入图片描述

1.3 带相机的遥操作

输入指令,查找摄像头ID

lerobot-find-cameras opencv
lerobot-record --robot.type=so101_follower --robot.port=COM24 --robot.id=my_awesome_follower_arm --robot.cameras="{ fixed: {type: opencv,index_or_path: 0, width: 640, height: 480, fps: 30, rotation: 180}, handeye: {type: opencv,index_or_path: 1, width: 640, height: 480, fps: 30}}" --teleop.type=so101_leader --teleop.port=COM22 --teleop.id=my_awesome_leader_arm --display_data=true --dataset.repo_id=my/demo --dataset.num_episodes=20 --dataset.single_task="Move the pink object to the yellow area." --dataset.push_to_hub=False   --dataset.num_episodes=5 

–dataset.root= 可以设定指令路径,如果没有设定就是根据dataset.repo_id 存放在 用户名.cache\huggingface\lerobot\dataset.repo_id

使用键盘快捷键控制数据记录流:

  • 按**右箭头():**提前停止当前剧集或重置时间并进入下一集。
  • 按**左箭头():**取消当前节目并重新录制。
  • 按下**Esc(ESC):**立即停止会话,编码视频并上传数据集。

在这里插入图片描述

上传到平台的数据 可以在线可视化

Visualize Dataset (v2.0+ latest dataset format) - a Hugging Face Space by lerobot

输入自己的数据集id 比如Syanyizhe/Move2

在这里插入图片描述

1.4 训练

lerobot-train --dataset.repo_id=Syanyizhe/Move2 --policy.type=act  --job_name=act_so101_test --policy.device=cuda --wandb.enable=false --output_dir=outputs/train/act  --policy.push_to_hub=False --steps 5000

也可以在服务器上训练,得到的模型可以上传到huggingface

在这里插入图片描述

训练策略核心只需运行脚本配置:

lerobot-train \
  --policy=策略 \
  --dataset.repo_id=数据集id
类别 模型
模仿学习 ACTpolicy_diffusionVQ-BeT
强化学习 HIL-SERLTDMPC 和 QC-FQL(即将推出)
VLA模型 Pi0.5,GR00T N1.5,SmolVLA,XVLA

1.5推理

评估推理

就和前面遥操作记录数据一样 使用lerobot-record ,但是增加了模型参数,这样就用于不是记录每个回合模型的运行的效果,把结果保存数据集 Syanyizhe/eval_act,然后可以用于下一步的处理,也可以用于在线分析,细看

lerobot-record --robot.type=so101_follower --robot.port=COM24 --robot.id=my_awesome_follower_arm  --robot.cameras="{ wrist: {type: opencv,index_or_path: 1, width: 640, height: 480, fps: 30, rotation: 180}, top: {type: opencv,index_or_path: 2, width: 640, height: 480, fps: 30}, right: {type: opencv,index_or_path: 3, width: 640, height: 480, fps: 30}}"  --dataset.single_task="Move the blue cube to the orange rectangle" --dataset.repo_id=Syanyizhe/eval_act  --dataset.episode_time_s=50  --dataset.num_episodes=10  --policy.path=outputs/train/act/checkpoints/002000/pretrained_model  --display_data=true --dataset.push_to_hub=False
异步推理

你在本地垃圾电脑连着机械臂,但是可以用服务器的算力

安装运行异步推理所需的额外依赖

pip install -e ".[async]"

然后,启动一个策略服务器(在一个终端或另一台机器上),指定客户端连接的主机地址和端口。

python -m lerobot.async_inference.policy

这会启动一个策略服务器监听(端口8080)。此时,策略服务器是空的,因为所有关于运行哪个策略和参数的信息都在与客户端的第一次握手时指定。启动一个客户:127.0.0.1:8080``localhost

在这里插入图片描述

python -m lerobot.async_inference.robot_client --robot.type=so101_follower --robot.port=COM24 --robot.id=my_awesome_follower_arm --robot.cameras="{ fixed: {type: opencv,index_or_path: 0, width: 640, height: 480, fps: 30, rotation: 180}, handeye: {type: opencv,index_or_path: 1, width: 640, height: 480, fps: 30}}" --server_address=120.79.120.177:8080 --policy_type=act --pretrained_name_or_path=outputs/train/act_so101_test/checkpoints/last/pretrained_model --policy_device=cpu --actions_per_chunk=50 --chunk_size_threshold=0.1 --aggregate_fn_name=weighted_average --task="Move the pink object to the yellow area." --debug_visualize_queue_size=True

2 前置准备与配置环境

如果你之前部署过相关的深度学习环境,可以快速跳过前置准备,进入配置环境

查看显卡型号、驱动版本、CUDA 驱动支持上限(关键!) ,如果版本太低就更新一下显卡驱动

nvidia-smi

在这里插入图片描述

显示已安装的CUDA Toolkit,如果没有那就去安装

nvcc -V 

在这里插入图片描述

甚至可以从已安装的应用中搜,版本太低了可以安装新版 CUDA Toolkit

CUDA Downloads | NVIDIA Developer
在这里插入图片描述

一般来说, nvidia-smi 显示版本 ≥ nvcc -V 版本 ≥ PyTorch 绑定版本,实际有时候nvcc -V 版本 < PyTorch 绑定版本 也可以运行

版本类型 命令 / 代码 本质含义
驱动支持的 CUDA 版本 nvidia-smi 驱动能兼容的最高 CUDA 版本
已安装的 CUDA Toolkit 版本 nvcc -V 实际可用的 CUDA 编译器 / 库版本
PyTorch 绑定的 CUDA 版本 import torch print(torch.version.cuda) PyTorch 编译时依赖的 CUDA 版本

创建虚拟环境

conda create -n leisaac_envhub python=3.11
conda activate leisaac_envhub

安装torch 低于自己的cuda版本即可

pip install -U torch==2.7.0 torchvision==0.22.0 --index-url https://download.pytorch.org/whl/cu128

安装 LeIsaac(含 IsaacLab 依赖)(时间比较久,需要魔法)(如果你只用实物可以跳过)

pip install "leisaac[isaaclab] @ git+https://github.com/LightwheelAI/leisaac.git#subdirectory=source/leisaac" --extra-index-url https://pypi.nvidia.com

安装 LeRobot

pip install lerobot
pip install numpy==1.26.0

3 LeIsaac 操控SO101 (尝鲜)

考虑到大家手头没有机械臂,这里可以先用仿真尝鲜。

github地址:https://github.com/LightwheelAI/leisaac

官方文档:Introduction | LeIsaac Document

LeIsaac 是一个与机器人学习和仿真相关的框架,主要用于远程操作和数据收集。它结合了 Isaac SimSO101机械臂,允许用户在仿真环境中进行任务的远程操作和训练。LeIsaac 通过 NVIDIA Isaac Lab 进行数据收集,并支持多种机器人学习任务,如摘橙子和搬立方体等

任务类型 环境 ID(部分) 任务描述 关联机器人
拣橙子 LeIsaac-SO101-PickOrange-v0(含 Direct 版) 拾取 3 个橙子放入盘子,机械臂复位 单臂 SO101 Follower
举方块 LeIsaac-SO101-LiftCube-v0(含 Direct 版) 举起红色方块 单臂 SO101 Follower
清理桌面 LeIsaac-SO101-CleanToyTable-v0(含双臂版) 拾取 2 个字母「e」形状物体放入盒子,机械臂复位 单臂 / 双臂 SO101 Follower
叠布 LeIsaac-SO101-FoldCloth-BiArm-v0(含 Direct 版) 折叠布料,机械臂复位(仅 Direct 版支持成功检测) 双臂 SO101 Follower

在这里插入图片描述

3.1 下载代码和模型

这里先不用 lerobot中集成的leisaac,先使用原生的leisaac,后面会讲原因

git clone https://github.com/LightwheelAI/leisaac.git

下载so101_follower.usd 和厨房与橙子场景 Release leisaac-example-scene · LightwheelAI/leisaac · GitHub

解压放到assets 中的robots 和scenes 文件夹下
在这里插入图片描述

<assets>
├── robots/
│   └── so101_follower.usd
└── scenes/
    └── kitchen_with_orange/
        ├── scene.usd
        ├── assets
        └── objects/
            ├── Orange001
            ├── Orange002
            ├── Orange003
            └── Plate

也可以自己选择其他场景

场景名称 描述 下载链接
厨房与橙子 带有橙子的厨房场景示例 下载
光轮玩具房 现代房间,里面有许多玩具 下载
带立方体的表格 一个立方体的简单表格 下载
光轮卧室 用布料的写实卧室场景 下载
光轮阁楼 大型两层阁楼 下载

3.2 键盘遥操作(仅体验)

python scripts/environments/teleoperation/teleop_se3_agent.py --task=LeIsaac-SO101-PickOrange-v0 --teleop_device=keyboard --num_envs=1 --device=cuda --enable_cameras 
目标帧 平移控制 旋转控制
在这里插入图片描述 在这里插入图片描述 在这里插入图片描述
输入键 描述
W / S 正反方向,与平移图中的红色箭头对齐
A / D 左右方向,与平移图中的绿色箭头对齐
Q / E 上下,与平移图中的蓝色箭头对齐
J / L 左右旋转(偏航),与旋转图中的蓝色箭头对齐
K / I 向上/向下旋转(音高),与旋转图中的绿色箭头对齐
U / O 夹子开合

在这里插入图片描述

进入 IsaacLab 窗口后,按下键盘上的 b 键以开始远程操作。随后,您可以通过指定的远程操作设备(teleop_device)在仿真环境中控制机器人。完成操作后,若需重置环境,只需按下 r 键或 n 键。其中,r 键表示重置环境并将任务标记为失败,而 n 键表示重置环境并将任务标记为成功。

如要要收集数据,详细的参数需要阅读teleop_se3_agent.py 代码

  • --record:启用数据记录;将远程作数据保存到HDF5文件中。
  • --dataset_file:保存已记录数据集的路径,例如。./datasets/record_data.hdf5
  • --resume: 启用从现有数据集文件记录简历数据。

以下脚本在仿真环境中回放已收集的数据集:

python scripts/environments/teleoperation/replay.py \
    --task=LeIsaac-SO101-PickOrange-v0 \
    --num_envs=1 \
    --device=cpu \
    --enable_cameras \
    --dataset_file=./datasets/dataset.hdf5 \
    --episode_index=0

其实用键盘还是很不方便的,收集的数据也不连贯,这里仅仅体验一下就可,最佳还是用物理主臂。收集的远程作数据以HDF5格将HDF5数据转换为LeRobot数据集格式python scripts/convert/isaaclab2lerobot.py ,可以用LeRobot框架训练。

3.3 训练 (pass)

可参考: Isaac GR00T N1.5 适用于 LeRobot SO-101 机械臂

可参考:通过 LeIsaac 仿真 SoArm101 | Seeed Studio Wiki

3.4 推理 (了解即可)

GR00T采用客户端-服务器架构进行推理

配置Isaac-GR00T 环境(很麻烦)

cd ..
git clone https://github.com/NVIDIA/Isaac-GR00T
cd Isaac-GR00T
conda create *-n* gr00t *python*=3.10
conda activate gr00t
pip install *--upgrade* setuptools
pip install *-e* .[base]
pip install --no-build-isolation flash-attn==2.7.1.post4

下载微调好的模型 LightwheelAI/leisaac-pick-orange-v0 at main(很大)

服务器

conda activate gr00t的环境
cd <Isaac-GR00T的路径>
python scripts/inference_service.py --server --model_path  ./so101-orange-checkpoints/checkpoint-10000 --embodiment_tag new_embodiment --data_config so100_dualcam --port 5555

客户端

打开一个新的终端窗口并运行:

conda activate leisaac的环境
cd <leisaac的路径>
python scripts/evaluation/policy_inference.py \
    --task=LeIsaac-SO101-PickOrange-v0 \
    --policy_type=gr00tn1.5 \
    --policy_host=localhost \
    --policy_port=5555 \
    --policy_timeout_ms=5000 \
    --policy_action_horizon=16 \
    --policy_language_instruction="Pick up the orange and place it on the plate" \
    --device=cuda \
    --enable_cameras

LeIsaac 主要用于远程操作和数据收集,对于训练推理集成程度是不够的。

4 使用LeIsaac × LeRobot EnvHub (简单了解)

2025年11月25日 LeIsaac 集成于 LeRobot 的 EnvHub,LeIsaac × LeRobot EnvHub 是一套机器人仿真训练闭环工具,支持从「任务搭建→遥操作数据收集→模型训练→成果共享」的全流程,核心优势:

  1. 遥操作优先:支持 SO101 Leader/Follower 设备,快速收集演示数据;
  2. 无缝适配 LeRobot:内置数据转换功能,收集的演示数据可直接用于 LeRobot 训练;
  3. 持续升级:支持云仿真、Sim2Real(仿真到现实)工具链等。

EnvHub 功能允许你用一行代码直接从 Hugging Face Hub 加载模拟环境

from lerobot.envs.factory import make_env

# Load a hub environment (requires explicit consent to run remote code)
env = make_env("lerobot/cartpole-env", trust_remote_code=True)

4.1 验证环境

创建 envhub_random_action.py,加载「拣橙子」环境,机械臂执行随机动作:

import torch
from lerobot.envs.factory import make_env

# 从 EnvHub 加载环境
envs_dict = make_env("LightwheelAI/leisaac_env:envs/so101_lift_cube.py", n_envs=1, trust_remote_code=True)

# 访问环境实例
suite_name = next(iter(envs_dict))
sync_vector_env = envs_dict[suite_name][0]
env = sync_vector_env.envs[0].unwrapped

# 仿真循环(类似 Gym 接口)
obs, info = env.reset()
while True:
    action = torch.tensor(env.action_space.sample())  # 随机动作
    obs, reward, terminated, truncated, info = env.step(action)
    if terminated or truncated:
        obs, info = env.reset()

env.close()

他会从huggingface_hub 下载,有魔法最好,没有就用镜像吧, 临时配置(仅当前 CMD 窗口生效,推荐)

先激活你的 Conda 环境

conda activate leisaac_envhub 

设置 HF_ENDPOINT 镜像源

set HF_ENDPOINT=https://hf-mirror.com

验证是否设置成功(CMD 用 %变量名% 读取)

echo %HF_ENDPOINT%

在cmd 中执行脚本

python envhub_random_action.py

需要等他下载完场景,按提示输入y ,载等待加载就可以看到乱摆动的机械臂了
在这里插入图片描述

4.2 遥操作(物理设备控制仿真机械臂)

注意!!!! 需连接 SO101 Leader 主臂,keybord遥操作lerobot官方没有适配需要自己设置。所以说如果没有实物还是用原生的leisaac。有实物的话,我建议直接用lerobot,自己布置实物场景

第一步:校准控制器

lerobot-calibrate \
    --teleop.type=so101_leader \
    --teleop.port=/dev/ttyACM0  # 端口根据系统调整(Windows 可能为 COMx)
    --teleop.id=leader

第二步:运行遥操作脚本(envhub_teleop_example.py

import logging
import time
import gymnasium as gym

from dataclasses import asdict, dataclass
from pprint import pformat

from lerobot.teleoperators import (  
    Teleoperator,
    TeleoperatorConfig,
    make_teleoperator_from_config,
    so_leader,
)
from lerobot.utils.robot_utils import precise_sleep
from lerobot.utils.utils import init_logging
from lerobot.envs.factory import make_env


class TeleoperateConfig:
    teleop: TeleoperatorConfig
    env_name: str = "so101_lift_cube"
    fps: int = 60

class EnvWrap:
    env: gym.Env

def make_env_from_leisaac(env_name: str = "so101_lift_cube"):
    envs_dict = make_env(
        f'LightwheelAI/leisaac_env:envs/{env_name}.py',
        n_envs=1,
        trust_remote_code=True
    )
    suite_name = next(iter(envs_dict))
    sync_vector_env = envs_dict[suite_name][0]
    env = sync_vector_env.envs[0].unwrapped

    return env


def teleop_loop(teleop: Teleoperator, env: gym.Env, fps: int):
    from leisaac.devices.action_process import preprocess_device_action
    from leisaac.assets.robots.lerobot import SO101_FOLLOWER_MOTOR_LIMITS
    from leisaac.utils.env_utils import dynamic_reset_gripper_effort_limit_sim

    env_wrap = EnvWrap(env=env)

    obs, info = env.reset()
    while True:
        loop_start = time.perf_counter()
        if env.cfg.dynamic_reset_gripper_effort_limit:
            dynamic_reset_gripper_effort_limit_sim(env, 'so101leader')

        raw_action = teleop.get_action()
        processed_action = preprocess_device_action(
            dict(
                so101_leader=True,
                joint_state={
                    k.removesuffix(".pos"): v for k, v in raw_action.items()},
                motor_limits=SO101_FOLLOWER_MOTOR_LIMITS),
            env_wrap
        )
        obs, reward, terminated, truncated, info = env.step(processed_action)
        if terminated or truncated:
            obs, info = env.reset()

        dt_s = time.perf_counter() - loop_start
        precise_sleep(max(1 / fps - dt_s, 0.0))
        loop_s = time.perf_counter() - loop_start
        print(f"\ntime: {loop_s * 1e3:.2f}ms ({1 / loop_s:.0f} Hz)")


def teleoperate(cfg: TeleoperateConfig):
    init_logging()
    logging.info(pformat(asdict(cfg)))

    teleop = make_teleoperator_from_config(cfg.teleop)
    env = make_env_from_leisaac(cfg.env_name)

    teleop.connect()
    if hasattr(env, 'initialize'):
        env.initialize()
    try:
        teleop_loop(teleop=teleop, env=env, fps=cfg.fps)
    except KeyboardInterrupt:
        pass
    finally:
        teleop.disconnect()
        env.close()


def main():
    teleoperate(TeleoperateConfig(
        teleop=so_leader.SO101LeaderConfig(
            port="/dev/ttyACM0",
            id='leader',
            use_degrees=False,
        ),
        env_name="so101_pick_orange",
        fps=60,
    ))

if __name__ == "__main__":
    main()

脚本核心逻辑:通过物理控制器获取动作,预处理后驱动仿真机械臂,支持 60 FPS 实时交互,可操作「拣橙子」等任务,中断时自动断开设备连接并关闭环境。

通过修改 make_env 的参数切换不同任务,示例:

# 拣橙子
envs_dict_pick_orange = make_env("LightwheelAI/leisaac_env:envs/so101_pick_orange.py", n_envs=1, trust_remote_code=True)
# 举方块
envs_dict_lift_cube = make_env("LightwheelAI/leisaac_env:envs/so101_lift_cube.py", n_envs=1, trust_remote_code=True)
# 清理桌面
envs_dict_clean_toytable = make_env("LightwheelAI/leisaac_env:envs/so101_clean_toytable.py", n_envs=1, trust_remote_code=True)
# 叠布(双臂)
envs_dict_fold_cloth = make_env("LightwheelAI/leisaac_env:envs/bi_so101_fold_cloth.py", n_envs=1, trust_remote_co

其他数据收集,训练,需要自己探索,官方没有给出

实时交互,可操作「拣橙子」等任务,中断时自动断开设备连接并关闭环境。

通过修改 make_env 的参数切换不同任务,示例:

# 拣橙子
envs_dict_pick_orange = make_env("LightwheelAI/leisaac_env:envs/so101_pick_orange.py", n_envs=1, trust_remote_code=True)
# 举方块
envs_dict_lift_cube = make_env("LightwheelAI/leisaac_env:envs/so101_lift_cube.py", n_envs=1, trust_remote_code=True)
# 清理桌面
envs_dict_clean_toytable = make_env("LightwheelAI/leisaac_env:envs/so101_clean_toytable.py", n_envs=1, trust_remote_code=True)
# 叠布(双臂)
envs_dict_fold_cloth = make_env("LightwheelAI/leisaac_env:envs/bi_so101_fold_cloth.py", n_envs=1, trust_remote_co

其他数据收集,训练,需要自己探索,官方没有给出

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐