Bài này ghi lại những gì mình đo được khi làm phần luyện nói có AI trong Thuộc Từ: một lượt hội thoại đi qua bao nhiêu bước, mỗi bước mất bao lâu, và sáu chỗ mình đã làm sai. Mình viết ra không phải để khoe hệ thống, mà vì người dùng có quyền biết họ đang chờ cái gì, còn mình thì có một chỗ để không tái phạm.
Một lưu ý trước khi đọc: mình chỉ công bố những số mình đo thật trên máy chủ đang chạy. Ở nào chưa có số, mình để trống và nói rõ là chưa đo. Cuối bài có danh sách những gì mình vẫn chưa biết.
Một lượt luyện nói đi qua bốn bước
Nhiều người tưởng "AI nghe và sửa phát âm" là một lời gọi API duy nhất. Thực tế nó là bốn bước nối tiếp, và cái thời gian bạn cảm nhận trên điện thoại là tổng của cả bốn, cộng thêm phần mạng giữa hai phía.
| Bước | Việc diễn ra | Cấu hình đang dùng | Điều mình biết chắc |
|---|---|---|---|
| 1. Thu âm và gửi lên kho lưu tạm | File ghi âm ngắn được đẩy lên kho tạm, hệ thống nhận về một đường dẫn nội bộ chứ không gửi kèm dữ liệu thô. | dashscope.asr.uploadUrl |
Đường dẫn tạm chỉ sống 48 giờ, nên mọi thứ phải được xử lý xong trong phiên. |
| 2. Nhận dạng giọng nói thành chữ | Gửi đường dẫn cho mô hình nhận dạng, rồi hỏi lại cho tới khi có kết quả. | fun-asr |
Mô hình này không nhận dữ liệu nhúng trực tiếp, chỉ nhận đường dẫn. Đây là lý do bắt buộc có bước 1. |
| 3. Mô hình ngôn ngữ soạn câu trả lời | Toàn bộ lịch sử hội thoại được gửi lại cùng câu hỏi mới, mô hình trả về phần nội dung. | qwen3.7-flash, khu vực ap-southeast-1 |
Nhiệt độ 0.8, phần suy luận ẩn đã tắt để rút ngắn thời gian chờ. |
| 4. Chuyển câu trả lời thành tiếng | Phần chữ được đưa sang mô hình đọc tiếng Việt, phát ra trên máy bạn. | qwen-audio-3.1-tts-flash + giọng longanfengyue_v3.1 |
Mình để thêm lời dặn "đọc chậm và rõ", và việc đó có phần đổi lại riêng — mình nói rõ ở mục dưới. |
Riêng phần chấm phát âm đi một con đường ngắn hơn: một mô hình duy nhất vừa nghe vừa cho điểm. Số đo thực tế trên hệ thống của mình là khoảng 2,3 giây ở mức giữa và chậm nhất cỡ 3,2 giây. Mình đặt trần thời gian chờ cho phần này là 90 giây — con số nghe rất thừa, nhưng nó được chỉnh từ chỗ hệ thống từng treo lâu hơn nhiều khi mô hình phía sau đáp chậm.
Toàn bộ tham số mình để công khai
Đây là nguyên văn các giá trị đang chạy, chỉ bỏ những thuộc về bí mật nội bộ của nhà cung cấp dịch vụ. Mình công bố vì hai lý do: người dùng hiểu vì sao tính năng có giới hạn, và mình không còn đường lùi để tự nói quá.
deepseek:
model: qwen3.7-flash
region: ap-southeast-1
temperature: 0.8
enable_thinking: false
timeout: connect 30s / read 600s
limit: 3 request / phut / nguoi dung
dashscope.asr:
model: fun-asr # chi nhan duong dan, khong nhan du lieu nhung
language_hints: vi # chi doc gia tri dau tien trong danh sach
limit: 20 / phut / nguoi, 40 / phut / IP
dashscope.tts:
model: qwen-audio-3.1-tts-flash
voice: longanfengyue_v3.1
instruction: "Please speak slowly and clearly..."
limit: 30 / phut / nguoi, 60 / phut / IP
ai.pronounce:
timeout.read: 90s # do thuc: p50 2,3s, cham nhat khoang 3,2s
evaluatePerMin: 6
modelFallback: qwen3.5-omni-flash
ai.spoken: chatPerMin: 10 ai.scene: chatPerMin: 10
chatFreeTotal: 20 chatFreeTotal: 40
Cái dòng chatFreeTotal kia là chỗ mình suy nghĩ lâu nhất. Mình chọn giới hạn theo tổng số lượt dành cho người mới thay vì theo số lượt mỗi ngày. Lý do rất thực dụng: một người học nghiêm túc cần được nói nhiều trong vài hôm đầu để biết mình có hợp hay không, còn một người dùng dăm ba hôm rồi bỏ thì hạn mức mỗi ngày cũng chẳng giữ họ lại. Đổi lại, mình mất khả năng "nuôi" người dùng lâu dài bằng một mức nhỏ đều đặn mỗi ngày. Đó là đánh đổi, không phải giải pháp.
Sáu chỗ mình đã làm sai
- Để lịch sử hội thoại dài quá mức cần thiết. Mỗi lượt nói, hệ thống gửi lại toàn bộ đoạn chat trước đó. Khi mình để trần 20 tin nhắn, cuộc nói chuyện càng về sau càng chậm — một cách đều đặn và khó nhận ra nếu chỉ nhìn vào một lần đo. Mình hạ xuống 10 tin cho phần luyện nói và 16 tin cho phần hội thoại theo tình huống, vì một màn hội thoại kiểu đó thường chỉ diễn bốn tới sáu lượt là hết chuyện.
- Tưởng danh sách ngôn ngữ sẽ được đọc nguyên danh sách. Tham số gợi ý ngôn ngữ chỉ lấy giá trị đầu tiên. Mình từng gửi hai giá trị và tin rằng hệ thống "linh động" giữa chúng; thực tế giá trị thứ hai bị bỏ qua hoàn toàn.
- Quên rằng "đọc chậm và rõ" phải trả bằng thời gian chờ. Lời dặn thêm vào phần đọc khiến lượng âm thanh phát ra dài hơn khoảng 15 tới 19 phần trăm cho cùng một nội dung. Nghĩa là bạn chờ lâu hơn và hệ thống tốn hơn, đổi lấy việc người nghe nhận đúng tốt hơn. Mình vẫn giữ, nhưng phải nói rõ cái được và cái mất thay vì để nó là một tùy chọn vô hình.
- Từng chọn mô hình chấm điểm chỉ vì nó cho điểm cao. Có một bản cho điểm rất tự tin — kể cả với file ghi âm im lặng. Đó không phải chấm phát âm, đó là đoán. Bây giờ bản dự phòng là một model khác, và mình không còn lấy "điểm trung bình cao" làm tiêu chí chọn mô hình nữa.
- Nói giảm nói tránh chuyện giới hạn theo phút. Các con số 3, 20, 30, 60 ở trên là phanh chi phí, không phải chiêu giữ chân người dùng. Mình từng diễn đạt nó trong ứng dụng như một "chính sách dùng hợp lý", nghe nhẹ nhàng hơn sự thật. Cách nói đúng nên là: tài nguyên tính theo lượt, và mình cần chắc nó không bị một vài người dùng khai thác hết.
- Đặt tên tính năng hứa nhiều hơn cái nó làm được. Mình từng mô tả phần sửa phát âm như thể nó nghe được mọi lỗi. Nó không làm được thế, nhất là với giọng nói rất nhẹ hoặc nhiều tiếng nền. Sau chuyện đó mình viết lại toàn bộ mô tả theo hướng nói rõ điều kiện.
Một thiết kế sai vì ngại ma sát
Mình từng đặt ra một cách đổi quà lấy phản hồi, và để tiết kiệm bước cho người tham gia, mình chọn cách công khai: ai muốn nhận thì để lại thông tin trong phần bình luận ở nơi ai cũng đọc được. Kết quả sau vài ngày: gần như không ai làm theo, dù phần thưởng không nhỏ.
Sau mình hiểu ra là mình đã tính sai chiều. Mình lo người dùng phải làm nhiều bước, trong khi cái họ ngại là làm một việc hiển thị công khai. Ma sát thật nằm ở sự bối rối, không nằm ở số cú chạm. Bây giờ mình nhận phản hồi qua hộp thư riêng và trả lời từng người một — nhiều bước hơn cho mình, ít ngượng hơn cho họ, và tỉ lệ người tham gia khác hẳn.
Những gì mình chưa đo
Để bài này không phải là một quảng cáo trá hình devlog, mình liệt kê phần chưa biết. Mình chưa có số đo độc lập cho chi phí mỗi lượt hội thoại theo từng quốc gia, vì hóa đơn của nhà cung cấp cộng gộp nhiều thứ và mình chưa tách được. Mình chưa thử nghiệm hệ thống với nhiều người dùng cùng lúc ở giờ cao điểm — các con số về thời gian chờ ở trên là đo trong điều kiện sử dụng bình thường. Mình cũng chưa đánh giá phần nhận dạng giọng nói với chất lượng đường truyền yếu, vốn rất phổ biến khi học trên xe buýt hay trong hẻm.
Nếu bạn dùng Thuộc Từ và thấy phần luyện nói chậm bất thường ở một khung giờ nào đó, đó chính là dữ liệu mình đang thiếu. Gửi mô tả ngắn (bạn đang làm gì, vào lúc nào, mất bao lâu thì xong hoặc không xong) về support@91word.com — mình ghi lại theo từng ca và sẽ công bố tổng hợp ở bài sau.
Tóm lại
Ba thứ mình học được: thứ nhất, một tính năng "AI" thật ra là bốn bước nối tiếp, và người dùng cảm nhận tổng của chúng chứ không từng phần. Thứ hai, giới hạn tài nguyên nên được nói thẳng là giới hạn, vì cách nói vòng chỉ làm mình mất tin tưởng khi bị soi. Thứ ba, đừng bắt người dùng làm điều gì công khai mà chính bạn cũng không muốn làm.
Bài tiếp theo trong loạt này mình định đo phần còn trống ở trên: thời gian chờ thực tế theo khung giờ, và chuyện gì xảy ra khi mạng yếu. Bạn muốn mình đo cái nào trước?
Còn thắc mắc về cách tính năng hoạt động? cứ hỏi thẳng trong phần bình luận — mình trả lời từng câu, và câu nào cần kiểm tra lại mã nguồn thì mình sẽ trả lời chậm nhưng trả lời đủ.