
Quản lý môi trường Python với uv
uv (viết bởi Astral) là một công cụ thay thế cực nhanh cho pip, pip-tools và virtualenv. Thay vì quản lý môi trường thủ công và chậm chạp, uv tập trung vào dự án (project) và tính tái lập (reproducibility). Chúng ta thường hay sử dụng uv so với conda, sau đây là các điểm khác nhau giữa hai cách quản lý môi trường này.
| Tiêu chí | Conda | uv |
|---|---|---|
| Tốc độ | Chậm hơn. (Do bộ giải dependency phức tạp và viết bằng Python/C). | Cực nhanh. (Viết bằng Rust, nhanh hơn 10-100x). |
| Phạm vi quản lý | Đa năng. Quản lý cả Python và các thư viện hệ thống (C++, R, CUDA...). | Chuyên Python. Tập trung tối ưu cho các gói Python (PyPI). |
| Loại môi trường | Tạo môi trường riêng kiểu Conda (thường nằm ở thư mục tập trung). | Tạo môi trường chuẩn venv (thường nằm ngay trong project .venv). |
| Quản lý Python | Python được coi là một "package" cài đặt vào môi trường. | Tự động tải, cài đặt và quản lý các phiên bản Python riêng biệt. |
| Dung lượng đĩa | Tốn dung lượng hơn (mỗi môi trường thường là bản sao riêng). | Tiết kiệm hơn (Dùng cơ chế hard links để chia sẻ file giữa các dự án). |
| Nguồn cài đặt | Anaconda Channels, Conda-forge. | PyPI (Python Package Index) chuẩn. |
uv cài đặt thư viện nhanh hơn rất nhiều so với pip vì được viết bằng RUST.
Dưới đây là quy trình sử dụng uv mà mình thường thực hiện với một dự án mới.
1. Cài đặt
Trên Ubuntu, bạn cài đặt uv bằng script có được từ website tại đây. Thư viện không cần quyền sudo và cài trực tiếp vào thư mục user của bạn.
curl -LsSf https://astral.sh/uv/install.sh | sh
Sau khi cài xong, hãy tắt terminal mở lại hoặc chạy lệnh source $HOME/.cargo/env để cập nhật đường dẫn. Kiểm tra:
uv --version
2. Khởi tạo dự án, tạo ra file pyproject.toml
Thay vì tạo thư mục rồi chạy python -m venv, với uv bạn bắt đầu bằng việc khởi tạo cấu trúc dự án chuẩn.
# Tạo thư mục dự án mới
mkdir my-ai-project
cd my-ai-project
# Khởi tạo uv
uv init
uv run main.py
Lúc này, thư mục sẽ có file pyproject.toml. Đây là file cấu hình hiện đại thay thế cho requirements.txt rời rạc. Nó chứa tên dự án, version Python yêu cầu và các thư viện chính mà chúng ta sẽ sử dụng.
3. So sánh giữa uv venv vs uv run
Nếu như là người dùng lâu năm của Conda, và UV, đôi lúc chúng ta sẽ thắc mắc tại sao lại có 2 câu lệnh để tạo môi trường (và chạy môi trường) là venv và run. Đây là nơi nhiều người mới dùng bị nhầm lẫn, uv cung cấp 2 cách tiếp cận để xử lý môi trường ảo.
Cách 1: uv venv (Kiểu truyền thống - Explicit)
Cách này giống hệt python -m venv cũ. Bạn tạo môi trường, kích hoạt nó, rồi làm việc.
- Lệnh:
uv venv - Hành động: Nó tạo một thư mục
.venvngay lập tức. - Cách dùng: Bạn phải chạy
source .venv/bin/activateđể vào môi trường. - Khi nào dùng? Khi bạn cần cấu hình đường dẫn interpreter cho VS Code hoặc PyCharm để IDE nhận diện được code, hoặc khi bạn muốn kiểm soát thủ công hoàn toàn. Đây là cách khuyên dùng nếu bạn muốn quản lý sâu và làm những project dài hạn. Ví dụ dưới đây là các mình sử dụng thư mục này để debug project của mình.
.vscode/launch.json
Cách 2: uv run (Kiểu hiện đại - Implicit)
Đây là sức mạnh thực sự của uv. Bạn không cần quan tâm môi trường đã được kích hoạt hay chưa.
- Lệnh:
uv run main.py(hoặcuv run python) - Hành động:
uvkiểm tra xem file.lockcó khớp với môi trường hiện tại không.- Nếu chưa có môi trường, nó tự động tạo.
- Nếu thiếu thư viện, nó tự động cài.
- Sau đó nó chạy lệnh của bạn trong môi trường đó.
- Khi nào dùng? Khi chạy script thực tế, chạy training model, hoặc viết Dockerfile. Nó đảm bảo code luôn chạy đúng với những gì đã khai báo. Chúng ta sẽ dùng cách này nếu chúng ta muốn test nhanh một điều gì đó và thường sẽ chạy chỉ một file duy nhất.
Khuyên dùng: Hãy dùng kết hợp. Dùng
uv venvđể VS Code không báo lỗi gạch đỏ. Dùnguv runkhi gõ lệnh chạy chương trình để đảm bảo tính đồng bộ.
4. Quản lý thư viện và file Lock
Thay vì pip install, chúng ta dùng uv add. Trong uv, chúng ta hoàn toàn có thể dùng lệnh uv pip install để cài đặt một thư viện, nhưng cách này không nên dùng vì các thư viện cài theo cách này sẽ không được thêm vào file Lock cho chúng ta.
# Cài đặt thư viện
uv add numpy pandas torch
Ngay khi bạn chạy lệnh này, 2 việc sẽ xảy ra đồng thời:
-
Cập nhật
pyproject.toml:
Nó thêm dòngdependencies = ["numpy", "pandas", "torch"]. Đây là yêu cầu trừu tượng (ví dụ: tôi cần numpy bản nào cũng được, miễn là mới). -
Tạo/Cập nhật
uv.lock:
Đây là file quan trọng nhất. Nó ghi lại chính xác phiên bản đã cài (ví dụ:numpy==1.26.4).
Tại sao cần uv.lock?
File này đảm bảo rằng: "Hôm nay code chạy được trên máy tôi, thì 10 năm sau nó vẫn chạy được y hệt trên máy bạn". Nó khóa chặt mọi dependency con (sub-dependencies) để tránh việc thư viện tự nâng cấp gây lỗi.
Chúng ta sẽ có một vài lưu ý về phần sử dụng uv như sau đây.
Chọn phiên bản python
uv giúp bạn dễ dàng quản lý và chuyển đổi giữa các phiên bản Python khác nhau mà không cần cài đặt thủ công, cũng như trong conda chúng ta dùng lệnh conda install python==3.10.
-
Tạo môi trường với phiên bản cụ thể:
bash uv venv --python 3.10
Lệnh này sẽ tự động tải Python 3.10 (nếu chưa có) và tạo môi trường ảo sử dụng phiên bản này. -
Ghim phiên bản Python cho dự án:
Bạn có thể quy định phiên bản Python yêu cầu trong filepyproject.tomlhoặc dùng lệnh:
bash uv python pin 3.11
Cài các thư viện bằng url và Index riêng
Đôi khi bạn cần cài đặt thư viện từ nguồn khác ngoài PyPI mặc định, ví dụ như PyTorch với hỗ trợ CUDA.
-
Cài đặt với Index URL (Ví dụ PyTorch):
Để cài PyTorch bản hỗ trợ CUDA 11.8, bạn có thể dùng cờ--index-urlhoặc--extra-index-url.
bash uv add torch torchvision --index https://download.pytorch.org/whl/cu126
Lưu ý: Khi dùnguv add, bạn nên cấu hình source trongpyproject.tomlđể đảm bảo tính nhất quán. -
Cài đặt từ Git:
bash uv add git+https://github.com/deepseek-ai/Janus
uv sync và các option
Lệnh uv sync đảm bảo thư mục .venv khớp hoàn toàn với file uv.lock. Đây là lệnh quan trọng nhất khi deploy hoặc làm việc nhóm.
uv sync(Mặc định): Cài đặt/Gỡ bỏ các gói để môi trường khớp với lock file.uv sync --frozen: Không cho phép thay đổi fileuv.lock. Nếu môi trường cần thay đổi mà lock file chưa cập nhật, lệnh sẽ báo lỗi. Rất hữu ích cho CI/CD để đảm bảo tính tái lập.uv sync --all-extras: Cài đặt tất cả các dependency tùy chọn (extras).
uv lock và các option
Lệnh uv lock chỉ thực hiện việc giải quyết dependency (resolve) và cập nhật file uv.lock, không cài đặt gì vào môi trường.
uv lock: Tính toán lại cây dependency và cập nhật file lock.uv lock --upgrade: Cố gắng nâng cấp tất cả các gói lên phiên bản mới nhất được phép.uv lock --upgrade-package <name>: Chỉ nâng cấp một gói cụ thể.
Chỉnh sửa configuration (pyproject.toml)
File pyproject.toml là trái tim của dự án. Ngoài việc dùng lệnh uv add, bạn có thể sửa thủ công file này. Dưới đây là một vài thành phần mình hay sửa trong file toml này.
[project]
name = "my-ai-project"
version = "0.1.0"
description = "Sample Project"
requires-python = ">=3.10"
dependencies = [
"numpy>=1.24.0",
"pandas",
"torch",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.uv]
# Các cấu hình nâng cao cho uv
[[tool.uv.index]]
url = "https://download.pytorch.org/whl/cu126"
[tool.uv.sources]
janus = { git = "https://github.com/deepseek-ai/Janus" }
Sau khi chỉnh sửa thủ công pyproject.toml, hãy chạy uv sync để áp dụng các thay đổi đó vào môi trường. Thông thường chúng ta sẽ sửa hai trường là dependencies và tool.uv.index nhiều nhất.
Để có thể xem project chúng ta cần gì, thông thường mình sẽ dùng lệnh uv tree để view toàn bộ cây thư viện. Cũng như kiểm tra xem hiện tại đang có conflict gì không.
5. Sử dụng mô trường trên máy khác
Đây là kịch bản bạn gặp phải: Bạn code trên máy cá nhân (hoặc thư mục riêng) và muốn đưa sang server chung, hoặc đưa cho đồng nghiệp.
Bước 1: Chuẩn bị file
Trong thư mục dự án, bạn chỉ cần copy 3 thành phần này sang máy đích:
- File
pyproject.toml - File
uv.lock(Bắt buộc phải có để đồng bộ version) - Source code của bạn (
main.py,src/,...)
Tuyệt đối KHÔNG copy thư mục
.venv. Môi trường ảo nên được tạo mới tại đích đến để phù hợp với hệ điều hành của máy đó.
Bước 2: Khôi phục tại máy đích (Server Linux)
Tại server (sau khi đã cd vào thư mục chứa các file trên), bạn chỉ cần chạy một lệnh duy nhất:
uv sync
Lệnh uv sync làm gì?
- Nó đọc file
uv.lock. - Nó xóa sạch các thư viện thừa không có trong lock.
- Nó tải và cài đặt chính xác các phiên bản được ghi trong lock vào thư mục
.venvtại server. - Nó đảm bảo môi trường trên server giống 100% môi trường trên máy bạn lúc dev.
Bước 3: Chạy code
# Chạy trực tiếp
uv run main.py
Cheatsheet
| Mục đích | Lệnh cũ (pip/conda) | Lệnh uv (Khuyên dùng) |
|---|---|---|
| Tạo dự án mới | mkdir, touch req.txt |
uv init |
| Tạo môi trường | python -m venv .venv |
uv venv (hoặc để uv run tự lo) |
| Cài thư viện | pip install package |
uv add package |
| Xóa thư viện | pip uninstall package |
uv remove package |
| Chạy script | source ... -> python main.py |
uv run main.py |
| Cài lại trên máy khác | pip install -r req.txt |
uv sync |
Sử dụng quy trình này, bạn sẽ không bao giờ gặp lại lỗi Permission denied ở /opt nữa, vì toàn bộ thư viện nằm gọn trong thư mục dự án của riêng bạn.
Ví dụ thực tế
Dưới đây là một ví dụ minh họa quá trình tạo dự án, thêm thư viện và chạy code với uv.
$ mkdir uv-demo
$ cd uv-demo
$ uv init
warning: `uv init` is experimental and may change without warning
Initialized project `uv-demo`
$ uv add click
warning: `uv add` is experimental and may change without warning
Using Python 3.12.3 interpreter at: /usr/bin/python3
Creating virtualenv at: .venv
Resolved 3 packages in 66ms
Built uv-demo @ file:///tmp/uv-demo
Prepared 2 packages in 430ms
Installed 2 packages in 0.62ms
+ click==8.1.7
+ uv-demo==0.1.0 (from file:///tmp/uv-demo)
$ tree
.
├── pyproject.toml
├── README.md
├── src
│ └── uv_demo
│ ├── __init__.py
└── uv.lock
3 directories, 4 files
$ uv run python -c "from uv_demo import hello; print(hello())"
Hello from uv-demo!
Cảm ơn tác giả <3. A Thịnh có thể viết thêm về cấu trúc các thư mục của một dự án AI và best pratices được không ạ?