AI atsaukšanās ietekmes mērīšana: analītika, žurnāli un paneļu ielasīšana
Ievads
Mākslīgā intelekta (MI) virzīta atklāšana tagad ir sadalīta vairākos mērījumu slāņos. Persona var redzēt uzņēmumu, kas citēts MI atbildē, noklikšķināt uz saites bez noderīga atsauces avota, apmeklēt vietni caur pārlūkprogrammu, kas noņem kampaņas datus, vai lasīt atbildi, vispār neklikšķinot. Tikmēr MI pārlūks (crawler) var pieprasīt uzņēmuma lapu, nepārstāvot cilvēku apmeklētāju.
Tādēļ noderīgai mērījumu sistēmai ir jānošķir četri jautājumi:
- Vai vietne tika pārlūkota vai izgūta?
- Vai vietne tika citēta MI atbildē?
- Vai persona apmeklēja vietni no šīs atbildes?
- Vai šis apmeklējums radīja jēgpilnu iesaisti vai ieņēmumus?
Sākot ar 2026. gada 22. septembri, pirmo pušu ziņošana uzlabojas. Google Search Console nodrošina ģeneratīvā MI veiktspējas pārskatu MI pārskatiem un MI režīmam, ieskaitot seansus, lapas, valstis, ierīces un datumus. Pārskats kļuva pieejams visā pasaulē 2026. gada 31. augustā. Google ģeneratīvā MI veiktspējas pārskats (support.google.com)
Microsoft arī nodrošina MI veiktspējas pārskatu Bing Webmaster Tools. Tā publiskais priekšskatījums ziņo par kopējām atsaucēm, citētajām lapām, pamatā esošajiem vaicājumiem un citātu tendencēm visās atbalstītajās Microsoft MI pieredzēs. Bing Webmaster Tools MI veiktspēja (blogs.bing.com)
Šie rīki ir jāuzskata par autoritatīviem savām virsmām, taču tie nerada pilnīgu starp-asistentu mērījumu sistēmu. Ieteicamā pieeja ir apvienot pirmo pušu pārskatus, serveru žurnālus, kontrolētas izsekošanas saites, analītikas eksportus un plānotus atbildes paneļu novērojumus.
1. Kāpēc MI atsauču mērīšana ir sarežģīta
Tradicionālā tīmekļa analītika lielā mērā ir atkarīga no Referer galvenes un kampaņas parametriem. Abi var būt trūkstoši vai nepilnīgi.
HTTP Referer galvene var saturēt iepriekšējo lapu, tikai iepriekšējās vietnes izcelsmi vai vispār nekādu vērtību. Pārlūkprogrammas atsauces politikas var apzināti ierobežot vai noņemt šo informāciju. MDN Referrer-Policy dokumentācija (developer.mozilla.org)
MI sistēmas rada papildu sarežģījumus:
- Asistents var saistīt lapu, nesūtot atpazīstamu atsauces avotu.
- Asistents var izmantot pāradresējošu vai pārrakstītu URL.
- Asistents var ielādēt saturu servera pusē pirms atbildes parādīšanas.
- MI pārlūks var apmeklēt lapu, to neredzot nevienam cilvēkam.
- Atbilde var citēt kanonisko URL, nevis sākotnēji izgūto URL.
- Atbilde var mainīties atkarībā no atrašanās vietas, ierīces, valodas, laika vai personalizācijas.
Piemēram, OpenAI atšķir OAI-SearchBot meklēšanas atklāšanai, GPTBot iespējamai apmācībai un ChatGPT-User lietotāja ierosinātām darbībām. Perplexity atsevišķi identificē PerplexityBot un Perplexity-User. Anthropic identificē ClaudeBot, Claude-SearchBot un Claude-User. Šie pieprasījumi nedrīkst tikt apvienoti vienā vispārīgā “MI datplūsmas” skaitlī. OpenAI pārlūka dokumentācija (openai.com) Perplexity pārlūka dokumentācija (docs.perplexity.ai) Anthropic pārlūka dokumentācija (support.anthropic.com)
Centrālais noteikums ir:
Pārlūka aktivitāte nav novirzīšanas datplūsma, citātu redzamība nav datplūsma, un datplūsma nav biznesa ietekme.
2. Mērījumu sistēma
Izmantojiet piecus mērījumu slāņus.
| Slānis | Galvenais jautājums | Ieteicamie dati |
|---|---|---|
| Piekļuve | Vai MI sistēma pieprasīja lapu? | Tīmekļa servera žurnāli, ugunsmūra žurnāli |
| Redzamība | Vai lapa tika parādīta vai citēta? | Google Search Console, Bing Webmaster Tools, atbildes paneļu novērojumi |
| Iegūšana | Vai persona ieradās no MI virsmas? | Atsauces avots, kampaņas parametri, īso saišu klikšķi, analītika |
| Iesaiste | Vai apmeklētājs jēgpilni mijiedarbojās? | Analītikas notikumi, lapu skatījumi, iesaistes laiks |
| Vērtība | Vai apmeklējums radīja vēlamo rezultātu? | Reģistrācijas, potenciālie klienti, pirkumi, abonementi |
Ieteicamā patiesības avota hierarhija
Izmantojiet spēcīgāko pieejamo signālu katram jautājumam:
- Pirmo pušu platformu pārskati par seansiem un atsaucēm.
- Atbildes paneļu novērojumi par redzamību pamudinājuma līmenī un konkurences salīdzinājumiem.
- Pāradresācijas žurnāli kontrolētiem saišu klikšķiem.
- Tīmekļa analītika sesijām, iesaistei un konversijām.
- Serveru žurnāli pārlūka un izguvēja aktivitātēm.
- Modelētas aplēses tikai tad, ja tieši pierādījumi nav pieejami.
Nekombinējiet visus signālus vienā skaitlī, nesaglabājot avotu un pārliecības līmeni.
3. Pamatdatu modelis
Izveidojiet datu noliktavu ar atsevišķām tabulām neapstrādātiem novērojumiem un atvasinātām metrikām.
panel_runs
Viena rinda katrai pamudinājuma un virsmas pārbaudei.
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
Viena rinda katrai atbildes panelī novērotajai saitei.
text run_id surface topic prompt_id cited_url cited_domain citation_position link_scope target_domain target_cited
ai_crawler_requests
Apkopoti servera žurnālu dati.
text date bot_name bot_role path requests successful_requests error_requests unique_ip_count
shortener_clicks
Viena rinda katram kontrolētās saites pieprasījumam.
text click_id occurred_at slug surface topic prompt_id asset_id referrer_host user_agent_family ip_hmac destination_path
ai_sessions
Normalizēta analītikas tabula.
text session_id date surface topic prompt_id landing_page attribution_method confidence engaged engagement_time_seconds key_event revenue
confidence lauks ir svarīgs. Ieteicamās vērtības ir:
- A — Tieši: kontrolēts īssaites klikšķis vai uzticams kampaņas parametrs.
- B — Spēcīgi: zināms asistenta atsauces avots vai verificēts lietotāja izgūšanas pieprasījums.
- C — Iespējami: kampaņas vai galvenās lapas pierādījumi bez pilnīga atsauces avota.
- D — Modelēti: secināti no laika, paneļu novērojumiem vai kopējām izmaiņām.
Ziņojiet par A un B atsevišķi no C un D.
4. Metriku definīcijas
Atsauču daļa pēc tēmas
Atsauču daļa pēc tēmas mēra, cik bieži mērķa domēns parādās starp tēmai novērotajiem avotiem.
[ \text{Citation Share}_{topic}
\frac{\text{Target-domain citation occurrences}} {\text{All citation occurrences}} ]
Piemērs:
- 100 kopējās atsauces, kas novērotas par “projektu vadības programmatūru”
- 12 atsauces norāda uz jūsu domēnu
- Atsauču daļa pēc tēmas = 12%
Šī metrika mēra avotu daļu, nevis to, vai atbilde vismaz vienreiz saturēja jūsu vietni.
Atsauču aptvērums
Izmantojiet otru metriku atbildes līmeņa klātbūtnei:
[ \text{Citation Coverage}_{topic}
\frac{\text{Answer runs containing a target citation}} {\text{Answer runs where a panel was present}} ]
Atsauču aptvērums bieži ir vieglāk saprotams netehniskai auditorijai:
“Mūsu vietne parādījās 34% no novērotajām MI atbildēm par šo tēmu.”
Atsauces pozīcija
Ierakstiet atsauces pozīciju atbildē:
1= pirmais novērotais avots2= otrais novērotais avots3= trešais novērotais avots
Tā kā MI saskarnes bieži grupē vai pārkārto avotus, pozīcija jāuztver kā aprakstošs novērojums, nevis universāls rangs.
Asistenta novirzīšanas likme
Asistenta novirzīšanas likme mēra to cilvēku vietnes sesiju proporciju, ko var attiecināt uz MI virsmu.
[ \text{Assistant Referral Rate}
\frac{\text{AI-attributed human sessions}} {\text{All human sessions}} ]
Ziņojiet vismaz divas versijas:
text Apstiprināta asistenta novirzīšanas likme = A-pārliecības MI sesijas / visas cilvēku sesijas
Paplašināta asistenta novirzīšanas likme = A + B + C-pārliecības MI sesijas / visas cilvēku sesijas
Apstiprinātā versija ir konservatīvāka. Paplašinātā versija ir noderīga tendenču analīzei, taču to nevajadzētu pasniegt kā pilnībā novērotu datplūsmu.
Neizmantojiet paneļu palaišanas reizes kā seansus
Ja jūs ielasāt 500 pamudinājumus, tas nenozīmē, ka 500 cilvēki redzēja šīs atbildes. Jūsu ielasītājs mēra kontrolētu atbilžu stāvokļu paraugu. Izmantojiet pirmo pušu platformu seansu pārskatus, kad tie ir pieejami.
Iesaiste pēc citēšanas
Iesaiste pēc citēšanas mēra, vai cilvēki, kuri ieradās caur MI atsauci, veica jēgpilnu darbību.
[ \text{Post-Citation Engagement}
\frac{\text{Engaged AI sessions}} {\text{AI-attributed sessions}} ]
Google Analytics 4 gadījumā iesaistīta sesija ilgst vairāk nekā 10 sekundes, ietver galveno notikumu vai vismaz divus lapu vai ekrāna skatījumus. Google Analytics iesaistes likmes dokumentācija (support.google.com)
Ziņojiet arī:
text Iesaistes laiks pēc citēšanas = vidējais iesaistes sekunžu skaits vienā MI sesijā
Konversijas likme pēc citēšanas = MI sesijas ar galveno notikumu / MI attiecinātās sesijas
Ieņēmumi no sesijas pēc citēšanas = ieņēmumi no MI sesijām / MI attiecinātās sesijas
Vidējais iesaistes laiks parasti ir stabilāks nekā vidējais iesaistes laiks, jo neliels skaits ļoti garu sesiju var sagrozīt vidējo.
Papildu noderīgas metrikas
MI pārlūka veiksmes likme
[ \text{Crawler Success Rate}
\frac{\text{AI crawler requests returning 2xx or 3xx}} {\text{AI crawler requests}} ]
Sadalīt to pēc robota un ceļa. Liels atsauču samazinājums apvienojumā ar pieaugošu pārlūka kļūdu līmeni var norādīt uz mitināšanas, ugunsmūra vai robotu konfigurācijas problēmu.
Atsauces uz klikšķu likme
Kontrolētiem atbildes paneļu novērojumiem:
[ \text{Observed Citation-to-Click Rate}
\frac{\text{Confirmed short-link clicks}} {\text{Observed target citations}} ]
Šī nav patiesa lietotāju klikšķu caurlūkošanas likme, ja vien saucējs nepārstāv faktiskos lietotāju seansus. Skaidri apzīmējiet to kā novērotu operatīvo metriku.
Atsauču aktualitāte
Mēriet, cik bieži citētais URL atspoguļo pašreizējo lapas versiju.
text Citation Freshness = cited pages with current content hash / cited pages
Tas ir noderīgi dokumentācijai, cenu, produktu un politikas lapām, kas bieži mainās.
5. Servera žurnālu analīze
Konfigurēt strukturētus piekļuves žurnālus
Strukturētie žurnāli ir vieglāk analizējami nekā tradicionālie ar atstarpēm atdalītie žurnāli.
Piemērs Nginx konfigurācija:
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;
Glabājiet žurnālu failus ierobežotā vietā. Nesūtiet neapstrādātas IP adreses uz vispārēju analītikas tabulu, ja vien jums nav skaidra operatīva iemesla.
Identificēt MI pieprasījumu veidus
Minimāli, atdalīt:
text OpenAI:
- OAI-SearchBot
- ChatGPT-User
- GPTBot
Anthropic:
- Claude-SearchBot
- Claude-User
- ClaudeBot
Perplexity:
- PerplexityBot
- Perplexity-User
Meklētājprogrammas:
- Googlebot
- Bingbot
Google MI meklēšanas funkcijas parasti izmanto esošās Google meklēšanas pārlūkošanas vadības ierīces, nevis atsevišķu universālu “MI pārskatu robotu”. Google apgalvo, ka Googlebot kontrolē piekļuvi meklēšanai, tostarp MI funkcijām. Google MI funkcijas un vietnes (developers.google.com)
Lietotāja aģenta virknes var viltot. Operatīviem lēmumiem apvienojiet lietotāja aģenta saskaņošanu ar pakalpojumu sniedzēju publicētajiem IP diapazoniem vai verificētu apgriezto DNS, ja pieejams. OpenAI un Perplexity publicē IP informāciju par saviem attiecīgajiem pārlūkiem un izguvējiem. (openai.com)
Atkārtojams žurnālu apkopotājs
Saglabājiet sekojošo kā 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", "aizstājiet-šo-ražošanā").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("Lietojums: python ai_log_summary.py /ceļš/uz/access.jsonl") sys.exit(1)
main(sys.argv[1])
Palaidiet to ar:
bash
HMAC_SECRET='garš-nejaušs-slepenais-teksts'
python ai_log_summary.py /var/log/nginx/ai-access.jsonl \
data/ai_crawler_daily.csv
Tas rada operatīvus pierādījumus par izguves aktivitāti, nevis cilvēku datplūsmu.
6. Pielāgoti saišu saīsinātāji MI vērstiem kopsavilkumiem
Pirmās puses saišu saīsinātājs nodrošina kontrolētu mērījumu punktu, publicējot kopsavilkumus vai avota materiālus, uz kuriem var atsaukties MI sistēmas.
Izmantojiet domēnu, ko kontrolējat, piemēram:
text https://go.example.com/ai-docs
Galamērķim jāietver kampaņas parametri, piemēram:
text utm_source=perplexity utm_medium=ai_answer utm_campaign=product_documentation utm_content=pricing_summary_v3
Google iesaka kampaņas parametrus datplūsmas avotu un kampaņu identificēšanai. Google Analytics kampaņas URL dokumentācija (support.google.com)
Ieteicamie saišu lauki
text surface topic prompt_id asset_id content_version destination_path
Neievietojiet personisko informāciju, e-pasta adreses vai lietotāju meklēšanas vaicājumus saitē. Kampaņas identifikatoriem jāapraksta publicētais resurss, nevis jāidentificē persona.
Svarīgi ierobežojumi
Īsa saite ir kalibrēšanas ierīce, nevis universāls risinājums:
- Asistents var pārrakstīt mērķa URL.
- Asistents tā vietā var citēt kanonisko URL.
- Saite var tikt parādīta, bet nekad netikt noklikšķināta.
- Pārlūkprogramma vai privātuma rīks var noņemt atsauces avotu.
- Dažas sistēmas var izgūt galamērķi servera pusē.
- Īsa saite nemēra lietotājus, kuri atceras zīmolu un atgriežas vēlāk.
Neizmantojiet saīsinātāju, lai paslēptu galamērķi, apietu drošības sistēmas vai manipulētu ar atsaucēm. Izmantojiet skaidru pāradresāciju uz atbilstošu, kanonisko lapu.
Minimāls pirmās puses saīsinātājs
Šis piemērs izmanto FastAPI un SQLite. Pirms lietošanas ražošanā aizsargājiet saišu izveides galapunktu ar autentifikāciju.
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", "aizstājiet-šo-ražošanā" ).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 jābūt vietnes relatīvam ceļam")
slug = secrets.token_urlsafe(7).replace("_", "-").replace("/", "-")
target = append_query(destination, {
"utm_source": payload.surface,
"utm_medium": "ai_answer",
"utm_campaign": "atsauču_mērīšana",
"utm_content": payload.asset_id or "nenorādīts",
})
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, "Nezināma saite")
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)
Palaidiet to ar:
bash pip install fastapi uvicorn uvicorn shortener:app --host 0.0.0.0 --port 8080
Izmantojiet 302 pāradresāciju mērījumu saitēm, lai pārlūkprogrammas un starpsistēmas retāk pastāvīgi kešotu pāradresāciju.
7. MI atbildes paneļu plānota ielasīšana
Paneļu ielasīšana ir noderīga, lai atbildētu uz jautājumiem, ko pirmo pušu analītika var neatklāt:
- Kādi konkurējošie avoti tiek citēti?
- Kura lapa tiek citēta konkrētam pamudinājumam?
- Vai atbilde mainās atkarībā no valsts vai ierīces?
- Vai atsauce parādās atbildē, avotu sarakstā vai abos?
- Cik stabila ir atbilde laika gaitā?
- Vai asistents citē īsu saiti vai kanonisko URL?
Tomēr ielasīšana jāveic uzmanīgi.
Atbildīgas datu vākšanas noteikumi
- Dodiet priekšroku oficiālai API, licencētam meklēšanas datu pakalpojumu sniedzējam vai pirmās puses pārskatam.
- Pirms pieprasījumu automatizēšanas pārskatiet pakalpojumu sniedzēja noteikumus.
- Ievērojiet robotu norādījumus, ja tie ir piemērojami.
- Neapiejiet CAPTCHA, pieteikšanās barjeras, likmju ierobežojumus vai botu aizsardzību.
- Izmantojiet nelielu, fiksētu pamudinājumu kopu.
- Palaidiet ar zemu frekvenci.
- Saglabājiet atbildi un laika zīmogu, lai rezultātus varētu pārbaudīt.
- Apstājieties, kad pakalpojumu sniedzējs atgriež izaicinājumu vai piekļuves lieguma atbildi.
Robots izslēgšanas protokols ir pārlūka preferenču mehānisms, nevis drošības sistēma. Tas neatļauj piekļuvi aizsargātam saturam. RFC 9309: Robots izslēgšanas protokols (rfc-editor.org)
Izveidot pamudinājumu manifestu
csv prompt_id,topic,query,locale,surface,target_domain pm_001,projektu-vadība,"labākā projektu vadības programmatūra attālinātām komandām",en-US,google,example.com pm_001,projektu-vadība,"labākā projektu vadības programmatūra attālinātām komandām",en-US,bing,example.com pm_002,analītika,"kā mērīt MI novirzīšanas datplūsmu",en-US,google,example.com
Uzturiet pamudinājumus stabilus. Ja pamudinājumi mainās, tendenču salīdzinājumi kļūst mazāk uzticami.
Saglabājiet arī:
- valsts
- valoda
- ierīces tips
- pārlūkprogrammas versija
- pamudinājuma versija
- satura versija
- vākšanas laiks UTC
Google norāda, ka MI Pārskats un MI Režīms atbildes var atšķirties, jo tie izmanto dažādas sistēmas un var izmantot saistītus meklējumus vai “vaicājumu izvērsumu”. Google MI funkcijas un vietnes dokumentācija (developers.google.com)
Playwright vākšanas skripts
Šis skripts ir vispārējas nozīmes pētījumu rīks. Tas ieraksta renderēto lapu, ekrānuzņēmumu, lapas saites un atbildes tekstu. Tas apzināti neapiet izaicinājumus un nemēģina pārvarēt piekļuves kontroli.
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", "neparasta datplūsma", "pārbaudiet, vai esat cilvēks", "piekļuve liegta", ]
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()
# Uzturēt zemu pieprasījumu apjomu.
await asyncio.sleep(8)
await browser.close()
if name == "main": asyncio.run(main("prompts.csv"))
Instalējiet un palaidiet:
bash pip install playwright playwright install chromium python scrape_panels.py
Ieplānojiet to ar bloķētāju, lai divi palaidieni nevarētu pārklāties:
cron
15 3 * * * flock -n /tmp/ai-panel.lock
/usr/bin/python3 /opt/ai-measure/scrape_panels.py
Uzlabojiet precizitāti ar virsmas adapteriem
Atkrituma skripts ieraksta lapas līmeņa saites. Tas ir noderīgi atklāšanai, bet var ietvert parastās meklēšanas rezultātu saites. Ražošanas vajadzībām:
- Izmantojiet licencētu atbildes paneļa API, ja tā ir pieejama.
- Izveidojiet atsevišķu selektora adapteri katrai virsmai.
- Glabājiet selektora versiju.
- Glabājiet neapstrādātu HTML un ekrānuzņēmumu.
- Atzīmējiet katru ierakstu ar
link_scope = "panel_selector"vailink_scope = "page_fallback".
Aprēķiniet atsauču daļu tikai no panel_selector datiem, ja varat droši identificēt paneli. Glabājiet atkrituma novērojumus atsevišķā izpētes ziņojumā.
8. Google Analytics un BigQuery integrācija
Google Analytics 4 var eksportēt neapstrādātus notikumu datus uz BigQuery. Ikdienas eksporti nodrošina stabilas tabulas, piemēram, events_YYYYMMDD; straumēšanas eksporti ir noderīgi gandrīz reāllaika uzraudzībai, taču tie var būt nepilnīgi, līdz ikdienas tabula ir pabeigta. Google Analytics BigQuery eksports (support.google.com)
Vienkāršots sesijas vaicājums varētu izskatīties šādi:
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;
Nobriedušai implementācijai pievienojiet surface, topic un prompt_id kampaņas struktūrai vai apvienojiet tos no saišu saīsinātāja klikšķu tabulas.
Neveidojiet augstas kardinalitātes analītikas dimensiju katram atsevišķam lietotājam vai sesijai. Google brīdina, ka pārmērīgas augstas kardinalitātes pielāgotās dimensijas var samazināt ziņošanas kvalitāti. Google Analytics pielāgotās dimensijas un metrikas (support.google.com)
9. Paneļa dizains
Praktiskam panelim jāsatur pieci skati.
Kopsavilkums vadībai
Parādīt:
- Atsauču daļa pēc tēmas
- Atsauču aptvērums pēc tēmas
- Apstiprināta asistenta novirzīšanas likme
- Paplašināta asistenta novirzīšanas likme
- Iesaiste pēc citēšanas
- MI pārlūka veiksmes likme
- MI attiecinātie galvenie notikumi vai ieņēmumi
Atsauču daļas tendence
Līniju diagramma:
text Datums × Tēma × Virsma
Parādīt abus:
- mērķa domēna atsauču gadījumi
- visi novērotie atsauču gadījumi
Asistenta datplūsmas piltuve
text Novērotās atsauces ↓ Kontrolēto saišu klikšķi ↓ MI attiecinātās sesijas ↓ Iesaistītās MI sesijas ↓ Galvenie notikumi
Katram posmam jārāda tā atribūcijas pārliecība.
Pārlūka veselība
Tabula pēc robota:
text bot_name requests successful_requests error_rate unique_ip_count top_paths
Brīdināt, ja:
- kļūdu līmenis pārsniedz 2 procentus
- bots pēkšņi pazūd
- iepriekš pieejama satura sadaļa atgriež 403 vai 429
- pārlūka pieprasījumi koncentrējas uz neparedzētu privātu ceļu
Satura iespēju tabula
Rindojiet lapas un tēmas pēc:
text augsta atsauču daļa + zema novirzīšanas likme augsti seansi + zems atsauču aptvērums augsta iesaiste + zema atsauču redzamība augsts pārlūka kļūdu skaits + augsta biznesa nozīme
Šīs kombinācijas parasti nodrošina labākus lēmumus nekā tikai datplūsmas apjoma aplūkošana.
Minimāls Streamlit panelis
Saglabāt kā 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="MI Atsauču Ietekme", 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("MI Atsauču Ietekmes Panelis")
if panels.empty: st.warning("Nav atrasti paneļu novērojumi.") 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("Atsauču daļa pēc tēmas") st.dataframe(citation_share, use_container_width=True) st.bar_chart( citation_share.set_index("topic")["citation_share"] )
with col2: st.subheader("Atsauču aptvērums pēc tēmas") st.dataframe(coverage, use_container_width=True) st.bar_chart( coverage.set_index("topic")["citation_coverage"] )
st.subheader("Atsauces pozīcija") 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("Ikdienas novērojumi") 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) )
Palaidiet to ar:
bash pip install streamlit pandas streamlit run dashboard.py
Ražošanā ielādējiet normalizētās tabulas DuckDB, BigQuery, Snowflake vai PostgreSQL, nevis lasiet neapstrādātus failus tieši.
10. Kvalitātes kontrole
Mērījumu sistēma var radīt precīzus, bet maldinošus skaitļus. Pievienojiet šīs kontroles.
Atdalīt robotus no cilvēkiem
Nekad neskaitiet OAI-SearchBot, GPTBot, ClaudeBot vai PerplexityBot kā cilvēku sesijas. Tie ir pārlūka vai izguves signāli.
Saglabāt neapstrādātus pierādījumus
Katram paneļa palaidienam saglabājiet:
- neapstrādātu HTML
- ekrānuzņēmumu
- atbildes tekstu
- laika zīmogu
- pārlūkprogrammas un vācēja versiju
- pamudinājumu un lokalizāciju
- atbildes jaucējkodu
Tas ļauj izskaidrot, kāpēc metrika mainījās.
Izsekot paneļa neesamību
Trūkstošs MI panelis nav tas pats, kas atbilde bez jūsu atsauces.
Izmantojiet:
text panel_not_present panel_present_no_target panel_present_target_cited blocked_or_challenged collection_error
Kontrolēt izlases novirzes
Plānotu ielasīšanu ietekmē:
- atrašanās vieta
- ierīce
- valoda
- laiks
- personalizācija
- pārlūkprogrammas stāvoklis
- pamudinājuma formulējums
Izmantojiet fiksētu pamata pamudinājumu kopu un rotējošu izpētes pamudinājumu kopu. Abas grupas atskaitēs saglabājiet atsevišķi.
Izvairīties no viltus precizitātes
Ziņojiet par ticamības intervāliem vai minimālajiem izlases lielumiem mazām tēmu grupām. Tēma ar trim novērojumiem nevajadzētu tieši salīdzināt ar tēmu, kas satur 300 novērojumus.
Salīdzināt līdzīgo ar līdzīgo
Salīdzinot virsmas, saglabājiet nemainīgus:
- pamudinājums
- lokalizācija
- valsts
- ierīce
- vākšanas stunda
- mērķa domēna noteikumi
- atsauču parsētāja versija
11. Ieteicamais ieviešanas plāns
1. nedēļa: Instrumentēšana
- Konfigurēt strukturētus servera žurnālus.
- Izveidot robotu reģistru.
- Izveidot saišu saīsinātāja domēnu.
- Pievienot kampaņas nosaukšanas noteikumus.
- Definēt tēmu taksonomiju.
- Iespējot Google Analytics 4 BigQuery eksportu.
2. nedēļa: Kontrolētās saites
- Publicēt piecus līdz desmit izsekotus kopsavilkumus.
- Izveidot saites dažādām tēmām un satura versijām.
- Validēt pāradresācijas žurnālus pret analītikas sesijām.
- Apstiprināt, ka personiskā informācija netiek ievietota URL vai analītikas parametros.
3. nedēļa: Paneļu novērojumi
- Izveidot pamudinājumu manifestu.
- Sākt ar divām virsmām un 20 līdz 50 stabilām pamudinājumiem.
- Palaist vienreiz dienā.
- Saglabāt ekrānuzņēmumus un HTML.
- Mērīt vākšanas kļūmes atsevišķi no atsauču neesamības.
4. nedēļa: Panelis un pārvaldība
- Izveidot tēmu un virsmu paneļus.
- Pievienot pārlūka veselības brīdinājumus.
- Definēt pārliecības noteikumus.
- Salīdzināt pirmo pušu pārskatus ar paneļu novērojumiem.
- Dokumentēt datu saglabāšanas, piekļuves un dzēšanas politikas.
Secinājums
MI atsauču mērīšana jāveido kā daudzsignālu atribūcijas sistēma, nevis kā vienots novirzīšanas pārskats.
Visuzticamākā sistēma apvieno:
- Google un Bing pirmo pušu redzamības pārskati
- serveru žurnāli pārlūka un izguvēja aktivitātēm
- pirmo pušu īsās saites kontrolētai klikšķu mērīšanai
- plānoti, atbilstoši atbildes paneļu novērojumi
- analītikas un konversiju dati par turpmāko vērtību
Trīs vissvarīgākās metrikas ir:
- Atsauču daļa pēc tēmas — cik liela daļa no novērotā avotu laukuma pieder jūsu domēnam.
- Asistenta novirzīšanas likme — cik liela cilvēku datplūsmas daļa var tikt attiecināta uz MI virsmām.
- Iesaiste pēc citēšanas — vai MI novirzītie apmeklētāji veic jēgpilnas darbības.
Sistēma kļūst noderīga, ja katrs skaitlis ietver tā virsmu, laika periodu, saucēju, atribūcijas metodi un pārliecības līmeni. Šāda disciplīna novērš to, ka pārlūka apmeklējumi tiek sajaukti ar lietotājiem, ielasītās atbildes — ar seansiem, un atsauces — ar biznesa rezultātiem.
Auto