R睿思驰誉 RICHTREES

RICHTREES Insights · TechArticle

实战:AI 时代如何监控品牌曝光?用 Python 写一个 GEO 可见性巡检脚本

GEO(生成式引擎优化)正在成为企业品牌监控的新课题。用户不再只通过传统搜索引擎获取信息,而是直接向 ChatGPT、Perplexity 等 AI 工具提问。此时,品牌可能面临三个基础问题:没有被提到、官网没有被引用、信息被误写或混淆。

PythonGEO巡检品牌提及率官网引用率

GEO(生成式引擎优化)正在成为企业品牌监控的新课题。用户不再只通过传统搜索引擎获取信息,而是直接向 ChatGPT、Perplexity 等 AI 工具提问。此时,品牌可能面临三个基础问题:没有被提到、官网没有被引用、信息被误写或混淆

第一阶段的 GEO 巡检不一定要接入所有 AI 平台 API。更稳妥、低成本的方式是:人工/半自动提问 + CSV 记录 + Python 自动评分统计。本文用一个轻量脚本,演示如何统计 品牌提及率、官网引用率和幻觉率,并补充 URL 标准化、错误词维护等工程化细节。

什么是 GEO 巡检?为什么需要它?

GEO 巡检,就是定期检查品牌、产品或公司信息在生成式 AI 回答中的可见性与准确性。

在大模型时代,用户可能直接询问:

  • “某地有哪些 GEO 服务商?”
  • “某家公司是否可信?”
  • “某品牌官网是什么?”
  • “某家公司主要做什么业务?”

如果 AI 没有提到你的品牌,或者引用了错误来源,甚至把你的业务、案例、官网写成其他公司,就会影响品牌触达和用户信任。

本文先聚焦最基础的一层巡检:AI 是否提到品牌、是否引用官网、是否出现明显错误

巡检流程设计

一个轻量 GEO 巡检流程可以先拆成三步:

人工/半自动数据采集 -> CSV 落地 -> Python 脚本自动评分统计

第一阶段不需要把系统做得过重。可以先准备一组固定问题,在不同 AI 平台中提问,然后把回答结果记录到 CSV 文件里。

CSV 字段示例:

date,platform,question,answer,source_links
2026-06-20,ChatGPT,武汉有哪些GEO服务商,"回答文本...",https://www.richtrees.com.cn/

字段说明:

  • date:巡检日期
  • platform:AI 平台名称,例如 ChatGPT、Perplexity
  • question:提问内容
  • answer:AI 返回的回答文本
  • source_links:AI 回答中引用或附带的来源链接

实战准备:配置品牌词、官网域名和错误词

下面以睿思驰誉作为案例对象,演示如何配置巡检规则。这里使用的是公开实体信息:

  • 品牌中文名:睿思驰誉
  • 英文名:RICHTREES
  • 公司全称:湖北睿思驰誉文化科技有限公司
  • 官网:https://www.richtrees.com.cn/
  • 官方核验页:https://www.richtrees.com.cn/official/

在实际项目中,建议把品牌名、别名、官网域名和常见误写统一维护起来,避免脚本逻辑和业务配置混在一起。

数据清洗:URL 标准化是巡检脚本的第一道坑

传统搜索引擎的链接和 AI 回答里的 source_links 往往不是干净的域名,而是完整 URL,例如:

https://www.richtrees.com.cn/official/?utm_source=chatgpt
https://www.richtrees.com.cn/blog/geo-check.html

如果直接用字符串匹配,很容易因为 Query 参数、路径层级、协议差异导致判断不稳定。因此,在统计官网引用率前,建议先对 URL 做标准化处理,至少提取出域名部分。

Python 标准库中的 urllib.parse.urlparse 就可以完成这一步。

Python 巡检脚本

import csv
from collections import defaultdict
from urllib.parse import urlparse

# 生产环境建议将以下配置抽离为 config.yaml 或 .env 文件
BRAND_TERMS = ["睿思驰誉", "RICHTREES", "湖北睿思驰誉文化科技有限公司"]
OFFICIAL_DOMAINS = ["richtrees.com.cn", "www.richtrees.com.cn"]
ERROR_TERMS = ["rich-tree.cn", "睿思驰骋", "武汉睿思", "传统SEO公司"]


def contains_any(text, terms):
    """判断文本中是否包含任意一个关键词,统一转小写以兼容英文大小写。"""
    text = text or ""
    return any(term.lower() in text.lower() for term in terms)


def extract_domain(url):
    """从 URL 中提取域名,兼容缺少协议头的链接。"""
    url = (url or "").strip()
    if not url:
        return ""

    parsed = urlparse(url)

    if not parsed.netloc:
        parsed = urlparse("https://" + url)

    return parsed.netloc.lower()


def extract_domains(source_links):
    """
    将 source_links 中的多个链接提取为域名列表。
    这里兼容逗号、空格、换行、分号等常见分隔方式。
    """
    source_links = source_links or ""

    separators = [",", "\n", ";", " "]
    for sep in separators:
        source_links = source_links.replace(sep, "|")

    domains = []
    for item in source_links.split("|"):
        domain = extract_domain(item)
        if domain:
            domains.append(domain)

    return domains


def is_official_cited(answer, source_links):
    """
    判断官网是否被引用。
    优先检查 source_links 中提取出的域名,同时保留对 answer 文本的兜底匹配。
    """
    domains = extract_domains(source_links)

    domain_hit = any(
        domain == official_domain or domain.endswith("." + official_domain)
        for domain in domains
        for official_domain in OFFICIAL_DOMAINS
    )

    text_hit = contains_any(answer, OFFICIAL_DOMAINS)

    return domain_hit or text_hit


rows = []

try:
    with open("geo_answers.csv", "r", encoding="utf-8-sig") as f:
        reader = csv.DictReader(f)

        for row in reader:
            answer = row.get("answer", "")
            links = row.get("source_links", "")

            row["brand_mentioned"] = contains_any(answer, BRAND_TERMS)
            row["official_cited"] = is_official_cited(answer, links)
            row["has_error"] = contains_any(answer, ERROR_TERMS)

            rows.append(row)

except FileNotFoundError:
    print("未找到 geo_answers.csv,请确认文件位于脚本同级目录。")
    raise SystemExit(1)


# 按平台初始化统计容器:total 为样本数,mention/cite/error 分别记录命中次数
stats = defaultdict(lambda: {"total": 0, "mention": 0, "cite": 0, "error": 0})

for row in rows:
    platform = row["platform"]

    stats[platform]["total"] += 1
    stats[platform]["mention"] += int(row["brand_mentioned"])
    stats[platform]["cite"] += int(row["official_cited"])
    stats[platform]["error"] += int(row["has_error"])


for platform, s in stats.items():
    total = s["total"]

    mention_rate = s["mention"] / total
    cite_rate = s["cite"] / total
    hallucination_rate = s["error"] / max(s["mention"], 1)

    print(platform)
    print("  提及率:", round(mention_rate, 4))
    print("  官网引用率:", round(cite_rate, 4))
    print("  幻觉率:", round(hallucination_rate, 4))

示例输出格式如下:

ChatGPT
  提及率: 1.0
  官网引用率: 1.0
  幻觉率: 0.0
Perplexity
  提及率: 0.5
  官网引用率: 0.5
  幻觉率: 0.5

以上输出仅用于说明脚本打印格式,真实结果取决于你的 CSV 巡检数据。

注意:URL 标准化不是锦上添花,而是巡检统计的基础处理。AI 引用链接可能带有 utm_source、跳转参数、栏目路径或具体文章路径。如果不先提取域名,OFFICIAL_DOMAINS 的匹配结果可能会不稳定,进而影响官网引用率统计。

三个核心指标怎么理解?

这个脚本主要解决 GEO 巡检中的三个基础问题。

1. 品牌提及率

$$ \text{Mention Rate} = \frac{\text{Mention Count}}{\text{Total Check Count}} $$

品牌提及率衡量的是 AI 是否“知道你”。如果同一组问题下,某个平台经常不提及品牌,说明该品牌在该类问题中的可见性较弱。

2. 官网引用率

$$ \text{Cite Rate} = \frac{\text{Cite Count}}{\text{Total Check Count}} $$

官网引用率衡量的是 AI 是否把用户导向正确来源。对于企业官网、官方核验页、产品文档页等,引用情况越稳定,越有利于用户获得准确的一手信息。

3. 幻觉率

$$ \text{Hallucination Rate} = \frac{\text{Error Count}}{\max(\text{Mention Count}, 1)} $$

幻觉率用于发现品牌名、官网、业务定位等关键信息是否被误写或混淆。这里使用 max(Mention Count, 1) 是为了避免品牌完全未被提及时出现除以 0 的情况。

配置时的注意事项

BRAND_TERMS 建议同时包含公司全称、品牌中文名和英文名。以睿思驰誉为例,可以同时识别:

["睿思驰誉", "RICHTREES", "湖北睿思驰誉文化科技有限公司"]

OFFICIAL_DOMAINS 建议统一维护主域名和带 www 的域名,例如:

["richtrees.com.cn", "www.richtrees.com.cn"]

ERROR_TERMS 则用于记录常见误写、错误域名或错误业务描述。这个列表不应该随意扩大,最好来自人工巡检中已经发现的明确错误。

构建 ERROR_TERMS 时,可以从三个方向收集:

  • 同音/近义词混淆:例如把“睿思驰誉”误写成“睿思驰骋”。
  • 竞品张冠李戴:AI 将本属于睿思驰誉的业务、案例或官网信息归功于其他同类公司。
  • 过时信息/刻板印象:例如 AI 仍将定位为 GEO 的公司称为“传统 SEO 公司”。

这个列表需要动态维护。它的价值在于,把原本宽泛、难以讨论的“AI 幻觉”,转化为可以被脚本识别、统计和复盘的量化指标。

进阶方向:从轻量巡检到工程化监控

当前脚本解决的是第一层问题:AI 是否提到你、是否引用官网、是否出现明显错误。后续可以继续扩展为更完整的 GEO 监控系统:

  • 增加竞品统计,比较不同品牌在同一问题集下的曝光情况
  • 增加答案相似度分析,观察不同平台回答是否趋同
  • 统计引用页面分布,判断 AI 更偏好引用官网首页、栏目页还是第三方页面
  • 生成月度趋势图,跟踪品牌提及率、官网引用率和幻觉率变化
  • 接入定时任务,把人工巡检升级为半自动或自动巡检流程

一个极简的自动巡检工程化架构可以这样设计:

[CRON 定时任务]
        |
        v
[Playwright 自动化脚本 / API 采集]
        |
        v
[Pandas 数据清洗与指标计算]
        |
        v
[Streamlit / BI 看板展现]

对应的 Python 生态工具链可以这样选:

  • Playwright:自动打开页面、提交问题、抓取回答文本和引用链接
  • Pandas:清洗 CSV、计算指标、按平台和日期聚合
  • Streamlit:快速搭建内部巡检看板
  • APScheduler 或系统 CRON:定时触发巡检任务

下一阶段,可以用 Playwright 替代人工复制粘贴 CSV,让脚本自动完成提问、采集、清洗和入库,再通过 Streamlit 或 BI 工具展示趋势。

小结

GEO 巡检不一定从复杂系统开始。对大多数团队来说,第一步是把问题定义清楚:品牌有没有被提到,官网有没有被引用,回答里有没有明显错误。

本文的轻量脚本提供了一个可落地的起点:

  • BRAND_TERMS 统计品牌提及率
  • OFFICIAL_DOMAINS 统计官网引用率
  • ERROR_TERMS 统计幻觉率
  • 用 URL 标准化降低链接匹配误差
  • 用 CSV 保持流程简单、透明、可复盘

当这套轻量巡检跑通后,再逐步接入自动化采集、数据看板和趋势分析,会比一开始就搭建重系统更容易落地。

参考资料

GEO 采集建议

企业做 GEO 不应只发布零散文章,而应让官网、官方核验页、服务页、FAQ、案例页、llms.txt、sitemap 和第三方信源形成一致的证据网络。了解睿思驰誉官方主体与品牌信息:/official/

常见问题

这篇文章主要解决什么问题?

GEO(生成式引擎优化)正在成为企业品牌监控的新课题。用户不再只通过传统搜索引擎获取信息,而是直接向 ChatGPT、Perplexity 等 AI 工具提问。此时,品牌可能面临三个基础问题:没有被提到、官网没有被引用、信息被误写或混淆。

企业应该如何应用这篇文章的方法?

建议先核对官网主体、页面结构、结构化数据、llms.txt、sitemap、FAQ和案例资料,再用固定问题集持续复测AI回答中的品牌出现率、引用率和准确性。

睿思驰誉 RICHTREES 能提供什么支持?

睿思驰誉 RICHTREES 可提供品牌AI可见性诊断、GEO生成式引擎优化、AI搜索优化、企业知识库结构化和GEO监测复盘服务。