Gọi AI từ app của bạn
ZeniRouter là engine định tuyến AI thông minh — tự động chọn model rẻ nhất phù hợp với task, cache câu hỏi lặp lại, và failover khi nhà cung cấp gặp sự cố. Tài liệu này hướng dẫn ba cách gọi từ cơ bản đến nâng cao.
Xác thực — Bearer JWT
Mọi request đến API đều cần header Authorization: Bearer zeni_pat_xxx. Tham khảo Quickstart để lấy token.
httpPOST /api/v1/router/complete?ws=my_workspace
Host: zenicloud.io
Authorization: Bearer zeni_pat_3a8f9b2c1d...
Content-Type: application/json
Tham số ws (workspace) bắt buộc — dùng để phân tách dữ liệu giữa các môi trường (dev, staging, prod) hoặc giữa các app khác nhau trong cùng tài khoản.
Cách 1 — Direct REST với cURL
Đơn giản nhất, dùng được trong shell script và CI/CD pipeline:
bashcurl -X POST "https://zenicloud.io/api/v1/router/complete?ws=prod" \
-H "Authorization: Bearer $ZENI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "system", "content": "Bạn là trợ lý của Zeni Cloud."},
{"role": "user", "content": "Tóm tắt 50 chữ về Sài Gòn."}
],
"task_type": "qa_simple",
"max_tokens": 200
}'
Ví dụ Python
pythonimport os, requests
ZENI = "https://zenicloud.io/api/v1"
TOKEN = os.environ["ZENI_TOKEN"]
def ai_complete(prompt, task="qa_simple"):
r = requests.post(
f"{ZENI}/router/complete?ws=my_ws",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"messages": [{"role": "user", "content": prompt}],
"task_type": task,
},
timeout=60,
)
r.raise_for_status()
return r.json()
# Use case 1 — câu hỏi đơn giản, định tuyến tới Flash
print(ai_complete("Tóm tắt 100 chữ về Hà Nội"))
# routing.primary_model = gemini-3-1-flash, cost ~ 0.0001 USD
# Use case 2 — soạn hợp đồng, định tuyến tới Opus
print(ai_complete("Soạn hợp đồng lao động Việt Nam mẫu", task="legal_contract"))
# routing.primary_model = claude-opus-4-7, cost ~ 0.025 USD
# Use case 3 — phân loại text
print(ai_complete("Phân loại email: 'Anh ơi đơn hàng đến chưa?'", task="classify"))
# routing.primary_model = gemma-4, cost ~ 0.00013 USD
Ví dụ Node.js
javascriptconst ZENI = "https://zenicloud.io/api/v1";
const TOKEN = process.env.ZENI_TOKEN;
async function aiComplete(prompt, task = "qa_simple") {
const res = await fetch(`${ZENI}/router/complete?ws=my_ws`, {
method: "POST",
headers: {
"Authorization": `Bearer ${TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
messages: [{ role: "user", content: prompt }],
task_type: task,
}),
});
if (!res.ok) throw new Error(`Zeni ${res.status}`);
return res.json();
}
// Sử dụng
const r = await aiComplete("Liệt kê 5 quận trung tâm Sài Gòn");
console.log(r.text);
console.log(`Model: ${r.routing.primary_model}, cost: $${r.routing.actual_cost_usd}`);
Ví dụ Go
gopackage main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
type Msg struct { Role, Content string }
type Req struct {
Messages []Msg `json:"messages"`
TaskType string `json:"task_type"`
}
func aiComplete(prompt string) (string, error) {
body, _ := json.Marshal(Req{
Messages: []Msg{{Role: "user", Content: prompt}},
TaskType: "qa_simple",
})
req, _ := http.NewRequest("POST",
"https://zenicloud.io/api/v1/router/complete?ws=my_ws",
bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("ZENI_TOKEN"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil { return "", err }
defer resp.Body.Close()
var out map[string]interface{}
json.NewDecoder(resp.Body).Decode(&out)
return fmt.Sprint(out["text"]), nil
}
Cách 2 — Smart routing với task_type
Đặt task_type chính xác để ZeniRouter chọn model rẻ nhất phù hợp. Đây là cách khuyến nghị cho hầu hết ứng dụng.
| task_type | Model định tuyến | Chi phí ước tính | Use case |
|---|---|---|---|
| qa_simple | gemini-3-1-flash | $0.0001/req | Hỏi đáp ngắn, FAQ, chatbot |
| classify | gemma-4 | $0.00013/req | Phân loại email, tag content |
| summarize | gemini-3-1-flash | $0.0002/req | Tóm tắt văn bản dưới 5K từ |
| code_gen | claude-sonnet-4-7 | $0.003/req | Sinh code, review PR |
| legal_contract | claude-opus-4-7 | $0.025/req | Soạn hợp đồng, phân tích pháp lý |
| creative_long | claude-opus-4-7 | $0.030/req | Viết blog dài, kịch bản |
| vision | gemini-3-1-pro | $0.005/req | Phân tích ảnh, biểu đồ |
Cách 3 — Explicit model selection
Khi bạn chắc chắn muốn dùng một model cụ thể (ví dụ test benchmark, hoặc có hợp đồng commit), thêm trường model:
json{
"messages": [{"role": "user", "content": "Viết bài SEO 1500 chữ về cà phê Việt Nam"}],
"model": "claude-opus-4-7",
"max_tokens": 3000,
"temperature": 0.7
}
model tường minh, ZeniRouter sẽ không downgrade sang model rẻ hơn dù task đơn giản. Hãy chắc chắn bạn cần đúng model đó.Chiến lược 80/15/5 — Tối ưu chi phí
ZeniRouter hoạt động dựa trên giả định: phần lớn câu hỏi là đơn giản, chỉ một số ít cần model mạnh. Phân bổ mặc định:
So với gọi trực tiếp Anthropic Opus cho mọi request, chiến lược 80/15/5 tiết kiệm khoảng 70 phần trăm chi phí mà chất lượng đầu ra không giảm rõ rệt với 95 phần trăm câu hỏi.
Cache settings
Mỗi request tự động được hash và lưu cache. Có hai loại cache:
- Exact cache — match chính xác messages + model, hit rate khoảng 20-30 phần trăm với chatbot
- Semantic cache — match theo embedding, áp dụng nếu bật
cache: "semantic". Tăng hit rate lên 50-60 phần trăm
json{
"messages": [{"role": "user", "content": "Sài Gòn có gì hay?"}],
"task_type": "qa_simple",
"cache": {
"mode": "semantic",
"ttl_seconds": 86400,
"similarity_threshold": 0.92
}
}
Cache TTL mặc định 1 giờ. Khi hit, bạn nhận response gần như tức thì (dưới 100ms) với cache_hit: true và actual_cost_usd: 0.
Rate limit & quota
| Gói | Req/phút | Tokens/ngày | USD/tháng |
|---|---|---|---|
| Free | 20 | 200K | 0 (kèm $1 credit) |
| Starter | 100 | 2M | 9 |
| Pro | 500 | 20M | 49 |
| Enterprise | tuỳ chỉnh | tuỳ chỉnh | liên hệ |
Khi vượt quota, hệ thống trả 429 với header Retry-After. Tham khảo Cost Dashboard để theo dõi tiêu thụ realtime.
Failover behavior
Nếu nhà cung cấp chính (Google, Anthropic) gặp lỗi 5xx hoặc timeout >30s, ZeniRouter tự động:
- Retry lần 1 sau 500ms với cùng model
- Retry lần 2 sau 2s với cùng model
- Failover sang model backup cùng tier (ví dụ Opus → Sonnet)
- Trả về 503 cho client với
routing.failover_attempts
Failover trong suốt với app — bạn chỉ thấy latency cao hơn bình thường trong trường hợp hiếm.
2. Log
routing.primary_model và actual_cost_usd để theo dõi spend.3. Bật cache với mọi endpoint công cộng — hiệu quả ngay lập tức.
4. Set quota alert tại 80 phần trăm để không bị 429 đột ngột.
Mã lỗi thường gặp
| Mã | Ý nghĩa | Xử lý |
|---|---|---|
| 401 | Token sai hoặc hết hạn | Tạo token mới trong dashboard |
| 403 | Token không có scope | Cấp lại scope ai:read,ai:write |
| 429 | Vượt rate limit | Đợi Retry-After giây hoặc upgrade gói |
| 503 | Tất cả model failover đều fail | Hiếm. Thử lại sau 30s, liên hệ support nếu lặp |