1. 先聊聊这个需求到底是怎么来的
做AI产品的品牌运营或者投放同学,这两年应该都碰到过一个特别挠头的问题:我花了大价钱投广告、做内容种草,结果用户转头去AI助手(比如豆包、DeepSeek这类对话式APP)里问“哪个牌子的XX好用”,AI给出的回答里居然没有提我的品牌,甚至推荐了竞品。这种“品牌在AI渠道里的存在感”正在变成新的兵家必争之地。
其实这个需求本质上是传统舆情监控在AI时代的延伸。以前我们监控的是搜索引擎里品牌词的收录率、排名位次,现在用户的信息获取入口从搜索框变成了对话窗口,那么“AI对品牌词的采纳率”就成了一个绕不开的新指标。所谓采纳率,通俗点说就是:在固定的提问模板下,AI回答中是否出现我们的品牌名,出现的次数和位置是怎样的。
我最初接到这个需求时,团队内部还叫它“AI种草率”。后来做了一版自动化脚本,每天晚上定时跑一批问题,把豆包、DeepSeek、文心一言、Kimi这些主流APP的回答全部拉下来,解析出品牌名出现情况,再汇总成趋势图表。整个过程跑通之后,运营同学每天早晨看一眼看板就能了解前一晚各AI渠道的“品牌提及表现”。
这篇文章就围绕这套“AI品牌采纳率自动化监控与可视化方案”展开,分享从零搭建时的核心设计、踩坑记录以及一些可复用的实操细节。无论你是做品牌运营、用户研究,还是对AI应用自动化有兴趣的开发者,这套思路都可以平移到自己的场景里。
我先把整体技术路线摆出来:问题模板管理、调度执行、多APP提问采集、结构化解析、数据入库、可视化看板。用到的技术栈以Python为主,调度用系统的定时任务,存储用SQLite轻量级起步,看板选择开源方案。
2. 整体方案设计:为什么选这个技术路线,而不是其他
这套方案可以理解为“把人工在AI里反复提问并肉眼记录结果”这件事自动化。核心一旦理顺,会发现它不是一个单点功能,而是一条数据流水线。
2.1 为什么优先考虑“模板驱动”而非“自然语言随机提问”
品牌词的采纳率统计,最怕的就是变量太多。如果你每次提问都随机组织语言,AI给你的回答差异会非常大,我们很难判断这个差异是“品牌真实知名度变化”导致的,还是“提问方式随机性”导致的。
所以我采用的是“固定模板+少量模糊替换”。比如:
模板A:预算2000元左右,适合通勤的降噪耳机,推荐几款? 模板B:平时健身用,想要轻便一点的蓝牙耳机,有哪些值得买? 模板C:学生党,主要听英语和流行音乐,200元内买什么耳机好?
每条模板对应一类真实用户场景,品牌词在模板里故意不出现,完全让AI自己联想。然后在解析阶段检查品牌名是否被AI提及,以及排在什么位置。这样跑出来的数据具备对比性——同一个模板在不同日期下问同一个APP,品牌提及率的变化就有意义了。
2.2 为什么用Python而不是Node.js或其他语言
做这种数据采集和解析的活儿,Python确实最顺手。请求库用requests、playwright或者selenium看情况选,解析用json或者正则,数据处理用pandas,存储用sqlite3,看板用pyecharts或者Grafana都行。生态齐全,社区里案例多,遇到问题搜索一下大多能找到现成答案。
不过这里有个容易忽略的点:AI APP的接口形态差异极大,有的有网页版,有的只能通过客户端访问,有的提供了内部接口但随时可能改。如果用纯requests模拟,多数情况下撑不了多久就会被风控。我的建议是优先选playwright这类浏览器自动化工具,模拟真实用户操作,稳定性和适应性都更好。
2.3 为什么存储和数据展示分离
早期我的方案是采集完直接把结果拼到一张Excel里,用数据透视表做统计,简单是简单,但问题很多:并发写入冲突、历史数据膨胀后打开缓慢、无法做权限控制。后来我把数据落到SQLite里,采集脚本只负责写入数据,看板服务只负责读取数据,两者解耦。好处很明显:哪怕是采集脚本跑到一半挂了,已落库的数据依然安全,看板也完全不受影响。
如果你团队已经有MySQL或者PostgreSQL,直接替换连接配置即可,表结构几乎不用改。SQLite作为个人单机项目起步,足够了。
2.4 整体结构图景
整套系统分为四层:
数据源层:豆包、DeepSeek、Kimi、文心一言、通义千问等对话入口 采集调度层:定时触发、模拟浏览器提问、等待并获取回答内容 解析清洗层:提取回答全文、判断品牌词出现情况、抽取上下文片段、归类模板场景 统计展示层:趋势折线图、品牌提及率排行榜、竞品对比表、原始回答备查
每一层职责单一,替换起来也方便。比如某天某个APP的页面结构变了,只需要改对应那一个采集适配器,其他层完全不用动。
3. 核心细节拆解:品牌采纳率的定义和判断逻辑,比想象中复杂
3.1 “采纳率”的几种口径
在开始写代码之前,建议团队内部先统一口径。标题里说的“采纳率”,实际落地时至少要拆成几个不同意义的指标:
硬提及率:AI回答的正文里,是否出现了品牌名。这个最简单粗暴,只要字符匹配成功就算1次。
推荐位排名:品牌名如果出现,是第几个被提到的。对话式AI的回答往往是一个列表式结构,品牌出现的顺序直接体现了优先级。排名越靠前,对用户的引导作用越强。
上下文情感方向:光出现还不够,还得看是怎么出现的。比如“XX品牌虽然销量高,但音质一般”和“XX品牌是综合体验最好的选择”,这两个虽然都算“采纳”,但实际价值完全不同。这个我们暂时没有做情感分析,而是人工抽样标注,因为对话式AI的情感表达太灵活,用情绪词典很难覆盖准确。
场景覆盖率:你的品牌在哪些场景模板下会稳定出现,哪些场景下完全沉寂。假设你做了10个场景模板,品牌只在2个场景中出现,说明品牌认知还很窄,需要针对性地补内容。
我建议你们至少先按“硬提及率”和“场景覆盖率”跑通,这两个指标实现简单又能反映问题。排名和情感方向可以作为迭代升级项。
3.2 品牌词匹配过程中的坑
做品牌词匹配时,有个细节很容易踩雷:品牌名变形。比如某品牌叫“声阔”,AI回答里写成“Soundcore”,如果你只匹配中文名就会漏算;反过来,有些品牌中文名有歧义,比如“石头”这种词,AI可能在说“石头路面”时也出现了这个词,但这根本不是品牌场景。
我的处理方式是分两层:
第一层精确匹配:把品牌全称、常用简称、英文名、官方旗舰店常用后缀这些写进品牌词表,任何一个命中即算提及。
第二层过滤词表:把一些明显不是品牌含义的同形词放进去,命中的话再结合上下文二次判断。这一步比较耗时,但能显著提升数据质量。比如“石头”的过滤词表里就包含“石头路”“石头剪刀布”这些词。
提示:品牌词表一定要让运营同学参与维护。我们第一版是我自己拍脑袋写的词表,漏掉了“K60”这种产品代号,漏了一周才发现,后来改成运营每季度更新一次品牌词表,情况好很多。
3.3 回答结果的多样性问题
同一批模板,同一天问同一个AI,不同账号、不同会话,回答都可能不一样。这意味着单次采集得到的品牌提及情况带有随机性,如果只跑一次就当成“真相”,很容易被误导。
为了解决这个问题,我做了两个调整:
重复实验:每个模板在每次采集时跑3轮(3个不同会话),提及情况取多数投票或者取出现次数均值。这样虽然成本增加,但数据稳定性高很多。
轮询随机种子:控制浏览器会话的Cookie、随机延迟、输入间隔,尽可能模拟不同用户,降低AI针对相同问题给出重复答案的“路径依赖”。
3.4 回答等待和超时处理
AI生成回答是需要时间的,有的快有的慢,而且同一个APP在高峰期和低峰期的生成速度差异很大。不能像请求普通接口那样设置固定超时,否则很容易误判失败。
我用的是“轮询检测+总超时上限”的思路。页面里出现“停止回答”按钮或者回答区域的文本长度不再变化时,判定为生成完成。总超时上限设置为90秒,超过后如果还没结束,就抓取当前已生成内容作为结果,并打一个“截断”的标记。后续统计时可以对截断数据单独分析,避免污染正常数据。
4. 实操过程:从环境准备到代码实现的完整流程
这部分我按实际搭建顺序来写,你照着走一遍基本能跑通自己的版本。我用的是Python 3.10、playwright、SQLite、pyecharts,操作系统的定时任务做调度。
4.1 环境准备和依赖安装
建议先建一个干净的Python虚拟环境,避免依赖冲突:
python -m venv venv source venv/bin/activate # Windows下是 venv\Scripts\activate pip install playwright pandas sqlite3 pyecharts playwright install chromiumplaywright是这套方案里最关键的依赖。它会自动下载Chromium内核,用来模拟用户访问AI APP的对话页面。对比selenium,playwright的API更现代,自带自动等待和网络拦截能力,对页面结构的解析也更方便。
4.2 问题模板配置文件
我采用YAML格式管理模板和品牌词表,方便不懂代码的运营同学直接修改。模板文件示例:
brands: - name: "声阔" aliases: ["Soundcore", "声阔Soundcore"] - name: "漫步者" aliases: ["Edifier", "漫步者耳机"] scenes: - id: "headset_commute" template: "预算2000元左右,适合通勤的降噪耳机,推荐几款?" category: "耳机" - id: "headset_fitness" template: "平时健身用,想要轻便一点的蓝牙耳机,有哪些值得买?" category: "耳机" - id: "headset_student" template: "学生党,主要听英语和流行音乐,200元内买什么耳机好?" category: "耳机"这个文件的维护频率取决于业务节奏。如果品牌出了新品或者有新品牌进入视野,运营同学更新这个文件就行,代码完全不用动。
4.3 核心采集模块写法
核心采集函数只需要做三件事:打开对话页面、输入问题、抓取完整回答。以playwright为例,伪代码如下:
async def fetch_answer(driver, question, wait_selector): # 定位输入框并输入问题 input_box = await driver.query_selector("textarea") await input_box.fill(question) await input_box.press("Enter") # 循环检测回答是否生成完毕 for _ in range(30): await asyncio.sleep(3) stop_btn = await driver.query_selector("text=停止回答") if not stop_btn: break # 抓取回答区域文本 answer_area = await driver.query_selector(wait_selector) full_text = await answer_area.inner_text() return full_text这只是最简版。实际操作中每个APP的页面结构都不一样,textArea选择器、回答区域选择器、停止按钮的文本都不一样,需要针对每个APP单独适配。我的做法是为每个APP建一个适配器目录,单独维护选择器和交互逻辑。新增一个APP的适配工作量大约半天到一天。
4.4 解析品牌词命中情况的实现
采集到回答全文后,进入解析环节。这里我维护一个核心解析函数:
def analyze_text(text, brands, scene_id): result = {"scene_id": scene_id, "hits": {}} for brand in brands: found_positions = [] for alias in brand["aliases"]: start = 0 while True: idx = text.find(alias, start) if idx == -1: break found_positions.append(idx) start = idx + len(alias) result["hits"][brand["name"]] = { "mentioned": len(found_positions) > 0, "count": len(found_positions), "first_position": min(found_positions) if found_positions else -1, } return result如果品牌名命中,我还要把命中位置前后的50个字符单独截取出来存到数据库里。这样运营同学在看板里点开原始命中记录时,能直接看到上下文,不需要再翻原始回答。
4.5 数据入库表结构设计
SQLite的表结构如下:
CREATE TABLE IF NOT EXISTS collect_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, collect_date TEXT, channel TEXT, scene_id TEXT, question TEXT, answer_text TEXT, truncated INTEGER DEFAULT 0, created_at TEXT ); CREATE TABLE IF NOT EXISTS brand_hit ( id INTEGER PRIMARY KEY AUTOINCREMENT, collect_log_id INTEGER, brand_name TEXT, mentioned INTEGER, mention_count INTEGER, first_position INTEGER, context_preview TEXT, FOREIGN KEY(collect_log_id) REFERENCES collect_log(id) );两个表分开的原因很简单:collect_log存的是原始回答,brand_hit存的是解析结果。这样如果品牌词表后续更新了,我们可以回刷历史数据,而不影响原始采集结果。回刷时只需要重新跑一遍analyze_text函数,插入新的brand_hit记录即可。
4.6 调度策略:跑太多会风控,跑太少没意义
调度频率是这套系统里最考验经验的地方。我踩过的频率从“每10分钟一次”降到“每天一次”,最终稳定在“每4小时一次”,具体取决于你监控的APP类型和问题模板数量。
风控问题是第一道坎。有的AI APP登录后有频率限制,短时间高频提问会直接触发验证码甚至封号。我的建议是:新方案上线的前三天,不要全量跑,先用10%的模板试跑,观察每个渠道的请求响应情况,确认没有异常再逐步放开。
账号隔离是第二道坎。如果模板量大,不要所有请求都走同一个账号。可以把品牌词库按类目拆成多组,每组绑一个账号,正常采集时间错开。实话说,这种操作对大多数业务方来说还比较遥远,起步阶段只需要注意“不要过度采集”就够了。
提示:如果你只是验证方案,完全可以用AI APP的网页版不登录状态来提问,部分渠道允许匿名使用,这样账号风险几乎为零,只是回答质量和个性化程度会略低。
4.7 可视化看板的搭建
到了展示环节,我用的是pyecharts生成HTML看板,好处是部署简单,生成的文件直接用浏览器打开就能看,不需要额外搭服务。如果你团队有Grafana,也可以直接把SQLite数据接进去。
看板上我固定放了四个视图:
整体采纳率趋势图:横轴日期,纵轴品牌提及率(在所有场景模板中的命中比例),每条线代表一个AI渠道。
场景覆盖率热力图:横轴是场景模板分类,纵轴是品牌名,颜色深浅代表该品牌在这个场景下被提及的频率。
竞品对比柱状图:选一个核心场景,把我们的主推品牌和2-3个竞品的提及次数做成柱状对比,运营周会直接截图用。
原始回答备查表:点击任意一天的数据,展示当日所有采集到的AI回答全文。这个视图平时用不到,但在复盘异常数据时很重要。
5. 常见问题和排查技巧实录
5.1 采集脚本运行到一半无响应
这是最常遇到的问题,可能原因有三个:AI页面加载了新的验证码、网络波动导致浏览器卡死、或者回答生成时间超过预期。
我的排查路线是:先看日志里最后一条记录卡在哪个阶段,再看页面截图。playwright支持随时截图,我在每一步关键操作后都会截一张图保存到本地文件夹。一旦脚本卡住,翻截图能快速定位问题,比什么日志都直观。
5.2 某知名品牌AI的页面元素经常变化
有些AI APP页面迭代很频繁,选择器隔几天就失效一次。我的应对方法是:把选择器配置外置,定期用一个小脚本检查当前页面能否命中所有关键选择器,如果发现失效,自动发送告警,而不是让采集脚本默默失败。
CHECK_LIST = [ ("input_box", "textarea"), ("submit_btn", "button[type=submit]"), ("answer_area", "[class*=answer]"), ]这个检查脚本每天定时跑一次,发现所有选择器都能命中时才会触发当日采集任务。相当于给采集脚本加了一个前置的“自检闸门”。
5.3 同一问题不同渠道的回答差异巨大
不同AI的中文理解能力、知识库更新频率、回答风格差异非常大。有些渠道特别爱列清单,有些则喜欢用自然段描述。这意味着同样的解析逻辑在不同渠道上表现不稳定。
我的处理方式是按渠道维护独立的解析规则,尤其是列表拆分逻辑。比如实测下来有些AI的回答里用序号分隔品牌,有些用分号,有些用换行。解析前先按渠道特征做文本清洗,再做品牌匹配,准确率会高很多。
5.4 数据量累积后查询变慢
SQLite在几十万条数据时性能还好,但一旦突破百万条量级,看板聚合查询会明显变慢。提前做两个优化:一是给collect_log表按日期字段建索引,二是给brand_hit表按collect_log_id和brand_name建联合索引。如果数据量继续膨胀,建议直接换MySQL或PostgreSQL,并加一层Redis缓存聚合结果,可以大幅降低查询压力。
5.5 高频采集导致IP被限
这个问题在量化评估时特别麻烦。限制IP不是IP被真的封死,而是热门AI服务会对同一IP的短时请求量做限制,轻则延迟增加,重则验证码。建议采集频率不要低于5分钟一次,单次任务控制在200个请求以内,任务间隔随机浮动而不是固定时间触发,这样能有效降低被限的概率。
6. 数据可信度评估和扩展方向
6.1 这个数据能说明什么,不能说明什么
把看板搭好之后,要控制一个预期:AI品牌采纳率能反映“AI模型对品牌的认知倾向”,但不能直接等同于真实用户购买行为。AI的回答只是信息整合的结果,不代表用户一定会采纳。所以这套数据最好是作为“品牌健康度”的辅助指标,和搜索引擎收录率、社交媒体讨论声量等传统指标放在一起看。
另外,AI的知识库更新存在滞后性。某个新品牌即使在线下已经卖爆了,如果AI训练数据和知识库没有覆盖到,它的回答说不出这个品牌也正常。所以当你发现某个品牌的采纳率连续一段时间为零,不要急着下结论“品牌无认知”,先排查一下这个品牌的公开信息是否足够丰富、容易被AI抓取。
6.2 后续可以考虑的三个扩展方向
方向一是情感倾向分析。也就是把“被提及”升级成“被推荐”“被提及但负面”“被提及但中立”的多分类标签。技术上可以用大模型做二次判断,把AI回答原文送到另一个大模型里打个标签,准确率比规则匹配高得多。
方向二是竞品动态追踪。模板不变,但品牌词表里加入竞品,这样每周可以出一份“竞品AI存在度周报”,用来反推竞品最近是否做了密集的内容铺设或公关动作。
方向三是跨语言监控。如果业务出海,可以增加英文提问模板,监控海外AI产品对品牌词的表现。解析逻辑基本不变,只要把品牌词表加入英文名,大部分代码可以复用。
6.3 月度复盘的小建议
我坚持每个月底出一份简短的“AI品牌采纳率月报”,总结趋势变化、渠道差异、异常波动。格式很简单:三张趋势图加两段文字说明。这份月报虽然技术含量不高,但坚持半年后你会发现,它其实是一份很好用的“品牌在AI渠道的资产沉淀记录”,对后续制定内容策略很有参考价值。
现在这套系统的后续扩展,我计划加入一个自动告警模块:如果核心品牌的采纳率较前一日下滑超过30%,直接通过邮件通知运营组,这样早上打开邮箱就能发现问题,不用再去翻看板了。