Có một khoảng cách rất lớn giữa "demo hoạt động ngon" và "chạy được ở production". Tôi đã chứng kiến điều này lặp lại quá nhiều lần: team mất 2 tuần build prototype, demo sếp thích, rồi mất 3 tháng tiếp theo chữa cháy khi đưa lên production thật.
LLM cộng thêm thêm một tầng phức tạp mà nhiều team chưa từng đối mặt. Latency không dự đoán được, chi phí có thể tăng đột biến, behavior của model thay đổi mà không báo trước, và toàn bộ hệ thống phụ thuộc vào một bên thứ ba mà bạn không kiểm soát được. Bài này là tổng hợp những gì tôi học được sau nhiều lần "đau thật".
Bẫy 1: Không Thiết Lập Latency Budget Sớm
Nhiều team xây dựng toàn bộ flow rồi mới nhận ra rằng end-to-end latency là 8-12 giây. Đến lúc đó, refactor rất tốn kém.
Một LLM call điển hình với GPT-4o mất khoảng 1-3 giây cho response ngắn, nhưng với prompt dài hoặc output dài có thể lên đến 10-20 giây. Nếu bạn có 3 LLM calls tuần tự trong một flow, bạn đang nhìn vào 30-60 giây latency — không ai chờ được.
Những gì phải làm trước khi viết code:
Latency Budget cho user-facing feature:
- Total: 3 giây
- LLM call: tối đa 1.5 giây (dùng streaming)
- Database: 200ms
- Overhead: 300ms
Quy tắc thực tế: nếu feature cần nhiều hơn 1 LLM call tuần tự, hãy hỏi ngay "có parallel được không?". Nếu không parallel được, hãy hỏi "có thực sự cần real-time không hay có thể async?".
Streaming output là bắt buộc cho mọi user-facing LLM call. Không streaming thì user nhìn màn hình trắng trong 5 giây — không thể chấp nhận được.
Bẫy 2: Chi Phí Token Vượt Kiểm Soát
Tôi biết một startup đã nhận được hóa đơn $23,000 từ OpenAI trong một tháng, gấp 10 lần dự tính. Nguyên nhân: không ai đặt rate limit, một vài user dùng feature nhiều bất thường, và system prompt quá dài được gửi trong mọi request.
Ba nguồn gây lãng phí token phổ biến nhất:
System prompt phình to. Team cứ thêm vào system prompt vì "cần thêm context" mà không kiểm tra xem bao nhiêu trong đó thực sự được dùng. System prompt 4,000 tokens được gửi 100,000 lần/tháng = 400 triệu input tokens chỉ cho system prompt.
Không có prompt caching. Anthropic và OpenAI đều hỗ trợ caching cho prefix cố định. Nếu system prompt của bạn cố định, enable caching ngay:
# Anthropic prompt caching
response = client.messages.create(
model="claude-opus-4-5",
system=[{
"type": "text",
"text": long_system_prompt,
"cache_control": {"type": "ephemeral"}
}],
messages=messages
)
# Token caching giảm 90% chi phí cho phần prefixKhông chọn đúng model. GPT-4o hay Claude Opus không phải lúc nào cũng cần thiết. Với classification đơn giản, sentiment analysis, hay extract thông tin có cấu trúc, GPT-4o-mini hoặc Claude Haiku đủ dùng và rẻ hơn 10-20 lần.
Thiết lập hard limit theo user và theo tháng là bắt buộc. Đừng tin vào "sẽ không ai dùng nhiều đến vậy".
Bẫy 3: Prompt Drift
Đây là vấn đề ít ai nhắc đến nhưng gây đau đầu nhất.
Một developer chỉnh prompt để fix một case cụ thể. Hai tuần sau developer khác chỉnh thêm. Một tháng sau không ai còn nhớ tại sao prompt lại có đoạn đó, nhưng cũng không ai dám xóa vì sợ break thứ gì đó.
Tệ hơn: provider update model (không thông báo trước, hoặc thông báo nhưng không ai đọc), output behavior thay đổi tinh tế, và không ai hay cho đến khi user complaint.
Prompt phải được versioned như code:
prompts/
summarizer/
v1.0.0.txt
v1.1.0.txt
current -> v1.1.0.txt
classifier/
v2.3.1.txt
current -> v2.3.1.txt
Cần có test suite cho prompt:
# Mỗi lần thay đổi prompt, chạy test này
def test_summarizer_prompt():
test_cases = load_golden_set("summarizer_evals.jsonl")
passed = 0
for case in test_cases:
output = run_llm(current_prompt, case["input"])
score = evaluate(output, case["expected"])
if score >= 0.8:
passed += 1
assert passed / len(test_cases) >= 0.95, \
f"Prompt regression: only {passed}/{len(test_cases)} passed"Golden set ít nhất 50-100 case, bao gồm edge cases. Chạy tự động trong CI trước mỗi lần deploy.
Bẫy 4: Thiếu Fallback Khi API Provider Down
OpenAI, Anthropic, Google — tất cả đều có downtime. Không nhiều, nhưng đủ để làm hỏng SLA của bạn vào thời điểm tệ nhất.
Nếu toàn bộ feature phụ thuộc vào một API provider và provider đó down, bạn có hai lựa chọn: feature down hoặc có fallback.
Fallback strategy theo mức độ quan trọng:
- Critical path (feature không dùng được nếu thiếu LLM): multi-provider với automatic failover
- Enhancement (feature vẫn dùng được nhưng kém hơn): graceful degradation, return cached response hoặc rule-based fallback
- Async processing: queue với retry, không cần failover real-time
import anthropic
import openai
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(3), wait=wait_exponential(min=1, max=10))
def call_with_fallback(prompt: str) -> str:
providers = [call_anthropic, call_openai, call_local_model]
for provider in providers:
try:
return provider(prompt)
except (APIError, RateLimitError) as e:
log_provider_failure(provider.__name__, e)
continue
raise AllProvidersFailedError("No LLM provider available")Circuit breaker pattern rất hữu ích ở đây — nếu một provider fail liên tục, tạm thời bypass nó thay vì tiếp tục gửi request rồi timeout.
Bẫy 5: Không Log và Monitor LLM Calls
Khi user report "AI trả lời sai", nếu không có logging đủ tốt, bạn không thể reproduce hay debug được. Bạn chỉ biết "có gì đó không đúng" mà không biết tại sao.
Minimum logging cần có:
@dataclass
class LLMCallLog:
call_id: str
timestamp: datetime
model: str
prompt_version: str
input_tokens: int
output_tokens: int
latency_ms: int
status: str # success/error/timeout
# KHÔNG log raw prompt/response nếu có PII
prompt_hash: str # hash để correlate mà không expose content
error_message: Optional[str]Metrics cần monitor:
- P50/P95/P99 latency theo model và prompt type
- Token usage và cost theo ngày/user/feature
- Error rate theo provider
- Cache hit rate (nếu dùng caching)
Alert khi: cost tăng đột biến hơn 50% so với ngày hôm qua, error rate vượt 5%, P99 latency vượt SLA.
Langfuse, Helicone, hay tự build đơn giản với Postgres đều được — quan trọng là phải có.
Bẫy 6: Eval Pipeline Chỉ Có Ở Research
Trong nhiều team, evaluation chỉ xảy ra khi build feature lần đầu. Sau đó không có ai chịu trách nhiệm duy trì eval suite, vì "tốn thời gian" và "mình chưa thấy vấn đề gì".
Rồi vấn đề xảy ra. Lúc đó mới bắt đầu build eval — sau khi damage đã xảy ra.
Eval production không phải benchmark học thuật. Bạn cần đo những gì thực sự quan trọng với business:
# Eval thực tế: track metrics theo thời gian
class ProductionEvaluator:
def evaluate_weekly(self):
# Lấy sample 500 calls từ production tuần qua
sample = self.get_production_sample(n=500, days=7)
metrics = {
"task_success_rate": self.measure_task_completion(sample),
"hallucination_rate": self.check_factual_claims(sample),
"format_compliance": self.check_output_format(sample),
"user_satisfaction": self.get_thumbs_rating(sample),
}
self.compare_to_baseline(metrics)
self.alert_if_regression(metrics, threshold=0.05)Dùng LLM-as-judge cho evaluation ở scale là hoàn toàn hợp lý — chi phí thấp hơn human eval 100 lần và đủ reliable cho hầu hết use cases.
Bẫy 7: Data Privacy Khi Gửi Customer Data Lên Third-Party API
Đây là bẫy có hậu quả pháp lý nghiêm trọng nhất.
Team build feature "AI tóm tắt email" và gửi toàn bộ email content lên OpenAI API. Không ai nghĩ đến việc email đó có thể chứa thông tin tài chính, hợp đồng, hay thông tin khách hàng. Không ai hỏi legal team. Không ai đọc DPA của OpenAI.
Checklist data privacy trước khi đưa LLM feature lên production:
Câu hỏi bắt buộc phải trả lời:
- Data này có phải PII không? (tên, email, số điện thoại, địa chỉ)
- Data này có phải PHI không? (thông tin y tế)
- Data này có thuộc về khách hàng enterprise của mình không? Họ có DPA yêu cầu data không được rời khỏi VN hay không?
- API provider có BAA/DPA phù hợp không?
Kỹ thuật giảm thiểu rủi ro:
# PII scrubbing trước khi gửi lên LLM
from presidio_analyzer import AnalyzerEngine
from presidio_anonymizer import AnonymizerEngine
def anonymize_before_llm(text: str) -> tuple[str, dict]:
analyzer = AnalyzerEngine()
anonymizer = AnonymizerEngine()
results = analyzer.analyze(text=text, language="en")
anonymized = anonymizer.anonymize(text=text, analyzer_results=results)
# Return anonymized text và mapping để restore sau nếu cần
return anonymized.text, build_restore_map(results)Với data nhạy cảm cao, xem xét on-premise model (vLLM với Llama hoặc Mistral). Chi phí cao hơn nhưng data không rời khỏi infrastructure của bạn.
Kết Luận
Checklist production-readiness cho LLM system:
- Latency budget đã định nghĩa, streaming đã enable
- Cost alert và per-user rate limit đã setup
- Prompt versioned trong Git, có golden test set
- Multi-provider fallback hoặc graceful degradation
- Structured logging cho mọi LLM call, dashboard monitoring
- Eval pipeline chạy tự động hàng tuần
- Legal review xong, PII scrubbing implement nếu cần
Không có gì trong danh sách này là rocket science. Nhưng dưới áp lực deadline "phải launch tuần sau", những thứ này hay bị skip. Rồi mất 3 tháng sau để fix hậu quả.
Production AI không phải là AI ngầu hơn. Production AI là AI đủ boring để không ai phải thức 2 giờ sáng chữa cháy.