0

Thiết kế pipeline AI Visibility Data Model

Missing data ≠ 0% visibility: thiết kế pipeline AI Visibility không biến lỗi hệ thống thành kết quả kinh doanh

Giả sử dashboard hôm qua hiển thị:

Mention Rate = 42%

Hôm nay:

Mention Rate = 31%

Nhìn vào chart, câu hỏi tự nhiên là:

“Brand visibility giảm 11 điểm phần trăm?”

Nhưng trước khi nói về brand, có một câu khác cần trả lời:

Hôm nay có bao nhiêu run thực sự tạo ra một observation hợp lệ?

Nếu 20% request timeout, provider trả lỗi, web-search tool fail hoặc parser không đọc được answer, việc biến tất cả thành:

mentioned = false

sẽ tạo ra một dashboard rất rõ ràng.

Và rất sai.

1. Valid negative khác unknown

Hai record:

{
  "status": "success",
  "answer": "...",
  "mentioned": false
}

và:

{
  "status": "timeout",
  "answer": null,
  "mentioned": false
}

trông giống nhau nếu schema chỉ nhìn field mentioned.

Nhưng về measurement:

success + not mentioned
= valid negative observation

timeout
= unknown

Đây là distinction nền tảng.

Nếu không tách, reliability của provider, network hoặc parser sẽ trở thành một phần ẩn trong brand score.

2. Attempt, response và observation nên là ba layer khác nhau

Một pipeline có thể hình dung như sau:

measurement_attempt
        ↓
provider_response
        ↓
classified_observation

Measurement attempt

attempt
---
attempt_id
batch_id
prompt_version_id
engine
model
interface
requested_at
status
error_code
retry_of

Provider response

response
---
response_id
attempt_id
received_at
raw_payload_ref
answer_text
search_used
citation_supported

Classified observation

observation
---
response_id
brand_id
mentioned
recommended
citation_observable
official_domain_cited
classifier_version
classification_status

Ba layer này giúp phân biệt:

  • request chưa bao giờ tới provider;
  • provider trả lỗi;
  • provider trả answer rỗng;
  • answer hợp lệ nhưng parser fail;
  • answer hợp lệ và brand thật sự không xuất hiện.

Nếu tất cả nằm chung trong một bảng run, vẫn có thể triển khai được.

Nhưng state model phải giữ được những semantics này.

3. Đừng dùng một boolean success

Không nên:

success: boolean

Vì false có thể nghĩa quá nhiều thứ.

Tốt hơn:

type AttemptStatus =
  | "queued"
  | "running"
  | "success"
  | "provider_error"
  | "timeout"
  | "rate_limited"
  | "blocked"
  | "cancelled";

Classification cũng cần state riêng:

type ClassificationStatus =
  | "classified"
  | "empty_answer"
  | "parser_error"
  | "unsupported"
  | "unknown";

Điểm quan trọng:

AttemptStatus
!=
BrandObservation

Infrastructure state không được phép masquerade thành marketing result.

4. Mention Rate cần denominator contract

Một định nghĩa đơn giản:

mention_rate =
valid_runs_with_mention
/
valid_classified_runs

SQL minh họa:

WITH valid AS (
  SELECT o.*
  FROM observation o
  JOIN response r
    ON r.response_id = o.response_id
  JOIN attempt a
    ON a.attempt_id = r.attempt_id
  WHERE a.status = 'success'
    AND o.classification_status = 'classified'
)
SELECT
  SUM(CASE WHEN mentioned THEN 1 ELSE 0 END)::float
  / NULLIF(COUNT(*), 0) AS mention_rate
FROM valid;

Nhưng một API chỉ trả:

{
  "mention_rate": 0.42
}

vẫn chưa đủ.

Tôi sẽ trả thêm:

{
  "mention_rate": 0.42,
  "numerator": 42,
  "denominator": 100,
  "scheduled": 120,
  "valid": 100,
  "unknown": 20,
  "coverage_rate": 0.8333
}

42% với coverage 100/120 khác rất nhiều 42% với coverage 100/101.

5. Coverage Rate là measurement-health metric

Tôi sẽ tách dashboard thành hai lớp:

Brand metrics
-------------
Mention Rate
Citation Rate
Recommendation Rate
Share of Voice

Measurement health
------------------
Coverage Rate
Provider Error Rate
Parser Error Rate
Retry Rate
Freshness

Ví dụ:

Mention Rate = 42%
Coverage Rate = 83%

Cách đọc:

Trong các observation hợp lệ, brand được mention 42%. Tuy nhiên chỉ 83% scheduled runs tạo được observation hợp lệ.

Điều đó trung thực hơn nhiều so với một:

AI Visibility = 35%

được tạo bằng cách âm thầm coi failed runs là zero.

6. Citation cần thêm observable

Citation phức tạp hơn mention.

Một provider hoặc mode có thể không hiển thị citation theo cách hệ thống đang quan sát được.

Nếu schema chỉ có:

official_domain_cited = false

thì không phân biệt được:

valid answer
+ citation observable
+ domain not cited

với:

valid answer
+ citation not observable

Tôi sẽ dùng:

type CitationState =
  | "cited"
  | "not_cited"
  | "not_observable"
  | "unknown";

Khi đó:

Citation Rate =
cited
/
(cited + not_cited)

nếu định nghĩa metric là:

citation among observable valid answers.

not_observable không được âm thầm trở thành not_cited.

7. Retry không được tạo thêm sample

Ví dụ:

Prompt P1

Attempt A1
→ timeout

Retry A2
→ success
→ mentioned = true

Nếu aggregate query đếm A1 và A2 như hai measurement observations, sample size sẽ bị inflate.

Retry nên thuộc cùng một logical observation slot:

observation_slot_id
=
batch
+ prompt_version
+ engine
+ repeat_index

Ví dụ:

Slot S1
 ├── A1 timeout
 └── A2 success

Final outcome:
valid / mentioned

Operational attempts có thể là 2.

Measurement observation vẫn là 1.

8. Idempotency quan trọng khi scheduler chạy lại

Distributed scheduler có thể enqueue cùng job nhiều lần.

Nếu không có idempotency key:

project_id
prompt_version_id
engine
batch_id
repeat_index

một duplicate execution có thể trở thành một observation mới và làm lệch metric.

Ví dụ:

const observationKey = [
  projectId,
  batchId,
  promptVersionId,
  engine,
  repeatIndex
].join(":");

Database nên enforce uniqueness.

Retry append attempt vào slot đã tồn tại.

Không tạo một slot measurement mới.

9. Parser failure là data-quality failure

Provider trả answer thành công.

Nhưng classifier/parser của bạn crash.

Ví dụ:

Provider = SUCCESS
Answer   = VALID
Parser   = ERROR

Nếu code fallback:

mentioned = parsed?.mentioned ?? false;

thì parser bug sẽ trở thành brand non-mention.

Đây là một anti-pattern nguy hiểm.

Tốt hơn:

if (!parsed) {
  classificationStatus = "parser_error";
  mentioned = null;
}

Ở measurement layer:

false = đã quan sát và không có

null = chưa biết

Hai giá trị không thể thay thế nhau.

10. Tri-state tốt hơn boolean

Một abstraction có thể là:

type Observation<T> =
  | {
      state: "observed";
      value: T;
    }
  | {
      state: "not_observable";
    }
  | {
      state: "unknown";
      reason: string;
    };

Brand mention:

observed(true)
observed(false)
unknown(provider_error)
unknown(parser_error)

Citation:

observed(true)
observed(false)
not_observable
unknown

UI có thể render đơn giản hơn.

Data layer không nên làm mất semantics.

11. Historical migration là nơi rất dễ tạo dữ liệu giả

Giả sử hệ thống cũ chỉ lưu:

{
  "mentionCount": 1,
  "totalQueries": 10
}

Không được convert record này thành:

{
  "mentioned": true
}

Bởi vì:

1 / 10

sẽ bị biến thành:

100%

Aggregate cũ không chứa đủ thông tin để reconstruct per-run outcomes.

Tôi sẽ giữ:

legacy_aggregate

known numerator   = 1
known denominator = 10

per-run outcome   = unknown

Nếu metric mới yêu cầu explicit run-level outcome thì record legacy đó không nên được giả lập thành dữ liệu chi tiết mà nó chưa từng có.

12. Metric definition cũng phải có version

Ví dụ v1:

Mention Rate =
mentions
/
successful responses

v2:

Mention Rate =
mentions
/
classified valid responses

Hai denominator khác nhau.

Nếu dashboard lịch sử tự động chạy formula mới trên data cũ thì trend có thể thay đổi retroactively.

Một bảng metric definition:

metric_definition
---
metric_id
name
version
numerator_rule
denominator_rule
unknown_rule
observable_rule
valid_from

Và snapshot:

metric_snapshot
---
batch_id
metric_id
metric_version
numerator
denominator
unknown_count
coverage_rate
value

Lúc đó một con số có provenance rõ hơn.

13. Alert data quality trước alert brand visibility

Nếu visibility giảm mạnh, pipeline nên kiểm tra:

coverage_rate dropped?
provider_error spiked?
parser_error spiked?
model/interface changed?
prompt panel changed?

trước khi phát alert:

Brand visibility dropped

Ví dụ:

if (coverageRate < 0.9) {
  alert("measurement_degraded");
} else if (mentionRateChange < -0.1) {
  alert("brand_visibility_drop");
}

0.9 và -0.1 ở đây chỉ là ví dụ.

Điểm quan trọng là diagnostic order.

14. API response nên trả cả metric lẫn measurement health

Ví dụ:

{
  "metric": {
    "name": "mention_rate",
    "version": "2.0",
    "value": 0.42,
    "numerator": 42,
    "denominator": 100
  },
  "measurement_health": {
    "scheduled": 120,
    "valid": 100,
    "unknown": 20,
    "coverage_rate": 0.8333,
    "provider_errors": 12,
    "parser_errors": 5,
    "unsupported": 3
  }
}

Client hoặc dashboard không phải tự đoán:

Con số 42% này đáng tin tới đâu?

15. Missing data không chỉ là vấn đề kỹ thuật

Hai report:

Report A

Mention Rate = 30%
Coverage     = 100%

Report B

Mention Rate = 30%
Coverage     = 55%

Cùng một Mention Rate.

Nhưng hai report không có cùng mức uncertainty.

Agency không nên trình bày hai con số này với khách hàng bằng cùng một mức tự tin.

Đây là điểm mà data-quality engineering bắt đầu trở thành reporting methodology.

16. Rule tôi sẽ dùng trước khi đưa một run vào denominator

Trước khi một run được tính:

  1. Attempt có hoàn thành hợp lệ?
  2. Answer có tồn tại?
  3. Observation có classify được?
  4. Metric có observable trên mode này?
  5. Run có thuộc đúng cohort/version?
  6. Duplicate/retry đã được collapse chưa?

Chỉ sau đó:

eligible_for_denominator = true

Kết luận

Một AI Visibility pipeline không chỉ là:

call LLM
→ parse answer
→ calculate %

Nó là một measurement system.

Và một measurement system phải biết nói:

“Tôi không biết.”

Nếu data model không thể biểu diễn unknown, mọi lỗi cuối cùng sẽ bị ép thành yes/no.

Trong AI Visibility, lỗi nguy hiểm nhất không phải một API call thất bại.

Lỗi nguy hiểm nhất là:

API call thất bại nhưng dashboard vẫn hiển thị một con số trông hoàn toàn hợp lệ.

Đó là lý do tôi luôn tách:

valid negative
!=
missing
!=
error
!=
unsupported

trước khi nói đến Mention Rate, Citation Rate hay bất kỳ AI Visibility Score nào.

Nguồn tham khảo


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí