Đêm 10/11/2025, tôi ngồi trước terminal ở một quán cà phê cạnh sông Sài Gòn. Hệ thống chatbot CSKH cho một shop thời trang local brand vừa bật flash sale 11.11, lưu lượng truy cập tăng gấp 8 lần chỉ trong 45 phút. Câu hỏi đầu tiên khách gửi vào khung chat: "Shop còn size M không ạ?" — phản hồi phải đến trong vòng 1.5 giây, không hơn. Tôi từng tin rằng cứ chọn model flagship đắt nhất là xong, nhưng sau 3 đêm benchmark thực tế qua HolySheep, tôi nhận ra: độ trễ token đầu tiên (TTFT) và chi phí/token mới là thứ giữ chân khách hàng, chứ không phải tên model. Bài viết này là toàn bộ số liệu thô, script benchmark, và bài học xương máu tôi rút ra để bạn đỡ phải mất ngủ như tôi.
Vì sao mỗi mili-giây đều có tiếng nói
Khi chatbot trả lời chậm hơn 1.2 giây, tỷ lệ thoát phiên tăng 32% (theo Baymard Institute 2025). Trong ngữ cảnh live chat thương mại điện tử, TTFT dưới 250ms được tính là "tức thì", 250–600ms là "chấp nhận được", trên 600ms là "khách đã bấm tắt tab". Một hệ thống RAG doanh nghiệp có thể tha thứ chậm hơn, nhưng endpoint CSKH thì không. Đó là lý do tôi cần đo streaming latency thật, không phải số liệu marketing trên blog của nhà cung cấp.
Hạ tầng benchmark và điều kiện đo
- Vị trí: VPS Singapore (region gần Việt Nam nhất có public endpoint), máy khách mô phỏng từ TP.HCM qua WireGuard, RTT nền 28ms.
- Relay:
https://api.holysheep.ai/v1, header chuẩn OpenAI-compat, keyYOUR_HOLYSHEEP_API_KEY. - Mô hình so sánh:
gemini-2.5-provàgpt-5.5. - Prompt chuẩn: 150 token input (system + context + câu hỏi khách), max output 256 token, temperature 0.7.
- Số lần chạy mỗi model: 200 request, lấy trung vị (P50) và P95.
- Tiêu chí: TTFT (ms), tốc độ giải mã (tok/s), tỷ lệ thành công (%), tổng chi phí/1 triệu token.
Mã Python đo TTFT và throughput
Đoạn mã dưới dùng httpx để stream qua SSE, bóc tách từng token và bấm giờ tại thời điểm nhận token đầu tiên. Tôi lưu lại thành benchmark.py trong thư mục dự án và chạy qua asyncio để tránh block event loop.
import time
import json
import asyncio
import httpx
from statistics import median
BASE_URL = "https://api.holysheep.ai/v1"
API_KEY = "YOUR_HOLYSHEEP_API_KEY"
async def run_one(client, model, prompt, max_tokens=256):
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
body = {
"model": model,
"messages": [{"role": "user", "content": prompt}],
"max_tokens": max_tokens,
"temperature": 0.7,
"stream": True,
}
t_start = time.perf_counter()
ttft_ms = None
token_count = 0
async with client.stream(
"POST", f"{BASE_URL}/chat/completions",
headers=headers, json=body, timeout=httpx.Timeout(30.0)
) as resp:
resp.raise_for_status()
async for line in resp.aiter_lines():
if not line.startswith("data: "):
continue
payload = line[6:]
if payload == "[DONE]":
break
chunk = json.loads(payload)
delta = chunk["choices"][0]["delta"].get("content")
if delta:
if ttft_ms is None:
ttft_ms = (time.perf_counter() - t_start) * 1000
token_count += 1
total_s = time.perf_counter() - t_start
decode_s = max(total_s - (ttft_ms or 0) / 1000, 0.001)
return {
"model": model,
"ttft_ms": round(ttft_ms, 1) if ttft_ms else None,
"tokens": token_count,
"total_s": round(total_s, 3),
"tok_per_s": round(token_count / decode_s, 2),
"ok": token_count > 0,
}
async def benchmark(models, prompt, n=200):
limits = httpx.Limits(max_connections=20)
async with httpx.AsyncClient(http2=True, limits=limits) as client:
results = []
for _ in range(n):
for m in models:
try:
r = await run_one(client, m, prompt)
if r["ok"]:
results.append(r)
except Exception as e:
print(f"[ERR] {m}: {e}")
return results
def summarize(rows):
by_model = {}
for r in rows:
by_model.setdefault(r["model"], []).append(r)
out = []
for m, rs in by_model.items():
ttfts = sorted(r["ttft_ms"] for r in rs if r["ttft_ms"])
speeds = sorted(r["tok_per_s"] for r in rs)
out.append({
"model": m,
"samples": len(rs),
"p50_ttft_ms": ttfts[len(ttfts)//2],
"p95_ttft_ms": ttfts[int(len(ttfts)*0.95)],
"p50_tok_s": speeds[len(speeds)//2],
"p95_tok_s": speeds[int(len(speeds)*0.95)],
"success_pct": round(100 * len(rs) / 200, 2),
})
return out
PROMPT = """Bạn là nhân viên CSKH cho shop thời trang local brand.
Khách hỏi: 'Shop còn size M cho áo khoác dạ XFW-204 không ạ, màu đen?'
Hãy trả lời ngắn gọn, thân thiện, dưới 60 từ."""
if __name__ == "__main__":
rows = asyncio.run(benchmark(["gemini-2.5-pro", "gpt-5.5"], PROMPT, n=200))
print(json.dumps(summarize(rows), indent=2, ensure_ascii=False))
Smoke-test nhanh với cURL
Trước khi chạy script nặng, tôi luôn bắn nhanh một request streaming để xác nhận header SSE và schema trả về khớp với OpenAI-compat. Đây là bản rút gọn có thể dán thẳng vào terminal:
curl -N -X POST "https://api.holysheep.ai/v1/chat/completions" \
-H "Authorization: Bearer YOUR_HOLYSHEEP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-2.5-pro",
"messages": [{"role":"user","content":"Xin chào, shop còn size M không?"}],
"max_tokens": 128,
"stream": true
}'
Kỳ