Nhiệm vụ: Xử lý trình xử lý lỗi trong trò chuyện AI
Xử lý trình xử lý lỗi trong trò chuyện AI
Theo thống kê, không hiếm trường hợp yêu cầu gửi tới tác nhân AI bị xử lý không chính xác ở phía nhà cung cấp AI. Nhà cung cấp trả về lỗi: Nhà cung cấp đã ngắt quãng quá trình tạo cho mô hình "google/gemini-3.5-flash-lite": phản hồi bị cắt xén hoặc bị hỏng. Vui lòng thử lại yêu cầu.
Hơn nữa, khách hàng khẳng định rằng nó không hoạt động cụ thể trên máy tính xách tay trong trình duyệt Chrome. Nghĩa là, họ gửi yêu cầu và nhận được lỗi. Từ điện thoại di động thì mọi thứ vẫn hoạt động. Một khả năng là trình duyệt có thể không hỗ trợ tính năng truyền phát http (http streamable). Nghĩa là, nếu người dùng gửi yêu cầu và ngay lập tức hủy nó (nếu luồng không được hỗ trợ), thì kết nối với nhà cung cấp có thể chỉ đơn giản là bị đóng.
Ворклоги
Đây là những gì ChatGPT nói:
Có, việc ngắt yêu cầu trong trình duyệt có thể dẫn đến việc hủy quá trình tạo phản hồi ở phía nhà cung cấp — nếu backend của bạn liên kết hai kết nối này và truyền tín hiệu hủy đi. Nhưng việc Chrome hiện đại thiếu hỗ trợ phản hồi truyền trực tuyến (streaming) là nguyên nhân khó xảy ra: fetch() hỗ trợ đọc phản hồi thông qua ReadableStream. MDN
Ở đây cần phân tách hai phần: trình duyệt → máy chủ của bạn và máy chủ của bạn → nhà cung cấp. Nếu trình duyệt ngắt yêu cầu, máy chủ có thể hủy yêu cầu đến nhà cung cấp thông qua AbortController. Khi đó, trình xử lý lỗi thực sự có thể nhầm lẫn việc hủy này với việc «nhà cung cấp gián đoạn quá trình tạo». Bản thân thông báo lỗi chưa chứng minh được bên nào đã ngắt kết nối trước. Việc hủy thông qua AbortSignal có thể kết thúc yêu cầu HTTP với lỗi AbortError. Tài liệu Node.js v26.10.0
Bạn có thể kiểm tra tính có sẵn của API trực tiếp trong bảng điều khiển (console) của trình duyệt:
const supportsResponseStreaming =
typeof fetch === 'function' &&
typeof ReadableStream === 'function' &&
typeof Response === 'function' &&
'body' in Response.prototype &&
typeof ReadableStream.prototype.getReader === 'function';
console.log({ supportsResponseStreaming });
Thao tác này kiểm tra tính hỗ trợ đọc phản hồi dạng stream. Không có hàm riêng biệt nào trong trình duyệt mang tên «hỗ trợ HTTP Streamable»; nếu chúng ta đang nói về yêu cầu JSON thông thường và phản hồi stream từ trợ lý ảo (agent), thì chính tính năng này là cần thiết. Việc gửi phần thân (body) yêu cầu theo dạng stream là một tính năng khác, với các giới hạn riêng của nó. MDN
Nhưng giá trị true không đảm bảo rằng stream hoạt động bình thường qua toàn bộ chuỗi. Để làm điều này, bạn cần một endpoint kiểm thử trên máy chủ của mình, ví dụ gửi năm thông điệp với khoảng cách một giây mỗi thông điệp, và kiểm tra trong trình duyệt:
async function testStream(url) {
const started = performance.now();
const response = await fetch(url, { cache: 'no-store' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
if (!response.body) throw new Error('Không có phần thân phản hồi');
const reader = response.body.getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
console.log({
elapsedMs: Math.round(performance.now() - started),
bytes: value.byteLength,
});
}
console.log('Stream đã hoàn tất');
} catch (error) {
console.error('Lỗi khi đọc stream:', error);
} finally {
reader.releaseLock();
}
}
testStream('/api/stream-test');
Địa chỉ ở đây chỉ mang tính ước lệ — bạn cần triển khai endpoint đó. Việc đọc qua getReader() cho phép theo dõi quá trình tiếp nhận các phần phản hồi. Ranh giới của các phần mạng không nhất thiết phải trùng khớp với ranh giới thông điệp của máy chủ. MDN
Diễn giải:
- Các phần đến dần dần — stream đang hoạt động.
- Mọi thứ đến trong một cục ở cuối — đâu đó đang có bộ đệm (buffering).
- Việc đọc gặp lỗi và dừng lại — kết nối hoặc quá trình xử lý stream bị gián đoạn; nguyên nhân cần được đối chiếu với nhật ký (log) của máy chủ.
Đối với trường hợp của bạn, bài kiểm tra quyết định chính là thứ tự sự kiện trong log của một yêu cầu duy nhất: ngắt kết nối từ phía client, gọi lệnh hủy yêu cầu tới nhà cung cấp, lỗi đọc phản hồi từ nhà cung cấp. Nếu client ngắt kết nối trước, sau đó mã của bạn mới hủy quá trình tạo, thì giả thuyết này được xác nhận. Nếu stream từ nhà cung cấp bị hỏng trước — nguyên nhân nằm ở một bộ phận khác.
Sự khác biệt giữa «máy tính xách tay / thiết bị di động» bản thân nó chỉ cho thấy sự khác biệt về điều kiện: mạng, VPN, tiện ích mở rộng (extension), phiên bản frontend hoặc logic hủy yêu cầu của nó. Không thể chọn ra một nguyên nhân cụ thể chỉ dựa vào dấu hiệu này.