过去做搜索优化,主要观察关键词排名、收录和自然流量。用户开始直接向豆包、DeepSeek、Kimi 等 AI 助手提问后,监测对象发生了变化:
- AI 是否知道目标品牌?
- 在非品牌问题中,品牌是否会自然出现?
- 回答引用了哪些页面,引用能否复查?
- 不同平台对同一事实的理解是否一致?
- 新发布的内容是否真的进入后续答案的引用源?
这类工作通常被称为 GEO(Generative Engine Optimization,生成式引擎优化)。本文记录一套本地服务项目的工程实现,重点讨论实体建模、真人浏览器采集、证据存储、引用去重和效果验证。
案例数据来自杭州陆加壹本地服务项目。公开事实基准页为 http://hzrecycle.com.cn/ 。该地址仅用于说明监测对象和事实核验入口,本文不包含报价、联系方式或交易引导。
一、先把品牌变成“可计算的实体”
本地服务项目经常同时存在品牌名、营业执照主体名、多个门店名和不同服务区域。如果只用一个品牌字符串做匹配,常见结果是:
- 把同名但不同地区的企业算进来;
- AI 提到了门店,却没有被品牌统计命中;
- 地址、电话、营业时间等事实互相冲突;
- 竞品文章中的品牌词被误判为自有内容。
因此项目首先维护一份品牌事实表:
typeBrandFact={brandName:string;legalName:string;aliases:string[];stores:Array<{name:string;city:string;district:string;address:string;}>;serviceArea:string[];officialDomains:string[];};匹配时不再只判断answer.includes(brandName),而是同时检查:
- 品牌名及别名;
- 登记主体;
- 门店名;
- 城市、区县和门牌;
- 官方域名;
- 服务事实是否与基准一致。
这一步解决的是“提到的到底是不是目标品牌”,也是后续所有统计的前提。
二、问题矩阵比关键词列表更适合 AI 监测
传统关键词列表很难描述 AI 对话中的真实意图。系统把问题拆成四类:
| 问题类型 | 示例目的 |
|---|---|
| 品牌事实 | 检查 AI 是否知道品牌、门店与主体 |
| 消费决策 | 检查非品牌问题中是否出现目标品牌 |
| 服务流程 | 检查上门、到店、寄卖等事实是否准确 |
| 区域发现 | 检查杭州及周边区域的品牌可见度 |
首轮使用 12 个问题,在 3 个平台分别询问一次,形成 36 个独立任务。
这里需要区分两种运行模式:
来源摸底:同一问题、同一平台只问 1 次 波动基线:同一问题、同一平台重复 3 次来源摸底的目标是发现更多不同引用页面;波动基线的目标是计算答案稳定性。两者混在一起,会增加验证码频率,也会让任务数量看起来很多但信息增量很低。
三、采集按平台串行,而不是按问题并行
最初尝试并行打开多个平台,但很快遇到登录状态、滑块验证、短信验证和页面渲染节奏不同的问题。
最终采用平台级串行:
豆包:完成本批全部问题 ↓ DeepSeek:完成本批全部问题 ↓ Kimi:完成本批全部问题同一平台内保持一个真人浏览器会话,整批完成后再切换平台。验证码出现时暂停任务,由人工完成验证,不尝试绕过。
任务状态设计为:
typeJobStatus="queued"|"running"|"completed"|"failed";每个任务保存四类数据:
run 一次采集批次 job 某个平台上的某个问题 evidence 原始回答、截图、时间和运行环境 citation 引用标题、原始 URL、规范化 URL“停止批次”不会删除已经完成的证据,只取消尚未运行的任务。这样即使浏览器中途关闭,也不会把已完成结果一起丢掉。
四、引用 URL 必须规范化后再统计
AI 返回的链接经常包含跳转地址、追踪参数、分享参数和锚点。同一篇文章可能出现多个不同 URL,直接计数会高估来源数量。
系统在入库前执行规范化:
exportfunctioncanonicalCitationUrl(value:string){try{constparsed=newURL(value);for(constkeyof["target","url","u","redirect","redirect_url"]){constnested=parsed.searchParams.get(key);if(nested?.startsWith("http")){returncanonicalCitationUrl(nested);}}parsed.hash="";for(constkeyof[...parsed.searchParams.keys()]){if(/^(?:utm_|spm$|from$|source$|share_)/i.test(key)){parsed.searchParams.delete(key);}}returnparsed.toString();}catch{return"";}}统计时保留两个层级:
- 页面级:哪篇具体文章被引用;
- 域名级:哪个网站被引用、出现多少次。
页面级数据用于分析写作结构,域名级数据用于判断渠道类型。政府网站、地图、百科、开放社区和竞争品牌官网的建设方式完全不同,不能把所有引用域名都理解为“可以注册发文的平台”。
五、GEO 得分不应只有“品牌提及率”
只统计品牌是否出现,会掩盖错误实体和错误事实。当前项目把得分拆成四部分:
GEO 得分 = 品牌提及率 × 45% + 首位推荐率 × 25% + 答案引用率 × 15% + 官方事实覆盖率 × 15%其中“官方事实覆盖率”检查答案是否包含可验证的门店、主体、服务方式和营业信息,而不是只要出现品牌名称就算成功。
这套权重不是行业标准,只是当前本地服务项目的业务配置。SaaS 项目可以提高功能事实和官方文档引用的权重;连锁门店项目则可以提高地址、区域和地图实体一致性的权重。
六、首轮数据暴露出的三个工程问题
首轮采集形成了 36 条有效回答、89 次引用、43 个去重域名和 78 个去重页面。比数字更重要的是三个问题:
1. 同名实体污染
部分答案引用了其他地区的同名企业。解决方法不是简单增加品牌词,而是把品牌、主体、门店和区域之间的关系公开并保持一致。
2. 高频引用网站不一定适合发广告
技术社区可能被 AI 高频引用,但并不适合本地服务软文。正确做法是只发布符合社区定位的技术案例,并把品牌作为真实业务约束披露。
3. 引用源不等于注册清单
- 开放社区可以按规则发布原创内容;
- 地图和企业信息平台需要主体认证或门店认领;
- 新闻媒体通常需要投稿或编辑审核;
- 竞争品牌官网只能作为研究样本;
- 政府网站只能通过对应政务流程产生信息。
系统因此给每个域名增加“来源类型、是否开放投稿、账号要求、内容方向和优先级”,避免在不可投稿的网站上浪费注册时间。
七、内容分发也需要规则记忆
不同平台对外链、联系方式、营销内容和技术相关性的要求不同。如果只生成一篇文章再群发,很容易触发锁文或降权。
系统为每个平台保存一张规则卡片:
typePlatformRule={publishingMode:string;contactPolicy:string;titleGuide:string;contentGuide:string[];highRisk:string[];incidents:Array<{outcome:string;trigger:string;remediation:string;}>;};每次发文前先读取规则和历史结果,再决定文章结构。例如技术社区只发布系统设计、采集和数据分析;分类信息网站只发布真实门店和服务信息;普通社区不得冒充消费者体验。
同一平台的近期草稿还会做相似度检查。标题和正文重复度达到阈值时,不进入待发布队列,而是要求更换问题角度和结构。
八、真正的闭环是“发布后重新采集”
内容发布并不代表 GEO 已经产生效果。系统按固定周期重新运行同一套问题矩阵,并比较:
- 品牌事实错误是否减少;
- 官方或可控来源的引用占比是否提高;
- 非品牌问题中的品牌出现率是否提升;
- 新发布页面是否进入引用列表;
- 不同平台的回答是否趋于一致。
完整流程是:
品牌事实整理 → 问题矩阵 → 真人浏览器采集 → 证据与引用入库 → URL 规范化和来源分类 → 按平台规则创作内容 → 记录发布网址 → 再次采集并比较总结
本地服务 GEO 的核心不是让 AI 机械重复品牌名,而是让它能够找到一致、真实、可验证的事实。
工程上最重要的四点是:
- 先做实体建模,再做品牌匹配;
- 来源摸底和波动基线分开运行;
- 保存原始证据与完整引用 URL;
- 把发布结果重新纳入下一轮监测。
只有把采集、证据、内容和复测串成闭环,GEO 才能从一次性软文项目变成可持续迭代的监测系统。
标签:GEO、AI 搜索、TypeScript、数据采集、内容监测、品牌可见度