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:
- Attempt có hoàn thành hợp lệ?
- Answer có tồn tại?
- Observation có classify được?
- Metric có observable trên mode này?
- Run có thuộc đúng cohort/version?
- 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
-
Ghim AI — Data model AI Visibility
https://ghimai.com/kien-thuc/ai-visibility-data-model -
Ghim AI — Phương pháp đo AI Visibility
https://ghimai.com/phuong-phap -
SEOmonitor — AI Visibility Index Methodology
https://www.seomonitor.com/ai-visibility/methodology -
Machine Relations — AI Visibility Methodology Transparency Benchmark 2026
https://machinerelations.ai/research/ai-visibility-methodology-transparency-benchmark-2026 -
Adviora — AI Visibility Research Methodology v1.0
https://adviora.ai/white-papers/ai-visibility-research-methodology
All rights reserved