Cách bạn thực sự gắn AI vào một web app: tự chạy model trên server, hoặc gọi API có sẵn. Cả hai đều chỉ là một HTTP service khác.
← / → để chuyển slide · chuyển EN/VI bên dưới
App của bạn đã nói chuyện qua HTTP (Flask, curl, nginx). AI chỉ là một thứ nữa nó có thể gọi qua cùng đường truyền đó — câu hỏi duy nhất là ai chạy model.
hỏi app của bạn một câu
/ask — chuyển tới model
cùng một lời gọi HTTP trong cả hai trường hợp — chỉ địa chỉ (và ai trả tiền) thay đổi
Chỉ có đúng hai hình dạng. Mọi thứ trong chủ đề này đều là chi tiết của một trong hai thứ đó.
Bạn tải file model về và tự serve bằng llama-server của llama.cpp. Nó trở thành endpoint HTTP cục bộ trả lời các request chat. Bạn sở hữu nó, nó nằm ngay trên máy của bạn.
Người khác chạy model. Bạn gửi request tới một URL (ví dụ OpenRouter) kèm API key và trả tiền theo token. Không phần cứng, không setup — chỉ một lời gọi HTTP tới nhà cung cấp.
AI không phải một loại công nghệ mới cho app của bạn. Nó chỉ là một service nữa bạn gọi qua HTTP — như database, như bất kỳ API bên thứ ba nào. Bạn gửi một message, nó gửi văn bản trả về.
Quyết định duy nhất định hình mọi thứ: bạn tự chạy model, hay người khác chạy?
Đây không phải khác biệt kỹ thuật — mà là khác biệt về kinh tế và quyền kiểm soát. Code phía bạn gần như giống hệt nhau.
Model chạy trên VPS của bạn. Prompt và dữ liệu của bạn không bao giờ rời máy. Không phí theo token — bạn trả tiền server và tiền điện.
Thắng về riêng tư, kiểm soát, chi phí vận hành. Đổi lại bạn trả bằng công setup, phần cứng và khả năng scale.
Model chạy trên GPU của nhà cung cấp. Prompt của bạn đi qua internet tới đó. Bạn trả theo token, chỉ khi dùng, và có thể đổi model bất cứ lúc nào.
Thắng về scale, công sức, và đa dạng. Đổi lại bạn trả phí theo token và dữ liệu rời khỏi máy.
Hầu hết sản phẩm thực tế nằm đâu đó ở giữa — hoặc chọn đầu khác cho từng tính năng. Bạn dịch chuyển trên trục này khi nhu cầu thay đổi.
Riêng tư, kiểm soát, chi phí cố định. Dữ liệu không rời máy. Nhưng bạn cũng tự chịu mọi hỏng hóc.
Scale, đa dạng, không setup. Chọn bất kỳ model nào, trả theo dùng. Prompt của bạn đi tới nhà cung cấp.
code giống nhau — chỉ endpoint và hóa đơn khác nhau
Cùng một request phía bạn. Năm hàng này là toàn bộ quyết định.
| Tiêu chí | 🏠 Tự host | ☁️ Có sẵn |
|---|---|---|
| Ai chạy model | Bạn — trên VPS của bạn | Nhà cung cấp — trên GPU của họ |
| Dữ liệu đi đâu | Ở lại trên máy của bạn | Đi qua internet tới họ |
| Chi phí trước / cố định | Server + GPU/RAM bạn phải mua | Không — không phần cứng |
| Chi phí theo dùng | Không theo request (bạn trả tiền server) | Trả theo token, chỉ khi dùng |
| Lựa chọn model & scale | Bị giới hạn bởi phần cứng | Hàng trăm model, scale linh hoạt |
Dù bạn gọi cái nào — local hay hosted — request và response luôn có hình dạng này. Vì vậy code gần như không đổi.
Một danh sách messages — mỗi cái có role (system / user / assistant) và nội dung. Đây là toàn bộ prompt.
Một POST tới URL /v1/chat/completions, kèm thân JSON. Cùng verb và hình dạng bạn đã dùng với curl suốt khóa.
Một JSON trả lời duy nhất — hoặc một stream trong đó token đến lần lượt. Dù thế nào: văn bản ra, đó là toàn bộ công việc.
Model thực sự là gì, bạn serve nó ra sao, và vì sao kích thước model là toàn bộ cuộc chơi.
Không có phép thuật. Một model đã được huấn luyện là một file chứa các con số (trọng số). Bạn nạp nó, nó chạy, và nó mở một endpoint HTTP.
Model là một file duy nhất — thường ở định dạng GGUF cho llama.cpp. Tải về là của bạn. 8B ≈ vài GB trên đĩa.
llama-server đọc file vào RAM/VRAM, rồi lắng nghe một port và trả lời request. Nó hoạt động như một server nhỏ.
Endpoint tương thích OpenAI — cùng hình dạng /v1/chat/completions như mọi nhà cung cấp có sẵn. Vì vậy code của bạn giống hệt.
Tải binary llama-server, cho nó chạy được, và khởi động nó trỏ tới file model. Giờ nó trả lời trên :8080.
Hai thứ tranh giành bộ nhớ máy bạn: chính model, và context (cuộc hội thoại nó phải nhớ). Kích thước quyết định cả hai.
Model 8B cần khoảng 6–8 GB RAM/VRAM chỉ để nạp. Model 70B cần nhiều hơn nhiều — hầu hết VPS nhỏ đơn giản không giữ nổi.
Mỗi token của hội thoại tốn bộ nhớ. --ctx-size lớn hơn nghĩa là hội thoại dài hơn nhưng tốn RAM hơn. Bạn chỉnh để khớp với model.
Trên một máy có bộ nhớ cố định bạn không thể có tất cả. Đây là giằng co thường ngày khi chạy model cục bộ.
Nạp model lớn nhất mà RAM của bạn cho phép. Trả lời thông minh hơn, nhưng model chỉ nhìn thấy một cửa sổ nhỏ của hội thoại.
Tốt cho hỏi-đáp một lượt trên phần cứng khiêm tốn.
Chọn model nhỏ hơn để còn chỗ cho một hội thoại dài, một file to, hay một tài liệu dài cần xử lý.
Tốt cho xử lý tài liệu hoặc các luồng chat dài.
Số liệu gần đúng cho model 4-bit. Con số chính xác của bạn thay đổi theo model và cách nén — đây là hình dạng để bạn lên kế hoạch theo.
| Kích thước model | RAM/VRAM cần để nạp (gần đúng) | Vừa ở đâu |
|---|---|---|
| ~7–8B | ≈ 6–8 GB | VPS 16 GB, thoải mái, còn chỗ cho context |
| ~13B | ≈ 10–12 GB | VPS 16 GB, chật hơn — context giảm |
| ~30–34B | ≈ 20–24 GB | Máy 32 GB, hoặc GPU có VRAM cỡ đó |
| ~70B | ≈ 40–48 GB | Nhiều GPU hoặc máy VRAM lớn — không phải VPS nhỏ |
Một request vào, một trả lời ra. Nó nói hình dạng tương thích OpenAI — nên local và hosted trông giống hệt.
Thân là một danh sách messages cộng vài núm chỉnh. model đặt tên model, messages là toàn bộ hội thoại, stream yêu cầu token lần-lượt.
{
"model": "llama-3.1-8b",
"messages": [
{"role": "user", "content": "Explain what a reverse proxy is, in one sentence."}
],
"max_tokens": 120,
"temperature": 0.7,
"stream": true
}
Đó là toàn bộ request. role gồm system / user / assistant; content là nội dung.
Một POST tới endpoint cục bộ. Thân -d đúng là JSON ở trên — không thêm, không bớt.
# local llama-server, OpenAI-compatible
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "llama-3.1-8b",
"messages": [{"role": "user", "content": "Hello there"}]
}'
Cùng verb, cùng path, cùng thân bạn gửi cho bất kỳ provider nào — chỉ host là 127.0.0.1.
Flag stream là khác biệt giữa một chat phải chờ và một chat tự gõ. Cùng request, khác cách đóng gói response.
Server suy ra toàn bộ câu trả lời, rồi trả về như một object JSON duy nhất. Đơn giản, nhưng người dùng phải chờ và không thấy gì tới khi xong.
Đủ dùng cho các câu trả lời ngắn, một lượt.
Server gửi câu trả lời thành một chuỗi các khối nhỏ, mỗi khối vài token kế tiếp. UI của bạn vẽ chúng khi đến — hiệu ứng đang gõ.
Cảm giác mặc định của mọi chat app hiện đại.
Với stream: true, response là một chuỗi các dòng data:. Mỗi dòng mang một mảnh tiếp theo; [DONE] đánh dấu kết thúc.
Bỏ qua phần cứng. Một key mở ra cổng dẫn tới hàng trăm model từ nhiều nhà cung cấp.
OpenRouter là một router đứng trước nhiều nhà cung cấp. Bạn gọi một URL; nó chuyển tiếp tới đúng model bạn đặt tên.
Trường model là toàn bộ công tắc — openai/gpt-4o-mini, anthropic/claude, một model cục bộ, và nhiều hơn, tất cả trong một trường.
Một token Bearer duy nhất dùng được cho mọi model trên nền tảng. Không phải juggling key từng provider trong app.
Bạn bị tính phí theo token, theo model, chỉ khi gửi request. Một vài model nhỏ thậm chí miễn phí. Không server nào phải chạy.
Hình dạng giống hệt lời gọi cục bộ — cùng thân, cùng path /v1/chat/completions. Hai thứ thay đổi: host, và header Authorization.
# one key, any model — pick the model in the body
curl https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $OPENROUTER_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-4o-mini",
"messages": [{"role": "user", "content": "Hello"}]
}'
Token Bearer trong header; model được chọn trong body. Đó là toàn bộ khác biệt so với local.
Đặt hai lời gọi cạnh nhau. Thân JSON giống nhau từng từ — chỉ URL và key khác nhau.
POST tới 127.0.0.1:8080/v1/chat/completions. Không cần header auth — nó là máy của bạn. Bạn trả bằng phần cứng.
http://127.0.0.1:8080/v1/chat/completions
POST tới openrouter.ai/api/v1/chat/completions kèm key Bearer. Không phần cứng — bạn trả theo token.
https://openrouter.ai/api/v1/chat/completions
Nó không 'tốt hơn' tự host — mà nó tốt hơn trong các tình huống này.
Lưu lượng đột biến, nhiều người dùng, hoặc bạn muốn thử mười model trong tuần. Bạn sẽ không mua mười GPU vì thế — nhưng một key xử lý được.
Với các tính năng tổng quát mà prompt không chứa dữ liệu nhạy cảm của người dùng, gửi cho provider là đánh đổi hợp lý để không phải tự vận hành.
Không model nào phải tải, không phải lo RAM, không server nào phải canh. Tạo key, gửi request, ship. Bạn có thể tự host sau.
Vì hình dạng request giống hệt, một tính năng xây trên OpenRouter có thể trỏ tới llama-server của bạn vào ngày mai — chỉ cần đổi URL và key.
App Flask của bạn trở thành một bộ chuyển tiếp: nó giữ key, gửi messages, và trả về văn bản.
Vài dòng: đọc message của người dùng, POST tới model (local hay OpenRouter), trả về văn bản. Bạn sẽ dùng AI để xây phần thật — đây là hình dạng.
# one endpoint that forwards the user's message to the model
@app.route("/ask", methods=["POST"])
def ask():
prompt = request.json.get("message")
r = requests.post(MODEL_URL, # local /v1 OR OpenRouter /v1
headers={"Authorization": "Bearer " + MODEL_KEY},
json={"model": "openai/gpt-4o-mini",
"messages": [{"role": "user", "content": prompt}]})
reply = r.json()["choices"][0]["message"]["content"]
return {"reply": reply}
MODEL_URL + MODEL_KEY là hai thứ duy nhất khác nhau giữa local và hosted. Mọi thứ còn lại giống nhau.
Theo một câu hỏi từ người dùng đến câu trả lời. App của bạn giữ key và không bao giờ lộ nó cho trình duyệt.
POST /ask
giữ key, tạo messages, chuyển tiếp
key nằm phía server
…và văn bản từ model chảy ngược lại theo cùng đường, đến người dùng.
Trước khi viết code, hãy chọn ba thứ này. Dễ chọn đúng, đắt nếu chọn sai.
Khớp model với RAM bạn có. Nếu chỉ có 8 GB, một model 8B 4-bit với context khiêm tốn là vùng vừa vặn — chứ không phải giấc mơ 70B.
Đặt --ctx-size (hoặc giới hạn trong request) đúng mức bạn cần. Quá nhỏ mất lịch sử; quá lớn tốn bộ nhớ vô ích.
Bật streaming cho chat — nó sống động và giấu được thời gian chờ. Giữ tắt cho câu trả lời ngắn, máy phân tích, nơi một JSON đơn giản hơn.
App của bạn không nói chuyện với 'AI'. Nó nói chuyện với một URL. URL đó có thể là llama-server của bạn hay một provider — và không gì khác trong app đổi cả.
gửi một message
tự host để có riêng tư và kiểm soát · một provider để có scale và đa dạng — và code gần như không dịch chuyển giữa chúng
Chúng có thật và quan trọng — nhưng không phải bước tiếp theo của bạn, và không đổi cách bạn gọi service.
Attention, các lớp, model thực sự tính ra sao. Thú vị, nhưng không liên quan đến việc nối nó vào app của bạn.
Huấn luyện model thêm trên dữ liệu của bạn. Mạnh mẽ, nhưng là một dự án riêng — hãy làm prompt và API trước.
Toán đằng sau 4-bit vs 8-bit. Bạn chỉ cần chọn một file GGUF vừa RAM của mình — phần 'vì sao' là tùy chọn.
Ép token-mỗi-giây ra từ một GPU. Chủ đề tối ưu, xa hơn nhiều so với tích hợp đầu tiên.
Bạn không cần hiểu model để dùng nó. Bạn cần hiểu thỏa thuận: gửi messages qua HTTP, nhận về văn bản. Sở hữu nó để riêng tư, thuê nó để scale — và code gần như không dịch chuyển.
Giờ bạn nhìn AI đúng bản chất: một HTTP service khác. Tự host bằng llama-server hoặc thuê từ OpenRouter — và chuyển tiếp nó qua app Flask của bạn.