AutoPodAutoPod

Đo lường Tác động Trích dẫn AI: Phân tích, Nhật ký và Trích xuất Bảng điều khiển

•33 phút đọc
Bài viết âm thanh
Đo lường Tác động Trích dẫn AI: Phân tích, Nhật ký và Trích xuất Bảng điều khiển
0:00—:—
Đo lường Tác động Trích dẫn AI: Phân tích, Nhật ký và Trích xuất Bảng điều khiển

Đo lường Tác động Trích dẫn AI: Phân tích, Nhật ký và Trích xuất Bảng điều khiển

Giới thiệu

Khám phá dựa trên AI hiện được chia thành nhiều lớp đo lường. Một người có thể thấy một công ty được trích dẫn trong câu trả lời của AI, nhấp vào một liên kết không có referrer hữu ích, truy cập qua một trình duyệt loại bỏ dữ liệu chiến dịch, hoặc đọc một câu trả lời mà không nhấp vào liên kết nào cả. Trong khi đó, một trình thu thập thông tin AI có thể yêu cầu trang của công ty mà không đại diện cho một khách truy cập là con người.

Do đó, một hệ thống đo lường hữu ích phải tách biệt bốn câu hỏi:

  1. Trang web đã được thu thập thông tin hay truy xuất?
  2. Trang web đã được trích dẫn trong một câu trả lời của AI?
  3. Có người đã truy cập trang web từ câu trả lời đó?
  4. Lượt truy cập đó có tạo ra tương tác hoặc doanh thu có ý nghĩa?

Tính đến ngày 22 tháng 9 năm 2026, báo cáo của bên thứ nhất đang được cải thiện. Google Search Console cung cấp báo cáo hiệu suất AI tạo sinh cho AI Overviews và AI Mode, bao gồm số lần hiển thị, trang, quốc gia, thiết bị và ngày. Báo cáo này đã có sẵn trên toàn thế giới vào ngày 31 tháng 8 năm 2026. Báo cáo hiệu suất AI tạo sinh của Google (support.google.com)

Microsoft cũng cung cấp báo cáo AI Performance trong Bing Webmaster Tools. Bản xem trước công khai của nó báo cáo tổng số trích dẫn, các trang được trích dẫn, truy vấn làm nền tảng và xu hướng trích dẫn trên các trải nghiệm AI được Microsoft hỗ trợ. Hiệu suất AI trong Bing Webmaster Tools (blogs.bing.com)

Các công cụ này nên được coi là có thẩm quyền đối với các bề mặt của riêng chúng, nhưng chúng không tạo ra một hệ thống đo lường toàn diện đa trợ lý. Cách tiếp cận được khuyến nghị là kết hợp báo cáo của bên thứ nhất, nhật ký máy chủ, liên kết theo dõi được kiểm soát, xuất phân tích và quan sát bảng câu trả lời theo lịch trình.


1. Tại sao Đo lường Giới thiệu AI lại Khó khăn

Phân tích web truyền thống phụ thuộc nhiều vào tiêu đề Referer và các tham số chiến dịch. Cả hai đều có thể bị thiếu hoặc không đầy đủ.

Tiêu đề HTTP Referer có thể chứa trang trước đó, chỉ nguồn gốc của trang web trước đó, hoặc không có giá trị nào cả. Các chính sách referrer của trình duyệt có thể cố ý giới hạn hoặc loại bỏ thông tin đó. Tài liệu Referrer-Policy của MDN (developer.mozilla.org)

Các hệ thống AI tạo ra các biến chứng bổ sung:

  • Một trợ lý có thể liên kết đến một trang mà không gửi một referrer có thể nhận dạng được.
  • Một trợ lý có thể sử dụng một URL chuyển hướng hoặc được viết lại.
  • Một trợ lý có thể tìm nạp nội dung phía máy chủ trước khi hiển thị câu trả lời.
  • Một trình thu thập thông tin AI có thể truy cập một trang mà không có con người nào nhìn thấy nó.
  • Câu trả lời có thể trích dẫn một URL chuẩn (canonical URL) thay vì URL gốc đã được truy xuất.
  • Câu trả lời có thể thay đổi tùy thuộc vào vị trí, thiết bị, ngôn ngữ, thời gian hoặc cá nhân hóa.

Ví dụ, OpenAI phân biệt giữa OAI-SearchBot cho khám phá tìm kiếm, GPTBot cho mục đích đào tạo có thể có và ChatGPT-User cho các hành động do người dùng khởi tạo. Perplexity riêng biệt xác định PerplexityBot và Perplexity-User. Anthropic xác định ClaudeBot, Claude-SearchBot và Claude-User. Các yêu cầu này không nên được kết hợp thành một số liệu “lưu lượng truy cập AI” chung chung. Tài liệu về trình thu thập thông tin của OpenAI (openai.com) Tài liệu về trình thu thập thông tin của Perplexity (docs.perplexity.ai) Tài liệu về trình thu thập thông tin của Anthropic (support.anthropic.com)

Quy tắc trung tâm là:

Hoạt động của trình thu thập thông tin không phải là lưu lượng truy cập giới thiệu, khả năng hiển thị trích dẫn không phải là lưu lượng truy cập, và lưu lượng truy cập không phải là tác động kinh doanh.


2. Khung Đo lường

Sử dụng năm lớp đo lường.

LớpCâu hỏi chínhDữ liệu được khuyến nghị
Truy cậpHệ thống AI có yêu cầu trang không?Nhật ký máy chủ web, nhật ký tường lửa
Hiển thịTrang có được hiển thị hoặc trích dẫn không?Google Search Console, Bing Webmaster Tools, quan sát bảng câu trả lời
Thu hútMột người có đến từ một bề mặt AI không?Referrer, tham số chiến dịch, nhấp vào liên kết ngắn, phân tích
Tương tácKhách truy cập có tương tác có ý nghĩa không?Sự kiện phân tích, lượt xem trang, thời gian tương tác
Giá trịLượt truy cập có tạo ra kết quả mong muốn không?Đăng ký, khách hàng tiềm năng, mua hàng, đăng ký thuê bao

Hệ thống phân cấp nguồn đáng tin cậy được khuyến nghị

Sử dụng tín hiệu mạnh nhất có sẵn cho mỗi câu hỏi:

  1. Báo cáo nền tảng của bên thứ nhất cho số lần hiển thị và trích dẫn.
  2. Quan sát bảng câu trả lời cho khả năng hiển thị cấp độ nhắc và so sánh cạnh tranh.
  3. Nhật ký chuyển hướng cho các nhấp chuột liên kết được kiểm soát.
  4. Phân tích web cho các phiên, tương tác và chuyển đổi.
  5. Nhật ký máy chủ cho hoạt động của trình thu thập thông tin và trình tìm nạp.
  6. Ước tính theo mô hình chỉ khi không có bằng chứng trực tiếp.

Không kết hợp tất cả các tín hiệu thành một số duy nhất mà không giữ lại nguồn và mức độ tin cậy.


3. Mô hình Dữ liệu Cốt lõi

Tạo một kho dữ liệu với các bảng riêng biệt cho các quan sát thô và các chỉ số phái sinh.

panel_runs

Một hàng cho mỗi lần kiểm tra nhắc và bề mặt.

text run_id observed_at surface topic prompt_id query_text locale country device panel_present panel_type answer_hash raw_html_path screenshot_path collector_version status

panel_citations

Một hàng cho mỗi liên kết được quan sát trong một bảng câu trả lời.

text run_id surface topic prompt_id cited_url cited_domain citation_position link_scope target_domain target_cited

ai_crawler_requests

Dữ liệu nhật ký máy chủ tổng hợp.

text date bot_name bot_role path requests successful_requests error_requests unique_ip_count

shortener_clicks

Một hàng cho mỗi yêu cầu liên kết được kiểm soát.

text click_id occurred_at slug surface topic prompt_id asset_id referrer_host user_agent_family ip_hmac destination_path

ai_sessions

Một bảng phân tích đã được chuẩn hóa.

text session_id date surface topic prompt_id landing_page attribution_method confidence engaged engagement_time_seconds key_event revenue

Trường confidence rất quan trọng. Các giá trị được khuyến nghị là:

  • A — Trực tiếp: nhấp vào liên kết ngắn được kiểm soát hoặc tham số chiến dịch đáng tin cậy.
  • B — Mạnh: referrer trợ lý đã biết hoặc yêu cầu tìm nạp của người dùng đã xác minh.
  • C — Có thể: bằng chứng về chiến dịch hoặc trang đích mà không có referrer hoàn chỉnh.
  • D — Theo mô hình: suy ra từ thời gian, quan sát bảng điều khiển hoặc các thay đổi tổng hợp.

Báo cáo A và B riêng biệt với C và D.


4. Định nghĩa Chỉ số

Tỷ lệ Trích dẫn theo Chủ đề

Tỷ lệ Trích dẫn theo Chủ đề (Citation Share by Topic) đo lường tần suất một miền mục tiêu xuất hiện trong số các nguồn được quan sát cho một chủ đề.

[ \text{Tỷ lệ Trích dẫn}_{chủ đề}

\frac{\text{Số lần xuất hiện trích dẫn của miền mục tiêu}} {\text{Tổng số lần xuất hiện trích dẫn}} ]

Ví dụ:

  • 100 tổng số trích dẫn được quan sát cho “phần mềm quản lý dự án”
  • 12 trích dẫn chỉ đến miền của bạn
  • Tỷ lệ Trích dẫn theo Chủ đề = 12%

Chỉ số này đo lường tỷ lệ nguồn, chứ không phải liệu một câu trả lời có chứa trang web của bạn ít nhất một lần hay không.

Độ bao phủ Trích dẫn

Sử dụng chỉ số thứ hai cho sự hiện diện ở cấp độ câu trả lời:

[ \text{Độ bao phủ Trích dẫn}_{chủ đề}

\frac{\text{Số lượt chạy câu trả lời chứa trích dẫn mục tiêu}} {\text{Số lượt chạy câu trả lời có bảng điều khiển}} ]

Độ bao phủ Trích dẫn thường dễ hiểu hơn đối với những đối tượng không chuyên về kỹ thuật:

“Trang web của chúng tôi xuất hiện trong 34% các câu trả lời AI được quan sát cho chủ đề này.”

Vị trí Trích dẫn

Ghi lại vị trí của một trích dẫn trong câu trả lời:

  • 1 = nguồn được quan sát đầu tiên
  • 2 = nguồn được quan sát thứ hai
  • 3 = nguồn được quan sát thứ ba

Vì các giao diện AI thường nhóm hoặc sắp xếp lại các nguồn, hãy coi vị trí là một quan sát mô tả, không phải là một xếp hạng phổ quát.


Tỷ lệ Giới thiệu Trợ lý

Tỷ lệ Giới thiệu Trợ lý (Assistant Referral Rate) đo lường tỷ lệ các phiên truy cập trang web của con người có thể được quy cho một bề mặt AI.

[ \text{Tỷ lệ Giới thiệu Trợ lý}

\frac{\text{Các phiên truy cập của con người được quy cho AI}} {\text{Tất cả các phiên truy cập của con người}} ]

Báo cáo ít nhất hai phiên bản:

text Tỷ lệ Giới thiệu Trợ lý Đã xác nhận = Số phiên AI có độ tin cậy A / tổng số phiên của con người

Tỷ lệ Giới thiệu Trợ lý Mở rộng = Số phiên AI có độ tin cậy A + B + C / tổng số phiên của con người

Phiên bản đã xác nhận thận trọng hơn. Phiên bản mở rộng hữu ích cho phân tích xu hướng nhưng không nên được trình bày như lưu lượng truy cập đã được quan sát đầy đủ.

Không sử dụng số lượt chạy bảng điều khiển làm số lần hiển thị

Nếu bạn trích xuất 500 lời nhắc, điều đó không có nghĩa là 500 người đã xem những câu trả lời đó. Trình trích xuất của bạn đo lường một mẫu được kiểm soát các trạng thái câu trả lời. Sử dụng báo cáo số lần hiển thị của nền tảng bên thứ nhất khi chúng có sẵn.


Tương tác Sau Trích dẫn

Tương tác Sau Trích dẫn (Post-Citation Engagement) đo lường liệu những người truy cập thông qua một trích dẫn AI có thực hiện một hành động có ý nghĩa hay không.

[ \text{Tương tác Sau Trích dẫn}

\frac{\text{Các phiên AI tương tác}} {\text{Các phiên được quy cho AI}} ]

Đối với Google Analytics 4, một phiên tương tác kéo dài hơn 10 giây, bao gồm một sự kiện quan trọng, hoặc bao gồm ít nhất hai lượt xem trang hoặc màn hình. Tài liệu về tỷ lệ tương tác của Google Analytics (support.google.com)

Cũng báo cáo:

text Thời gian Tương tác Sau Trích dẫn = số giây tương tác trung vị trên mỗi phiên AI

Tỷ lệ Chuyển đổi Sau Trích dẫn = số phiên AI có sự kiện quan trọng / số phiên được quy cho AI

Doanh thu Sau Trích dẫn trên mỗi Phiên = doanh thu từ các phiên AI / số phiên được quy cho AI

Thời gian tương tác trung vị thường ổn định hơn thời gian tương tác trung bình vì một số ít phiên rất dài có thể làm sai lệch giá trị trung bình.


Các Chỉ số Hữu ích Bổ sung

Tỷ lệ Thành công của Trình thu thập thông tin AI

[ \text{Tỷ lệ Thành công của Trình thu thập thông tin}

\frac{\text{Số yêu cầu của trình thu thập thông tin AI trả về 2xx hoặc 3xx}} {\text{Tổng số yêu cầu của trình thu thập thông tin AI}} ]

Phân tích điều này theo bot và đường dẫn. Sự suy giảm trích dẫn cao kết hợp với tỷ lệ lỗi trình thu thập thông tin tăng có thể cho thấy vấn đề về hosting, tường lửa hoặc cấu hình robots.

Tỷ lệ Từ Trích dẫn đến Nhấp chuột

Đối với các quan sát bảng câu trả lời được kiểm soát:

[ \text{Tỷ lệ Từ Trích dẫn đến Nhấp chuột Được quan sát}

\frac{\text{Số nhấp chuột liên kết ngắn đã xác nhận}} {\text{Số trích dẫn mục tiêu được quan sát}} ]

Đây không phải là tỷ lệ nhấp thực tế của người dùng trừ khi mẫu số đại diện cho số lần hiển thị thực tế của người dùng. Hãy ghi nhãn rõ ràng đây là một chỉ số hoạt động được quan sát.

Độ mới của Trích dẫn

Đo lường tần suất URL được trích dẫn phản ánh phiên bản trang hiện tại.

text Độ mới của Trích dẫn = số trang được trích dẫn có hash nội dung hiện tại / số trang được trích dẫn

Điều này hữu ích cho các trang tài liệu, giá cả, sản phẩm và chính sách thay đổi thường xuyên.


5. Phân tích Nhật ký Máy chủ

Cấu hình Nhật ký Truy cập có cấu trúc

Các nhật ký có cấu trúc dễ phân tích hơn các nhật ký truyền thống được phân tách bằng dấu cách.

Ví dụ cấu hình Nginx:

nginx log_format ai_json escape=json '{' '"ts":"$time_iso8601",' '"remote_addr":"$remote_addr",' '"request":"$request",' '"status":$status,' '"bytes":$body_bytes_sent,' '"referer":"$http_referer",' '"user_agent":"$http_user_agent",' '"host":"$host"' '}';

access_log /var/log/nginx/ai-access.jsonl ai_json;

Lưu trữ các tệp nhật ký ở một vị trí hạn chế. Không gửi địa chỉ IP thô đến bảng phân tích chung trừ khi bạn có lý do hoạt động rõ ràng.

Xác định các Loại Yêu cầu AI

Ở mức tối thiểu, phân tách:

text OpenAI:

  • OAI-SearchBot
  • ChatGPT-User
  • GPTBot

Anthropic:

  • Claude-SearchBot
  • Claude-User
  • ClaudeBot

Perplexity:

  • PerplexityBot
  • Perplexity-User

Search engines:

  • Googlebot
  • Bingbot

Các tính năng AI Search của Google thường sử dụng các kiểm soát thu thập thông tin của Google Search hiện có thay vì một “bot tổng quan AI” phổ quát riêng biệt. Google tuyên bố rằng Googlebot kiểm soát quyền truy cập cho Search, bao gồm các tính năng AI. Các tính năng AI và trang web của Google (developers.google.com)

Chuỗi tác nhân người dùng (user-agent strings) có thể bị giả mạo. Đối với các quyết định hoạt động, hãy kết hợp đối sánh tác nhân người dùng với các dải IP được nhà cung cấp công bố hoặc DNS ngược đã xác minh nếu có. OpenAI và Perplexity công bố thông tin IP cho các trình thu thập thông tin và trình tìm nạp có liên quan của họ. (openai.com)

Công cụ Tóm tắt Nhật ký có thể tái tạo

Lưu mã sau dưới dạng ai_log_summary.py.

python #!/usr/bin/env python3

import csv import hashlib import hmac import json import os import re import sys from collections import Counter, defaultdict from datetime import datetime from urllib.parse import urlsplit

BOT_PATTERNS = { "OAI-SearchBot": ("openai", re.compile(r"\bOAI-SearchBot\b", re.I)), "ChatGPT-User": ("openai_user", re.compile(r"\bChatGPT-User\b", re.I)), "GPTBot": ("openai_training", re.compile(r"\bGPTBot\b", re.I)), "Claude-SearchBot": ("anthropic", re.compile(r"\bClaude-SearchBot\b", re.I)), "Claude-User": ("anthropic_user", re.compile(r"\bClaude-User\b", re.I)), "ClaudeBot": ("anthropic_training", re.compile(r"\bClaudeBot\b", re.I)), "PerplexityBot": ("perplexity", re.compile(r"\bPerplexityBot\b", re.I)), "Perplexity-User": ("perplexity_user", re.compile(r"\bPerplexity-User\b", re.I)), "Googlebot": ("google_search", re.compile(r"\bGooglebot\b", re.I)), "Bingbot": ("bing_search", re.compile(r"\bbingbot\b", re.I)), }

SECRET = os.environ.get("HMAC_SECRET", "replace-this-in-production").encode()

def hmac_ip(ip): return hmac.new(SECRET, ip.encode(), hashlib.sha256).hexdigest()[:16]

def classify_bot(user_agent): for bot_name, (role, pattern) in BOT_PATTERNS.items(): if pattern.search(user_agent or ""): return bot_name, role return None, None

def parse_path(request_line): try: parts = request_line.split() return urlsplit(parts[1]).path except Exception: return "/"

def main(input_path): totals = defaultdict(lambda: { "requests": 0, "success": 0, "errors": 0, "ips": set(), "paths": Counter(), })

with open(input_path, "r", encoding="utf-8") as source:
    for line in source:
        try:
            record = json.loads(line)
        except json.JSONDecodeError:
            continue

        bot_name, bot_role = classify_bot(record.get("user_agent", ""))
        if not bot_name:
            continue

        timestamp = record.get("ts", "")
        date = datetime.fromisoformat(
            timestamp.replace("Z", "+00:00")
        ).date().isoformat()

        status = int(record.get("status", 0))
        path = parse_path(record.get("request", ""))
        key = (date, bot_name, bot_role)

        totals[key]["requests"] += 1
        totals[key]["ips"].add(hmac_ip(record.get("remote_addr", "")))
        totals[key]["paths"][path] += 1

        if 200 <= status < 400:
            totals[key]["success"] += 1
        else:
            totals[key]["errors"] += 1

writer = csv.writer(sys.stdout)
writer.writerow([
    "date",
    "bot_name",
    "bot_role",
    "requests",
    "successful_requests",
    "error_requests",
    "unique_ip_count",
    "top_paths",
])

for (date, bot_name, bot_role), values in sorted(totals.items()):
    top_paths = values["paths"].most_common(10)
    writer.writerow([
        date,
        bot_name,
        bot_role,
        values["requests"],
        values["success"],
        values["errors"],
        len(values["ips"]),
        json.dumps(top_paths),
    ])

if name == "main": if len(sys.argv) != 2: print("Usage: python ai_log_summary.py /path/to/access.jsonl") sys.exit(1)

main(sys.argv[1])

Chạy nó với:

bash HMAC_SECRET='a-long-random-secret'
python ai_log_summary.py /var/log/nginx/ai-access.jsonl \

data/ai_crawler_daily.csv

Điều này cung cấp bằng chứng hoạt động về hoạt động truy xuất, không phải lưu lượng truy cập của con người.


6. Công cụ Rút gọn Liên kết Tùy chỉnh cho Các Tóm tắt Hướng AI

Một công cụ rút gọn liên kết của bên thứ nhất cung cấp một điểm đo lường được kiểm soát khi bạn xuất bản các bản tóm tắt hoặc tài liệu nguồn có thể được các hệ thống AI tham chiếu.

Sử dụng một miền bạn kiểm soát, chẳng hạn như:

text https://go.example.com/ai-docs

Đích đến nên bao gồm các tham số chiến dịch như:

text utm_source=perplexity utm_medium=ai_answer utm_campaign=product_documentation utm_content=pricing_summary_v3

Google khuyến nghị các tham số chiến dịch để xác định nguồn lưu lượng truy cập và các chiến dịch. Tài liệu URL chiến dịch của Google Analytics (support.google.com)

Các trường liên kết được khuyến nghị

text surface topic prompt_id asset_id content_version destination_path

Không đưa thông tin cá nhân, địa chỉ email hoặc truy vấn tìm kiếm của người dùng vào liên kết. Các định danh chiến dịch nên mô tả tài sản đã xuất bản, không phải xác định một người.

Các hạn chế quan trọng

Một liên kết ngắn là một thiết bị hiệu chuẩn, không phải một giải pháp phổ quát:

  • Trợ lý có thể viết lại URL đích.
  • Trợ lý có thể trích dẫn URL chuẩn thay thế.
  • Liên kết có thể được hiển thị nhưng không bao giờ được nhấp.
  • Trình duyệt hoặc công cụ bảo mật có thể loại bỏ referrer.
  • Một số hệ thống có thể tìm nạp đích ở phía máy chủ.
  • Một liên kết ngắn không đo lường người dùng nhớ thương hiệu và quay lại sau.

Không sử dụng công cụ rút gọn để che giấu đích đến, bỏ qua các hệ thống an toàn hoặc thao túng các trích dẫn. Sử dụng một chuyển hướng rõ ràng đến một trang liên quan, chuẩn.

Công cụ Rút gọn Bên thứ nhất Tối thiểu

Ví dụ sau sử dụng FastAPI và SQLite. Bảo vệ điểm cuối tạo liên kết bằng xác thực trước khi sử dụng nó trong môi trường sản xuất.

python

shortener.py

import hashlib import hmac import os import secrets import sqlite3 from datetime import datetime, timezone from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit

from fastapi import FastAPI, HTTPException, Request from fastapi.responses import RedirectResponse from pydantic import BaseModel

DB_PATH = os.environ.get("SHORTENER_DB", "shortener.db") HMAC_SECRET = os.environ.get( "HMAC_SECRET", "replace-this-in-production" ).encode()

ALLOWED_HOST = "www.example.com"

app = FastAPI()

def db(): connection = sqlite3.connect(DB_PATH) connection.row_factory = sqlite3.Row return connection

def init_db(): connection = db() connection.execute(""" CREATE TABLE IF NOT EXISTS links ( slug TEXT PRIMARY KEY, destination TEXT NOT NULL, surface TEXT NOT NULL, topic TEXT, prompt_id TEXT, asset_id TEXT, created_at TEXT NOT NULL ) """) connection.execute(""" CREATE TABLE IF NOT EXISTS clicks ( id INTEGER PRIMARY KEY AUTOINCREMENT, occurred_at TEXT NOT NULL, slug TEXT NOT NULL, surface TEXT, topic TEXT, prompt_id TEXT, referrer_host TEXT, user_agent TEXT, ip_hmac TEXT ) """) connection.commit() connection.close()

def append_query(url, params): parsed = urlsplit(url) query = dict(parse_qsl(parsed.query, keep_blank_values=True)) query.update(params) return urlunsplit(( parsed.scheme, parsed.netloc, parsed.path, urlencode(query), parsed.fragment, ))

def hash_ip(ip): return hmac.new( HMAC_SECRET, (ip or "").encode(), hashlib.sha256 ).hexdigest()[:16]

class LinkRequest(BaseModel): destination_path: str surface: str topic: str | None = None prompt_id: str | None = None asset_id: str | None = None

@app.on_event("startup") def startup(): init_db()

@app.post("/links") def create_link(payload: LinkRequest): destination = f"https://{ALLOWED_HOST}{payload.destination_path}"

if not payload.destination_path.startswith("/"):
    raise HTTPException(400, "destination_path must be a site-relative path")

slug = secrets.token_urlsafe(7).replace("_", "-").replace("/", "-")

target = append_query(destination, {
    "utm_source": payload.surface,
    "utm_medium": "ai_answer",
    "utm_campaign": "citation_measurement",
    "utm_content": payload.asset_id or "unspecified",
})

connection = db()
connection.execute("""
    INSERT INTO links
    (slug, destination, surface, topic, prompt_id, asset_id, created_at)
    VALUES (?, ?, ?, ?, ?, ?, ?)
""", (
    slug,
    target,
    payload.surface,
    payload.topic,
    payload.prompt_id,
    payload.asset_id,
    datetime.now(timezone.utc).isoformat(),
))
connection.commit()
connection.close()

return {"slug": slug, "url": f"https://go.example.com/{slug}"}

@app.get("/{slug}") def redirect(slug: str, request: Request): connection = db() row = connection.execute( "SELECT * FROM links WHERE slug = ?", (slug,) ).fetchone()

if not row:
    connection.close()
    raise HTTPException(404, "Unknown link")

referrer = request.headers.get("referer", "")
referrer_host = urlsplit(referrer).hostname or ""

connection.execute("""
    INSERT INTO clicks
    (occurred_at, slug, surface, topic, prompt_id,
     referrer_host, user_agent, ip_hmac)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?)
""", (
    datetime.now(timezone.utc).isoformat(),
    slug,
    row["surface"],
    row["topic"],
    row["prompt_id"],
    referrer_host,
    request.headers.get("user-agent", "")[:300],
    hash_ip(request.client.host if request.client else ""),
))
connection.commit()
connection.close()

return RedirectResponse(row["destination"], status_code=302)

Chạy nó với:

bash pip install fastapi uvicorn uvicorn shortener:app --host 0.0.0.0 --port 8080

Sử dụng chuyển hướng 302 cho các liên kết đo lường để trình duyệt và các hệ thống trung gian ít có khả năng lưu trữ vĩnh viễn chuyển hướng.


7. Trích xuất Định kỳ các Bảng Câu trả lời AI

Trích xuất bảng điều khiển hữu ích để trả lời các câu hỏi mà phân tích của bên thứ nhất có thể không tiết lộ:

  • Những nguồn cạnh tranh nào được trích dẫn?
  • Trang nào được trích dẫn cho một lời nhắc cụ thể?
  • Câu trả lời có thay đổi theo quốc gia hoặc thiết bị không?
  • Trích dẫn có xuất hiện trong câu trả lời, danh sách nguồn hay cả hai?
  • Câu trả lời ổn định như thế nào theo thời gian?
  • Trợ lý có trích dẫn một liên kết ngắn hay URL chuẩn?

Tuy nhiên, việc trích xuất phải được thực hiện cẩn thận.

Quy tắc thu thập có trách nhiệm

  1. Ưu tiên API chính thức, nhà cung cấp dữ liệu tìm kiếm được cấp phép hoặc báo cáo của bên thứ nhất.
  2. Xem xét các điều khoản của nhà cung cấp trước khi tự động hóa yêu cầu.
  3. Tuân thủ các hướng dẫn robots nếu có thể áp dụng.
  4. Không bỏ qua CAPTCHA, rào cản đăng nhập, giới hạn tỷ lệ hoặc bảo vệ bot.
  5. Sử dụng một tập hợp lời nhắc nhỏ, cố định.
  6. Chạy với tần suất thấp.
  7. Lưu phản hồi và dấu thời gian để kết quả có thể được kiểm toán.
  8. Dừng lại khi nhà cung cấp trả về một thử thách hoặc phản hồi từ chối truy cập.

Giao thức Loại trừ Robots là một cơ chế ưu tiên của trình thu thập thông tin, không phải hệ thống bảo mật. Nó không ủy quyền truy cập vào nội dung được bảo vệ. RFC 9309: Giao thức Loại trừ Robots (rfc-editor.org)

Xây dựng một Manifest Lời nhắc

csv prompt_id,topic,query,locale,surface,target_domain pm_001,project-management,"best project management software for remote teams",en-US,google,example.com pm_001,project-management,"best project management software for remote teams",en-US,bing,example.com pm_002,analytics,"how to measure AI referral traffic",en-US,google,example.com

Giữ lời nhắc ổn định. Nếu lời nhắc thay đổi, việc so sánh xu hướng trở nên kém đáng tin cậy hơn.

Cũng lưu trữ:

  • quốc gia
  • ngôn ngữ
  • loại thiết bị
  • phiên bản trình duyệt
  • phiên bản lời nhắc
  • phiên bản nội dung
  • thời gian thu thập theo UTC

Google lưu ý rằng các phản hồi của AI Overview và AI Mode có thể khác nhau vì chúng sử dụng các hệ thống khác nhau và có thể sử dụng các tìm kiếm liên quan hoặc “mở rộng truy vấn” (query fan-out). Các tính năng AI và tài liệu trang web của Google (developers.google.com)

Script Thu thập Playwright

Script sau là một công cụ nghiên cứu đa năng. Nó ghi lại trang được hiển thị, ảnh chụp màn hình, liên kết trang và văn bản câu trả lời. Nó cố ý không bỏ qua các thử thách hoặc cố gắng đánh bại các kiểm soát truy cập.

python

scrape_panels.py

import asyncio import csv import hashlib import json import os import re from datetime import datetime, timezone from pathlib import Path from urllib.parse import quote_plus, urljoin, urlsplit

from playwright.async_api import async_playwright

DATA_DIR = Path("data/panels") DATA_DIR.mkdir(parents=True, exist_ok=True)

SURFACE_URLS = { "google": "https://www.google.com/search?q={query}&hl=en&gl=us", "bing": "https://www.bing.com/search?q={query}&setlang=en-us", }

PANEL_MARKERS = { "google": ["AI Overview", "AI Mode"], "bing": ["Copilot", "Generative search"], }

BLOCK_MARKERS = [ "captcha", "unusual traffic", "verify you are human", "access denied", ]

def clean_text(value): return re.sub(r"\s+", " ", value or "").strip()

def host_matches(url, target_domain): host = (urlsplit(url).hostname or "").lower() target = target_domain.lower().lstrip("www.") return host == target or host.endswith("." + target)

def page_hash(text): normalized = clean_text(text).encode("utf-8") return hashlib.sha256(normalized).hexdigest()

async def collect_one(page, row): surface = row["surface"] query = row["query"] target_domain = row["target_domain"]

search_url = SURFACE_URLS[surface].format(
    query=quote_plus(query)
)

await page.goto(
    search_url,
    wait_until="domcontentloaded",
    timeout=45_000,
)
await page.wait_for_timeout(2500)

text = await page.locator("body").inner_text()
lowered = text.lower()

if any(marker in lowered for marker in BLOCK_MARKERS):
    return {
        **row,
        "observed_at": datetime.now(timezone.utc).isoformat(),
        "status": "blocked_or_challenged",
        "panel_present": False,
        "links": [],
    }

links = await page.locator("a").evaluate_all("""
    anchors => anchors.map(a => ({
        href: a.href || "",
        text: (a.innerText || "").trim()
    })).filter(x => x.href)
""")

panel_present = any(
    marker.lower() in lowered
    for marker in PANEL_MARKERS.get(surface, [])
)

observed_at = datetime.now(timezone.utc)
run_id = hashlib.sha256(
    f"{surface}|{row['prompt_id']}|{observed_at.isoformat()}".encode()
).hexdigest()[:20]

html_path = DATA_DIR / f"{run_id}.html"
screenshot_path = DATA_DIR / f"{run_id}.png"

await page.screenshot(path=str(screenshot_path), full_page=True)
html_path.write_text(await page.content(), encoding="utf-8")

output_links = []
for position, link in enumerate(links, start=1):
    output_links.append({
        "href": urljoin(search_url, link["href"]),
        "text": clean_text(link["text"])[:300],
        "position": position,
        "target_cited": host_matches(
            link["href"],
            target_domain
        ),
    })

return {
    **row,
    "run_id": run_id,
    "observed_at": observed_at.isoformat(),
    "status": "ok",
    "panel_present": panel_present,
    "answer_hash": page_hash(text),
    "answer_text": clean_text(text)[:50_000],
    "html_path": str(html_path),
    "screenshot_path": str(screenshot_path),
    "link_scope": "page_fallback",
    "links": output_links,
}

async def main(manifest_path): rows = [] with open(manifest_path, newline="", encoding="utf-8") as source: rows = list(csv.DictReader(source))

output_path = DATA_DIR / (
    datetime.now(timezone.utc).strftime("%Y-%m-%d") + ".jsonl"
)

async with async_playwright() as playwright:
    browser = await playwright.chromium.launch(headless=True)
    context = await browser.new_context(
        locale="en-US",
        timezone_id="UTC",
    )
    page = await context.new_page()

    with open(output_path, "w", encoding="utf-8") as output:
        for row in rows:
            try:
                result = await collect_one(page, row)
            except Exception as exc:
                result = {
                    **row,
                    "observed_at": datetime.now(timezone.utc).isoformat(),
                    "status": f"error:{type(exc).__name__}",
                    "panel_present": False,
                    "links": [],
                }

            output.write(json.dumps(result) + "\n")
            output.flush()

            # Keep request volume low.
            await asyncio.sleep(8)

    await browser.close()

if name == "main": asyncio.run(main("prompts.csv"))

Cài đặt và chạy:

bash pip install playwright playwright install chromium python scrape_panels.py

Lên lịch với một khóa để hai lần chạy không thể chồng chéo:

cron 15 3 * * * flock -n /tmp/ai-panel.lock
/usr/bin/python3 /opt/ai-measure/scrape_panels.py

Cải thiện độ chính xác với bộ điều hợp bề mặt

Script dự phòng ghi lại các liên kết cấp trang. Điều này hữu ích cho việc khám phá nhưng có thể bao gồm các liên kết kết quả tìm kiếm thông thường. Để sử dụng trong sản xuất:

  • Sử dụng API bảng câu trả lời được cấp phép khi có sẵn.
  • Tạo một bộ điều hợp bộ chọn riêng cho mỗi bề mặt.
  • Lưu trữ phiên bản bộ chọn.
  • Lưu trữ HTML thô và ảnh chụp màn hình.
  • Đánh dấu mỗi bản ghi bằng link_scope = "panel_selector" hoặc link_scope = "page_fallback".

Chỉ tính Tỷ lệ Trích dẫn từ dữ liệu panel_selector khi bạn có thể xác định bảng điều khiển một cách đáng tin cậy. Giữ các quan sát dự phòng trong một báo cáo khám phá riêng biệt.


8. Tích hợp Google Analytics và BigQuery

Google Analytics 4 có thể xuất dữ liệu sự kiện thô sang BigQuery. Xuất hàng ngày cung cấp các bảng ổn định như events_YYYYMMDD; xuất streaming hữu ích cho việc giám sát gần thời gian thực nhưng có thể không đầy đủ cho đến khi bảng hàng ngày được hoàn thiện. Xuất Google Analytics BigQuery (support.google.com)

Một truy vấn phiên đơn giản có thể trông như thế này:

sql WITH page_events AS ( SELECT event_date, user_pseudo_id,

(
  SELECT value.int_value
  FROM UNNEST(event_params)
  WHERE key = 'ga_session_id'
) AS session_id,

(
  SELECT value.string_value
  FROM UNNEST(event_params)
  WHERE key = 'page_location'
) AS page_location,

(
  SELECT value.string_value
  FROM UNNEST(event_params)
  WHERE key = 'session_engaged'
) AS session_engaged,

event_name

FROM PROJECT.analytics_PROPERTY.events_* WHERE _TABLE_SUFFIX BETWEEN '20260901' AND '20260921' ),

session_rollup AS ( SELECT event_date, user_pseudo_id, session_id,

MAX(
  CASE
    WHEN REGEXP_CONTAINS(
      LOWER(page_location),
      r'[?&]utm_medium=ai_answer'
    )
    THEN 1 ELSE 0
  END
) AS ai_session,

MAX(
  CASE
    WHEN session_engaged = '1'
    THEN 1 ELSE 0
  END
) AS engaged_session,

MAX(
  CASE
    WHEN event_name IN ('purchase', 'generate_lead', 'sign_up')
    THEN 1 ELSE 0
  END
) AS key_event

FROM page_events GROUP BY event_date, user_pseudo_id, session_id )

SELECT event_date, COUNTIF(ai_session = 1) AS ai_sessions, COUNTIF(ai_session = 1 AND engaged_session = 1) AS engaged_ai_sessions, COUNTIF(ai_session = 1 AND key_event = 1) AS ai_key_events, SAFE_DIVIDE( COUNTIF(ai_session = 1 AND engaged_session = 1), COUNTIF(ai_session = 1) ) AS post_citation_engagement_rate FROM session_rollup GROUP BY event_date ORDER BY event_date;

Đối với một triển khai trưởng thành, hãy thêm surface, topic và prompt_id vào cấu trúc chiến dịch hoặc nối chúng từ bảng nhấp chuột của công cụ rút gọn.

Không tạo một thứ nguyên phân tích có số lượng giá trị lớn (high-cardinality analytics dimension) cho mỗi người dùng hoặc phiên cá nhân. Google cảnh báo rằng các thứ nguyên tùy chỉnh có số lượng giá trị lớn quá mức có thể làm giảm chất lượng báo cáo. Các thứ nguyên và chỉ số tùy chỉnh của Google Analytics (support.google.com)


9. Thiết kế Bảng điều khiển

Một bảng điều khiển thực tế nên chứa năm chế độ xem.

Tóm tắt Điều hành

Hiển thị:

  • Tỷ lệ Trích dẫn theo Chủ đề
  • Độ bao phủ Trích dẫn theo Chủ đề
  • Tỷ lệ Giới thiệu Trợ lý Đã xác nhận
  • Tỷ lệ Giới thiệu Trợ lý Mở rộng
  • Tương tác Sau Trích dẫn
  • Tỷ lệ thành công của trình thu thập thông tin AI
  • Các sự kiện quan trọng hoặc doanh thu được quy cho AI

Xu hướng Tỷ lệ Trích dẫn

Biểu đồ đường:

text Ngày × Chủ đề × Bề mặt

Hiển thị cả:

  • số lần xuất hiện trích dẫn của miền mục tiêu
  • tất cả các lần xuất hiện trích dẫn được quan sát

Phễu Lưu lượng Trợ lý

text Các trích dẫn được quan sát ↓ Các nhấp chuột liên kết được kiểm soát ↓ Các phiên được quy cho AI ↓ Các phiên AI tương tác ↓ Các sự kiện quan trọng

Mỗi giai đoạn nên hiển thị mức độ tin cậy của việc phân bổ.

Tình trạng Trình thu thập thông tin

Bảng theo bot:

text bot_name requests successful_requests error_rate unique_ip_count top_paths

Cảnh báo khi:

  • tỷ lệ lỗi vượt quá 2 phần trăm
  • một bot đột nhiên biến mất
  • một phần nội dung trước đây có thể truy cập trả về 403 hoặc 429
  • các yêu cầu của trình thu thập thông tin tập trung vào một đường dẫn riêng tư không mong muốn

Bảng Cơ hội Nội dung

Xếp hạng các trang và chủ đề theo:

text tỷ lệ trích dẫn cao + tỷ lệ giới thiệu thấp số lần hiển thị cao + độ bao phủ trích dẫn thấp tương tác cao + khả năng hiển thị trích dẫn thấp lỗi trình thu thập thông tin cao + tầm quan trọng kinh doanh cao

Những sự kết hợp này thường tạo ra các quyết định tốt hơn so với việc chỉ nhìn vào khối lượng lưu lượng truy cập.

Bảng điều khiển Streamlit Tối thiểu

Lưu dưới dạng dashboard.py.

python import glob import json from pathlib import Path

import pandas as pd import streamlit as st

st.set_page_config( page_title="AI Citation Impact", layout="wide", )

@st.cache_data(ttl=300) def load_panel_rows(): rows = []

for filename in glob.glob("data/panels/*.jsonl"):
    with open(filename, encoding="utf-8") as source:
        for line in source:
            record = json.loads(line)

            run_id = record.get("run_id")
            for link in record.get("links", []):
                hostname = link.get("href", "").split("/")[2]
                rows.append({
                    "run_id": run_id,
                    "observed_at": record.get("observed_at"),
                    "surface": record.get("surface"),
                    "topic": record.get("topic"),
                    "prompt_id": record.get("prompt_id"),
                    "panel_present": record.get("panel_present"),
                    "target_domain": record.get("target_domain"),
                    "cited_domain": hostname,
                    "target_cited": link.get("target_cited", False),
                    "position": link.get("position"),
                    "link_scope": record.get("link_scope"),
                })

return pd.DataFrame(rows)

panels = load_panel_rows()

st.title("AI Citation Impact Dashboard")

if panels.empty: st.warning("No panel observations found.") st.stop()

panels["date"] = pd.to_datetime( panels["observed_at"], errors="coerce" ).dt.date

citation_share = ( panels.groupby("topic") .apply( lambda group: group["target_cited"].sum() / max(len(group), 1) ) .reset_index(name="citation_share") )

coverage = ( panels.groupby(["topic", "run_id"], dropna=False) .agg( panel_present=("panel_present", "max"), target_cited=("target_cited", "max"), ) .reset_index() )

coverage = ( coverage[coverage["panel_present"] == True] .groupby("topic") .apply(lambda group: group["target_cited"].mean()) .reset_index(name="citation_coverage") )

col1, col2 = st.columns(2)

with col1: st.subheader("Citation Share by Topic") st.dataframe(citation_share, use_container_width=True) st.bar_chart( citation_share.set_index("topic")["citation_share"] )

with col2: st.subheader("Citation Coverage by Topic") st.dataframe(coverage, use_container_width=True) st.bar_chart( coverage.set_index("topic")["citation_coverage"] )

st.subheader("Citation Position") st.dataframe( panels.groupby(["topic", "surface"], dropna=False) .agg( citations=("target_cited", "sum"), median_position=("position", "median"), observations=("run_id", "nunique"), ) .reset_index(), use_container_width=True, )

st.subheader("Daily Observations") daily = ( panels.groupby(["date", "surface"], dropna=False) .agg( citations=("target_cited", "sum"), observed_links=("cited_domain", "count"), ) .reset_index() )

st.line_chart( daily.pivot( index="date", columns="surface", values="citations" ).fillna(0) )

Chạy nó với:

bash pip install streamlit pandas streamlit run dashboard.py

Đối với sản xuất, hãy tải các bảng được chuẩn hóa vào DuckDB, BigQuery, Snowflake hoặc PostgreSQL thay vì đọc trực tiếp các tệp thô.


10. Kiểm soát Chất lượng

Một hệ thống đo lường có thể tạo ra các con số trông chính xác nhưng lại gây hiểu lầm. Hãy thêm các kiểm soát này.

Tách biệt bot khỏi người

Không bao giờ tính OAI-SearchBot, GPTBot, ClaudeBot hoặc PerplexityBot là các phiên của con người. Đây là các tín hiệu của trình thu thập thông tin hoặc truy xuất.

Giữ lại bằng chứng thô

Đối với mỗi lần chạy bảng điều khiển, giữ lại:

  • HTML thô
  • ảnh chụp màn hình
  • văn bản câu trả lời
  • dấu thời gian
  • phiên bản trình duyệt và trình thu thập
  • lời nhắc và ngôn ngữ
  • hash câu trả lời

Điều này giúp giải thích tại sao một chỉ số thay đổi.

Theo dõi sự vắng mặt của bảng điều khiển

Một bảng AI bị thiếu không giống như một câu trả lời không có trích dẫn của bạn.

Sử dụng:

text panel_not_present panel_present_no_target panel_present_target_cited blocked_or_challenged collection_error

Kiểm soát sai lệch lấy mẫu

Một lần trích xuất theo lịch trình bị ảnh hưởng bởi:

  • vị trí
  • thiết bị
  • ngôn ngữ
  • thời gian
  • cá nhân hóa
  • trạng thái trình duyệt
  • cách diễn đạt lời nhắc

Sử dụng một tập hợp cốt lõi các lời nhắc cố định và một tập hợp các lời nhắc khám phá luân phiên. Giữ hai nhóm riêng biệt trong các báo cáo.

Tránh độ chính xác sai lệch

Báo cáo khoảng tin cậy hoặc kích thước mẫu tối thiểu cho các nhóm chủ đề nhỏ. Một chủ đề với ba quan sát không nên được so sánh trực tiếp với một chủ đề chứa 300 quan sát.

So sánh những thứ tương tự

Khi so sánh các bề mặt, giữ ổn định:

  • lời nhắc
  • ngôn ngữ
  • quốc gia
  • thiết bị
  • giờ thu thập
  • quy tắc miền mục tiêu
  • phiên bản trình phân tích trích dẫn

11. Kế hoạch Triển khai được khuyến nghị

Tuần 1: Công cụ

  • Cấu hình nhật ký máy chủ có cấu trúc.
  • Tạo sổ đăng ký bot.
  • Tạo miền rút gọn.
  • Thêm quy tắc đặt tên chiến dịch.
  • Xác định phân loại chủ đề.
  • Bật xuất Google Analytics 4 BigQuery.

Tuần 2: Liên kết được kiểm soát

  • Xuất bản năm đến mười bản tóm tắt được theo dõi.
  • Tạo liên kết cho các chủ đề và phiên bản nội dung khác nhau.
  • Xác thực nhật ký chuyển hướng so với các phiên phân tích.
  • Xác nhận rằng không có thông tin cá nhân nào đi vào URL hoặc tham số phân tích.

Tuần 3: Quan sát bảng điều khiển

  • Tạo một manifest lời nhắc.
  • Bắt đầu với hai bề mặt và 20 đến 50 lời nhắc ổn định.
  • Chạy mỗi ngày một lần.
  • Lưu ảnh chụp màn hình và HTML.
  • Đo lường các lỗi thu thập riêng biệt với sự vắng mặt của trích dẫn.

Tuần 4: Bảng điều khiển và quản trị

  • Xây dựng bảng điều khiển chủ đề và bề mặt.
  • Thêm cảnh báo tình trạng trình thu thập thông tin.
  • Xác định các quy tắc tin cậy.
  • So sánh các báo cáo của bên thứ nhất với các quan sát bảng điều khiển.
  • Tài liệu hóa các chính sách lưu giữ, truy cập và xóa.

Kết luận

Đo lường trích dẫn AI nên được xây dựng như một hệ thống phân bổ đa tín hiệu, chứ không phải là một báo cáo giới thiệu duy nhất.

Khung đáng tin cậy nhất kết hợp:

  • Báo cáo khả năng hiển thị của bên thứ nhất từ Google và Bing
  • nhật ký máy chủ cho hoạt động của trình thu thập thông tin và trình tìm nạp
  • liên kết ngắn của bên thứ nhất để đo lường nhấp chuột có kiểm soát
  • quan sát bảng câu trả lời theo lịch trình, tuân thủ
  • dữ liệu phân tích và chuyển đổi cho giá trị hạ nguồn

Ba chỉ số quan trọng nhất là:

  1. Tỷ lệ Trích dẫn theo Chủ đề — bao nhiêu phần trong không gian nguồn được quan sát thuộc về miền của bạn.
  2. Tỷ lệ Giới thiệu Trợ lý — bao nhiêu lưu lượng truy cập của con người có thể được quy cho các bề mặt AI.
  3. Tương tác Sau Trích dẫn — liệu khách truy cập được giới thiệu bởi AI có thực hiện các hành động có ý nghĩa hay không.

Hệ thống trở nên hữu ích khi mỗi con số bao gồm bề mặt, khoảng thời gian, mẫu số, phương pháp phân bổ và mức độ tin cậy của nó. Kỷ luật đó ngăn chặn việc nhầm lẫn lượt truy cập của trình thu thập thông tin với người dùng, các câu trả lời được trích xuất với số lần hiển thị, và các trích dẫn với kết quả kinh doanh.

Bài viết liên quan

Thích nội dung này?

Đăng ký nhận bản tin của chúng tôi để biết thông tin chi tiết về content marketing và hướng dẫn tăng trưởng mới nhất.

Bài viết này chỉ dành cho mục đích thông tin. Nội dung và chiến lược có thể thay đổi tùy theo nhu cầu cụ thể của bạn.
Đo lường Tác động Trích dẫn AI: Phân tích, Nhật ký và Trích xuất Bảng điều khiển | AutoPod