灵瞳GEO:一个 AI 搜索引用追踪系统的设计与实现

灵瞳GEO:一个 AI 搜索引用追踪系统的设计与实现

灵瞳GEO:一个 AI 搜索引用追踪系统的设计与实现

这是什么

AI 搜索正在吃掉一部分传统搜索的份额,但企业几乎没有办法回答一个基础问题:当用户问豆包"上海电商财务外包哪家好"时,AI 的回答里到底引用了谁?

灵瞳GEO 是我为解决这个问题做的引用追踪系统。它定时向豆包、元宝、通义千问、Kimi、DeepSeek 五个平台发起真实提问,解析每次回答背后的引用来源,按「话题 × 平台 × 日期」聚合出引用次数、引用源域名分布,以及自有站点的引用占比。

技术栈是 FastAPI + LangGraph + React + MySQL。采集层不是单一方案——三个平台走官方 API 的结构化 citation 字段,两个平台走 RPA,选型依据是哪种方式能拿到最接近用户真实所见的引用,而不是哪种技术更"干净"。这个取舍是整个系统里我认为最值得写的部分。

系统已上线运行 3 天,覆盖 14 个监控话题,累计 309 次采样。

灵瞳 GEO 总览看板:提及率 13.5% / 首位率 5.7% / 平均排名 9.2 / SOV 3.3% / 品牌健康度 38,雷达图覆盖 5 大国产 AI 平台对比

一、为什么要做这个

1.1 GEO 和 SEO 不是一回事

传统 SEO 的目标是排名:让页面在搜索结果列表里靠前。GEO(Generative Engine Optimization,生成引擎优化)的目标是被引用:让内容成为 AI 生成回答时所依据的信息源。

两者的底层机制完全不同。SEO 依赖搜索引擎的索引库和排序算法,页面必须先被收录、进入索引,才谈得上排名。而 AI 回答走的是 RAG 式的检索增强——模型在回答时实时检索一批候选内容,选取其中若干条作为依据,并在回答中标注引用。

这个差异带来一个反直觉的现象:页面没被收录,也可能被 AI 引用。我在做公司官网的 GEO 时实测到过——头条站长平台显示官网索引量为 0,但豆包回答相关问题时已经能引用官网内容。原因是豆包的检索是多源的,包含实时抓取,和头条搜索的主索引库不是同一套东西。

这也意味着,传统 SEO 的那套监控指标(收录量、关键词排名)在 GEO 场景下基本失效。你需要监控的是另一组东西:引用次数、引用源分布、品牌提及率。

1.2 效果完全黑盒

公司在做 GEO,整套站内技术栈是我搭的:SSR、Schema 结构化标记、llms.txt、sitemap、robots 配置、向百度和字节的主动 URL 推送。站外也在铺内容。

但做完之后有个绕不过去的问题:怎么证明有效?

手工验证的方式是打开豆包、元宝挨个搜关键词,看回答里有没有自己。这个方法的问题很明显:

  • 不可持续:五个平台 × 二十个话题 = 每天一百次手工搜索
  • 不可比较:今天搜到了、明天没搜到,是波动还是下滑?没有基线就没法判断
  • 不可归因:知道"被引用了",但不知道引用的是官网哪篇文章,还是第三方平台上的转载

没有量化,GEO 就退化成玄学——做了一堆动作,但说不清哪个动作有效。

1.3 商业工具为什么没直接买

市面上做 AI 可见性监测的商业产品不少,国内外都有。没选它们的原因有三个:

。这类工具基本按监控话题数和平台数阶梯定价,一个中小企业要覆盖五个平台、二十个话题,年费不是小数目。

黑盒。它们给出的"引用率""可见度分数"往往是自定义的复合指标,不公开算法。我需要的是原始数据——具体哪次提问、哪个平台、引用了哪个 URL——而不是一个我无法复核的分数。

同质化严重。国内这个赛道有个公开的现象:相当一部分工具是同一批源码的贴牌产品,换个前端皮肤重新包装。

更关键的是,这件事的技术复杂度在我的能力范围内,而自建能拿到完整的原始数据。


二、核心问题:什么才算"一次引用"

这是设计阶段最先要想清楚的事,也是后面所有技术选型的依据。

2.1 检索到 ≠ 引用了

AI 回答一个问题时,通常会检索出十几到几十条候选内容,但最终生成的回答里只会依据其中少数几条。这两者必须分开:

  • retrieved_sources:模型检索到的候选池
  • cited_sources:模型在最终回答中实际依据/标注的来源

对 GEO 来说,后者才是真正有价值的。被检索到但没被引用,说明内容进入了候选池却没能说服模型——这是一类问题;根本没进候选池,则是另一类问题。混在一起统计会掩盖掉真实的优化方向。

2.2 API 拿到的引用 ≠ 用户看到的引用

这一条是整个系统里最关键的认知,也是我做出 RPA 选型的直接原因。

各家大模型的开放平台 API 和它们自己的 C 端产品,搜索后端往往不是同一套

最典型的是腾讯元宝。元宝在 C 端的引用来源高度依赖微信生态——微信公众号内容占其引用源的绝大部分,腾讯新闻占一小部分。而微信公众号是一个封闭生态,腾讯云对外开放的联网搜索 API 覆盖的是腾讯新闻、企鹅号、搜狗这些源,根本够不着占比最高的那部分公众号内容

结论很直接:如果我用混元 API 去采集"元宝的引用",拿到的数据结构是干净的、字段是结构化的,但它反映的不是用户在元宝 App 里真实看到的东西。数据越干净,结论越错。

Kimi 是同类问题的另一种形态:它的开放平台 API 和 kimi.com 网页版的 Agentic Search 是两套不同的检索实现,而且 API 侧拿不到结构化的引用字段。

2.3 引入保真度分级

所以我在数据模型里加了一个字段 citation_fidelity,取值 exactproxy:

  • exact:采集到的引用等同于用户真实所见
  • proxy:采集到的引用是近似值,来自与 C 端不同的检索后端

配套的还有 attribution_method 枚举,记录这条引用是怎么拿到的:

含义
native_api_annotation 平台 API 原生返回的结构化 citation 字段
ui_observed 从 C 端界面的引用卡片/角标解析
answer_url_parse 从回答正文中抽取 URL
model_selected_from_candidates 由自建候选池喂给模型后选出(仅实验用,不入正式统计)

有了这两个字段,同一张表里可以并存不同来源、不同可信度的数据,做统计时按保真度分层输出,而不是把它们混成一个数。

这个设计直接决定了下一章的采集架构。


三、采集架构:按保真度分层,不按技术偏好

3.1 分层结果

平台 采集方式 保真度
豆包 火山方舟 API exact
通义千问 DashScope API exact
DeepSeek DeepSeek 官方 API exact
元宝 RPA(C 端界面采集) exact
Kimi RPA(C 端界面采集) exact

前三个平台的官方 API 本身就返回结构化的引用来源,且搜索后端与其 C 端一致或足够接近,直接走 API 是成本最低、最稳定的选择。

后两个平台走 RPA,不是因为它们没有 API,而是因为它们的 API 拿到的是 proxy 数据。为了 exact 保真度,值得付出维护浏览器自动化的代价。

3.2 关于 RPA 的取舍

这个赛道的商业产品普遍全量依赖 RPA:养一批账号,用浏览器自动化模拟真人提问,解析界面上的引用卡片。这套方案的缺点是显性的——账号有封禁风险、频控严格导致采样量受限、界面改版就要重写解析逻辑、跑起来慢且资源占用高。

但它有一个 API 方案无法替代的优点:它采到的就是用户真正看到的东西

所以我的选型逻辑不是"API 优于 RPA",而是:

优先用 API;当 API 与 C 端的检索后端存在实质差异、会导致 proxy 数据时,降级到 RPA 换取 exact 保真度。

混合架构的代价是工程复杂度上升——两类采集器的错误处理、重试策略、并发模型、耗时量级完全不同,需要在编排层做隔离。


四、五个平台的具体实现

4.1 豆包

走火山方舟,直接拿结构化 references。豆包是这套系统里数据质量最好的一个源,原因有二:一是引用字段完全结构化;二是它恰好是国内 AI 搜索里对我们业务最重要的平台。

4.2 通义千问

走 DashScope,开启 enable_search + enable_source,响应中带回本次检索所用的来源列表。需要做二次归因区分 retrieved 和 cited。

4.3 DeepSeek

DeepSeek 官方 API 现在支持联网搜索,所以直接走 API 拿引用。

但比实现方式更重要的是一个产品设计上的判断:"DeepSeek"根本不应该作为一个单一的监控维度。

同样是 DeepSeek 模型,用户可能是在 DeepSeek 官网用、在火山方舟上调、在腾讯元宝里用、在百度的入口里用。这几个入口的联网搜索后端各不相同,同一个问题在不同入口得到的引用来源可能完全不重叠。把它们聚合成一个叫"DeepSeek"的数字,统计上是错的。

系统里我按托管平台把它拆成了独立维度,报表中分开展示。这是我认为整个产品设计里最不显眼但最重要的一个决定。

4.4 元宝

选 RPA 的理由前面讲过了:混元 API 的搜索源池覆盖不到元宝 C 端引用占比最高的微信公众号内容。

实现上的几个要点:持久化的浏览器上下文保存会话、引用卡片 DOM 解析、采集间隔随机化与单账号单日采样量上限、解析失败时保存页面快照。

顺带一提,采集过程中确认了一件对内容策略有直接指导意义的事:元宝的引用源高度集中在微信生态。这意味着针对元宝做 GEO,发公众号的性价比远高于优化官网。

4.5 Kimi

Kimi 是唯一一个我先走了 API、验证后退回 RPA 的平台。API 路线上试过两条都不通:$web_search builtin 拿不到 URL 列表,只能从模型回答里正则抽取;moonshot/web-search Formula 输出是加密密文连正文都解析不了。

即便解决了以上所有问题,还剩最后一个无解的问题:Kimi 开放平台 API 的搜索和 kimi.com 网页版的 Agentic Search 是两套东西,采到的数据只能算 proxy。

所以最终结论是 API 路线整体作废,改走 RPA 采集 C 端界面。验证一条路走不通,和验证一条路走得通,工程价值是一样的


五、数据模型与编排

5.1 表结构

核心是两张表:

answer_records —— 一次提问的完整记录

关键字段:run_id / topic_id / platform / questionanswer_textis_mentionedrank_positionsentiment_label、原始响应存档与哈希。

citations —— 引用记录,与 answer_records 一对多

关键字段:answer_record_idurl / domainsource_type(retrieved / cited)、attribution_methodcitation_fidelityrankis_own_domain

raw_response 全量存档这一条值得展开说。采集类系统最容易出的事故是解析逻辑有 bug 却发现得晚,导致一段时间的数据全废。存原始响应意味着解析逻辑修好后可以重放历史数据重新入库,而不是丢掉重采。

5.2 用 LangGraph 编排

采集流程是一个典型的多阶段有状态流程:

话题分发 → 平台采集(并行) → 引用解析 → 域名归一化 → 品牌归因 → 入库

用 LangGraph 而不是裸写 asyncio,主要考虑三点:

  1. 节点级重试与状态保持。RPA 采集单次耗时可能是 API 的几十倍,失败率也高得多。节点化之后,失败的只重跑该节点,已完成的阶段不用重来。
  2. 异构并发隔离。API 采集可以高并发,RPA 采集必须严格串行加限速。两类任务在同一个图里但用不同的并发策略。
  3. 可观测性。每个节点的输入输出可追溯,排查"某天某平台数据缺失"这类问题时能直接定位到卡在哪一步。

六、指标体系

原始数据落库之后,聚合出的指标分两组。

可见性组

  • 提及率 = 品牌被提及的回答数 / 总采样数
  • 首位率 = 品牌出现在回答首位的次数 / 被提及次数
  • 引用次数 = 自有域名被引用的总次数

引用源结构组

  • 引用源域名分布 = 按域名聚合的引用次数 Top N
  • 自有域名占比 = 自有站点引用次数 / 全部引用次数
  • 竞品共现率 = 回答中同时出现竞品的比例

其中自有域名占比是最能反映 GEO 真实水平的单一指标。品牌被提及可能只是因为模型的参数化知识里有你,而自有域名被引用,说明你的内容真正进入了 AI 的检索链路——这是 GEO 动作能直接影响的部分。


七、前端

React + Recharts,三块内容:

  • 总览页:提及率、首位率、自有占比的当期数值与环比,雷达图做平台维度对比
  • 引用源页:域名分布环形图,可下钻到具体 URL 和对应的原始回答
  • 话题页:单话题在各平台的表现明细

有一个刻意的设计:任何一个聚合数字都可以点进去看到支撑它的原始回答。做监控类产品,不可下钻的数字等于不可信的数字——这也是我不愿意用黑盒商业工具的原因,不能在自己的产品上犯同样的错。


八、3 天实测

系统上线运行 3 天,累计 309 次采样(各平台 53-64 次),覆盖 14 个监控话题

引用源 Top 域名(全部 5 个平台聚合):

域名 引用次数
sohu.com(含 business/m/news 子域) 376
mp.weixin.qq.com 146
cnblogs.com 135
zhuanlan.zhihu.com 100
xiaohongshu.com 90
163.com 74
baike.baidu.com 72
caigeek.com(自有) 34

几个值得说的观察:

1. 搜狐生态是绝对主力。 sohu.com 全家桶加起来 376 次引用,占我们统计的引用源的 13.7%。原因是搜狐自媒体号在做财经外包话题的内容铺量,跟我们业务重叠度高,且 SEO 基础好——AI 检索把这部分老内容都捞起来了。

2. 自有域名 caigeek.com 的引用完全来自 RPA 采集的两个平台(Kimi 26 次、元宝 5 次、豆包 3 次),DashScope 和 DeepSeek 这两个 API 平台的自有域引用是 0。这印证了第二章的判断——API 拿到的引用结构干净,但未必反映了 C 端的真实引用链路。自有站点被 AI 引用的样本,得从 RPA 那条路才采得到。

3. 微信生态在元宝里占比极高。mp.weixin.qq.com 一个域名就贡献了元宝引用源的相当一部分(具体平台分布暂未单独切分,下一步会单独出按平台的域名分布报表)。

必须说明的是:3 天的数据只能作为基线,不足以支撑任何趋势判断。 样本量在这个量级上,日间波动大概率来自采样噪声而非真实变化。这个系统的价值要在持续运行数月、积累足够长的时间序列之后才能真正兑现。之所以现在就写出来,是因为架构和数据模型已经稳定,而这两部分才是这个项目里真正的工程内容。


九、这套方案的边界

任何监控系统都有它测不到的东西,把边界写清楚比把结果吹大更重要。

1. 采样不等于全量。 系统采集的是"我提出的问题"得到的回答,不是真实用户提问的分布。监控话题库是人工设计的,再全也覆盖不了长尾。所以引用次数是相对指标,只能横向比较平台、纵向比较时间,不能解读成"我的品牌被引用了 N 次"这种绝对量。

2. API 侧数据是 proxy。 走 API 采集的平台,其检索后端与 C 端可能存在差异。系统用 citation_fidelity 标记了这一点,但标记不等于消除——统计时必须分层看。

3. RPA 侧受频控限制,样本量天然小。 元宝和 Kimi 的采样密度低于 API 平台,两类数据的置信区间不一样,直接放在同一张对比图里会产生误导。

4. 模型输出本身不稳定。 同一个问题问两次,回答和引用可能不同。要区分"真实变化"和"模型随机性",需要同一话题多次重复采样取分布,而不是单次采样。

5. 归因链条不完整。 系统能告诉你"哪个域名被引用了",但不能告诉你"为什么它被引用而我没有"。从监控走到诊断,还差一层内容维度的分析。



结语

做这个系统最大的收获不是技术上的,而是想明白了一件事:在 AI 搜索这个领域,数据的保真度比数据的整洁度重要得多。

一开始我的方案是全 API 的,理由很充分——结构化、稳定、可规模化、无封禁风险。但验证到元宝和 Kimi 的时候发现,拿到的干净数据描述的不是用户真实看到的世界。那一刻的选择是:要一份漂亮但不准的数据,还是要一份难采但真实的数据。

最后的架构是混合的,工程上更丑,但数据是对的。


本文所述系统 灵瞳GEO 目前持续运行中。作为一个小小的闭环:这篇文章发布后,我会用它自己来追踪这篇文章有没有被 AI 引用。