→ From Coder to Shipper
From Coder to Shipper · AI

AI trong stack của bạn — llama-server & OpenRouter

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

Toàn cảnh

Gắn AI vào stack của bạn

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.

🌐 Trình duyệt

hỏi app của bạn một câu

▶

⚙️ App Flask

/ask — chuyển tới model

▶
🏠 llama-server — model của bạn, chạy trên máy của bạn
☁️ OpenRouter — model có sẵn, một API key duy nhất

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

Toàn cảnh · hai kiểu

Hai cách đưa AI vào

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ứ đó.

(a) Tự chạy model

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.

(b) Gọi API có sẵ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ề.
toàn bộ mô hình tư duy, trong một dòng
01
Phần 1

Mô hình tư duy

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?

Mô hình · sự đánh đổi cốt lõi

Tự host vs có sẵn

Đâ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.

Tự host — bạn sở hữu

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.

Có sẵn — nhà cung cấp sở hữu

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.

Mô hình · trục đánh đổi

Một trục, hai đầu

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.

← bạn trả bằng công + phần cứng bạn trả theo token →

🏠 Tự host (llama-server)

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.

☁️ Có sẵn (OpenRouter)

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

Mô hình · cạnh nhau

Tự host vs có sẵn, qua từng tiêu chí

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 modelBạn — trên VPS của bạnNhà 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ố địnhServer + GPU/RAM bạn phải muaKhông — không phần cứng
Chi phí theo dùngKhông theo request (bạn trả tiền server)Trả theo token, chỉ khi dùng
Lựa chọn model & scaleBị giới hạn bởi phần cứngHàng trăm model, scale linh hoạt
Mô hình · hình dạng

Hình dạng cuộc hội thoại

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.

Bạn gửi messages

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.

Nó nói HTTP

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.

Nó trả về văn bản

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.

02
Phần 2

LLM cục bộ — llama.cpp / llama-server

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.

Cục bộ · model là gì

Model chỉ là một file to

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.

Trọng số, trong một file

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.

Bạn nạp và serve nó

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

Nó nói một API

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.

Cục bộ · chạy nó

Serve một model trong hai lệnh

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.

ops@vps — zsh
$ curl -LO https://github.com/ggml-org/llama.cpp/releases/latest/download/llama-server
$ chmod +x llama-server
$ ./llama-server -m models/llama-3.1-8b.Q4_K_M.gguf --port 8080 --ctx-size 4096
llama server: loading model models/llama-3.1-8b.Q4_K_M.gguf
llama server: loaded in 3.2s
llama server: listening on http://127.0.0.1:8080
Cục bộ · kích thước là tất cả

RAM/VRAM là giới hạn cứng

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.

Kích thước model → cái gì vừa

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.

Kích thước context → nó nhớ bao nhiêu

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.

Cục bộ · sự đánh đổi

Model lớn hơn, context nhiều hơn — chọn một

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

Model to, context ngắn

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.

Model nhỏ, context dài

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.

Cục bộ · một bản đồ thô

Kích thước → bộ nhớ → cái gì vừa trên một VPS

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 modelRAM/VRAM cần để nạp (gần đúng)Vừa ở đâu
~7–8B≈ 6–8 GBVPS 16 GB, thoải mái, còn chỗ cho context
~13B≈ 10–12 GBVPS 16 GB, chật hơn — context giảm
~30–34B≈ 20–24 GBMáy 32 GB, hoặc GPU có VRAM cỡ đó
~70B≈ 40–48 GBNhiều GPU hoặc máy VRAM lớn — không phải VPS nhỏ
03
Phần 3

Hình dạng API

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.

API · request

Những gì bạn thực sự gửi

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.

request.json
{
  "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.

API · với curl

Hỏi model cục bộ của bạn

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.

bash
# 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.

API · một lần vs stream

Một trả lời, hay một stream

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.

stream: false — một khối

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.

stream: true — từng token mộ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.

API · streaming

Streaming, từng chút một

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.

ops@vps — zsh
$ curl -N http://localhost:8080/v1/chat/completions -d '{"stream": true}'
data: {"choices":[{"delta":{"content":"Hi"}}]}
data: {"choices":[{"delta":{"content":"! I'm"}}]}
data: {"choices":[{"delta":{"content":" a model."}}]}
data: [DONE]
04
Phần 4

OpenRouter — API có sẵn

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 · ý tưởng

Một key, nhiều model

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.

Chọn model theo từng request

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 API key

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.

Trả theo dùng

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.

OpenRouter · request

Một request tới OpenRouter

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.

bash
# 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.

OpenRouter · cùng hình dạng, hai cánh cửa

Cùng thân, hai địa chỉ

Đặ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.

Cục bộ — llama-server

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

Có sẵn — OpenRouter

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

OpenRouter · vì sao dùng nó

Khi nào dùng có sẵn là đúng

Nó không 'tốt hơn' tự host — mà nó tốt hơn trong các tình huống này.

Bạn cần scale hoặc đa dạng

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.

Riêng tư không phải rào cản

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.

Bạn muốn bắt đầu ngay hôm nay

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à giữ một lối thoát cục bộ

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.

05
Phần 5

Dùng nó trong app của bạn

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.

App · bộ chuyển tiếp

Chuyển tiếp trong Flask

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.

app.py
# 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.

App · luồng

Một endpoint, một lượt đi về

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.

🌐 Người dùng

POST /ask

▶

⚙️ Flask /ask

giữ key, tạo messages, chuyển tiếp

key nằm phía server

▶
🏠 llama-server :8080/v1
☁️ OpenRouter /api/v1
◀

…và văn bản từ model chảy ngược lại theo cùng đường, đến người dùng.

App · lựa chọn thực tế

Ba quyết định trước khi ship

Trước khi viết code, hãy chọn ba thứ này. Dễ chọn đúng, đắt nếu chọn sai.

Kích thước model cho VPS

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.

Độ dài context

Đặ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.

Stream hay không

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.

Toàn cảnh · bài học

AI chỉ là một service nữa

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

⚙️ App của bạn

gửi một message

HTTP ▶ ◀ văn bản
🧠 bất kỳ model, bất kỳ provider
🏠 llama-server — tự host, riêng tư, của bạn
☁️ OpenRouter — có sẵn, nhiều model, trả theo dùng

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

Toàn cảnh · ngoài phạm vi

Những gì cố tình bỏ qua

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.

Bên trong transformer

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.

Fine-tuning

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.

Chi tiết nén (quantization)

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.

Tinh chỉnh GPU & batching

É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.
góc nhìn của kiến trúc sư

Model đã chọn. Key đã đặt. Văn bản đang chảy.

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.