SSD Nodes Learn Hosting plans →
Hướng dẫn Matt ConnorBởi Matt Connor

Tự host LiteLLM làm gateway LLM trên VPS

Dùng một endpoint OpenAI compatible cho mọi provider với LiteLLM trên VPS: virtual key, ngân sách theo key, fallback và image được pin phiên bản.

Gateway LLM tự host làm được gì

LiteLLM là một gateway LLM mã nguồn mở mà bạn tự host: một HTTP endpoint duy nhất mà tất cả ứng dụng của bạn gọi đến, sau đó nó chuyển tiếp mỗi request tới nhà cung cấp phù hợp để xử lý. LLM là viết tắt của large language model. Gateway này sử dụng OpenAI chat completions API (application programming interface), vì vậy bất kỳ thư viện client nào đã hỗ trợ OpenAI đều hoạt động được với nó sau khi thay đổi hai thông số: base URL và key.

Lớp trung gian đó chính là mục đích sử dụng. Các ứng dụng của bạn không cần lưu trữ credential của nhà cung cấp nữa. Việc đổi model chỉ cần sửa một dòng trong file cấu hình trên server thay vì phải thay đổi code ở năm dịch vụ khác nhau. Và vì mọi cuộc gọi đều đi qua một tiến trình, bạn có nơi để thiết lập ngân sách và lưu lại hồ sơ về chi phí đã phát sinh.

Dưới đây là những gì bạn có khi hệ thống đã chạy:

  • Một endpoint duy nhất. Các ứng dụng trỏ tới https://gateway.example.com/v1 và yêu cầu một tên model do bạn tự đặt, ví dụ như bulk hoặc strong.
  • Virtual key. Mỗi ứng dụng nhận một key riêng với danh sách model được phép truy cập và hạn mức chi tiêu riêng. Bạn có thể thu hồi một key mà không ảnh hưởng đến các key khác.
  • Cơ chế fallback. Một cuộc gọi thất bại hoặc một prompt quá lớn sẽ được tự động thử lại với một model khác.
  • Hồ sơ log. Mỗi request ghi lại một dòng kèm theo chi phí, nhờ đó câu hỏi "ứng dụng nào đã chi khoản đó" sẽ có câu trả lời.

Vì sao nên tự chạy gateway

Một router được quản lý có cùng mô hình, nhưng có thêm quy trình của bên khác đứng giữa mọi request. Tự chạy gateway giúp giữ provider key và nội dung prompt trên máy chủ do bạn kiểm soát. Chi phí vận hành là có thật: giờ đây bạn phải quản lý component mà mọi ứng dụng đều phụ thuộc vào. Phần cuối của hướng dẫn này tập trung vào chi phí đó, vì đây là phần mà hầu hết tài liệu thường bỏ qua.

Cần chuẩn bị

  • Một VPS (máy chủ riêng ảo) chạy Ubuntu 24.04, đã cài Docker và plugin Compose.
  • Một tên miền trỏ đến VPS đó nếu các máy bên ngoài sẽ truy cập gateway qua TLS (bảo mật tầng truyền tải).
  • Ít nhất một API key của provider.

Gateway không chạy inference. Gateway chuyển tiếp request và stream câu trả lời về cho client, nên tải CPU phụ thuộc vào số lượng request thay vì kích thước model. Một máy có 1 vCPU có thể chạy ổn một số ứng dụng nội bộ. Phần tăng lên là database, vì gateway ghi một bản ghi chi phí cho mỗi request.

Viết config.yaml trước

File cấu hình quyết định client được phép yêu cầu model nào. Có 4 section cấp cao cần chú ý: model_list, litellm_settings, router_settings và general_settings.

model_list:
  - model_name: bulk
    litellm_params:
      model: anthropic/claude-haiku-4-5
      api_key: os.environ/ANTHROPIC_API_KEY
  - model_name: strong
    litellm_params:
      model: anthropic/claude-sonnet-5
      api_key: os.environ/ANTHROPIC_API_KEY
  - model_name: strong
    litellm_params:
      model: openai/gpt-5.5
      api_key: os.environ/OPENAI_API_KEY

litellm_settings:
  num_retries: 2
  request_timeout: 120
  json_logs: true
  set_verbose: false

router_settings:
  allowed_fails: 3
  cooldown_time: 30
  fallbacks: [{"bulk": ["strong"]}]
  context_window_fallbacks: [{"bulk": ["strong"]}]

general_settings:
  background_health_checks: true
  health_check_interval: 300

model_name là tên client gửi lên. litellm_params.model là model thực tế, được ghi dưới dạng provider/model. Hãy đặt tên model theo công việc thay vì theo vendor. Một ứng dụng yêu cầu bulk sẽ tiếp tục hoạt động khi tháng sau bạn quyết định bulk phải dùng một model khác.

api_key: os.environ/ANTHROPIC_API_KEY yêu cầu LiteLLM đọc biến đó lúc runtime. Key cụ thể không xuất hiện trong file. Điều này quan trọng vì bạn commit file config.yaml.

Hai entry cùng dùng tên strong, và đây là chủ ý. Khi nhiều deployment có cùng model_name, router xem chúng là các deployment có thể thay thế cho nhau và phân phối request mang tên đó giữa chúng. Đây là cách strong vẫn hoạt động khi một provider gặp sự cố trong một khoảng thời gian: khi một deployment đã được đưa vào cooldown (bên dưới), các request mới cho strong sẽ được chuyển sang deployment còn lại.

num_retries: 2 retry lỗi có thể retry tối đa 2 lần. Các lần retry đó có thể chọn một deployment khác đang khả dụng trong cùng model group: tài liệu kiến trúc của LiteLLM, được kiểm tra vào 2026-10-29, mô tả retry trong group và fallback giữa các group là 2 bước riêng biệt. Vì vậy, retry cho strong có thể chạy trên provider còn lại mà không cần bật weighted failover. Fallback chỉ chạy sau khi đã dùng hết các lần retry đó.

allowed_fails và cooldown_time là các tùy chọn của router, nên chúng nằm dưới router_settings. Proxy tạo router từ section đó. Trong v1.95.0, nếu ghi cooldown_time dưới litellm_settings thì nó không bao giờ đến được router, nên cooldown âm thầm giữ giá trị mặc định là 5 giây. cooldown_time: 30 đặt thời gian deployment bị loại khỏi vòng phân phối sau khi được đưa vào cooldown. Tài liệu tham chiếu cấu hình mô tả allowed_fails là số lỗi mà deployment phải vượt qua trong khoảng cooldown_time trước khi bị đưa vào cooldown. Trong source của v1.95.0, allowed_fails: 3 là giá trị mặc định. Với giá trị mặc định này, router dùng các trigger tích hợp sẵn; ngưỡng số lỗi chỉ có tác dụng khi bạn đặt một giá trị khác. Các trigger đó gồm: đưa vào cooldown ngay khi nhận response 429 đối với group có nhiều hơn 1 deployment; có hơn 50% request lỗi trong phút hiện tại sau ít nhất 5 request đối với group như vậy; và các lỗi router sẽ không retry, chẳng hạn response 401 do key sai. Một trigger riêng cũng đưa một deployment duy nhất vào cooldown khi tất cả request trong phút hiện tại đều lỗi và lưu lượng đạt SINGLE_DEPLOYMENT_TRAFFIC_FAILURE_THRESHOLD; giá trị mặc định là 1000 request. Provider trả về lỗi 500 liên tục sẽ không bị thử lại ở từng request, còn một lỗi 500 ngẫu nhiên mỗi vài phút sẽ không kích hoạt cooldown.

fallbacks và context_window_fallbacks có các trigger khác nhau, trong đó trigger thứ hai hữu ích nhưng thường bị bỏ qua.

  • fallbacks chạy khi call chính thất bại.
  • context_window_fallbacks chạy khi provider từ chối request vì request dài hơn context window của model đó. Khi đó, prompt quá lớn được chuyển đến model còn đủ chỗ thay vì trả lỗi cho caller.

Ngoài ra còn có content_policy_fallbacks, dùng khi provider từ chối request vì policy về nội dung. Chỉ bật tùy chọn này nếu bạn có nơi hợp lý để chuyển các call đó đến.

Triển khai LiteLLM trên VPS bằng Docker Compose

Tạo một thư mục chứa 3 file: config.yaml, docker-compose.yml và .env. Quickstart của upstream kéo tag latest. Hãy ghim một release tag cụ thể thay vào đó, để docker compose up -d vào tháng sau vẫn cung cấp cùng gateway như hôm nay, đồng thời rollback chỉ cần một dòng.

services:
  litellm:
    image: ghcr.io/berriai/litellm:v1.95.0
    restart: unless-stopped
    command: ["--config", "/app/config.yaml", "--num_workers", "1"]
    ports:
      - "127.0.0.1:4000:4000"
    volumes:
      - ./config.yaml:/app/config.yaml:ro
    env_file: .env
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16
    restart: unless-stopped
    environment:
      POSTGRES_USER: litellm
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
      POSTGRES_DB: litellm
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U litellm"]
      interval: 5s
      timeout: 5s
      retries: 10
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

Compose đọc .env hai lần ở đây. Một lần để thay thế ${POSTGRES_PASSWORD} bên trong chính file compose, và một lần thông qua env_file để truyền mọi biến vào container.

v1.95.0 là release hiện tại vào tháng 8 năm 2026. Hãy kiểm tra trang releases của dự án và ghim phiên bản hiện tại tại thời điểm triển khai. Mỗi release đều công bố một chữ ký, nên bạn có thể kiểm tra image trước khi tin cậy image đó:

cosign verify --key https://raw.githubusercontent.com/BerriAI/litellm/v1.95.0/cosign.pub ghcr.io/berriai/litellm:v1.95.0

Dòng port là 127.0.0.1:4000:4000, chỉ publish port trên loopback interface. Nếu viết 4000:4000, gateway sẽ có thể được truy cập từ toàn bộ Internet, vì Docker tự thêm rule vào chuỗi FORWARD của iptables và các rule này được đánh giá trước rule của ufw, nên ufw deny 4000 không chặn được. Đây là cách phổ biến nhất khiến một gateway tự host bị mở ra Internet: xem cách Docker publish port của container vượt qua ufw. Lưu lượng từ bên ngoài sẽ đi qua reverse proxy.

Không đưa key của provider vào image

File .env chứa toàn bộ secret. File này được truyền vào dưới dạng biến môi trường khi chạy, nên không bao giờ được ghi sẵn vào image và cũng không bao giờ được commit.

LITELLM_MASTER_KEY=sk-REPLACE_ME
LITELLM_SALT_KEY=sk-REPLACE_ME_TOO
POSTGRES_PASSWORD=REPLACE_ME_AS_WELL
DATABASE_URL=postgresql://litellm:REPLACE_ME_AS_WELL@db:5432/litellm
STORE_MODEL_IN_DB=True
LITELLM_MODE=PRODUCTION
LITELLM_LOG=ERROR
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-proj-...

Tạo hai key của LiteLLM bằng nguồn ngẫu nhiên thực sự, sau đó giới hạn quyền truy cập file:

printf 'sk-%s\n' "$(openssl rand -hex 32)"
chmod 600 .env

LITELLM_MASTER_KEY là credential quản trị. Nó dùng để xác thực management API và là mật khẩu cho Admin UI tại /ui. Không ứng dụng nào được giữ credential này.

LITELLM_SALT_KEY mã hóa credential của provider được lưu trong database. Hãy đặt giá trị này một lần rồi giữ nguyên. Nếu thay đổi sau đó, các credential đã lưu sẽ không thể giải mã. Gateway vẫn khởi động bình thường, nhưng mọi lần gọi đến các provider đó đều thất bại do lỗi xác thực.

STORE_MODEL_IN_DB=True cho phép bạn thêm và chỉnh sửa model từ Admin UI mà không cần sửa config.yaml. Cách này tiện, nhưng khiến source of truth bị chia thành hai nơi. Hãy quyết định nơi nào là nguồn chính thức và ghi lại quyết định đó ngay cạnh config.

Lý do không đưa key vào file config cũng giống lý do không đưa chúng vào các công cụ bạn cung cấp cho agent. Không đưa secret của provider vào AI agent trình bày mẫu triển khai này, còn file env và secret trong Docker Compose trình bày các thao tác cụ thể.

Khởi động dịch vụ và theo dõi lần boot đầu tiên:

docker compose up -d
docker compose logs -f litellm

Kiểm tra xem hệ thống có thực sự hoạt động không

Có 2 probe không cần xác thực và 1 probe có xác thực. Chúng có thể thất bại vì các nguyên nhân khác nhau.

curl -s http://127.0.0.1:4000/health/liveliness
curl -s http://127.0.0.1:4000/health/readiness

/health/liveliness không cần xác thực và trả về "I'm alive!" khi tiến trình đang chạy. /health/readiness cũng không cần xác thực. Endpoint này trả về một object JSON có trường "status": "healthy" và trường db, hoặc trả về 503 khi không thể truy cập database. Hãy cấu hình hệ thống monitoring kiểm tra readiness, vì liveliness vẫn có thể ở trạng thái xanh trên một gateway không thể tra cứu dù chỉ một virtual key.

Probe có xác thực là probe giao tiếp với các provider:

curl -s http://127.0.0.1:4000/health \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY"

Probe này trả về các mảng healthy_endpoints và unhealthy_endpoints. Nếu một model nằm trong unhealthy_endpoints kèm lỗi xác thực, provider key trong .env bị sai hoặc bị thiếu. Đây là lỗi bạn cần tìm lúc này. Vì background_health_checks: true được bật, proxy tự chạy các probe này mỗi health_check_interval giây. /health trả về kết quả gần nhất, nên việc polling endpoint này không gửi test request đến các provider mỗi lần.

Khóa ảo và ngân sách riêng cho từng khóa

Mỗi ứng dụng có một key riêng, được tạo dựa trên master key.

curl -s http://127.0.0.1:4000/key/generate \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "key_alias": "nightly-summariser",
    "models": ["bulk"],
    "max_budget": 5,
    "budget_duration": "30d",
    "rpm_limit": 60,
    "tpm_limit": 200000
  }'

Response chứa một field key bắt đầu bằng sk-. Chuỗi đó là thứ ứng dụng nhận được, và ứng dụng không bao giờ nhận được bất kỳ thứ gì khác.

  • models là allowlist xác định những gì key này được phép request. Key ở trên chỉ có thể yêu cầu bulk, không được yêu cầu gì khác.
  • max_budget: 5 với budget_duration: "30d" là 5 đô la Mỹ cho mỗi tháng dương lịch. LiteLLM reset ngân sách 30d vào lúc 00:00 ngày 1 mỗi tháng, theo UTC trừ khi bạn đặt timezone trong litellm_settings, thay vì tính theo chu kỳ 30 ngày trượt. Vì vậy, khi key đã tiêu hết 5 đô la, key sẽ ngừng hoạt động cho đến ngày 1 tiếp theo.
  • rpm_limit và tpm_limit giới hạn số request mỗi phút và số token mỗi phút riêng cho key này.
  • key_alias là tên bạn sẽ nhận ra trong spend log sau 6 tuần. Luôn đặt giá trị này.

Khi ngân sách đã hết, call sẽ fail với error type budget_exceeded và message có dạng sau:

Budget has been exceeded! Key=<key> Current cost: <spend>, Max budget: <max_budget>

Status code phụ thuộc vào release. Ở v1.95.0 được ghim, đó là HTTP 429. Từ v1.104.0, mặc định là HTTP 422; đặt budget_exceeded_status_code: 429 trong litellm_settings sẽ khôi phục status code trước đây. Các trường hợp thực sự chạm giới hạn rpm_limit và tpm_limit vẫn trả về 429 ở cả hai release. Sau mỗi lần upgrade, hãy kiểm tra bạn đang nhận status code nào.

Status code là nguyên nhân khiến việc này khó chẩn đoán, vì không code nào trong hai code cho biết "budget". Client library thường báo 429 là rate limit và có thể retry với backoff trong khi budget sẽ không quay lại cho đến lần reset tiếp theo. Client library cũng báo 422 là request không thể được xử lý. Hãy log response body cùng với status code. Nếu không, mỗi lần hết budget sẽ trông giống một lỗi khác.

Dùng cùng management API để kiểm tra và điều chỉnh các key:

curl -s "http://127.0.0.1:4000/key/info?key=sk-..." \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY"

curl -s -X POST http://127.0.0.1:4000/key/update \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"key": "sk-...", "max_budget": 25}'

Budget được enforce tại gateway vẫn có hiệu lực ngay cả khi vấn đề nằm ở chính agent. Vì vậy, đây là nền tảng của việc kiểm soát chi phí cho AI agent trên VPS.

Chuyển tác vụ hàng loạt sang model giá rẻ

Trỏ client vào gateway. Base URL, key và tên model:

curl -s http://127.0.0.1:4000/v1/chat/completions \
  -H "Authorization: Bearer sk-<the virtual key>" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "bulk",
    "messages": [{"role": "user", "content": "Say hello in five words."}]
  }'

Mọi thư viện client OpenAI đều hoạt động theo cùng cách: đặt base_url thành https://gateway.example.com/v1 và api_key thành virtual key.

Routing policy trong config.yaml hiện được áp dụng mà caller không cần biết. Request cho bulk sẽ được chuyển đến model giá rẻ. Nếu lần gọi đó thất bại sau khi đã retry, request sẽ được retry với strong. Nếu prompt quá dài đối với bulk, context_window_fallbacks sẽ chuyển nó sang strong thay vì trả về lỗi. Các tác vụ hàng loạt như chạy phân loại hoặc tóm tắt backlog mặc định sẽ dùng model giá rẻ, chỉ những request khó mới tốn nhiều chi phí hơn.

Đây cũng là trường hợp gateway phát huy giá trị với các agent sử dụng tool. Một MCP (model context protocol) server trên cùng VPS và agent điều khiển nó đều có thể trỏ đến một endpoint, nên có thể thay đổi model phía sau mà không cần redeploy bất kỳ thành phần nào.

Làm sao biết đã xảy ra fallback?

Đây là kiểu lỗi gây tốn tiền vì không có dấu hiệu rõ ràng. Fallback thành công trả về HTTP 200 cùng một response body bình thường. Model giá rẻ có thể ngừng hoạt động cả ngày, mọi request vẫn âm thầm được xử lý bằng model đắt tiền, và bằng chứng đầu tiên là hóa đơn.

Bằng chứng nằm trong response header. Hãy yêu cầu các header này:

curl -s -D - -o /dev/null http://127.0.0.1:4000/v1/chat/completions \
  -H "Authorization: Bearer sk-<the virtual key>" \
  -H 'Content-Type: application/json' \
  -d '{"model":"bulk","messages":[{"role":"user","content":"ping"}]}' \
  | grep -i '^x-litellm'
  • x-litellm-model-group là tên model mà request được định tuyến đến, chẳng hạn bulk. x-litellm-model-id là ID của deployment đã trả lời request; bạn có thể tra ID này bằng /v1/model/info?litellm_model_id=.... Nếu ID đó không thuộc các deployment bulk của bạn thì đã xảy ra fallback.
  • x-litellm-attempted-fallbacks và x-litellm-attempted-retries đếm số lần fallback. Trong một request bình thường, không giá trị nào được lớn hơn 0.
  • x-litellm-response-cost là chi phí của request đó, tính bằng đô la Mỹ.
  • x-litellm-call-id là identifier dùng để tìm cùng request đó trong log.

Ghi lại x-litellm-attempted-fallbacks cho mọi request và tạo alert khi giá trị này lớn hơn 0. Con số đó cho biết sự khác biệt giữa routing policy hoạt động đúng và routing policy đã âm thầm chuyển thành “luôn dùng model đắt tiền”.

Cách đầy đủ để làm việc này là tracing và cần một quy trình setup riêng: tự host Langfuse để tracing các agent call. LiteLLM đã có sẵn callback, nên việc kết nối chỉ cần 2 dòng và credentials.

litellm_settings:
  success_callback: ["langfuse"]
  failure_callback: ["langfuse"]
LANGFUSE_PUBLIC_KEY=pk-lf-...
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_HOST=https://langfuse.example.com

Với Langfuse v3 trở lên, trang Langfuse của LiteLLM hiện khuyến nghị preset langfuse_otel; callback langfuse ở trên vẫn được document. Hãy cấu hình cả failure_callback và success_callback. Nếu bỏ qua, bạn chỉ lưu được những trace mà không có lỗi. Ngoài các phần này, LiteLLM ghi một spend row cho mỗi request vào Postgres, còn Admin UI tại /ui đọc bảng đó. Bảng sẽ tăng theo traffic, vì vậy hãy theo dõi nếu disk còn ít dung lượng.

Đặt gateway phía sau reverse proxy

Không được để bất kỳ thứ gì bên ngoài máy chủ truy cập cổng 4000. Terminate TLS trong nginx hoặc Caddy rồi forward đến địa chỉ loopback.

location / {
    proxy_pass http://127.0.0.1:4000;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_buffering off;
    proxy_read_timeout 600s;
}

Hai dòng đó thường bị bỏ qua. proxy_buffering off quan trọng vì một streaming completion là một chuỗi server-sent event. Khi bật buffering, nginx sẽ gom các chunk vào buffer trước khi forward, làm chậm việc gửi dữ liệu đến client. proxy_read_timeout 600s quan trọng vì mặc định 60 giây của nginx là khoảng thời gian tối đa nginx chờ giữa hai lần đọc từ gateway, không phải giới hạn cho toàn bộ response. Completion không streaming sẽ không gửi gì cho đến khi generation hoàn tất. Vì vậy, một completion dài sẽ vượt quá 60 giây mà không có byte nào được gửi đến, client nhận 504 và error log ghi lại upstream timed out (110: Connection timed out) while reading response header from upstream. Completion streaming vẫn có thể chạy lâu hơn 60 giây nếu liên tục gửi chunk; timeout chỉ xảy ra khi model không gửi dữ liệu trong khoảng thời gian đó.

Để cấp certificate, Certbot với Let's Encrypt trên nginx là cách ngắn gọn nhất. Nếu máy chủ đã chạy nhiều container, Traefik phía trước nhiều ứng dụng Compose sẽ xử lý routing và certificate tại một nơi.

Gateway hiện là điểm lỗi đơn

Hãy đánh giá đúng những gì bạn đã xây dựng. Mọi ứng dụng bạn sở hữu hiện đều phụ thuộc vào một container trên một VPS. Khi container đó ngừng hoạt động, không ứng dụng nào có thể gọi bất kỳ model nào, kể cả các provider vẫn đang hoạt động bình thường. Điều này dẫn đến 4 vấn đề.

  • Cấu hình sai khiến mọi thứ ngừng hoạt động cùng lúc. restart: unless-stopped khởi động lại tiến trình bị crash, đồng thời liên tục khởi động lại container không thể đọc config.yaml. Hãy đọc docker compose logs litellm sau mỗi lần thay đổi cấu hình và chỉ thay đổi cấu hình khi bạn có thời gian theo dõi.
  • Postgres nằm trong đường đi của request khi cache miss. Việc tra cứu virtual key sử dụng Postgres khi key chưa có trong cache; việc ghi chi phí chạy bất đồng bộ sau khi trả response. /health/readiness trả về 503 là cảnh báo rằng gateway vẫn đang chạy nhưng không thể thực hiện cả hai việc này.
  • Dùng hết số core trước, rồi mới thêm instance. Khuyến nghị production của dự án là một worker cho mỗi instance (--num_workers 1), áp dụng cho Kubernetes hoặc một pod autoscaler khác có thể tự thêm instance. Với một VM hoặc bare container như hệ thống này, khuyến nghị đó có ý ngược lại: đặt số worker bằng số vCPU của máy. Trên máy 1 vCPU ở trên, giá trị đó vẫn là --num_workers 1; nếu máy lớn hơn, hãy tăng giá trị này và nhớ rằng mỗi worker sử dụng bộ nhớ riêng. Thêm một gateway thứ hai phía sau load balancer sẽ loại bỏ container đơn lẻ khỏi điểm lỗi này. Tuy nhiên, database vẫn còn là một điểm lỗi.
  • Sao lưu những thứ không thể tạo lại. Đó là config.yaml và .env, cùng với một pg_dump của database. Mất LITELLM_SALT_KEY sẽ khiến thông tin xác thực đã mã hóa của provider trong bản dump đó trở nên vô dụng. Vì vậy, env file và bản dump phải nằm trong cùng một backup job: backup restic vào storage bên ngoài máy chủ.

Để nâng cấp, hãy sửa image tag rồi chạy docker compose up -d. Theo mặc định, LiteLLM chạy prisma migrate deploy khi khởi động, nên container mới sẽ migrate schema của database trong lần boot đầu tiên. Hãy tạo bản dump trước khi đổi tag, vì đưa image cũ trở lại không hoàn tác được migration đã chạy.

Hãy đọc release notes của mọi version bạn bỏ qua, không chỉ version bạn nâng cấp đến. Việc chuyển từ v1.95.0 lên v1.104.0 hoặc mới hơn sẽ đi qua nhiều breaking change: status code cho budget ở trên, proxy từ chối khởi động khi master key chưa được đặt, để trống hoặc là key đã được công khai, và proxy thoát khi việc thiết lập database thất bại lúc khởi động; dưới restart: unless-stopped, lỗi này xuất hiện dưới dạng restart loop. Nếu nâng cấp từ v1.102.x hoặc cũ hơn, release notes của v1.104.0 cũng yêu cầu bạn tự tạo 2 index LiteLLM_SpendLogs.

FAQ

LiteLLM có làm tăng độ trễ đáng kể cho mọi lần gọi không?

Dự án công bố độ trễ 8 ms ở percentile 95 với 1000 request mỗi giây, theo README vào tháng 10 năm 2026. Hãy xem đây là số liệu do vendor cung cấp. Yếu tố thực sự làm thay đổi độ trễ là khoảng cách mạng giữa các ứng dụng của bạn và gateway, vì bạn đã thêm một round trip vào mỗi lần gọi. Chạy gateway trong cùng region với các ứng dụng gọi đến nó, sau đó đo overhead thực tế bằng header x-litellm-overhead-duration-ms trên một response thực.

Vì sao streaming ngừng hoạt động sau khi tôi đặt nginx phía trước?

Vì nginx mặc định buffer response từ upstream, trong khi một streaming completion là chuỗi server-sent event. Khi bật proxy_buffering, nginx thu thập các chunk vào buffer trước khi chuyển tiếp, làm chậm việc gửi dữ liệu đến client. Đặt proxy_buffering off; trong location block. Đồng thời tăng proxy_read_timeout trong cùng block. Mặc định, nginx sẽ từ bỏ sau 60 giây không nhận được dữ liệu từ gateway. Một lần generate không streaming kéo dài dễ đạt đến thời hạn này, khiến client nhận 504.

Điều gì xảy ra khi virtual key hết budget?

Lần gọi sẽ fail với error type budget_exceeded và message có dạng Budget has been exceeded! Key=<key> Current cost: <spend>, Max budget: <max_budget>. Trong phiên bản cố định v1.95.0, status là HTTP 429; từ v1.104.0, mặc định là HTTP 422. Không code nào trong hai code này nói rõ về budget. Đây là điểm dễ nhầm: client library báo 429 là rate limit và có thể retry, nên mọi người bắt đầu truy tìm throttling thay vì đọc message. Hãy log response body cùng với status code. Xác nhận vị trí thực tế của key bằng /key/info?key=sk-... với master key, rồi tăng giới hạn bằng /key/update nếu budget được đặt quá thấp.

Gateway có thể route đến model local cũng như các model hosted không?

Có. Đây là một entry khác trong model_list. Dùng prefix ollama_chat/ cùng với một api_base, ví dụ model: ollama_chat/llama3.1 bên cạnh api_base: http://ollama:11434. Với networking mặc định của Compose, localhost bên trong container có nghĩa là chính container đó. Vì vậy, hãy dùng tên Compose service hoặc địa chỉ của host trên Docker network, tuyệt đối không dùng 127.0.0.1. Host networking, trong đó container dùng chung network stack của host, là ngoại lệ. Dựng model local là một công việc riêng; xem tự host LLM bằng Ollama trên VPS.

Bài viết này có hữu ích không?