Khi build MKT Content AI — một SaaS multi-tenant generate marketing content cho doanh nghiệp Việt — tôi gặp một vấn đề điển hình: cost của Anthropic API tăng tuyến tính với traffic, trong khi nhiều phần của prompt là static.
Vấn đề
Mỗi request đến Claude API có cấu trúc:
{
system: "Bạn là chuyên gia content marketing...", // ~2000 tokens, static
tools: [/* 12 tools với schema dài */], // ~1500 tokens, static per tenant
messages: [
{ role: "user", content: "Viết bài Facebook về..." }
]
}
Trong mỗi tenant, system prompt và tools schema gần như không đổi. Nhưng mỗi request lại gửi toàn bộ — Anthropic charge full token mỗi lần.
Với 1000 requests/ngày, system + tools chiếm ~3500 token × 1000 = 3.5M tokens/ngày chỉ để gửi cùng một nội dung.
Giải pháp: 4 tầng cache
Anthropic API có cache_control cho phép mark một phần prompt là cacheable. Cache TTL 5 phút (default) hoặc 1 giờ (extended). Cache hit chỉ tính 10% cost so với cache miss.
Tôi tổ chức thành 4 tầng theo mức độ ổn định:
Tầng 1: Global system (TTL: 1 giờ)
Nội dung không bao giờ thay đổi giữa tenants:
{
type: "text",
text: SYSTEM_PROMPT_BASE, // "Bạn là Claude, trợ lý..."
cache_control: { type: "ephemeral", ttl: "1h" }
}
Tầng 2: Tenant config (TTL: 1 giờ)
Mỗi tenant có cấu hình riêng (brand voice, style guide, audience profile):
{
type: "text",
text: `Tenant: ${tenant.name}\nBrand voice: ${tenant.voice}...`,
cache_control: { type: "ephemeral", ttl: "1h" }
}
Tầng 3: Tools schema (TTL: 5 phút)
Tools schema cũng cacheable. Đặt sau system prompt:
{
tools: [
,
,
/* tool 1 */ /* tool 2 */ {
/* tool cuối */
cache_control: { type: 'ephemeral', ttl: '5m' },
},
];
}
Lưu ý: chỉ cần đặt cache_control ở tool CUỐI CÙNG — Anthropic cache mọi thứ TRƯỚC marker đó.
Tầng 4: Conversation history (no cache)
Phần này thay đổi mọi request, không cache.
Kết quả thực tế
Sau khi triển khai trên production:
| Metric | Trước | Sau | Tiết kiệm |
|---|---|---|---|
| Input tokens/request | 3,847 | 287 | 92.5% |
| Cost/request | $0.0115 | $0.0008 | 93% |
| Latency p50 | 2.1s | 1.4s | 33% |
Pitfalls đã gặp
1. Cache key sensitive với whitespace
Một thay đổi nhỏ trong template string — thêm space, đổi newline — = cache miss. Phải hash cache key trước deploy.
2. Cache cold start tốn 25% phụ phí
Lần đầu cache miss, Anthropic charge 1.25× normal token cost (để build cache). Sau đó hit chỉ 0.1×. Vẫn lãi lớn nhưng phải tính vào ROI.
3. Multi-tenant cache pollution
Nếu mày dùng chung cache key giữa tenants → leak data. Phải include tenant_id vào cache namespace.
Code mẫu
Đây là buildCachedPrompt final:
async function buildCachedPrompt(tenant: Tenant, userMessage: string): Promise<MessagesRequest> {
return {
model: 'claude-sonnet-4-5',
max_tokens: 4096,
system: [
{
type: 'text',
text: SYSTEM_BASE,
cache_control: { type: 'ephemeral', ttl: '1h' },
},
{
type: 'text',
text: buildTenantContext(tenant),
cache_control: { type: 'ephemeral', ttl: '1h' },
},
],
tools: [
...TOOLS.slice(0, -1),
{
...TOOLS.at(-1)!,
cache_control: { type: 'ephemeral', ttl: '5m' },
},
],
messages: [{ role: 'user', content: userMessage }],
};
}
Kết
Prompt caching là một “free lunch” hiếm có trong tech — không có trade-off thực sự nào ngoài việc phải hiểu rõ thứ tự cache hierarchy. Nếu ứng dụng AI của mày chưa dùng nó, mày đang đốt tiền.
Bài tiếp theo tôi sẽ viết về multi-tenant RLS với PostgreSQL — vấn đề bảo mật data isolation song hành với prompt caching trong kiến trúc SaaS.
Tham khảo: Anthropic Prompt Caching docs