AkiDev

Sửa lỗi dữ liệu đã lên production: kiểm toán bản sao DB, sửa một chỗ, hoàn Sao theo số đã trả

productiond1kiem-toan-du-lieuai-agent

Lỗi bắt đầu từ đâu và vì sao không phải lỗi model?

Lỗi nằm ở dữ liệu đưa vào model, không nằm ở model hay prompt. Chủ dự án báo bài luận của Kinh Dịch AkiNet "lỗi luận khá nhiều", kèm ví dụ chữ tiếng Anh "child" lọt vào câu trả lời. Giả thuyết đầu tiên là prompt hoặc model. Prompt lại ra lệnh cho model "không tính lại, không nghi ngờ dữ liệu an quẻ", nên bất kỳ sai sót nào ở dữ liệu an quẻ đi thẳng vào bài luận mà không bị chặn.

Điều này đổi câu hỏi từ "model luận sai vì sao" thành "dữ liệu chúng ta đưa cho model có đúng không". Câu hỏi thứ hai kiểm chứng được bằng máy.

Màn hình hướng dẫn gieo 3 đồng xu của tính năng ghi quẻ trong bản 2.20.0 của Kinh Dịch AkiNet

Kiểm toán dữ liệu production an toàn bằng cách nào?

Kéo một bản sao D1 production về máy rồi truy vấn trên bản sao, không chạm vào dữ liệu thật. Bản sao ngày 26/09/2026 có 544 bài luận và 155 lượt hỏi thêm. Payload gửi cho model không được lưu vào DB, nhưng tái dựng được hoàn toàn từ bảng casts (số quẻ, quẻ biến, hào động, Can Chi), nên có thể tính lại payload cho mọi quẻ đã có bài luận và so với phép an quẻ cổ điển.

Quy trình gồm 4 bước:

  1. Đo lỗi bề mặt (chữ tiếng Anh lọt, dấu gạch dài) trên toàn bộ bài luận, gom theo gói và model.
  2. Truy dòng dữ liệu từ chỗ tính (buildHexagramResult) đến chỗ ghép payload, đối chiếu từng bước với phép Lục Hào.
  3. Tái tính cho mọi quẻ, đếm số bài nhận dữ liệu sai theo gói, số người và số Sao đã trả.
  4. Đọc tận mắt vài bài để xác nhận model thực sự luận theo nhãn sai, không chỉ "có nhãn sai trong payload".

Nguyên nhân gốc là gì?

Quẻ biến được an lục thân theo cung của chính quẻ biến, đúng phải theo cung của quẻ chủ. Hàm tính metadata lấy ngũ hành cung của quẻ được truyền vào làm "ta", nên khi truyền quẻ biến, "ta" đổi theo. Phép Lục Hào cổ điển giữ "ta" là cung quẻ chủ cho cả hào biến.

Hai điểm khiến lỗi sống lâu:

  • Lỗi có từ commit đầu tiên của tính năng (15/06/2026), trước cả gói trả phí đầu tiên (05/07/2026).
  • Không có phép thử nào kiểm lục thân quẻ biến. Bộ test chỉ kiểm số thứ tự quẻ biến, và tài liệu chỉ có bảng quẻ chủ.

Về lý thuyết, 3.200 trong 4.032 cặp quẻ chủ và quẻ biến (79%) khác ngũ hành cung. Ánh xạ lục thân là song ánh trên 5 hành, nên khác hành cung thì cả 6 nhãn sai, cùng hành cung thì cả 6 đều đúng. Không có trường hợp "sai một hào".

Mức ảnh hưởng đo được ra sao?

Gói Bài có hào động Nhận nhãn hào động sai Người dùng
Miễn phí 283 210 (chỉ bảng UI, payload không có lục thân) 37
Học Đồ (9★) 72 57 44
Đại Dịch Sư (79★) 52 37 17
Trả phí 124 94 (76%) 55

Bài đọc tận mắt xác nhận model luận theo nhãn sai. Ví dụ quẻ Tiệm biến Sư: bài viết "hào 6 động biến thành Phụ Mẫu" trong khi đúng là Tử Tôn, rồi dựng luận điểm "giấy tờ, quyết định còn lửng lơ" trên nhãn sai đó.

Lỗi thứ hai độc lập: chữ "child" xuất hiện ở 18 trong 91 lượt hỏi thêm của gói cao nhất, do khối chỉ dẫn xưng hô ở prompt hỏi thêm đã lệch khỏi bản chính. Sửa bằng cách cho prompt hỏi thêm dùng lại đúng khối ngôn ngữ và dấu câu dùng chung.

Sửa ở đâu để đúng mọi nơi cùng lúc?

Sửa tại một hàm. Gieo quẻ, ghi quẻ, Lịch sử, trang chia sẻ và trang quản trị đều dựng quẻ qua buildHexagramResult, nên đổi cách chọn ngũ hành "ta" ở đó là đủ. Bảng quẻ biến cũng bỏ Thế/Ứng riêng, vì Thế/Ứng thuộc quẻ chủ.

Bộ test mới khóa quy tắc bằng ca thật: Tiệm biến Sư, hào 6 là Tử Tôn, hào 3 là Phụ Mẫu, và quẻ biến không mang Thế/Ứng. Đáp án lấy từ bảng nạp giáp tham chiếu trong tài liệu dự án, không tính lại bằng chính hàm đang được kiểm.

Migration và deploy đi theo thứ tự nào?

Bản này còn thêm ba cột cho tính năng ghi quẻ (cast_method, cast_at, cast_tz) qua hai migration, nên thứ tự là mở rộng, migrate, deploy code, không bao giờ ngược lại:

  1. Diễn tập hai migration ADD COLUMN trên bản sao production trước, để chắc chắn chạy được trên dữ liệu thật.
  2. Chạy migration --remote trước khi push, theo đúng thứ tự, rồi kiểm PRAGMA table_info(casts). Cả 712 dòng cũ nhận giá trị mặc định virtual, cast_at và cast_tz để rỗng.
  3. Push, để Cloudflare Pages tự build và deploy.
  4. Xác minh sau deploy bằng đường dữ liệu thật, không chỉ chuỗi phiên bản: một API công khai đọc được ba cột mới từ D1 production và trả 200.

Chuỗi phiên bản chỉ chứng minh code đã lên, không chứng minh chức năng chạy được trên schema mới.

Hoàn Sao cho người bị ảnh hưởng theo nguyên tắc nào?

Hoàn đúng số Sao người dùng đã trả cho các bài bị ảnh hưởng, không làm tròn và không đồng loạt. Kết quả: 72 bài, 52 người, tổng 2.608★ (từ 9★ đến 641★ mỗi người), sau khi loại các tài khoản nội bộ và các bài không đủ điều kiện.

Ba thiết kế giữ việc hoàn an toàn:

  • Xem trước rồi mới cấp. Script chạy chế độ xem thử liệt kê người nhận và số Sao, chỉ cấp khi có cờ --grant.
  • Cấp qua luồng admin, không ghi thẳng sổ cái. Mỗi khoản đi qua endpoint tặng quà, có kiểm quyền và ghi nhận. Ví chỉ cộng khi người dùng bấm nhận.
  • Chạy lại không tặng trùng. Script bỏ qua người đã có quà cùng lời nhắn.

Bài học rút ra là gì?

  • Khi model "luận sai", kiểm dữ liệu vào trước khi sửa prompt, nhất là khi prompt cấm model tự tính lại.
  • Test chỉ bắt được điều đã từng nghĩ tới. Lỗi sống 3 tháng vì không ai viết phép thử cho lục thân quẻ biến.
  • Kiểm toán trên bản sao production cho ra số liệu thật (94 bài, 55 người, 3.648★ đã trả) mà không rủi ro cho dữ liệu sống.
  • Số tiền hoàn nên bằng số người dùng thực trả, có danh sách xem trước và có cờ chặn cấp trùng.

Cùng chuỗi bài về công cụ AI cho lập trình viên, xem thêm WebMCP trên Chrome và các dự án trong hệ sinh thái Aki.