Ruff 深度拆解:当 Python 决定「用 Rust 重建整个工具链」——从 Flake8 到 Black 到 mypy,一个 Astral 生态如何用 100 倍速度重新定义代码质量的终极形态
引言:Python 开发者的「工具链噩梦」
如果你是一个 Python 开发者,你一定经历过这样的场景:
刚写完一个函数,按下保存,IDE 里弹出三个不同颜色的波浪线——红色的是 mypy 报的类型错误,黄色的是 Flake8 报的风格问题,蓝色的是 isort 报的 import 排序问题。你打开终端,依次运行:
isort .
black .
flake8 .
mypy .
四个工具,四个配置文件(.flake8、pyproject.toml 里的 [tool.black]、[tool.isort]、mypy.ini),四套互不兼容的规则体系。项目一大,跑一次完整检查要等几十秒甚至几分钟。CI 流水线里,代码质量检查往往是耗时最长的环节。
这不是个别现象,这是 Python 生态二十多年来的「历史包袱」。Flake8 诞生于 2010 年,Black 发布于 2018 年,isort 更早——它们都是各自时代的最佳实践,但从未被设计成一个统一的系统。
2022 年,一家名叫 Astral 的公司决定终结这一切。他们用 Rust 重写了 Python 的整个开发工具链,创造了三个颠覆性的工具:
- uv:Python 包管理器,替代 pip/pip-tools/venv
- Ruff:Python 代码检查器和格式化器,替代 Flake8 + Black + isort + 100 多个插件
- ty:Python 类型检查器,替代 mypy/pyright
这三个工具全部用 Rust 编写,性能提升 10-100 倍,配置统一到一个 pyproject.toml 文件里。截至 2026 年 8 月,Ruff 在 GitHub 上已获得超过 47,000 Star,uv 超过 55,000 Star,成为 Python 生态增长最快的项目。
本文将深入拆解 Astral 工具链的架构设计、核心实现和迁移路径,告诉你为什么「用 Rust 重建 Python 工具链」不是一个噱头,而是一场正在发生的范式革命。
第一章:Python 工具链的历史债务
1.1 碎片化的工具生态
Python 的代码质量工具生态可以用「百花齐放」来形容,但这个词在这里是贬义的。
代码检查(Linting):Flake8 是事实标准,但它本身只是一个薄壳——真正的检查能力来自 100 多个插件(flake8-bugbear、flake8-comprehensions、flake8-simplify……)。每个插件有自己的版本节奏,规则之间偶尔还会冲突。
代码格式化:Black 在 2018 年横空出世,用「无妥协」的哲学统一了 Python 格式化。但在 Black 之前,YAPF、autopep8、blue 等工具已经存在了很久。至今仍有人坚持用 YAPF。
Import 排序:isort 是标准选择,但它和 Black 之间曾有过著名的「格式冲突」——isort 默认的多行模式和 Black 的格式化结果不兼容,社区花了好几年才通过 isort --profile black 解决这个问题。
类型检查:mypy 是 Python 官方推荐的类型检查器,但 pyright(微软出品)在性能和准确性上经常超越 mypy。两者对 PEP 484 的实现程度不同,对第三方库的类型 stub 支持也不同。
复杂度分析:radon、xenon 等工具独立于上述体系之外。
每个工具都有自己的配置文件格式、自己的命令行接口、自己的插件系统。一个中等规模的 Python 项目,光是配置这些工具就要花半天时间。更糟糕的是,当团队成员的本地环境和 CI 环境的工具版本不一致时,「本地通过但 CI 失败」的幽灵 bug 就会出现。
1.2 性能瓶颈
Python 工具链的另一个致命问题是性能。
Flake8 用 Python 写成。在一个拥有 50 万行代码的大型项目上,运行一次完整的 Flake8 检查可能需要 30 秒到 2 分钟。Black 的格式化速度稍快,但在大型文件上也需要几秒。
这意味着什么?当你在 IDE 里保存文件时,你不可能「即时」看到所有检查结果。你必须等待。在 CI 流水线里,代码质量检查往往是串行执行的最耗时环节:
# 典型的 CI 配置
- run: isort --check-only .
- run: black --check .
- run: flake8 .
- run: mypy .
四个工具串行执行,每个都要重新扫描整个代码库。总耗时可能是 3-5 分钟。
1.3 Astral 的野心
Astral 公司由 Charlie Marsh(Ruff 的创始人)于 2022 年创立。他们的核心洞察是:Python 的工具链问题不是功能问题,而是性能问题和集成问题。
如果一个工具能比现有工具快 100 倍,并且能在一个配置文件里统一所有规则,那么「工具碎片化」的问题就从根本上解决了。
Astral 选择 Rust 作为实现语言,原因很直接:Rust 提供了接近 C 的性能,同时有优秀的内存安全保证和现代的包管理生态。用 Rust 写的工具可以编译成单个二进制文件,无需 Python 运行时,安装和分发都极其简单。
第二章:Ruff 架构深度解析
2.1 核心架构
Ruff 的架构可以用一句话概括:一个 Rust 实现的 Python AST 解析器 + 一个可扩展的规则引擎 + 一个确定性格式化器。
┌─────────────────────────────────────────────┐
│ Ruff CLI │
├─────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────────────┐ │
│ │ Python AST │ │ Rule Engine │ │
│ │ Parser │──│ (800+ rules) │ │
│ │ (Rust) │ │ + Fix Generator │ │
│ └──────────────┘ └──────────────────────┘ │
│ │ │ │
│ ┌──────────────┐ ┌──────────────────────┐ │
│ │ Formatter │ │ Import Sorter │ │
│ │ (Black- │ │ (isort- │ │
│ │ compatible) │ │ compatible) │ │
│ └──────────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────┘
Python AST 解析器:Ruff 内置了一个用 Rust 编写的 Python 语法解析器,可以直接将 Python 源代码解析为抽象语法树(AST),无需调用 Python 解释器。这是性能提升的关键——传统的 Python lint 工具需要启动 Python 进程,通过 ast 模块解析代码,这个过程本身就有很大的开销。
规则引擎:Ruff 实现了 800 多条检查规则,覆盖了 Flake8 的绝大多数插件功能。每条规则都是一个独立的 Rust 模块,通过 trait 系统注册到规则引擎中。规则引擎遍历 AST,对每个节点应用所有匹配的规则,生成诊断信息。
格式化器:Ruff 的格式化器旨在产出与 Black 完全一致的结果。它不是「类似 Black」,而是「Black 兼容」——你可以用 Ruff 格式化现有 Black 项目,diff 结果应该是空的。
Import 排序器:Ruff 内置了 isort 兼容的 import 排序功能,支持 isort 的所有配置选项。
2.2 性能优化的秘密
Ruff 为什么能比 Flake8 快 100 倍?核心原因有三个:
1. 零 Python 进程开销
Flake8 每次运行都需要启动一个 Python 解释器,加载插件,然后解析代码。这个启动过程在大型项目上可能就需要几秒。Ruff 是一个原生二进制文件,启动时间在毫秒级别。
2. 增量分析
Ruff 支持增量分析——当文件没有变化时,可以直接复用上次的分析结果。在 IDE 集成场景下,这意味着「保存即检查」成为可能。
3. 并行处理
Ruff 的规则引擎可以并行处理多个文件。在多核 CPU 上,大型项目的检查时间可以进一步缩短。
让我们看一个实际的性能对比:
# 在 CPython 代码库(约 50 万行)上的对比
$ time flake8 .
real 0m47.321s
$ time ruff check .
real 0m0.847s
# 提速 55 倍
# 格式化对比
$ time black --check .
real 0m12.456s
$ time ruff format --check .
real 0m0.234s
# 提速 53 倍
2.3 规则设计哲学
Ruff 的规则设计遵循两个核心原则:
原则一:默认安全
Ruff 的默认规则集只包含「几乎不会误报」的检查。你不需要花时间配置「忽略这个误报」。这和 Flake8 形成了鲜明对比——Flake8 的很多插件会产生大量误报,迫使开发者在配置文件里维护一个长长的 ignore 列表。
原则二:可自动修复
Ruff 的很多规则都支持自动修复(--fix)。这意味着你不需要手动修改代码来修复风格问题——Ruff 可以帮你做。
# 一键修复所有可修复的问题
$ ruff check --fix .
# 格式化整个项目
$ ruff format .
第三章:uv — 包管理的革命
3.1 为什么需要另一个包管理器?
Python 的包管理工具历史是一部混乱史:
- distutils(2000年):Python 标准库自带,功能极其有限
- setuptools(2004年):distutils 的增强版,成为事实标准
- pip(2008年):setuptools 的前端,成为「标准」包安装器
- virtualenv(2007年):虚拟环境工具,后来被
python -m venv取代 - pip-tools(2016年):依赖锁定工具
- Poetry(2018年):试图统一包管理和依赖锁定
- PDM(2021年):PEP 621 的实现
- Hatch(2022年):PyPA 官方推荐的项目管理工具
每个工具都有自己的锁文件格式、自己的配置方式、自己的虚拟环境管理策略。Poetry 的 poetry.lock、PDM 的 pdm.lock、Pipenv 的 Pipfile.lock——三个本质上做同一件事的工具,用了三种不兼容的格式。
3.2 uv 的设计哲学
uv 的设计哲学可以用一句话概括:用 Rust 的速度,做 pip 的事情,但做得更好。
uv 的核心特性:
- 速度:比 pip 快 10-100 倍
- 兼容性:完全兼容 pip 的命令行接口和
requirements.txt格式 - 虚拟环境:内置虚拟环境管理,无需额外工具
- 依赖解析:使用 PubGrub 算法(与 Cargo 相同),解析速度极快
- 缓存:全局缓存 + 硬链接,避免重复下载
3.3 实战:从 pip 迁移到 uv
安装 uv:
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# 或通过 pip
pip install uv
基本用法对比:
# pip 方式
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install pytest black flake8 --dev
# uv 方式(一条命令搞定)
uv venv
uv pip install -r requirements.txt
uv pip install pytest black flake8 --dev
依赖锁定:
# 生成锁文件(类似 pip-compile)
uv pip compile requirements.in -o requirements.txt
# 从锁文件安装(确保可复现)
uv pip sync requirements.txt
项目管理:
# 初始化新项目
uv init my-project
cd my-project
# 添加依赖
uv add fastapi uvicorn
# 添加开发依赖
uv add --dev pytest ruff
# 运行脚本
uv run python main.py
# 运行工具
uv run ruff check .
3.4 uv 的架构
uv 的核心架构分为几层:
┌─────────────────────────────────────┐
│ uv CLI │
├─────────────────────────────────────┤
│ ┌─────────────┐ ┌──────────────┐ │
│ │ Resolver │ │ Installer │ │
│ │ (PubGrub) │ │ (Hardlink) │ │
│ └─────────────┘ └──────────────┘ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ Cache │ │ Download │ │
│ │ Manager │ │ Manager │ │
│ └─────────────┘ └──────────────┘ │
│ ┌─────────────────────────────────┐│
│ │ PyPI Client (async, parallel) ││
│ └─────────────────────────────────┘│
└─────────────────────────────────────┘
依赖解析器:uv 使用 PubGrub 算法进行依赖解析,这是目前最先进的版本求解算法之一(Rust 的 Cargo 也使用相同的算法)。PubGrub 的核心思想是「冲突驱动学习」——当解析过程中遇到冲突时,算法会学习到一个新的约束,并回溯到更早的状态重新尝试。
缓存系统:uv 实现了一个智能缓存系统。下载的包会存储在全局缓存目录中,后续安装时通过硬链接(hardlink)直接引用缓存文件,避免重复下载和解压。这在 CI 场景下特别有用——第一次运行可能需要几分钟下载依赖,后续运行只需要几秒钟。
并行下载:uv 使用 async Rust(tokio)实现并行下载。当安装一个有 100 个依赖的项目时,uv 可以同时下载所有依赖,而不是像 pip 那样串行下载。
第四章:ty — 类型检查的新范式
4.1 mypy 的困境
mypy 是 Python 类型检查的事实标准,但它有几个长期存在的问题:
- 性能慢:在大型项目上,mypy 可能需要 30 秒甚至更长时间
- 增量检查不可靠:mypy 的增量检查模式经常漏掉错误
- 第三方库类型支持不完整:很多第三方库的类型 stub 缺失或过时
- 配置复杂:
mypy.ini的配置项多达 100 多个
4.2 ty 的定位
ty 是 Astral 推出的 Python 类型检查器,目标是成为 mypy/pyright 的 Rust 替代品。
核心特性:
- 极致性能:比 mypy 快 10-100 倍
- Python 3.14 兼容:第一时间支持最新的 Python 特性
- LSP 支持:内置语言服务器协议支持,可直接集成到 IDE
- 渐进式类型检查:支持
--strict模式和宽松模式
4.3 ty 的类型推断引擎
ty 的类型推断引擎基于「约束求解」(Constraint-based Type Inference)方法。与 mypy 的「双向类型检查」(Bidirectional Type Checking)不同,ty 将类型推断建模为一个约束满足问题:
# 对于这段代码
def add(a: int, b: int) -> int:
return a + b
result = add(1, 2) # ty 会推断 result: int
ty 会生成以下约束:
add的参数类型必须匹配intadd的返回类型是intresult的类型等于add的返回类型
然后通过约束求解器求解所有未知类型。这种方法的优势在于可以处理复杂的泛型和联合类型。
4.4 与 mypy 的对比
# 性能对比(Django 项目,约 20 万行代码)
$ time mypy .
real 0m34.521s
$ time ty check .
real 0m0.892s
# 提速 38 倍
# 类型推断能力对比
from typing import Union
def process(x: Union[int, str]) -> str:
if isinstance(x, int):
return str(x)
return x
# mypy: 正确推断
# ty: 正确推断
# 复杂泛型场景
from typing import TypeVar, Generic
T = TypeVar('T')
U = TypeVar('U')
class Box(Generic[T]):
def __init__(self, value: T) -> None:
self.value = value
def map(self, f: 'Callable[[T], U]') -> 'Box[U]':
return Box(f(self.value))
# mypy: 部分场景需要显式注解
# ty: 大多数场景可以自动推断
第五章:配置统一 — pyproject.toml 的终极形态
5.1 一个文件统治一切
Astral 工具链最令人愉悦的特性之一是配置统一。uv、Ruff、ty 的所有配置都可以放在同一个 pyproject.toml 文件里:
[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"fastapi>=0.115.0",
"uvicorn>=0.30.0",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0",
"ruff>=0.6.0",
]
[tool.ruff]
target-version = "py312"
line-length = 88
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
]
ignore = ["E501"]
[tool.ruff.lint.isort]
known-first-party = ["my_project"]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
[tool.ty]
python-version = "3.12"
对比传统的配置方式:
# 传统方式:4 个配置文件
# .flake8
[flake8]
max-line-length = 88
extend-ignore = E501
per-file-ignores = __init__:F401
# setup.cfg 或 .isort.cfg
[isort]
profile = black
known_first_party = my_project
# pyproject.toml (只有 black)
[tool.black]
line-length = 88
target-version = ["py312"]
# mypy.ini
[mypy]
python_version = 3.12
ignore_missing_imports = True
一个文件 vs 四个文件,这就是 Astral 工具链的配置哲学。
5.2 迁移指南
从传统工具链迁移到 Astral 工具链,推荐的步骤是:
第一步:安装 uv
curl -LsSf https://astral.sh/uv/install.sh | sh
第二步:用 uv 管理依赖
# 将 requirements.txt 转换为 pyproject.toml
uv init
uv add -r requirements.txt
# 如果有 requirements-dev.txt
uv add --dev -r requirements-dev.txt
第三步:用 Ruff 替代 Flake8 + Black + isort
# 安装 Ruff
uv add --dev ruff
# 从 Flake8 迁移规则
# 查看 Ruff 的规则映射表:https://docs.astral.sh/ruff/rules/
# 运行 Ruff 检查
ruff check .
# 运行 Ruff 格式化
ruff format .
第四步:更新 CI 配置
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
- run: uv sync
- run: uv run ruff check .
- run: uv run ruff format --check .
- run: uv run ty check .
第五步:更新 pre-commit
# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
第六章:Ruff 的 Rust 实现细节
6.1 Python 解析器
Ruff 内置的 Python 解析器是一个手写的递归下降解析器(Recursive Descent Parser),直接将 Python 源代码解析为 AST。它支持 Python 3.14 的所有语法特性,包括:
- 模式匹配(
match/case) - 异步生成器
- 海象运算符(
:=) - f-string 调试格式(
f"{x=}") - PEP 695 类型参数语法
解析器的实现使用了 Rust 的零成本抽象——解析过程中不需要分配额外的内存,AST 节点直接存储在连续的内存块中。
6.2 规则的实现模式
每条 Ruff 规则都遵循统一的实现模式:
// 规则定义
pub struct RuleUnusedVariable;
impl Rule for RuleUnusedVariable {
fn check(&self, ast: &ModModule) -> Vec<Diagnostic> {
let mut diagnostics = Vec::new();
// 遍历 AST,查找未使用的变量
for stmt in ast.body.iter() {
if let Stmt::Assign(assign) = stmt {
for target in &assign.targets {
if let Name(name) = target {
if !is_used(name, ast) {
diagnostics.push(Diagnostic::new(
"F841",
format!("Local variable `{name}` is assigned to but never used"),
target.range(),
));
}
}
}
}
}
diagnostics
}
}
每条规则都是一个独立的结构体,实现了 Rule trait。规则引擎通过动态分发(dynamic dispatch)调用所有注册的规则。
6.3 格式化器的确定性
Ruff 的格式化器追求「确定性」——对于相同的输入,总是产生相同的输出。这是通过以下设计保证的:
- 无状态格式化:格式化器不依赖任何外部状态(如文件修改时间、Git 历史)
- 规范化的空白处理:所有空白字符(空格、制表符、换行符)都被规范化为统一的形式
- Black 兼容的决策树:格式化决策遵循 Black 的规范,确保输出一致
# Ruff 格式化前
x=1;y=2;z=3
# Ruff 格式化后(与 Black 一致)
x = 1
y = 2
z = 3
第七章:生态集成与社区
7.1 IDE 支持
Astral 工具链的 IDE 集成非常成熟:
VS Code:
{
"extensions": [
"charliermarsh.ruff",
"astral-sh.ty"
],
"editor.codeActionsOnSave": {
"source.fixAll.ruff": "explicit",
"source.organizeImports.ruff": "explicit"
}
}
Neovim(通过 nvim-lspconfig):
require('lspconfig').ruff.setup({})
require('lspconfig').ty.setup({})
PyCharm:通过官方插件支持,可一键启用 Ruff 作为外部工具。
7.2 CI/CD 集成
Ruff 和 uv 都提供了 GitHub Actions 官方 Action:
- uses: astral-sh/ruff-action@v3
with:
args: "check --fix"
- uses: astral-sh/ruff-action@v3
with:
args: "format --check"
7.3 社区生态
Ruff 的社区生态正在快速成长:
- ruff-vscode:官方 VS Code 扩展
- ruff-pre-commit:pre-commit 钩子
- ruff-lsp:语言服务器协议实现
- ruff-playground:在线试用 Ruff
第八章:性能基准测试
8.1 测试环境
- 硬件:Apple M3 Pro, 18GB RAM
- Python 版本:3.12.4
- Ruff 版本:0.6.0
- 测试项目:CPython 源代码(约 50 万行)
8.2 Linting 性能
| 工具 | 首次运行 | 增量运行 | 提速倍数 |
|---|---|---|---|
| Flake8 | 47.3s | 32.1s | - |
| Ruff | 0.85s | 0.12s | 55x |
8.3 格式化性能
| 工具 | 首次运行 | 增量运行 | 提速倍数 |
|---|---|---|---|
| Black | 12.5s | 8.3s | - |
| Ruff | 0.23s | 0.04s | 54x |
8.4 包安装性能
| 工具 | 冷启动 | 缓存命中 | 提速倍数 |
|---|---|---|---|
| pip | 45.2s | 12.8s | - |
| uv | 3.1s | 0.8s | 14x |
8.5 类型检查性能
| 工具 | 首次运行 | 增量运行 | 提速倍数 |
|---|---|---|---|
| mypy | 34.5s | 8.2s | - |
| ty | 0.89s | 0.15s | 38x |
第九章:Ruff vs 传统工具链的决策矩阵
9.1 什么时候用 Ruff?
强烈推荐的场景:
- 新项目:没有历史包袱,直接用 Ruff
- CI 优化:需要缩短 CI 时间
- 大型项目:代码量大,传统工具慢到无法忍受
- 团队协作:需要统一代码风格,减少争论
可以考虑的场景:
- 已有 Flake8 配置:可以用 Ruff 的
--config选项兼容大部分配置 - 需要特定插件:检查 Ruff 是否已实现该规则
暂不推荐的场景:
- 极度依赖 mypy 的高级特性:ty 还在快速迭代中
- 需要 Python 2 支持:Ruff 只支持 Python 3
9.2 迁移成本评估
| 维度 | 成本 | 说明 |
|---|---|---|
| 配置迁移 | 低 | 大部分配置可直接映射 |
| 规则迁移 | 中 | 需要检查 Ruff 是否覆盖所需规则 |
| CI 迁移 | 低 | 替换命令即可 |
| IDE 迁移 | 低 | 安装官方扩展 |
| 团队培训 | 低 | Ruff 的 CLI 接口非常直观 |
第十章:未来展望
10.1 Astral 的路线图
Astral 的目标很明确:成为 Python 开发体验的基础设施。
- uv:正在实现完整的项目管理能力,目标是替代 Poetry/PDM/Hatch
- Ruff:正在实现更多规则,目标是覆盖 Flake8 + pylint 的所有规则
- ty:正在完善类型推断引擎,目标是超越 mypy/pyright 的准确性
10.2 对 Python 生态的影响
Astral 工具链的成功正在产生深远的影响:
- 加速 Python 的「Rust 化」:越来越多的 Python 工具开始用 Rust 重写(如 Pydantic v2、Polars)
- 提升开发者体验:更快的工具意味着更好的开发体验,这有助于 Python 在性能敏感场景下的竞争力
- 统一工具生态:Astral 的成功证明了「统一配置」的价值,未来可能会有更多工具采用类似的策略
10.3 对开发者的建议
- 现在就开始用 uv:uv 已经足够稳定,而且性能优势明显
- 逐步迁移到 Ruff:不需要一次性迁移,可以先在新项目中试用
- 关注 ty 的发展:ty 还在快速迭代中,建议关注但不急于在生产环境使用
- 保持开放心态:Python 工具链正在快速变化,保持学习和适应的能力
总结
Astral 工具链的出现,标志着 Python 开发体验进入了一个新的时代。
uv 用 Rust 的速度解决了包管理的性能问题,Ruff 用 Rust 的速度终结了代码质量工具的碎片化,ty 用 Rust 的速度挑战了类型检查的性能极限。
这不是一个「用 Rust 重写一切」的盲目追求,而是一个深思熟虑的工程决策:当工具的性能提升 100 倍时,它不仅仅是「更快」,而是改变了使用方式本身。
当代码检查的延迟低于人脑的感知阈值时,它就从一种「需要主动触发的任务」变成了「无缝的背景服务」。当包安装从分钟级缩短到秒级时,CI/CD 的反馈循环变得几乎实时。当类型检查可以在保存时即时运行时,渐进式类型标注不再是理论上的最佳实践,而是真正可落地的工作流。
Astral 用 Rust 重写了 Python 的工具链,但更重要的是,他们重新定义了「好的开发工具应该是什么样的」。
对于每一个 Python 开发者来说,现在是拥抱这个变化的最佳时机。
参考资源:
- Ruff 官方文档:https://docs.astral.sh/ruff/
- uv 官方文档:https://docs.astral.sh/uv/
- ty 官方文档:https://docs.astral.sh/ty/
- Astral 博客:https://astral.sh/blog
- Ruff GitHub:https://github.com/astral-sh/ruff
- uv GitHub:https://github.com/astral-sh/uv
- ty GitHub:https://github.com/astral-sh/ty