Bỏ qua tới nội dung chính
Quay lại tin tức

Ba lý do khiến LLM trong kho dữ liệu của bạn trả lời sai câu hỏi "Tại sao doanh thu giảm?" và cách khắc phục từng lý do

Medium Towards AI· Roman Beseda· 31/5/2026general

Kết nối một mô hình ngôn ngữ với kho dữ liệu của bạn là một bản demo tuyệt vời nhưng lại là một công cụ chẩn đoán kém hiệu quả. Dưới đây là ba lỗi bạn thực sự sẽ gặp phải, mỗi lỗi đều có cách khắc phục, bằng SQL thuần túy. Cắm một LLM vào kho dữ liệu của bạn, gõ "tại sao doanh thu giảm 8% vào tuần trước?", và bạn sẽ nhận được một đoạn văn tự tin trong bốn mươi giây. Cảm giác như nút thắt cổ chai của nhà phân tích vừa biến mất. Sau đó, bạn bắt đầu kiểm tra các câu trả lời, và ba vấn đề xuất hiện – theo thứ tự, mỗi vấn đề lại ít rõ ràng hơn vấn đề trước. Không có vấn đề nào gây ra lỗi. Dưới đây là từng vấn đề trên một ví dụ Postgres thực tế, và cách khắc phục chúng. Lỗi 1 – SQL chạy, nhưng đó không phải là con số bạn muốn

Việc kết nối một mô hình ngôn ngữ với kho dữ liệu của bạn là một bản trình diễn tuyệt vời nhưng lại là một công cụ chẩn đoán kém hiệu quả. Dưới đây là ba lỗi thực tế bạn sẽ gặp phải, mỗi lỗi đều có cách khắc phục bằng SQL thuần túy. Cắm một LLM (mô hình ngôn ngữ lớn) vào kho dữ liệu của bạn, gõ "tại sao doanh thu giảm 8% vào tuần trước?", và bạn sẽ nhận được một đoạn văn tự tin trong bốn mươi giây. Cảm giác như nút thắt cổ chai của nhà phân tích vừa biến mất. Sau đó, bạn bắt đầu kiểm tra các câu trả lời, và ba vấn đề xuất hiện – theo thứ tự, mỗi vấn đề lại ít rõ ràng hơn vấn đề trước. Không có vấn đề nào gây ra lỗi. Dưới đây là từng vấn đề trên một ví dụ Postgres thực tế, và cách khắc phục. Lỗi 1 – SQL chạy, nhưng không phải là con số bạn muốn Câu hỏi: "Doanh thu của chúng ta tháng trước là bao nhiêu?" Mô hình viết: SELECT SUM(amount) AS revenue FROM orders WHERE created_at >= date_trunc('month', now()) - interval '1 month' AND created_at < date_trunc('month', now()); SQL hợp lệ. Chạy sạch. Trả về một con số. Và nó sai, bởi vì bảng orders chứa những thứ mà "doanh thu" không bao gồm: các đơn hàng bị hủy và hoàn tiền vẫn còn trong đó các đơn hàng thử nghiệm (is_test = true) vẫn còn trong đó amount trộn lẫn các loại tiền tệ – AED và EGP được cộng lại thành một tổng vô nghĩa created_at đếm các đơn hàng đã được đặt vào tháng trước, chứ không phải đã được giao – doanh thu mà bạn có thể không bao giờ thu được Mô hình không biết bất kỳ điều nào trong số này, bởi vì định nghĩa "doanh thu" cho doanh nghiệp của bạn không nằm trong lược đồ. Nó nằm trong một mô hình dbt không ai ghi lại, hoặc trong đầu của nhà phân tích đã nghỉ việc. Vì vậy, mô hình đã đoán, và phỏng đoán đó đã được thực thi một cách sạch sẽ. Đó là phần nguy hiểm. Một con số sai gây ra lỗi, bạn sẽ phát hiện ra. Một con số sai được trả về, bạn sẽ gửi cho Giám đốc điều hành của mình. Cách khắc phục – ghim định nghĩa một lần, không bao giờ để mô hình chạm vào các bảng thô. Xác định chỉ số mà doanh nghiệp thực sự muốn, dưới dạng một view (hoặc một mô hình dbt), và trỏ mô hình vào đó: CREATE VIEW finance.net_revenue_orders AS -- một hàng cho mỗi đơn hàng đã giao SELECT o.order_id, date_trunc('day', o.delivered_at) AS day, -- đã giao, không phải đã đặt o.city, o.gmv_usd AS net_revenue_usd -- tiền tệ đã được chuẩn hóa ở upstream FROM orders o WHERE o.status = 'delivered' -- không phải đã đặt, không phải đã hủy AND o.is_test = false; -- không có lưu lượng truy cập thử nghiệm Một hàng cho mỗi đơn hàng đã giao – view duy nhất này là nguồn duy nhất cho mọi truy vấn bên dưới. Bây giờ "doanh thu tháng trước là bao nhiêu" trở thành SELECT SUM(net_revenue_usd) FROM finance.net_revenue_orders WHERE day >= ... – chính xác một định nghĩa về doanh thu, định nghĩa mà bộ phận tài chính đã đồng ý. Đây là mục đích của một lớp ngữ nghĩa: mô hình dịch câu hỏi, nhưng phép tính chạy trên các định nghĩa mà bạn kiểm soát. Lỗi không còn giống như một con số sai có thể chấp nhận được mà bắt đầu giống như một lỗi nếu một cột không tồn tại – đó là loại lỗi bạn muốn. Cùng một cái bẫy, sâu hơn một cấp độ: phép nối fan-out. Nối bảng orders với order_items (một đơn hàng, nhiều mặt hàng) và mỗi đơn hàng được đếm một lần cho mỗi mặt hàng – vì vậy SUM(net_revenue_usd) cộng nó hai hoặc ba lần. Không có lỗi, chỉ là một tổng số bị thổi phồng. Việc ghim view cũng khắc phục được điều này. Lỗi 2 – Hỏi tại sao, nhận được một câu chuyện thay vì một chẩn đoán Câu hỏi: "Tại sao doanh thu giảm 8% vào tuần trước?" Những gì mô hình cung cấp cho bạn: một đoạn văn. "Doanh thu giảm vì tỷ lệ chuyển đổi trên thiết bị di động giảm, có thể do thay đổi quy trình thanh toán vào thứ Ba, với hiệu ứng thứ cấp từ lưu lượng truy cập trả phí thấp hơn." Nghe có vẻ giống một nhà phân tích. Nó không phải là một chẩn đoán. Mô hình không phân tích hay kiểm tra bất cứ điều gì – nó tạo ra lời giải thích nghe có vẻ hợp lý nhất dựa trên các từ trong câu hỏi của bạn. Đôi khi câu chuyện đó đúng. Thường thì nó chỉ ra nguyên nhân sai, và bạn không thể biết cái nào. Một chẩn đoán thực sự là một cuộc tìm kiếm, không phải một câu chuyện. Và cuộc tìm kiếm đó chính là SQL. Khắc phục, bước 1 – phân tích chỉ số và tìm yếu tố đã thay đổi. Doanh thu ≈ số đơn hàng × giá trị đơn hàng trung bình. Trước khi phỏng đoán lý do, hãy tìm hiểu điều gì đã xảy ra: ```sql SELECT date_trunc('week', day) AS week, COUNT(*) AS orders, SUM(net_revenue_usd) AS revenue, SUM(net_revenue_usd) / COUNT(*) AS aov FROM finance.net_revenue_orders WHERE day >= date '2026-05-11' AND day < date '2026-05-25' GROUP BY 1 ORDER BY 1; ``` Số đơn hàng hầu như không thay đổi. Toàn bộ sự sụt giảm nằm ở quy mô giỏ hàng. Bạn chưa tìm ra nguyên nhân, nhưng bạn đã giảm một nửa vấn đề – đây không phải là vấn đề về lưu lượng truy cập hay tỷ lệ chuyển đổi, vì vậy câu chuyện "chuyển đổi trên thiết bị di động" của mô hình đã sai ngay từ bước đầu tiên. Khắc phục, bước 2 – tách tỷ lệ khỏi hỗn hợp (cái bẫy mà mọi người đều mắc phải). Giá trị đơn hàng trung bình (AOV) của bạn có thể giảm trong khi AOV của mỗi thành phố vẫn ổn định – nếu cơ cấu đơn hàng của bạn chuyển dịch sang các thị trường có giá rẻ hơn. Đây là nghịch lý tương tự khiến một tổng thể di chuyển theo hướng ngược lại với tất cả các phần của nó. ```sql SELECT city, COUNT(*) FILTER ( WHERE day >= date '2026-05-11' AND day < date '2026-05-18') AS orders_wk1, COUNT(*) FILTER ( WHERE day >= date '2026-05-18' AND day < date '2026-05-25') AS orders_wk2, AVG(net_revenue_usd) FILTER ( WHERE day >= date '2026-05-11' AND day < date '2026-05-18') AS aov_wk1, AVG(net_revenue_usd) FILTER ( WHERE day >= date '2026-05-18' AND day < date '2026-05-25') AS aov_wk2 FROM finance.net_revenue_orders WHERE day >= date '2026-05-11' AND day < date '2026-05-25' GROUP BY city ORDER BY orders_wk2 DESC; ``` Nếu AOV trên mỗi thành phố không đổi nhưng tỷ lệ đơn hàng của một thành phố có AOV thấp tăng vọt, thì việc "AOV giảm" của bạn thực chất là "cơ cấu đã thay đổi" – và giải pháp là một câu hỏi về tiếp thị/cung ứng, không phải về định giá. Hai chẩn đoán dẫn đến các quyết định đối lập. Việc phân tích giúp phân biệt chúng; câu chuyện thì không. Khắc phục, bước 3 – chỉ bây giờ mới hỏi tại sao, và kiểm tra nó. Một khi bạn đã xác định được sự sụt giảm ở một yếu tố và một phân khúc, bạn có một giả thuyết ("một chương trình khuyến mãi ở thành phố có AOV thấp đã kéo cơ cấu xuống"). Điều đó bạn xác nhận bằng dữ liệu hoặc một thử nghiệm – không phải bằng một đoạn văn. Đây là toàn bộ sự khác biệt: mô hình liên kết tự do một nguyên nhân; việc phân tích liệt kê và cô lập chúng. Ba truy vấn, hoàn toàn có thể tái tạo, và bạn thực sự biết. Lỗi 3 – Hỏi cùng một câu hỏi hai lần, nhận hai câu trả lời khác nhau Thử nghiệm: chạy "tại sao doanh thu giảm vào tuần trước?" vào thứ Hai. Chạy lại vào thứ Tư. So sánh. Bạn có thể nhận được hai con số khác nhau từ cùng một câu hỏi trên cùng một dữ liệu – ngay cả khi chỉ số được cố định. Nguyên nhân là do mô hình.

Nguồn tin: Medium Towards AI — Tác giả: Roman Beseda. Bản dịch tiếng Việt do AI thực hiện, có thể có sai sót.