Vấn đề cốt lõi: developer ghét sự bất định họ không kiểm soát được
Lập trình viên xây hệ thống dựa trên giả định "input này → output kia". AI tooling phá vỡ giả định đó: cùng prompt cho kết quả khác nhau, độ trễ dao động, đôi khi mô hình "bịa" (hallucinate). DX PM không thể xóa bỏ tính bất định — nó là bản chất — nhưng có thể thiết kế API để dev kiểm soát, dự đoán và xử lý được sự bất định đó. Đây là kỹ năng đặc trưng nhất của DX PM mảng AI.
Nguyên tắc 1: Cho dev đòn bẩy kiểm soát
Mọi API AI nên phơi ra các tham số giúp dev điều chỉnh mức độ bất định:
temperature/top_p: điều khiển độ ngẫu nhiên. Đặt mặc định hợp lý và giải thích rõ.seed: nếu backend hỗ trợ, cho phép tái lập kết quả — cực kỳ quý cho testing.max_tokens: chặn trên độ dài, tránh phản hồi tràn và chi phí bất ngờ.response_format/ structured output: cho phép ép output theo JSON schema, biến thứ khó đoán thành thứ máy đọc được.
Nguyên tắc 2: Làm sự bất định trở nên minh bạch, không im lặng
- Trả về metadata:
usage(token in/out),model(phiên bản mô hình đã dùng),finish_reason(kết thúc do đủ, domax_tokens, hay do content filter). Dev cần biết tại sao output ra như vậy. - Phân biệt rõ các trạng thái kết thúc: một phản hồi bị cắt vì
max_tokenskhác hoàn toàn một phản hồi hoàn chỉnh — dev phải phân biệt được để retry đúng. - Confidence / safety signals nếu có: giúp dev quyết định có nên tin output không.
Nguyên tắc 3: Thiết kế lỗi như một tính năng
Với AI API, lỗi đa dạng và cần xử lý khác nhau. Một taxonomy lỗi tốt:
| Loại | Ý nghĩa | Dev nên làm gì |
|---|---|---|
rate_limit (429) | Vượt giới hạn | Retry với backoff, đọc header Retry-After |
context_length | Prompt quá dài | Cắt bớt input |
content_filter | Bị chặn nội dung | Đổi prompt, không retry mù |
timeout (504) | Quá lâu | Retry hoặc giảm kích thước |
invalid_request (400) | Sai tham số | Sửa code — không retry |
code), thông điệp người-đọc-được, và gợi ý hành động. Đừng gộp tất cả thành 500 Internal Error.Nguyên tắc 4: Idempotency và streaming
- Idempotency key: vì AI call đắt và có thể timeout giữa chừng, cho phép dev gửi
idempotency_keyđể retry an toàn không bị tính phí/tạo kết quả hai lần. - Streaming (SSE): với LLM, trả token dần dần cải thiện cảm nhận độ trễ rất nhiều. Nhưng phải thiết kế rõ: định dạng event, cách báo kết thúc, cách trả lỗi giữa dòng stream.
Ví dụ cụ thể
Một API đổi từ trả về text thô sang cho phép response_format: json_schema. Trước đó dev phải viết regex mong manh để parse output LLM và thường xuyên vỡ khi mô hình đổi cách diễn đạt. Sau khi có structured output khớp schema, tỉ lệ lỗi parse phía dev giảm mạnh và số ticket support về "output không đúng định dạng" gần như biến mất — dù mô hình bên dưới vẫn non-deterministic.
Khung tư duy: "Contract ổn định bọc quanh lõi biến thiên"
Dev không cần lõi tất định; họ cần một hợp đồng (contract) ổn định: schema cố định, taxonomy lỗi cố định, metadata nhất quán, hành vi versioning rõ ràng. Bên trong lõi có thể biến thiên bao nhiêu tùy ý, miễn là lớp vỏ hợp đồng không đổi bất ngờ.
Checklist thiết kế API AI
- [ ] Có tham số kiểm soát bất định (
temperature,seed,max_tokens) với mặc định hợp lý chưa? - [ ] Có structured output / JSON schema chưa?
- [ ] Response có
finish_reason,usage,modelchưa? - [ ] Taxonomy lỗi có mã ổn định + gợi ý hành động chưa?
- [ ] Có idempotency key cho retry an toàn chưa?
- [ ] Streaming (nếu có) đã định nghĩa rõ event và cách báo lỗi giữa dòng chưa?
Sai lầm thường gặp
- Ẩn phiên bản mô hình, khiến dev không hiểu vì sao output đổi sau một đợt cập nhật thầm lặng.
- Gộp mọi lỗi thành 500, buộc dev đoán mò và retry mù cả những lỗi không nên retry.
- Không có structured output, đẩy gánh nặng parse text bấp bênh sang dev.
- Bỏ qua idempotency, khiến retry sau timeout tạo double-charge hoặc kết quả trùng.
- Đặt
temperaturemặc định cao rồi để dev bối rối vì output "lúc nào cũng khác".