本地部署 · 数据不出内网 · 隐私优先

把评论区的声音
变成可行动的预警

Whochat —— 舆情分析 Agent

一条完整的本地工具链:多平台采集 → 本地清洗去重 → 情感 / 主题分析 → 看板 + 企微预警。 零依赖即可跑通全链路,LLM 可选接入,用不用模型由你决定。

bash — Whochat
# 零依赖跑通全链路(不需要爬虫、不需要模型)
$ python -m Whochat.cli demo
造数 · 清洗 · 去重 · 情感 · 预警 —— 全链路通过

# 打开看板(双入口)
$ python -m Whochat.cli dashboard
看板端 /console · http://localhost:8501
7支持平台
6层处理链路 L1–L6
308回归测试用例
90.9%情感基线准确率
Architecture

六层链路,一条数据流走到底

每层职责单一、接口清晰。采集层与分析层之间只有 CrawlerSource 协议一个解耦点,换数据源不动下游。

L1采集
MediaCrawler(Playwright) · MockSource · ManualImport
抖音 / 小红书 / 快手 / B站 / 微博 / 贴吧 / 知乎 —— 只取评论区文本,但抓全字段
L2清洗
规则清洗 → 精确去重(SHA256) → 近重复(MinHash/SimHash 分桶) → LLM 打标(可选)
L3分析
快通道 规则引擎(秒级 · 无模型) │ 慢通道 情感分析 · BERTopic · 词云 · 时序
L4存储
Repository 统一读写接口 —— 上层不碰 SQL,这层就是事实上的「中台」边界
L5预警
聚合 · 分级 · 冷却 → 企业微信机器人;失败保持 pending 自动重试,不丢警
L6看板
Streamlit :8501 双入口 —— 看板端(只读:趋势/情感/主题/词云/传播/预警记录)+ 操作端(L1~L5 触发与微调)
Capabilities

不只是一条爬虫加一个词云

从「抓到数据」到「知道该做什么」,中间每一步都有对应的工程决策。

🕷️

多平台采集

基于 MediaCrawler 的浏览器自动化,零逆向、不随平台加密更新失效。采集层抓全字段 —— 采集不可逆,分析可重跑。

🧹

精确 + 近重复去重

SHA256 精确去重,叠加 MinHash / SimHash 分桶处理改字、加表情的搬运内容,避免同一波声量被重复计数。

💬

词典法情感分析

子串扫描 + 否定 + 程度 + 转折。实测 90.9%,比同标注集上的 transformer(60.6%)更准,且零依赖、毫秒级、可复现。

🧭

主题建模 + 离线兜底

BERTopic 中文嵌入;HuggingFace 不可达时自动降级到 TF-IDF + SVD + HDBSCAN 的零下载离线方案,功能不报废。

🌊

传播分析

传播曲线(起爆点 / 峰值 / 增速拐点)+ 传播路径(parent_content_id 还原转发链 DOT 图),看清事情怎么扩散的。

🚨

快慢双通道预警

秒级规则快通道先发警,不等模型清洗;慢通道补深度分析。等模型跑完再告警,时效性已经没了。

🏷️

LLM 打标(可选)

广告识别看意图不看关键词、主体识别、关键词抽取、主题命名。只填 base_url + api_key,任何 OpenAI 兼容接口都能用。

📊

双入口看板

看板端只读、操作端可写。采集 / 分析 / 规则 / 推送都能在页面上触发和微调,不用记命令行。

🔐

本地优先

SQLite 落库、本地清洗、本地分析。数据不出内网;LLM 是否启用、走哪个端点,完全由你决定。

Optional LLM

LLM 只做它擅长的,不做它不擅长的

开不开模型是两套结果:开启后写入 lexicon-v1-llm,与 lexicon-v1 并存不覆盖,事后能对比差异。

✅ 用 LLM 做❌ 不用 LLM 做
广告识别 —— 判意图而非关键词
「商家刷单太明显了」是在批评,纯正则会误杀
情感判定 —— 永远走词典法
实测 90.9% vs 模型 60.6%,封闭分类任务更快更准更可复现
主体识别 —— 这条在骂哪个产品 / 型号
写入 subject 字段,规则完全做不到
声量统计 —— 必须是精确计数
概率性输出不能用来数数
关键词抽取 / 主题命名
把「发热 / 续航 / 掉电」归纳成「屏幕发热与续航」
快通道预警 —— 秒级链路
设计前提就是「无模型、秒级」
字段映射import --llm-map
字段名陌生的数据集,学一次就能导入并落盘缓存
逐条判情感
拿大炮打蚊子,还更不准
漏项不丢数据:模型少返回几条时,那几条会继续被正常分析,只是不带 LLM 标签。 丢数据比少打一个标严重得多 —— 这条有测试钉死。
Design Decisions

十条踩坑之后定下来的决策

改之前建议先看方案文档 §13。这里挑几条最能说明「为什么长这样」的。

01

采集不自研,用 MediaCrawler

抖音 a_bogus 是 JSVMP 混淆 + 环境检测 + 数月一升级;浏览器自动化零逆向,且不随加密更新失效。

02

国内平台采集不走代理

代理 IP 特征反而触发风控,出口地域跳变与登录态冲突。代理只用于下载依赖。

03

只取评论区文本

评论区是情绪最集中处,信噪比高于视频正文。

04

采集层抓全字段

采集不可逆,分析可重跑。parent_content_id / follower_count 内容一删就补不回来。

05

LLM 只打标,不判情感

情感是封闭分类任务,词典法更快更准更可复现。用 LLM 逐条判是拿大炮打蚊子。

06

预警走快慢双通道

等模型清洗完再告警,时效性已丧失(行业标准 30 秒 ~ 分钟级)。

07

不建真「数据中台」

单人本地工具,过度工程化是最大死因。但保留存储 / 展示边界。

08

编排用 APScheduler,不用 Airflow

Windows 本机开发,Airflow 需要 WSL / Docker 且过重。

09

MVP 用 Streamlit,二期换 FastAPI

先抢时间验证,再演进架构。

10

看板措辞限定「讨论区」

评论区样本天然偏向极端情绪,不可外推为「公众意见」。

Quick Start

三分钟跑起来

demo 是幂等的:固定种子造数,连跑多次落库量与告警数都不变 —— 所以它也能当回归基线用。

# 1. 安装(可编辑模式)
$ pip install -e .

# 2. 环境自检 —— 一次说清「什么能跑、什么没装」
$ python -m Whochat.cli init

# 3. 零依赖跑通全链路(不需要爬虫 / 模型)
$ python -m Whochat.cli demo

# 4. 可视化:看板端 + 操作端
$ python -m Whochat.cli dashboard
  → http://localhost:8501
# 换真实数据源
$ python -m Whochat.cli crawl --platform xhs --keyword "你的品牌"
$ python -m Whochat.cli crawl --platform douyin --keyword "你的品牌"

# 或导入已有的 JSONL / JSON / CSV
$ python -m Whochat.cli import comments.jsonl --platform xhs

# 分析 → 主题 → 词云
$ python -m Whochat.cli analyze
$ python -m Whochat.cli topics
$ python -m Whochat.cli wordcloud

# 预警(--since-hours 24 可回放补数 / 复盘)
$ python -m Whochat.cli alert --seed-rules
$ python -m Whochat.cli status
# 可选:接入任意 OpenAI 兼容接口(不装额外包,直接走 HTTP)。模型名可留空,会自动挑一个对话模型。
WHOCHAT_LLM_BASE_URL=https://api.deepseek.com/v1
WHOCHAT_LLM_API_KEY=sk-xxxxxxxxxxxxxxxx
不想改文件?打开操作端 http://127.0.0.1:8501/consoleL2 清洗 → 「LLM 分析」, 三个输入框填完点「保存并测试连接」,写进 .env 并立即生效,不用重启看板。
Honest Limits

已知限制(诚实清单)

一个工具好不好用,取决于它有没有把边界说清楚。以下是它做不到做不好的地方。

MediaCrawler 是 NON-COMMERCIAL 许可,明确禁止商业用途。要商业交付必须实现 OfficialAPISource 替换它 —— 这正是协议层存在的意义。

采集成功率 70~90%。403 / 滑块 / 登录态失效是常态,这是健康水平,不是 bug。

反讽识别基本无解。「这手机真好用,用了三天就送修了」规则法处理不了,需要模型或上下文。

评论区样本天然偏斜,只代表「愿意评论的人」,情绪偏极端,不可外推为公众意见。

主题建模需 ≥ 100 文档,小样本会退化成一堆碎片主题;文档数 < 20 时直接拒绝并说明原因。

HuggingFace 可达性不稳定,嵌入模型下载会失败。此时自动降级到零下载离线方案,效果弱于 BERTopic 但功能不报废。

LLM 输出是概率性的,同一条文本两次调用可能给不同标签。所以它只做可容忍抖动的打标,不参与情感判定与声量统计。

LLM 打标未在真实数据上评估过。现有测试验证的是契约(不漏项、不错位、不丢数据),不是准确率 —— 请用自己的标注集来测。

情感基线样本量小。33 条标注集证明的是链路可用,不是「准确率有 90.9%」。请务必用业务数据建 300~500 条重测。

字段映射可能学错。已有防护(只认 schema 内字段、别名优先),但学错仍会往库里写错数据;缓存可查看 / 删除重学。

没有基线,后面所有的情感统计、预警阈值、主题分析都建立在流沙上。 —— 这是项目文档里反复强调的一句话。