Screenshot 2025-11-23 004235.png

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-toolsvirtualenv. 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.

Image
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 .venv ngay 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.

Image
.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ặc uv run python)
  • Hành động:
    1. uv kiểm tra xem file .lock có khớp với môi trường hiện tại không.
    2. Nếu chưa có môi trường, nó tự động tạo.
    3. Nếu thiếu thư viện, nó tự động cài.
    4. 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ùng uv run khi 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:

  1. Cập nhật pyproject.toml:
    Nó thêm dòng dependencies = ["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).

  2. 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 file pyproject.toml hoặ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-url hoặc --extra-index-url.
    bash uv add torch torchvision --index https://download.pytorch.org/whl/cu126
    Lưu ý: Khi dùng uv add, bạn nên cấu hình source trong pyproject.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 file uv.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à dependenciestool.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:

  1. File pyproject.toml
  2. File uv.lock (Bắt buộc phải có để đồng bộ version)
  3. 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ì?

  1. Nó đọc file uv.lock.
  2. Nó xóa sạch các thư viện thừa không có trong lock.
  3. 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 .venv tại server.
  4. 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!