Bạn gõ vào app chat: "Giải thích quantum computing trong 1 câu." — nhấn Enter. 3 giây sau, câu trả lời hiện ra.
- Mô tả 5 bước trong vòng đời của một request đến Claude API
- Giải thích vì sao không bao giờ gọi API trực tiếp từ client-side
- Hiểu điều gì xảy ra bên trong Claude (tokenization → embedding → contextualization → generation)
- Nhận diện các tham số bắt buộc trong mỗi request
- Đọc và interpret được object response, đặc biệt trường stop_reason
5 bước của một request
Mỗi bước có chi tiết riêng. Cùng đi qua.
┌────────────────────────────────────────────────────────────┐ │ │ │ [1] Client → Your Server │ │ │ User type message trong UI │ │ │ Frontend gửi POST /chat đến backend của bạn │ │ ▼ │ │ [2] Your Server → Anthropic API │ │ │ Backend gắn API key + system prompt │ │ │ Gửi HTTPS request đến api.anthropic.com │ │ ▼ │ │ [3] Inside Anthropic │ │ │ Token → Embedding → Context → Generation │ │ │ ~1-30 giây tùy model + độ dài │ │ ▼ │ │ [4] Anthropic API → Your Server │ │ │ JSON response với content, usage, stop_reason │ │ ▼ │ │ [5] Your Server → Client │ │ Frontend render text lên UI │ │ │ └────────────────────────────────────────────────────────────┘
Bước 1-2: Vì sao LUÔN phải có server trung gian?
Quy tắc vàng: KHÔNG BAO GIỜ gọi Anthropic API trực tiếp từ browser / mobile app.
3 lý do
1. Security — API key là tài sản quý giá
Mỗi key có thể tiêu tiền của bạn. Nếu lộ trong code client, bất kỳ ai mở DevTools đều thấy → dùng để gọi Claude miễn phí với tiền của bạn → hoặc tệ hơn, bán key trên forum.
2. Abuse protection — Bạn kiểm soát được request
Server của bạn có thể:
Không có server = không có gate.
3. Business logic — Bạn thêm logic riêng
Giữa user prompt và Anthropic, server thường:
Logic này không thể ở client.
Architecture điển hình
- Rate limit mỗi user (max 10 message/phút)
- Validate input (chặn prompt injection)
- Log để audit
- Charge user khi vượt quota
- Prepend system prompt tùy tenant
- Inject RAG context từ DB
- Pick model (A/B test)
- Track metrics
┌──────────┐ ┌─────────────┐ ┌──────────────┐
│ Client │──▶│ Your API │──▶│ Anthropic │
│ (React, │ │ (FastAPI, │ │ API │
│ iOS) │ │ Express) │ │ │
└──────────┘ └─────────────┘ └──────────────┘
│
▼
┌──────────┐
│ Database │
│ (history,│
│ users) │
└──────────┘Các tham số bắt buộc trong mỗi request
Mỗi call đến client.messages.create() phải có tối thiểu 4 trường:
Giải thích từng trường
messages — Mảng các dict, mỗi dict là 1 lượt trong hội thoại:
Quy tắc messages:
max_tokens — Trần cứng cho output. Claude sẽ dừng sớm nếu hoàn thành, không cố đạt số này.
- Phải bắt đầu bằng role: user (không phải assistant)
- Role alternating: user → assistant → user → assistant...
- Không được 2 user liên tiếp (Claude sẽ lỗi)
| Trường | Mô tả | Ví dụ |
|---|---|---|
| api_key | Khóa xác thực | sk-ant-api03-... (qua env var) |
| model | Model ID | claude-sonnet-5-20260205 |
| messages | Danh sách tin nhắn | [{"role": "user", "content": "..."}] |
| max_tokens | Giới hạn token output | 1000 |
messages = [
{"role": "user", "content": "Hello"},
{"role": "assistant", "content": "Hi! How can I help?"},
{"role": "user", "content": "What's 2+2?"},
]Giải thích từng trường
Quy tắc chọn max_tokens:
- Chatbot ngắn: 500-1000
- Article / long-form: 4000-8000
- Reasoning chain: 8000-16000
- Max cho Sonnet 5: 64000 (output limit)
max_tokens = 1000 → Claude có thể output 50 token (nếu câu trả lời ngắn)
hoặc 1000 token (nếu câu dài và đạt trần)
Không bao giờ > 1000Bước 3: Bên trong Claude — 4 giai đoạn
Khi request đến Anthropic, Claude xử lý qua 4 giai đoạn:
1. Tokenization
Text → sequence tokens. Không phải lúc nào 1 token = 1 từ.
Quy tắc ngón cái:
Implication: Prompt tiếng Việt dài hơn English ~50% về token count. Budget token theo đó.
2. Embedding
Mỗi token → vector ~4000 chiều (dãy 4000 số thực). Vector này encode "ý nghĩa" của token trong không gian đa chiều.
Ví dụ "quantum" có thể có nhiều nghĩa:
Embedding ban đầu chứa tất cả các nghĩa này.
3. Contextualization
Đây là ma thuật. Claude refine embedding của mỗi token dựa vào các token xung quanh.
"quantum" sau "computing" → vector "quantum" được điều chỉnh để nhấn mạnh nghĩa liên quan quantum computing, không còn "extremely small" hay "physics particle".
Cơ chế này là attention — core của transformer architecture. Không cần hiểu sâu về math, nhưng nhớ: context quyết định meaning. Đó là lý do "cho examples" và "clear structure" (prompt engineering) quan trọng — giúp Claude contextualize đúng.
4. Generation
Với context đã xây, Claude predict next token:
Claude sample một token theo phân phối này (dựa vào temperature, bài 6.12). Sau đó append token vào sequence và lặp lại từ bước 3.
Quá trình chạy cho đến khi 1 trong 3 điều kiện dừng:
Đây là lý do stop_reason trong response quan trọng — cho bạn biết vì sao dừng.
- "Hello" → 1 token
- "Claude" → 1 token
- "photosynthesis" → 2 token (photo + synthesis)
- "你好" → 3 token (mỗi ký tự Trung 1-2 token)
- English: 1 token ≈ 0.75 từ
- Tiếng Việt: 1 token ≈ 0.5 từ (tiếng Việt tốn token hơn)
- Code: 1 token ≈ 2-3 ký tự
- Unit physics
- Field mechanics lượng tử
- Adj "extremely small"
- Context computing
- max_tokens đạt trần
- Claude sinh end-of-sequence token (model tự thấy đã xong)
- Claude gặp stop sequence bạn định nghĩa
"What is quantum computing?"
│
▼
┌──────────────────┐
│ 1. TOKENIZATION │ "What" "is" "quantum" "computing" "?"
└──────────────────┘
│
▼
┌──────────────────┐
│ 2. EMBEDDING │ mỗi token → vector ~4000 số
└──────────────────┘
│
▼
┌──────────────────┐
│ 3. CONTEXTUALIZE │ "quantum" + "computing" → meaning nghĩa physics
└──────────────────┘
│
▼
┌──────────────────┐
│ 4. GENERATION │ next token probabilities → sample → append → repeat
└──────────────────┘
│
▼
"Quantum computing is..."Input tokens → [model] → probability distribution over 200,000 tokens
Ví dụ:
"Quantum computing is a type of" →
" computation" (30%)
" technology" (20%)
" computing" (10%)
" system" (5%)
... (các token khác)Bước 4-5: Response trở về
Anthropic trả về JSON structure:
Trường quan trọng
content — Mảng content block. Thông thường 1 element type text. Với tool use sẽ có thêm type tool_use. Với extended thinking có thêm thinking.
stop_reason — Quyết định logic app của bạn:
usage — Metrics cho billing và logging:
Best practice: Log usage mỗi request để monitor cost.
- input_tokens: số token input (bao gồm system prompt + history)
- output_tokens: số token Claude sinh ra
- (Tùy model) cache_creation_input_tokens / cache_read_input_tokens cho caching
| stop_reason | Ý nghĩa | Hành động |
|---|---|---|
| end_turn | Claude tự kết thúc (bình thường) | Hiển thị response |
| max_tokens | Đạt trần max_tokens | Có thể cần tăng limit, hoặc continue |
| stop_sequence | Gặp stop sequence | Check logic |
| tool_use | Claude muốn gọi tool | Execute tool, gửi kết quả (xem Module 5) |
{
"id": "msg_01XYZ...",
"type": "message",
"role": "assistant",
"model": "claude-sonnet-5-20260205",
"content": [
{
"type": "text",
"text": "Quantum computing is a type of computation..."
}
],
"stop_reason": "end_turn",
"usage": {
"input_tokens": 12,
"output_tokens": 87
}
}Ví dụ thực chiến: Debug một issue kỳ lạ
Tình huống
User báo: "Chatbot của anh bị cắt ngang giữa câu!". Bạn check log, thấy response dừng ở "... because of the Heisenberg uncer"
Phân tích theo vòng đời
Bước 1-2: Request đến server đúng, forward đúng. OK.
Bước 3: Trong Anthropic, generation chạy, sinh token đến lúc... dừng.
Bước 4: Response có:
Root cause: max_tokens=500 trong code của bạn. Câu trả lời dài hơn 500 token → bị cắt.
Fix:
{
"stop_reason": "max_tokens", // ← Đây!
"usage": {
"input_tokens": 2340,
"output_tokens": 500
}
}Phân tích theo vòng đời
Bài học: Luôn check stop_reason trước khi hiển thị response. Nếu max_tokens → cảnh báo user hoặc tự động continue.
Ví dụ code handle stop_reason
message = client.messages.create(
model=model,
max_tokens=4000, # ← Tăng limit
messages=messages,
)Ví dụ code handle stop_reason
def chat_with_check(messages):
msg = client.messages.create(
model=model,
max_tokens=2000,
messages=messages,
)
if msg.stop_reason == "max_tokens":
# Log warning
print("⚠️ Response truncated! Consider continuing.")
if msg.stop_reason == "end_turn":
return msg.content[0].text
# Tool use sẽ xử lý ở Module 5
raise NotImplementedError(f"Unhandled stop_reason: {msg.stop_reason}")Case studies theo ngành
💻 Developer — API cost blowup
Pain: Bill API tháng này $3000, dự kiến chỉ $500.
Analysis theo vòng đời:
Fix: Implement conversation summarization mỗi 20 turn. Hoặc bật prompt caching (Module 6).
📊 Data Engineer — Batch processing chậm
Pain: Xử lý 1000 document, cần 12 giờ.
Analysis:
Fix:
🎧 Customer Support — Response kỳ quặc
Pain: Chatbot trả lời không liên quan.
Analysis: Check messages array gửi đi — bị trùng, hoặc role order sai.
Fix: Validate trước khi gọi:
- Kiểm tra usage trong log: input_tokens trung bình 8000/request
- Root cause: Mỗi request gửi toàn bộ history (multi-turn), history ngày càng dài
- Sau 50 lượt chat, input_tokens gấp 10 lần bình thường
- Bước 3 (generation) chiếm 95% thời gian
- Làm tuần tự → 50 giây × 1000 = 14 giờ
- Gọi parallel (10 concurrent) → 1.4 giờ
- Hoặc dùng Batch API (Haiku) → trả trong vài giờ với giá nửa
def validate_messages(messages):
assert messages[0]["role"] == "user"
for i in range(1, len(messages)):
assert messages[i]["role"] != messages[i-1]["role"], \
"Two consecutive same-role messages"Anti-patterns — Lỗi vòng đời phổ biến
❌ Gọi API từ client
Hiểu hiện: Code React/iOS có biến ANTHROPIC_API_KEY.
Fix: Luôn proxy qua server của bạn. Không bao giờ ship API key ra client.
❌ Không handle stop_reason
Hiểu hiện: return message.content[0].text không check stop_reason.
Fix: Check stop_reason, cảnh báo user nếu bị truncate, raise error nếu unexpected.
❌ Gửi history vô tận
Hiểu hiện: Mỗi request gửi toàn bộ history từ ngày user tạo tài khoản.
Fix: Trim history: giữ N message gần nhất, summary phần cũ.
❌ Không log usage
Hiểu hiện: Bill đột biến, không biết request nào gây ra.
Fix: Log usage + model + user_id mỗi request. Dashboard theo user/day/model.
❌ Hardcode max_tokens=4096 universally
Hiểu hiện: Mọi endpoint dùng 4096, từ chatbot ngắn đến document analysis.
Fix: Set max_tokens theo use case. Endpoint classify chỉ cần 50. Endpoint write article cần 4000.
Áp dụng ngay
Bài tập 1: Vẽ lại flow cho app của bạn (10 phút)
Trong notebook, vẽ 5 bước cho use case bạn đang dự định:
Bài tập 2: Đọc 1 response thật (5 phút)
Nếu bạn đã có API key (Bài 6.5 hướng dẫn), chạy code và in ra full response object, không chỉ text:
[1] User nhập gì ở đâu?
[2] Server của bạn có prepend gì (system prompt, RAG context)?
[3] Model nào, max_tokens bao nhiêu?
[4] Server xử lý response như thế nào (check stop_reason?)?
[5] Client hiển thị gì?Bài tập 2: Đọc 1 response thật (5 phút)
Nhận diện: id, content, stop_reason, usage. Đây sẽ là "bạn đồng hành" trong mọi bài sau.
msg = client.messages.create(
model="claude-haiku-4-5",
max_tokens=100,
messages=[{"role": "user", "content": "Say hello"}]
)
print(msg) # Xem toàn bộ objectTóm tắt bài học
🎯 5 bước vòng đời: Client → Your server → Anthropic → Your server → Client. Server là bắt buộc, không bỏ qua.
🎯 Trong Claude có 4 giai đoạn: Tokenize → Embed → Contextualize → Generate. Hiểu quá trình giúp debug và optimize.
🎯 4 tham số bắt buộc: api_key, model, messages, max_tokens. Mỗi cái có quy tắc riêng (role alternating, max_tokens chỉ là trần).
🎯 stop_reason là thông tin critical — phải handle đúng cho từng case (end_turn, max_tokens, tool_use).
🎯 Tokenization khác ngôn ngữ: Tiếng Việt tốn token hơn English ~50%. Budget theo đó.
- Anthropic API reference
- Rate limits & pricing
- Stop reason documentation