0

LiteLLM (Phần 1) — Điều Gì Xảy Ra Khi OpenAI Không Còn Là Lựa Chọn Duy Nhất?

1. Bài Toán Đặt Ra

Hai năm trước, việc tích hợp AI vào sản phẩm là một quyết định khá đơn giản: chọn OpenAI, lấy API key, gọi vài endpoint, xong. Cả tổ chức dùng chung một provider, một SDK, một cách tính chi phí. Kiến trúc gọn gàng vì lựa chọn cũng gọn gàng. Hiện nay bức tranh đó đã thay đổi . Thị trường mô hình ngôn ngữ giờ đây không còn một "người thắng cuộc" duy nhất, mà là một hệ sinh thái nơi mỗi mô hình có thế mạnh riêng, mức giá riêng, và tốc độ tiến hóa riêng. Một mô hình dẫn đầu hôm nay có thể bị vượt qua sau ba tháng; một mô hình đắt đỏ cho tác vụ này lại là lựa chọn lãng phí cho tác vụ khác. Hệ quả tất yếu: các tổ chức trưởng thành không còn cược tất cả vào một nhà cung cấp, mà vận hành một danh mục (portfolio) nhiều mô hình giống như cách một quỹ đầu tư đa dạng hóa danh mục để tối ưu rủi ro và lợi nhuận. Việc chọn nhiều mô hình xuất phát từ những lý do kinh tế và kỹ thuật rất cụ thể:

  • Tối ưu chi phí theo tác vụ: Dùng mô hình flagship đắt tiền để phân loại email là lãng phí. Một mô hình nhỏ, nhanh, rẻ làm việc đó tốt hơn nhiều lần về mặt chi phí.
  • Tối ưu chất lượng theo tác vụ: Ngược lại, với bài toán reasoning phức tạp hay phân tích tài liệu dài, mô hình mạnh nhất sẽ tiết kiệm nhiều giờ sửa lỗi về sau.
  • Tránh phụ thuộc một nhà cung cấp (vendor lock-in): Phụ thuộc hoàn toàn vào một provider đồng nghĩa với việc chấp nhận mọi đợt tăng giá, mọi thay đổi điều khoản, và mọi sự cố downtime của họ.
  • Yêu cầu chủ quyền dữ liệu: Một số dữ liệu như hồ sơ khách hàng, tài liệu pháp lý, bí mật kinh doanh đơn giản là không được phép rời khỏi hạ tầng nội bộ, buộc phải dùng mô hình tự host.

Đa dạng hóa mô hình mang lại lợi ích rõ ràng, nhưng nó cũng âm thầm tạo ra một lớp phức tạp mà nhiều đội ngũ chỉ nhận ra khi đã quá muộn. Vấn đề không nằm ở chỗ "gọi được nhiều mô hình" . Vấn đề nằm ở chỗ quản lý và vận hành chúng

  • Mỗi provider có một SDK riêng, với cú pháp, kiểu dữ liệu trả về và cơ chế streaming khác nhau.
  • Mỗi provider có một cách báo lỗi và rate limit riêng, nghĩa là logic retry phải viết lại cho từng cái.
  • Mỗi provider có một bảng giá và đơn vị tính token riêng, khiến việc tổng hợp chi phí rất phức tạp.
  • Mỗi provider có độ tin cậy khác nhau theo thời gian, provider tốt nhất hôm nay có thể downtime vào đúng giờ cao điểm ngày mai.

Khi một tổ chức có bốn provider, đó là bốn SDK, bốn cách xử lý lỗi, bốn cách tính chi phí phải duy trì song song. Logic này thường bị nhúng rải rác khắp codebase, lặp lại ở mỗi service, và mỗi khi muốn thêm một provider mới hay đổi cách routing, kỹ sư phải sửa ở hàng chục nơi. Đây chính là điểm đau kỹ thuật đầu tiên. Nếu chỉ dừng ở vấn đề SDK, ta đã có thể giải quyết bằng một lớp abstraction đơn giản. Tuy nhiên, khi AI lan rộng từ một dự án thử nghiệm thành hạ tầng dùng chung cho cả tổ chức hoặc những dự án lớn những câu hỏi quản trị mới là thứ thực sự khiến các lãnh đạo kỹ thuật mất ngủ:

  • Kiểm soát chi phí: Khi 10 team cùng gọi AI song song mà không có giới hạn, hóa đơn cuối tháng có thể vượt ngân sách gấp nhiều lần. Làm sao đặt budget cho từng team, từng dự án, và chặn lại trước khi vượt trần?
  • Đảm bảo tính sẵn sàng (uptime): Khi một provider gặp sự cố vào đúng giờ cao điểm, toàn bộ tính năng AI có nên sập theo không? Làm sao để hệ thống tự động chuyển sang phương án dự phòng mà người dùng không hề hay biết?
  • Truy vết và tuân thủ (audit & compliance): Với các tiêu chuẩn như SOC 2, GDPR, ISO 27001, tổ chức phải chứng minh được ai đã gọi cái gì, khi nào, và kết quả ra sao. Làm sao ghi lại toàn bộ traffic AI một cách đầy đủ và đáng tin cậy?
  • Bảo vệ dữ liệu nhạy cảm: Một nhân viên có thể vô tình dán số CCCD, số tài khoản ngân hàng, hay thông tin khách hàng vào prompt rồi gửi thẳng lên cloud. Làm sao phát hiện và chặn điều đó trước khi dữ liệu rời khỏi tổ chức?

Những câu hỏi này không thể giải quyết bằng việc nhúng thêm code vào từng ứng dụng, chúng đòi hỏi một tầng hạ tầng tập trung, đứng giữa ứng dụng và các nhà cung cấp mô hình, nơi mọi request đều đi qua và đều được kiểm soát. Đây chính là lý do LiteLLM ra đời

2. LiteLLM Là Gì?

LiteLLM là một dự án mã nguồn mở (MIT license) do BerriAI phát triển, cung cấp một API thống nhất tương thích OpenAI để gọi hơn 100+ LLM providers. Nói cách khác: bạn viết code một lần theo cú pháp OpenAI, LiteLLM lo việc dịch sang Anthropic, Gemini, AWS Bedrock, Azure, Vertex AI, Cohere, Ollama, vLLM, hay bất kỳ provider nào khác trong danh sách hỗ trợ. Quan trọng hơn là LiteLLM cung cấp toàn bộ hạ tầng cần thiết để chạy một LLM Gateway ở quy mô doanh nghiệp: virtual keys, budget tracking, rate limiting, caching, load balancing, fallback, và observability tất cả tích hợp sẵn, không cần viết thêm.

Theo bài viết "A gentle introduction to LiteLLM" trên Medium (MITB For All), điểm hấp dẫn nhất của LiteLLM nằm ở triết lý "zero code change" và "OpenAI as the lingua franca" đó là

  • OpenAI SDK đã là chuẩn de-facto: Mọi framework AI hiện đại (LangChain, LlamaIndex, Haystack, Autogen, AutoGPT) đều hỗ trợ OpenAI-compatible endpoint. LiteLLM tận dụng điều đó nên khi bạn dùng bất kỳ framework nào, miễn nó nói được OpenAI là chạy với LiteLLM.
  • Migration: Ứng dụng đang dùng OpenAI thật chỉ cần đổi base_url là chuyển hết sang LiteLLM, không sửa code logic.
  • Cộng đồng và tốc độ phát triển: Repository LiteLLM trên GitHub có hơn 20K stars và release liên tục, provider mới ra đời thường có hỗ trợ trong vòng vài ngày.

2.1 Một số các tính năng

Tính năng Mô tả ngắn
Unified API Một cú pháp duy nhất cho 100+ providers, format response luôn theo OpenAI
Proxy Server HTTP server độc lập, dùng được từ mọi ngôn ngữ (không chỉ Python)
Router & Load Balancing 6 chiến lược: simple-shuffle, least-busy, latency-based, usage-based, cost-based...
Automatic Fallback Tự chuyển sang model dự phòng khi gặp lỗi (timeout, rate limit, content policy)
Caching Exact cache + Semantic cache với Redis/Qdrant; DualCache (L1 in-memory + L2 Redis)
Virtual Keys Cấp key riêng cho từng team/app với budget, rate limit, model whitelist
Multi-Tenant Phân cấp Organization → Team → Key với budget và quota riêng biệt
Spend Tracking Theo dõi chi phí theo từng key, user, team, model — lưu trong PostgreSQL
Observability Tích hợp sẵn 20+ platforms: Langfuse, Prometheus, OpenTelemetry, Datadog, MLflow...
Guardrails Hỗ trợ content filtering, PII masking qua plugin (presidio, lakera, aporia...)
Streaming Hỗ trợ streaming response đồng nhất, kể cả khi provider gốc có cú pháp khác

3. Hai Chế Độ Vận Hành: SDK và Proxy

Một điểm gây nhầm lẫn cho người mới: LiteLLM có hai cách dùng hoàn toàn khác nhau, và lựa chọn giữa chúng quyết định toàn bộ kiến trúc về sau.

3.1 Chế độ SDK: Thư viện Python

┌─────────────────────────────────────┐
│       Python Application            │
│  ┌───────────────────────────────┐  │
│  │  import litellm               │  │
│  │  litellm.completion(...)      │  │
│  └──────────┬────────────────────┘  │
└─────────────┼───────────────────────┘
              │ HTTP trực tiếp
              ▼
   OpenAI / Anthropic / Gemini / ...

Bạn pip install litellm rồi gọi litellm.completion() ngay trong code Python. Đơn giản, ít overhead. Nhưng:

  • Phù hợp cho: prototype, script nhỏ, notebook, ứng dụng Python đơn lẻ
  • Không phù hợp khi: nhiều team cùng dùng, cần audit tập trung, không phải Python, cần quản lý chi phí

3.2 Chế độ Proxy: HTTP gateway độc lập

┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐
│  Python App     │  │  Node.js App    │  │  Go Service     │
│ (OpenAI SDK)    │  │ (OpenAI SDK)    │  │ (any HTTP)      │
└────────┬────────┘  └────────┬────────┘  └────────┬────────┘
         │                    │                    │
         └──────────┬─────────┴───────────────┬────┘
                    ▼                          
            ┌──────────────────────────┐       
            │   LiteLLM Proxy Server   │       
            │  Auth · Cache · Router   │       
            │  Budget · Logging · ...  │       
            └──────────┬───────────────┘       
                       │                       
   ┌───────────────────┼───────────────────┐   
   ▼                   ▼                   ▼   
OpenAI API     Anthropic API         Local Ollama

LiteLLM chạy như một HTTP server riêng biệt (mặc định port 4000). Mọi app đều gọi vào proxy như đang gọi OpenAI. Đây là chế độ phù hợp cho hệ thống lớn vì:

  • Đa ngôn ngữ: Bất kỳ app HTTP nào cũng dùng được
  • Tập trung: Một điểm để cấu hình routing, budget, logging
  • Cô lập credentials: App chỉ cần virtual key, không bao giờ biết key thật của provider
  • Observability: Mọi request đều đi qua proxy nên trace được hết

4. Kiến Trúc và Các Thành Phần Cốt Lõi

Kiến trúc tham chiếu của một LiteLLM Proxy ở quy mô production:

┌─────────────────────────────────────────────────────────────┐
│                 CLIENT APPLICATIONS                          │
└────────────────────────────┬────────────────────────────────┘
                             │ HTTPS (OpenAI-compatible)
┌────────────────────────────▼────────────────────────────────┐
│              LITELLM PROXY SERVER (cluster N pods)           │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐  │
│  │  1. Authentication Layer                               │  │
│  │     ├─ Validate virtual key                            │  │
│  │     ├─ Check key/team/user budget                      │  │
│  │     └─ Apply rate limits (RPM/TPM)                     │  │
│  └────────────────────────────────────────────────────────┘  │
│  ┌────────────────────────────────────────────────────────┐  │
│  │  2. Cache Lookup                                       │  │
│  │     ├─ L1: In-memory exact match                       │  │
│  │     ├─ L2: Redis exact match                           │  │
│  │     └─ Semantic cache (Redis vector / Qdrant)          │  │
│  └────────────────────────────────────────────────────────┘  │
│  ┌────────────────────────────────────────────────────────┐  │
│  │  3. Router                                             │  │
│  │     ├─ Pick deployment by strategy                     │  │
│  │     ├─ Skip deployments in cooldown                    │  │
│  │     └─ Handle fallback chain                           │  │
│  └────────────────────────────────────────────────────────┘  │
│  ┌────────────────────────────────────────────────────────┐  │
│  │  4. Provider Call + Retry                              │  │
│  └────────────────────────────────────────────────────────┘  │
│  ┌────────────────────────────────────────────────────────┐  │
│  │  5. Post-Call: Update spend, fire callbacks, cache     │  │
│  └────────────────────────────────────────────────────────┘  │
└─────────┬────────────────┬──────────────────┬───────────────┘
          │                │                  │
   ┌──────▼──────┐  ┌──────▼──────┐    ┌──────▼─────────┐
   │  Redis      │  │  PostgreSQL │    │  Callbacks     │
   │  (Cache +   │  │  (Keys,     │    │  (Langfuse,    │
   │  shared     │  │  Teams,     │    │  Prometheus,   │
   │  state)     │  │  Spend)     │    │  Datadog...)   │
   └─────────────┘  └─────────────┘    └────────────────┘
          │
          ▼
   ┌───────────────────────────────────────────────────────┐
   │  LLM PROVIDERS                                        │
   │  OpenAI · Anthropic · Gemini · Bedrock · Azure ·      │
   │  Ollama · vLLM · Vertex AI · Cohere · ...             │
   └───────────────────────────────────────────────────────┘

Hai thành phần state quan trọng cần hiểu rõ:

  • PostgreSQL: Lưu virtual keys, teams, spend logs, budget state. Đây là single source of truth — LiteLLM không dùng MySQL vì lý do về tính chính xác trong cập nhật budget dưới tải cao (xem FAQ chính thức của LiteLLM).
  • Redis: Lưu cache responses và shared state cho rate limiting/cooldown. Khi có nhiều pod LiteLLM, Redis là thứ cho phép chúng "nói chuyện" với nhau về việc deployment nào đang trong cooldown, budget nào sắp cạn. Hai service này được tách riêng có chủ đích: PostgreSQL ưu tiên tính toàn vẹn (ACID), Redis ưu tiên tốc độ. Trộn lẫn chức năng của hai cái sẽ phá vỡ một trong hai mục tiêu.

5. Cài Đặt và Thiết Lập

5.1 Yêu cầu hệ thống

  • Python 3.9+ (khuyến nghị 3.11)
  • PostgreSQL 14+ (bắt buộc cho proxy production — không dùng SQLite)
  • Redis 6+ (khuyến nghị, không bắt buộc tuyệt đối nhưng thực tế là cần)

5.2 Cài đặt

# Cài thư viện cơ bản (chỉ SDK)
pip install litellm

# Cài thêm dependencies cho Proxy
pip install 'litellm[proxy]'

# Kiểm tra
litellm --version

Với Docker — cách khuyến nghị cho production:

docker pull ghcr.io/berriai/litellm:main-latest

# Hoặc dùng image stable
docker pull ghcr.io/berriai/litellm-database:main-latest

5.3 Biến môi trường cơ bản

# .env

# API keys của các provider thực
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GEMINI_API_KEY=AIza...

# Master key cho LiteLLM Proxy — chỉ dùng cho admin
# Format: phải bắt đầu bằng "sk-"
LITELLM_MASTER_KEY=sk-master-very-secret-string

# Salt key dùng để mã hóa các giá trị nhạy cảm trong DB
LITELLM_SALT_KEY=sk-salt-very-secret-string

# Database
DATABASE_URL=postgresql://user:password@host:5432/litellm

# Redis (tùy chọn nhưng khuyến nghị)
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=your-password

Lưu ý quan trọng về key: LITELLM_MASTER_KEY có toàn quyền admin — chỉ dùng nó để tạo virtual key cho từng team/app, không bao giờ dùng trực tiếp trong ứng dụng. Đây là sai lầm phổ biến nhất theo bài viết "LiteLLM Virtual Keys Best Practices" trên Success Knocks.


6. Demo 1: Gọi Đa Provider Với Một Cú Pháp Duy Nhất

Đây là demo đơn giản nhất nhưng cho thấy ngay sức mạnh của LiteLLM — cùng một đoạn code, chỉ đổi tên model:

# demo_unified_api.py
import litellm
import os
from dotenv import load_dotenv

load_dotenv()

def ask(model: str, question: str) -> dict:
    """Gọi bất kỳ provider nào với cùng một interface."""
    response = litellm.completion(
        model=model,
        messages=[
            {"role": "system", "content": "Trả lời ngắn gọn trong 2 câu."},
            {"role": "user", "content": question}
        ],
        max_tokens=150,
        temperature=0.3,
    )
    return {
        "answer": response.choices[0].message.content,
        "model": response.model,
        "tokens": response.usage.total_tokens,
        "cost": litellm.completion_cost(completion_response=response),
    }

def main():
    question = "Load balancing là gì, giải thích trong 2 câu?"

    providers = [
        "openai/gpt-4o",
        "anthropic/claude-sonnet-4-20250514",
        "gemini/gemini-2.0-flash",
    ]

    print(f" {question}\n" + "="*70)

    for model in providers:
        try:
            result = ask(model, question)
            print(f"\n {result['model']}")
            print(f"   {result['answer']}")
            print(f"    ${result['cost']:.6f}  |  {result['tokens']} tokens")
        except Exception as e:
            print(f"\n  {model}: {e}")

    print("\n" + "="*70)

if __name__ == "__main__":
    main()

Output mẫu:

Load balancing là gì, giải thích trong 2 câu?
======================================================================

 gpt-4o-2024-11-20
   Load balancing là kỹ thuật phân phối các yêu cầu mạng đến nhiều
   máy chủ nhằm tối ưu hóa hiệu suất và đảm bảo tính sẵn sàng.
    $0.000245  |   87 tokens

 claude-sonnet-4-20250514
   Load balancing là việc phân phối lưu lượng truy cập đều giữa
   nhiều server backend để tránh quá tải và tăng độ tin cậy.
    $0.000312  |   92 tokens

 gemini-2.0-flash
   Load balancing phân tán traffic đến nhiều servers giúp hệ thống
   xử lý nhiều requests và tránh single point of failure.
    $0.000089  |   78 tokens

======================================================================

Cùng một hàm ask(), ba provider khác nhau, không cần if-else xử lý từng SDK riêng. Đây mới chỉ là bước "abstraction" sức mạnh thực sự đến khi ta đưa LiteLLM lên chế độ Proxy.


7. Demo 2: Khởi Động LiteLLM Proxy Server

7.1 Tạo file cấu hình tối thiểu

# litellm_config.yaml
model_list:
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_API_KEY

  - model_name: claude-sonnet
    litellm_params:
      model: anthropic/claude-sonnet-4-20250514
      api_key: os.environ/ANTHROPIC_API_KEY

  - model_name: gemini-flash
    litellm_params:
      model: gemini/gemini-2.0-flash
      api_key: os.environ/GEMINI_API_KEY

  # Load-balanced group: 3 entries cùng tên "smart-model"
  # → LiteLLM tự phân phối traffic giữa chúng
  - model_name: smart-model
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_API_KEY
  - model_name: smart-model
    litellm_params:
      model: anthropic/claude-sonnet-4-20250514
      api_key: os.environ/ANTHROPIC_API_KEY

# Fallback đơn giản
litellm_settings:
  fallbacks:
    - gpt-4o: ["claude-sonnet", "gemini-flash"]

general_settings:
  master_key: os.environ/LITELLM_MASTER_KEY

7.2 Khởi động proxy

litellm --config litellm_config.yaml --port 4000

# Sẽ thấy log:
# INFO:     Started server process [12345]
# INFO:     Uvicorn running on http://0.0.0.0:4000
# INFO:     LiteLLM Proxy: Loaded 5 models

Kiểm tra server đã sẵn sàng:

# Health check
curl http://localhost:4000/health/readiness
# {"status": "ok", "db": "connected", "cache": "redis"}

# Xem các model đang active
curl http://localhost:4000/models \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY"

7.3 Gọi proxy từ client

Không cần thay đổi code OpenAI đang có — chỉ đổi base_url:

# client.py
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["LITELLM_MASTER_KEY"],  # Tạm dùng master cho demo
    base_url="http://localhost:4000/v1",        # Trỏ về LiteLLM
)

# Mọi thứ còn lại giống hệt OpenAI gốc
response = client.chat.completions.create(
    model="smart-model",   # Load-balanced group đã định nghĩa
    messages=[
        {"role": "user", "content": "Microservices là gì?"}
    ],
)

print(response.choices[0].message.content)
print(f"Provider thực tế đã xử lý: {response.model}")

Bạn có thể chạy lại lệnh 5 lần và sẽ thấy response.model thay đổi giữa gpt-4o-2024-11-20claude-sonnet-4-20250514 đó chính là load balancing đang hoạt động.


8. Demo 3: Virtual Keys và Quản Lý Chi Phí Cơ Bản

Trong production, không bao giờ chia sẻ master key cho ứng dụng. Thay vào đó, tạo virtual key riêng cho từng team/app với budget và quyền hạn cụ thể.

8.1 Tạo virtual key cho team

curl -X POST http://localhost:4000/key/generate \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "key_alias": "team-marketing-prod",
    "max_budget": 100,
    "budget_duration": "30d",
    "tpm_limit": 200000,
    "rpm_limit": 100,
    "models": ["gpt-4o", "gemini-flash"],
    "metadata": {
      "team": "Marketing",
      "owner": "tran.thi.b@company.com",
      "env": "production"
    }
  }'

Phản hồi:

{
  "key": "sk-ls-mkt-AbCdEf123XyZ...",
  "key_name": "sk-ls-...XyZ",
  "expires": null,
  "max_budget": 100,
  "budget_duration": "30d",
  "budget_reset_at": "2026-06-30T00:00:00Z",
  "tpm_limit": 200000,
  "rpm_limit": 100,
  "models": ["gpt-4o", "gemini-flash"]
}

Lúc này team Marketing có một "thẻ tín dụng AI" riêng của họ:

  • Budget cứng $100/tháng — vượt sẽ bị chặn
  • Chỉ được gọi gpt-4ogemini-flash
  • Tối đa 100 requests/phút và 200K tokens/phút
  • Tự động reset budget sau 30 ngày

8.2 Team dùng key của họ

client = OpenAI(
    api_key="sk-ls-mkt-AbCdEf123XyZ...",     # Key riêng của team
    base_url="http://litellm-proxy:4000/v1"
)

# Nếu thử gọi model không nằm trong whitelist
response = client.chat.completions.create(
    model="claude-sonnet",  # Không có trong whitelist của key
    messages=[...]
)
# → Lỗi: "Model 'claude-sonnet' not allowed for this key"

8.3 Theo dõi chi phí

# Xem thông tin và spend hiện tại của key
curl http://localhost:4000/key/info?key=sk-ls-mkt-AbCdEf123XyZ... \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY"
{
  "key_name": "sk-ls-...XyZ",
  "spend": 23.45,
  "max_budget": 100,
  "budget_reset_at": "2026-06-30T00:00:00Z",
  "models": ["gpt-4o", "gemini-flash"],
  "metadata": {"team": "Marketing", "env": "production"}
}

Tài Liệu Tham Khảo — Phần 1


→ Tiếp tục với Phần 2: Triển Khai Nâng Cao


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí