Bỏ qua tới nội dung
TIAHợp tác

Tài liệu API

API quyết định theo giao thức System One. Gọi trực tiếp bằng HTTP hoặc dùng typesafe-sdk với base URL của TIA.

Endpoint

POST https://staging-j97-api-9tm2.encr.app/v1/systemone

Base URL: https://staging-j97-api-9tm2.encr.app

Không có key? POST /demo/systemone nhận cùng body, không cần xác thực, không tính phí, giới hạn theo IP: 10 request mỗi phút, 60 mỗi giờ, 300 mỗi ngày.

Xác thực

Authorization: Bearer tia_live_<32 url-safe characters>

Gửi API key trong header Authorization. Key có dạng tia_live_ theo sau 32 ký tự, tạo trong trang Tài khoản và chỉ hiện một lần. Hệ thống chỉ lưu bản băm SHA-256; mất key thì thu hồi và tạo key mới.

Request body

Body là một object JSON:

fieldBắt buộcMô tả
modeltuỳ chọnNên bỏ trống: API trả lời bằng bản đang phục vụ. Các tên bắt đầu bằng "jev" được chấp nhận để tương thích typesafe-sdk. Giá trị khác trả 400.
statebắt buộcVăn bản hoặc JSON bất kỳ, trừ null. Đây là thứ mô hình đọc.
questionsbắt buộcObject từ tên câu hỏi tới định nghĩa câu hỏi, từ 1 tới 64 câu.
{
  "state": {
    "kenh": "zalo",
    "goi_dich_vu": "Pro năm",
    "tin_nhan": "Chào shop, tháng này em bị trừ tiền 2 lần cho gói Pro, 499.000đ mỗi lần, hoá đơn thứ hai vẫn đang treo. Nhờ shop hoàn lại khoản bị trừ trùng trong hôm nay giúp em, mai kế toán bên em chốt sổ rồi."
  },
  "questions": {
    "hoan_tien": {
      "type": "noul",
      "instructions": "Khách có đang yêu cầu trả lại tiền không?",
      "criteria": {
        "true": "đòi hoàn tiền, huỷ giao dịch hoặc bù tiền",
        "false": "không đòi lại tiền"
      }
    },
    "doi_xu_ly": {
      "type": "choice",
      "instructions": "Đội nào nên nhận ticket này?",
      "criteria": {
        "thanh_toan": "hoá đơn, trừ tiền, hoàn tiền, gói cước",
        "ky_thuat": "lỗi, sự cố, tích hợp",
        "tai_khoan": "đăng nhập, quyền truy cập, bảo mật",
        "ban_hang": "mua mới, nâng cấp, báo giá"
      }
    },
    "muc_do_gap": {
      "type": "score",
      "instructions": "Ticket này gấp đến mức nào?",
      "criteria": [
        "để tuần sau được",
        "bình thường, trả lời trong 2 ngày",
        "ảnh hưởng tiền hoặc công việc hôm nay",
        "sự cố diện rộng, rủi ro pháp lý hoặc bảo mật"
      ]
    }
  }
}

Kiểu câu hỏi

typecriteriaCâu trả lời
noul (hoặc boolean)Tuỳ chọn: {"true": mô tả, "false": mô tả}{"type":"noul","noul": P(có)}
choiceBắt buộc: {nhãn: mô tả}, 2 tới 10 nhãnchoice (nhãn có xác suất cao nhất), confidence, probabilities theo nhãn
scoreBắt buộc: mảng mô tả, thấp nhất trước, 2 tới 10 mứcscore (mức kỳ vọng, số thực), confidence (xác suất mức cao nhất), legend, probabilities theo mức

Mỗi câu hỏi cần instructions: chuỗi nêu câu hỏi.

Định nghĩa một quyết định như định nghĩa một tool

Nếu bạn đã viết tool cho agent, bạn đã biết cách hỏi TIA. Ba phần giống nhau: tên, mô tả, và các lựa chọn, mỗi lựa chọn một dòng mô tả.

Tool cho agent (function calling)
{
  "name": "chuyen_ticket",
  "description": "Đội nào nên xử lý ticket hỗ trợ này?",
  "parameters": {
    "type": "object",
    "properties": {
      "doi": {
        "oneOf": [
          { "const": "thanh_toan",
            "description": "hoá đơn, trừ tiền hai lần, hoàn tiền" },
          { "const": "ky_thuat",
            "description": "lỗi, ứng dụng bị treo, không đăng nhập được" },
          { "const": "ban_hang",
            "description": "hỏi giá, nâng cấp gói, hợp đồng mới" }
        ]
      }
    },
    "required": ["doi"]
  }
}
Cùng quyết định đó gửi cho TIA (POST /v1/systemone)
{
  "state": "Em bị trừ tiền 2 lần cho gói Pro tháng này, nhờ shop hoàn lại một lần giúp em.",
  "questions": {
    "chuyen_ticket": {
      "type": "choice",
      "instructions": "Đội nào nên xử lý ticket hỗ trợ này?",
      "criteria": {
        "thanh_toan": "hoá đơn, trừ tiền hai lần, hoàn tiền",
        "ky_thuat": "lỗi, ứng dụng bị treo, không đăng nhập được",
        "ban_hang": "hỏi giá, nâng cấp gói, hợp đồng mới"
      }
    }
  }
}
Tool cho agentQuyết định trong TIA
nametên câu hỏi, khoá trong questions
descriptioninstructions
các giá trị enum / oneOf, mỗi giá trị có descriptioncriteria: {nhãn: mô tả}, 2 tới 10 nhãn (bắt buộc với choice)
tham số true/falsetype "noul" (hoặc "boolean"), criteria tuỳ chọn {"true": ..., "false": ...}
thang có thứ tự (ví dụ 0 tới 3)type "score", criteria là mảng mô tả, mức thấp nhất trước
Câu trả lời thật đã lưu
"chuyen_ticket": {
  "type": "choice",
  "choice": "ky_thuat",
  "confidence": 0.483,
  "probabilities": {
    "thanh_toan": 0.313,
    "ky_thuat": 0.483,
    "ban_hang": 0.203
  }
}

Output đã lưu của POST /demo/systemone với đúng request trên, 30/09/2026, req_00d26492d6820b877ebf041e. Làm tròn 3 chữ số; không phải output trực tiếp của bản hiện phục vụ.

Ở ví dụ này mô hình chọn sai (ky_thuat), với xác suất cao nhất chỉ 0,48. Nếu đặt ngưỡng 0,8, quy trình sẽ chuyển ticket cho người duyệt. Đây là ví dụ về cách dùng ngưỡng, không phải ngưỡng vận hành đã được kiểm chứng.

Bảo đảm về cấu trúc

Mọi câu trả lời là một phân phối xác suất trên đúng các lựa chọn bạn đã định nghĩa. Mô hình không thể trả về văn bản tự do hay một lựa chọn không có trong danh sách, nên tỷ lệ câu trả lời nằm ngoài schema là 0%. Bảo đảm này nói về hình dạng câu trả lời, không nói về độ đúng: lựa chọn có xác suất cao nhất vẫn có thể sai.

Câu hỏi và mô tả lựa chọn quan trọng tới đâu

Bỏ bất kỳ phần nào cũng làm KL tăng (kém đi) ở cả bốn ô, trên cả hai tập. Accuracy giảm ở ba ô; ô còn lại, câu hỏi trung tính trên typed-decisions (-1,3 điểm, KTC 95% [-3,2; +0,5]), chưa kết luận. Phần nào quan trọng hơn thì tuỳ tác vụ. Khi nhãn tự nó không mang nghĩa (true/false, 1 tới 5), mô tả lựa chọn quyết định kết quả (-20,4 điểm accuracy trên typed-decisions). Khi nhãn đã tự giải thích, câu hỏi quyết định (-13,9 điểm trên tập tổng hợp). Vì vậy hãy định nghĩa mỗi quyết định như một tool: tên và câu hỏi rõ ràng, và một dòng mô tả cho mọi lựa chọn.

Câu hỏi và mô tả lựa chọn quan trọng tới đâu, TIA 1.1 mini
Requesttập dev typed-decisions (930)tập dev tổng hợp (8.875)
AccuracyKL (thấp là tốt)AccuracyKL (thấp là tốt)
Đầy đủ: câu hỏi và mô tả cho mọi lựa chọn0,7590,1340,8780,173
Bỏ mô tả lựa chọn, chỉ còn nhãn-20,4 điểm [-24,0; -16,8]+0,246 [+0,217; +0,277]-2,6 điểm [-2,9; -2,2]+0,064 [+0,057; +0,073]
Thay câu hỏi bằng một từ trung tính-1,3 điểm [-3,2; +0,5], chưa kết luận+0,029 [+0,021; +0,039]-13,9 điểm [-14,8; -13,0]+0,236 [+0,220; +0,254]

Các hàng dưới dòng đầu là chênh lệch so với request đầy đủ, kèm khoảng tin cậy 95%. Mô hình được xây để đọc câu hỏi và mô tả lựa chọn, nên số này đo mức nó dựa vào chúng, không phải một quy luật chung cho mọi mô hình. Hãy luôn mô tả các lựa chọn của bạn.

Nguồn: TIA đo ngày 30/09/2026, TIA 1.1 mini (mô hình chạy System One API lúc đo, trước TIA 1.2 mini), báo cáo nội bộ về mô tả lựa chọn; bootstrap ghép cặp, 2.000 lần lấy mẫu lại, khoảng tin cậy 95%. tập dev typed-decisions: 930 quyết định, cùng tập "dev" trên trang Benchmark. tập dev tổng hợp: 8.875 quyết định, nhiều loại tác vụ quyết định hơn, dễ hơn tập typed-decisions.

Response

Response 200 có dạng sau (kiểu dữ liệu TypeScript):

type Response = {
  id: string;                    // "req_…", quote it for support
  object: "systemone";
  model: string;
  answers: Record<string,        // one entry per question name
    | { type: "noul"; noul: number }                      // P(yes), 0..1
    | { type: "choice"; choice: string; confidence: number;
        probabilities: Record<string, number> }           // sums to 1
    | { type: "score"; score: number; confidence: number; // score = expected level
        legend: Record<string, string>;                   // "0" → lowest description
        probabilities: Record<string, number> }
  >;
  cached: boolean;               // served from a stored result: cached price
  usage: { input_tokens: number; output_tokens: 0;
           cached_input_tokens: number; // input_tokens if cached, else 0
           free_tokens: number;         // free quota used (1/10 per cached token)
           cost_micro_vnd: number; cost_display: string };
  balance_display: string;       // e.g. "12.345 đ"; absent on /demo/systemone
};

Lỗi

Mọi lỗi có dạng {"code": ..., "message": ..., "details": ...}. message viết cho người đọc, code để code rẽ nhánh. Lỗi 400 từ mô hình có details.type là input_too_long hoặc invalid_request.

HTTPcodeKhi nàoNên làm gì
400invalid_argumentBody sai: thiếu state, sai type, số nhãn ngoài 2 tới 10, quá 64 câu, model lạ (details.type = invalid_request).Sửa request theo message.
400invalid_argumentTổng token đầu vào vượt giới hạn (details.type = input_too_long).Rút gọn state hoặc chia request.
401unauthenticatedThiếu key, key sai hoặc đã thu hồi.Kiểm tra header Authorization.
402payment_requiredHết lượt miễn phí tháng này và hết số dư. Kiểm tra trước khi gọi mô hình.Nạp tiền rồi gửi lại.
429rate_limitedVượt một giới hạn của hạng tài khoản (phút, giờ, ngày, số request cùng lúc) hoặc giới hạn theo IP của demo. Body nói rõ khung nào.Chờ đúng số giây trong Retry-After.
503unavailableMô hình tạm thời chưa sẵn sàng. details.reason = "warming": mô hình đang khởi động sau thời gian nghỉ (thường 1 tới 4 phút).Thử lại sau Retry-After. Không tính phí.

Tính phí và giới hạn

  • Mỗi tháng (giờ Việt Nam) có 100.000.000 token đầu vào miễn phí, trừ trước; hết lượt thì 500 đ cho 1 triệu token đầu vào, trừ vào ví. Output miễn phí. Áp dụng từ 01/10/2026.
  • Request lặp lại được trả từ kết quả đã lưu ("cached": true; cùng tài khoản, cùng nội dung JSON, cùng phiên bản mô hình) tính 50 đ cho 1 triệu token và trừ 1/10 lượt miễn phí; usage.cached_input_tokens cho biết số token tính giá này.
  • Token đầu vào gồm state, instructions và mô tả trong criteria. usage.input_tokens và usage.cost_display trong response là của chính request đó.
  • Giới hạn request tính theo tài khoản (mọi key của tài khoản dùng chung) và tăng theo hạng. Hạng là tổng số tiền đã nạp thành công từ trước tới nay.
  • Mỗi response có trường id (req_…). Gửi id này khi cần hỗ trợ.
HạngTổng nạpRequest/phút (dồn)Request/giờRequest/ngàyCùng lúcToken vào/request
Miễn phí0 đ30 (10)1.00010.00024.096
Hạng 1≥ 20.000 đ300 (60)15.000300.000164.096
Hạng 2≥ 500.000 đ1.200 (200)60.0001.200.000644.096
Hạng 3≥ 5.000.000 đ3.000 (500)150.0003.000.0001284.096

Hạng Miễn phí còn bị giới hạn theo IP: mọi tài khoản miễn phí trên cùng một IP dùng chung một hạn mức ngày (window ip_day).

Mọi hạng có cùng một giới hạn đầu vào: 4.096 token mỗi request, là giới hạn cứng của chính mô hình. GET /v1/models trả về giá trị này ở max_input_tokens. Vượt giới hạn, response là 400 với details.type input_too_long.

Response 429 có các header sau (dùng chúng để giãn nhịp gọi):

headerMô tả
X-RateLimit-LimitGiới hạn request mỗi phút của hạng.
X-RateLimit-RemainingSố request còn lại trong phút này.
X-RateLimit-ResetSố giây tới khi hạn mức phút hồi lại.
X-RateLimit-Limit-DayGiới hạn request mỗi ngày (giờ Việt Nam).
X-RateLimit-Remaining-DaySố request còn lại hôm nay.
Retry-AfterChỉ có trên 429 và 503: số giây nên chờ.

Body của 429 nói rõ khung nào bị chạm (minute, hour, day, concurrency, ip_day):

{
  "code": "rate_limited",
  "message": "rate limit exceeded",
  "window": "minute",
  "limit": 30,
  "retry_after_seconds": 2,
  "tier": "free",
  "upgrade_url": "https://tia.8syncdev.com/pricing"
}

Endpoint khác

endpointMô tả
GET /v1/modelsMô hình đang phục vụ và giới hạn (max_input_tokens, max_questions, số lựa chọn).
GET /v1/requests/{id}Cần key. Bản ghi của một request thuộc tài khoản của key; giữ 7 ngày.
GET /statusKhông cần key. Số máy chủ mô hình đang sẵn sàng, mô hình và revision; waking: true khi mô hình đang khởi động sau thời gian nghỉ (gọi lại sau ít giây).
POST /demo/systemoneKhông cần key. Cùng body, giới hạn theo IP, không tính phí.

Ví dụ

Ví dụ đọc base URL và key từ biến môi trường, không ghi key vào code.

export TIA_API_URL="https://staging-j97-api-9tm2.encr.app"
export TIA_API_KEY="tia_live_..."

curl -sS "$TIA_API_URL/v1/systemone" \
  -H "Authorization: Bearer $TIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"state":{"kenh":"zalo","goi_dich_vu":"Pro năm","tin_nhan":"Chào shop, tháng này em bị trừ tiền 2 lần cho gói Pro, 499.000đ mỗi lần, hoá đơn thứ hai vẫn đang treo. Nhờ shop hoàn lại khoản bị trừ trùng trong hôm nay giúp em, mai kế toán bên em chốt sổ rồi."},"questions":{"hoan_tien":{"type":"noul","instructions":"Khách có đang yêu cầu trả lại tiền không?","criteria":{"true":"đòi hoàn tiền, huỷ giao dịch hoặc bù tiền","false":"không đòi lại tiền"}},"doi_xu_ly":{"type":"choice","instructions":"Đội nào nên nhận ticket này?","criteria":{"thanh_toan":"hoá đơn, trừ tiền, hoàn tiền, gói cước","ky_thuat":"lỗi, sự cố, tích hợp","tai_khoan":"đăng nhập, quyền truy cập, bảo mật","ban_hang":"mua mới, nâng cấp, báo giá"}},"muc_do_gap":{"type":"score","instructions":"Ticket này gấp đến mức nào?","criteria":["để tuần sau được","bình thường, trả lời trong 2 ngày","ảnh hưởng tiền hoặc công việc hôm nay","sự cố diện rộng, rủi ro pháp lý hoặc bảo mật"]}}}'

typesafe-sdk

Ví dụ dưới đọc TIA_API_URL và TIA_API_KEY, rồi chuyển chúng sang biến cấu hình TYPESAFE_BASE_URL và TYPESAFE_API_KEY mà @typesafe-ai/sdk sử dụng. Ví dụ không chỉ định model, nên API trả lời bằng bản đang phục vụ, không phải ứng viên thử nghiệm TIA 1.5.

TYPESAFE_BASE_URL=https://staging-j97-api-9tm2.encr.app
TYPESAFE_API_KEY=tia_live_...