← Về danh sách bài viết
Phần 2

Bốn cái bẫy khi tự làm hệ thống đo cuộc gọi

28 tháng 7, 2026

Phần 1 dừng ở chỗ: cách duy nhất còn lại là tự cấp số điện thoại Việt Nam cho từng người xem web. Bài này kể hệ thống đó hoạt động ra sao, và bốn chỗ đã sập phải khi chạy thật trên 1fix.vn, đơn vị dịch vụ sửa chữa nhà tại TP.HCM, hệ thống do chính chúng tôi xây và vận hành.

Bốn cái bẫy này không có trong tài liệu nào. Chúng chỉ hiện ra khi có khách thật gọi vào.

Hệ thống chạy thế nào

Bảy bước, từ lúc khách bấm quảng cáo tới lúc Google học được điều gì đó.

  1. Khách bấm quảng cáo. Google gắn vào địa chỉ một mã nhận dạng riêng cho lần bấm đó.
  2. Website đọc mã, lưu lại, nhưng vẫn hiện số hotline thật. Đây là chi tiết quan trọng: nếu tráo số ngay lúc tải trang thì công cụ tìm kiếm cũng đọc được số tráo, và số điện thoại của bạn trên Google sẽ loạn.
  3. Khách bấm nút gọi. Đúng khoảnh khắc đó, hệ thống mới lấy một số trong kho ra, đổi số trên nút, rồi mới quay máy.
  4. Khách gọi vào số đó. Tổng đài nhận cuộc gọi kèm số máy khách và số bị gọi.
  5. Hệ thống tra ngược: số bị gọi này vừa cấp cho ai, người đó vào từ quảng cáo nào.
  6. Nếu khách chốt đơn, doanh thu thật của đơn đó được nối vào cuộc gọi.
  7. Mỗi sáng, toàn bộ dữ liệu đó được đẩy về Google Ads.
Hình 1
  1. 1
    Khách bấm quảng cáo
    Google gắn mã nhận dạng lần bấm
  2. 2
    Web vẫn hiện số thật
    chưa tráo, để công cụ tìm kiếm đọc đúng
  3. 3
    Khách bấm nút gọi
    lúc này mới lấy một số từ kho ra
  4. 4
    Khách gọi vào số đó
    tổng đài nhận số máy khách + số bị gọi
  5. 5
    Hệ thống tra ngược
    số này vừa cấp cho ai, họ đến từ đâu
  6. 6
    Khách chốt đơn
    doanh thu thật của đơn nối vào cuộc gọi
  7. 7
    Đẩy về Google mỗi sáng
    Google học từ khoá nào ra tiền
Bảy bước từ lượt bấm quảng cáo tới lúc Google học được từ khoá nào ra tiền. Bước 2 là chi tiết dễ bỏ qua nhất: web vẫn hiện số thật cho tới khi khách bấm nút.

Kho số của chúng tôi có 3 số. Nghe ít, nhưng nó vừa đủ vì mỗi số chỉ bị giữ trong 3 phút. Con số 3 phút không phải chọn bừa: đo trên dữ liệu thật, 77% khách gọi trong vòng 1 phút sau khi bấm nút, 82% trong vòng 3 phút. Ai bấm rồi để đó nửa tiếng mới gọi thì hệ thống thà không ghi nhận nguồn còn hơn ghi nhầm. Lý do nằm ở cái bẫy đầu tiên.

Bẫy 1. Cửa sổ tra ngược quá rộng: 168 đơn bị gán nhầm nguồn

Trước hết cần nói rõ việc tra ngược này để làm gì. Cuộc gọi điện thoại không mang theo bất kỳ thông tin quảng cáo nào: tổng đài chỉ biết số máy của khách và số nào bị gọi. Còn dấu vết quảng cáo thì nằm bên phía website, gắn với người vừa được cấp số đó. Nên số điện thoại là cầu nối duy nhất giữa hai bên. Tra ngược "số này vừa cấp cho ai" chính là để lấy được dấu vết quảng cáo của người đó, và có nó thì mới báo về Google được.

Bản đầu tiên tra ngược trong 24 giờ: cuộc gọi vào số X, tìm xem trong 24 giờ qua ai được cấp số X, lấy nguồn quảng cáo của người đó.

Với khách gọi ngay thì cách này cho kết quả đúng, và đúng gần như mọi lần. Đo trên dữ liệu thật: 77% khách gọi trong vòng 1 phút sau khi bấm nút, 82% trong vòng 3 phút. Với nhóm này, nhìn ngược 24 giờ hay 3 phút đều ra cùng một người.

Chỗ hỏng nằm ở những cuộc gọi không thuộc về ai cả. Khách gọi lại số còn trong nhật ký cuộc gọi từ lần trước, khách bấm nút rồi để đó nửa tiếng sau mới gọi — những cuộc này đúng ra phải để trống nguồn.

Nhưng cửa sổ 24 giờ thì lúc nào cũng tìm ra một người. Mỗi số được cấp cho khách mới trung bình mỗi 1,4 giờ, nên nhìn ngược suốt 24 giờ thì chắc chắn có ai đó trong danh sách. Hệ thống không bao giờ có cơ hội trả lời "không biết" — nó luôn tìm được người gần nhất để gán vào.

Một ca thật: một khách bấm nút và được cấp số. Trong 14 phút sau đó, bốn số máy khác nhau gọi vào chính số ấy. Hệ thống gán cả bốn cuộc vào cùng một người. Dấu vết quảng cáo của một khách bị sao ra bốn bản, dán lên bốn người khác nhau. Trong toàn bộ các cuộc bị gán nhầm, 40% là khách gọi lại số đã lưu.

Hình 2
Cách cũ · nhìn ngược 24 giờlúc nào cũng tìm ra một người, kể cả khi cuộc gọi không thuộc về ai
gọi lại số cũgọi ngaygán nhầm ngườigán đúng
24 giờ trướcbây giờ
Cách mới · nhìn ngược 3 phútkhông có ai vừa được cấp số thì bỏ trống, không đoán
gọi lại số cũgọi ngaykhông gán aigán đúng
24 giờ trướcbây giờ

Mỗi vạch mảnh là một lần số được cấp cho một khách mới, trung bình mỗi 1,4 giờ một lần. Khách bấm nút rồi gọi ngay thì cả hai cách đều ra đúng một người. Khác biệt chỉ lộ ra ở cuộc gọi lại số đã lưu trong danh bạ: cửa sổ rộng vẫn vơ được người gần nhất để gán, cửa sổ hẹp thì không thấy ai và chấp nhận bỏ trống.

Khách gọi ngay sau khi bấm nút thì cách nào cũng ra đúng một người. Khác biệt nằm ở cuộc gọi muộn hoặc gọi lại số cũ: nhìn ngược 24 giờ thì vẫn vơ được một người để gán, nhìn ngược 3 phút thì không thấy ai và bỏ trống.

Kết quả: 168 đơn hàng bị gán nhầm nguồn quảng cáo. Tệ hơn cả việc không đo, vì số liệu sai vẫn được đẩy về Google, và Google học theo số sai đó.

Cách sửa gồm hai phần. Thứ nhất, thu cửa sổ tra ngược từ 24 giờ xuống 3 phút, bằng đúng thời gian giữ số — cuộc gọi nào không có ai vừa được cấp số trong 3 phút đó thì để trống nguồn, thay vì vơ đại người gần nhất. Thứ hai, mỗi lần cấp số chỉ nhận đúng một cuộc gọi; cuộc thứ hai trở đi gọi vào cùng số đó không được ăn theo nguồn của người đầu nữa, để chặn kiểu sao ra bốn bản như ca trên.

Hệ quả là những cuộc gọi đến muộn không còn nguồn, và tỷ lệ khớp rơi từ 96% xuống 87%. Đó là đánh đổi có chủ đích: thà thiếu dữ liệu còn hơn có dữ liệu sai. Thiếu thì Google học chậm; sai thì Google học nhầm hướng, và cái đó tốn tiền thật.

Bẫy 2. Múi giờ: lỗi cùng một nguyên nhân, hai lần

Tổng đài gửi thời gian cuộc gọi theo giờ Việt Nam. Cơ sở dữ liệu lưu theo giờ quốc tế. Không ai để ý cho tới khi số liệu vô lý.

Lỗi này gây ra hai sự cố khác nhau. Lần một: phần nối cuộc gọi với đơn hàng so sánh giờ Việt Nam với giờ quốc tế, lệch 7 tiếng nên ghép nhầm cuộc gọi vào đơn của người khác. Lần hai: phần chống trùng lặp lẽ ra chỉ nhìn lại 2 phút, vì lệch múi giờ mà thành nhìn lại 7 tiếng, nghĩa là mọi cuộc gọi trong 7 tiếng đó bị coi là trùng và bị bỏ.

Bài học không phải "nhớ đổi múi giờ". Bài học là: mọi cột thời gian phải ghi rõ nó ở múi giờ nào ngay tại chỗ định nghĩa, và mọi phép so sánh phải quy về một múi trước khi so. Sửa xong lần một mà không ghi lại quy ước thì lần hai vẫn sập, đúng như đã xảy ra.

Bẫy 3. Tổng đài gửi trùng một cuộc gọi

Tổng đài không gửi mỗi cuộc gọi đúng một lần. Nó gửi nhiều lần, với định dạng khác nhau tuỳ chặng: máy lễ tân bắt, chuyển tiếp sang di động, kết thúc.

Bản đầu chống trùng bằng cách: cùng số khách gọi, trong vòng 2 phút, thì coi là một cuộc. Nghe hợp lý cho tới khi gặp khách gọi lại thật sau 90 giây vì lần đầu chưa nói xong. Cuộc thứ hai bị nuốt.

Cách sửa: chống trùng theo file ghi âm thay vì theo cặp số máy và khoảng thời gian. Cùng một cuộc gọi thì cùng một file ghi âm, dù tổng đài báo về mấy lần. Hai cuộc gọi khác nhau thì hai file khác nhau, dù cách nhau 10 giây.

Nguyên tắc rút ra: chống trùng phải dựa trên thứ định danh duy nhất của sự kiện, không dựa trên phỏng đoán theo thời gian.

Bẫy 4. Hai người gọi vào cùng một số

Đây là cái tinh vi nhất, và nó chỉ tồn tại vì kho số nhỏ.

Người A bấm nút, được cấp số X. Trong lúc phiên của A còn sống, người B gọi vào số X. B là khách cũ: lần trước B từng gọi qua số X nên nó còn nằm trong nhật ký cuộc gọi máy B, giờ B bấm gọi lại. Hệ thống thấy cuộc gọi vào số X, tra ra phiên của A, và gán nguồn quảng cáo của A cho cuộc gọi của B.

Cần nói rõ vì sao B chỉ có thể là khách cũ chứ không phải người được ai đó gửi ảnh chụp màn hình: số riêng không bao giờ hiện trên trang web. Trang luôn hiển thị hotline thật, số riêng chỉ được nạp vào lệnh quay máy đúng lúc bấm nút, như đã nói ở bước 2. Nên cách duy nhất để một số riêng nằm trong máy ai đó là chính họ đã từng gọi qua nó.

Nguồn quảng cáo của A vừa bị "lem" sang người khác.

Hình 3
Người A
Bấm quảng cáo, bấm nút gọi, được cấp số …1111
có nguồn quảng cáo
…1111
Người B
Khách cũ, số này còn trong nhật ký cuộc gọi, bấm gọi lại
lần này không qua quảng cáo
Hệ thống thấy cuộc gọi vào …1111, tra ra phiên của A, rồi gán nguồn quảng cáo của A cho cuộc gọi của B. Nguồn của A vừa bị lem sang người khác.
nấc 1Tắtkhông kiểm tra gìnấc 2Chạy thửghi lại quyết định, chưa đổi dữ liệunấc 3Bật thậtmới thực sự bỏ nguồn
Hai người khác nhau, cùng một số. Bộ lọc rất dễ chặn nhầm nên nó được bật theo ba nấc — và nấc chạy thử đã cứu một đơn 2,2 triệu khỏi bị gỡ mất dấu quảng cáo.

Cách xử lý phải bắt đầu bằng một câu hỏi khó: làm sao hệ thống biết ai mới là chủ của số đó, khi nó không hề biết trước số máy của khách? Khách chỉ bấm nút trên web, chưa để lại số điện thoại nào cả.

Câu trả lời là nó không cần biết trước. Nó xác định chủ theo thứ tự gọi: ai gọi vào số đó sớm nhất kể từ lúc số được cấp thì người đó là chủ, còn ai gọi vào sau đều là người mượn số.

Hai chi tiết phải làm cho đúng, vì cả hai đều đã gây sự cố thật:

Xếp theo giờ khách bấm máy, không phải giờ tổng đài báo về. Tổng đài chỉ gửi dữ liệu lúc cúp máy, nên một cuộc gọi dài bấm trước có thể về hệ thống sau một cuộc ngắn bấm sau. Ngày 19/07, cuộc bấm lúc 10:08:24 về hệ thống lúc 10:09:15 và suýt mất quyền chủ vào tay cuộc bấm lúc 10:08:41 chỉ vì về sớm hơn 3 giây.

Ai bấm máy trước khi số được cấp thì không thể là chủ. Người đó đang quay lại số lưu trong danh bạ từ lần trước. Ngày 21/07, có cuộc bấm lúc 08:08:42 trong khi phiên mãi 08:10:57 mới sinh ra.

Lớp bảo vệ đầu tiên chống chặn nhầm: cùng một người gọi qua nhiều chặng thì luôn cho qua — chuông đổ qua lễ tân rồi chuyển sang di động khiến một cuộc gọi hiện ra dưới nhiều bản ghi, nếu số máy đó đã xuất hiện trong phiên thì đây là chặng tiếp theo của chính họ.

Bấy nhiêu vẫn chưa đủ. Chúng tôi biết được điều đó chỉ vì đã không bật thẳng bộ lọc, mà cho nó chạy theo ba nấc:

  • Tắt: không kiểm tra gì, giữ nguyên cách cũ.
  • Chạy thử: bộ lọc tính toán và ghi lại quyết định của nó, nhưng không thay đổi dữ liệu thật.
  • Bật thật: bộ lọc mới thực sự có quyền bỏ nguồn.

Chạy thử 11 ngày trên lưu lượng thật cho ra sáu trường hợp bộ lọc định chặn. Năm trường hợp chặn đúng. Trường hợp thứ sáu là khách thật, và nếu bộ lọc có quyền chặn thì nó đã gỡ mất dấu quảng cáo của một đơn hàng 2,2 triệu đồng. Người đặt đơn đó là người gọi sau, lại không có dấu quảng cáo riêng nào ở chỗ khác — nhìn từ phía hệ thống thì trông y hệt một ca lem nguồn.

Chính ca đó sinh ra lớp bảo vệ thứ hai: chỉ bỏ nguồn của người mượn số khi chứng minh được họ có nguồn riêng ở chỗ khác. Nếu người mượn cũng là khách từ quảng cáo và lần bấm của họ đã được ghi nhận ở phiên khác, bỏ bản sao ở đây không mất gì. Còn nếu họ không có nguồn riêng nào thì giữ nguyên, vì không chứng minh được. Rà lại trên 30 ngày dữ liệu thật, cách này giữ được 16 đơn hàng mà bản trước sẽ gỡ mất, đồng thời vẫn gỡ đúng 32 ca chứng minh được là lem nguồn.

Cần nói rõ "bỏ nguồn" nghĩa là gì: chỉ để trống nguồn quảng cáo của cuộc gọi đó. Cuộc gọi vẫn được ghi nhận, đơn hàng vẫn nguyên vẹn, lễ tân vẫn tiếp khách bình thường — chỉ là cuộc đó không được báo về Google nữa.

Mọi bộ lọc có quyền xoá dữ liệu đều nên có nấc chạy thử. Không có nấc đó thì đơn 2,2 triệu kia đã mất dấu mà không ai biết vì sao, và lớp bảo vệ thứ hai sẽ không bao giờ được nghĩ ra.

Về chuyện dùng AI để viết phần lớn code

Hệ thống này viết trong khoảng 4 tuần, phần lớn code do AI sinh ra, một người đọc và duyệt toàn bộ.

Điều AI làm tốt: gõ nhanh, dựng khung, tra tài liệu, viết đúng cú pháp thư viện lạ. Điều AI không làm thay được: quyết định thu cửa sổ tra ngược từ 24 giờ xuống 3 phút. Đó không phải câu hỏi kỹ thuật mà là câu hỏi kinh doanh: chấp nhận mất bao nhiêu dữ liệu để đổi lấy dữ liệu còn lại đáng tin. Không đọc dữ liệu thật của chính mình thì không ai trả lời được, kể cả AI.

Cả bốn cái bẫy trên đều được phát hiện bằng cách ngồi đọc số liệu thấy vô lý rồi lần ngược, không phải bằng cách đọc code.

Phần 3 nói về những gì đo được sau khi vá hết bốn chỗ này, và cả những gì vẫn chưa chứng minh được.