- Added comprehensive technical design document for AI Brand Monitoring System V5, outlining system architecture, data models, sampling strategies, and monitoring protocols. - Key changes include a shift to a sampling-based trend monitoring approach, updated data collection and storage strategies, and new metrics for performance evaluation. - Implemented migration scripts to support the flattening of brand questions and versioning of question texts, ensuring historical data integrity and version control.
28 KiB
AI 品牌曝光监测系统技术方案 V5
1. 文档信息
| 项目 | 内容 |
|---|---|
| 文档名称 | AI 品牌曝光监测系统技术方案 V5(采样型趋势监测 + 异步解耦) |
| 文档版本 | V5.1 |
| 文档状态 | 待评审 |
| 创建日期 | 2026-04-08 |
| 基线文档 | docs/ai-brand-monitoring-tech-design-v4.md |
| 适用范围 | 数据追踪模块全部页面 |
| 关联文档 | docs/geo-platform-prd-v1.md(PRD 8.4 数据追踪) |
| 关联文档 | docs/question-driven-monitoring-design-v1.md(问题驱动模型) |
| 核心约束 | 单租户仅 1 个监测插件实例,插件所在设备不保证全天在线 |
2. V5 核心结论
V5 不再把该能力定义为“全量、精确、准实时监控”,而是明确收敛为:
- 采样型趋势监测系统,不是审计系统。
- 单实例插件 + 非全天在线设备前提下,只承诺趋势参考,不承诺全量覆盖。
- 页面百分比全部按实际采样成功样本计算,不再暗示“全量真实占比”。
- 页面必须展示采样覆盖信息,包括计划采样数、实际采样数、覆盖率、最近更新时间。
- 引入 RabbitMQ 和独立 Monitoring PostgreSQL 隔离写链路,但聚合仍以日批为主,不承诺准实时展示。
2.1 相比 V4 的根本变化
| 维度 | V4 | V5 |
|---|---|---|
| 产品定位 | 全量品牌曝光监测 | 采样型趋势参考 |
| 采集目标 | 尽量覆盖全部问题 × 全平台 | 每日仅覆盖活跃监测题池 |
| 插件节点假设 | 大量用户端节点可互补 | 单租户单主插件实例 |
| 数据时效 | 准实时 + T+1 | T+1 为主,允许延迟 |
| 数据精度承诺 | 接近真实全量 | 趋势可参考,精度受覆盖率影响 |
| 任务处理 | PG + Redis 锁 + RabbitMQ | Monitoring PG 任务表 + PG 租约状态机 + RabbitMQ 结果异步化 |
| 存储边界 | 单业务库承载配置与监测结果 | 主业务 PG 存配置,Monitoring PG 存监测数据 |
| 页面表达 | 指标卡直接展示百分比 | 指标卡 + 采样覆盖信息 + 置信度提示 |
2.2 非目标
V5 明确不做以下承诺:
- 不承诺所有问题每天都有结果。
- 不承诺所有 AI 平台每天都有样本。
- 不承诺分钟级实时更新。
- 不承诺百分比可用于财务、法务、投放结算或精确 KPI 审计。
3. 产品口径与页面表达
3.1 页面定位
数据追踪页展示的是:
- 在“当前监测题池”上的 AI 曝光趋势
- 在“实际采样成功样本”上的品牌表现
- 在“可归因引用样本”上的文章引用趋势
不是:
- 品牌在全网 AI 场景中的绝对真实份额
- 所有问题、所有平台、所有时间点的完整监控
3.2 页面必须新增的展示项
为避免误导,数据追踪页和 Dashboard composite 接口必须返回并展示:
planned_sample_count:计划采样数actual_sample_count:实际采样成功数coverage_rate:覆盖率 =actual / plannedlast_sampled_at:最近成功采样时间confidence_level:high / medium / low
推荐前端呈现方式:
- 顶部右侧信息条:
采样模式 - 趋势图上方副文案:
已采样 18/30,覆盖率 60%,更新于 04-08 09:20 - 覆盖率过低时展示
样本不足,仅供参考
3.3 低覆盖场景的展示规则
| 覆盖率 | 置信度 | 页面表现 |
|---|---|---|
| >= 70% | high | 正常展示百分比和趋势 |
| 40% - 69% | medium | 展示百分比,并提示“样本偏少” |
| < 40% | low | 保留原始计数,百分比弱化展示或标记“仅供参考” |
当 actual_sample_count < 5 时:
- 不展示“精确到整数”的百分比变化解释。
- 趋势线可以显示,但需打低置信度标记。
- 引用排行允许为空,不用补零。
4. 采样配额与容量模型
4.1 套餐定义
V5 中配额控制的不是“题库总量”,而是“每日活跃监测问题数”。
| 配额项 | Free | Pro | Enterprise |
|---|---|---|---|
| 最大品牌数 | 1 | 3 | 自定义 |
| 题库总量 | 不限于监测能力,只做配置资产 | 不限于监测能力,只做配置资产 | 自定义 |
| 每日活跃监测问题数 | 3-5 | 5-10 | 自定义 |
| 采集频率 | 每天 | 每天 | 每天 / 自定义 |
| 平台范围 | 当前已接入且已登录的平台 | 当前已接入且已登录的平台 | 同左 |
| 数据承诺 | 趋势参考 | 趋势参考 | 趋势参考 / 专属增强 |
4.2 活跃监测题池
系统将问题分成两层:
- 问题题库:品牌下维护的全部问题,仅做配置和运营资产。
- 活跃监测题池:每日实际参与采样的问题集合,数量受套餐限制。
推荐实现:
brand_questions保留全部题库- 新增
monitor_priority、monitor_enabled - 调度器每日只选 Top N 问题进入任务生成
4.3 单实例前提下的目标任务量
按首批 6 个平台测算:
| 套餐 | 活跃问题数 | 平台数 | 目标计划任务/天 |
|---|---|---|---|
| Free | 3-5 | 6 | 18-30 |
| Pro | 5-10 | 6 | 30-60 |
说明:
- 这是 计划采样量,不是保证完成量。
- 实际完成量取决于:
- 主监测插件是否在线
- 插件机器当日在线时长
- 对应 AI 平台是否已登录
- 平台风控和采集成功率
4.4 核心调度原则
V5 的调度器不追求“补齐所有漏采任务”,而追求“稳定输出可比较样本”。
因此:
- 每天只生成当天计划任务,不补历史大积压。
- 超过 48 小时未完成的任务自动过期,不回补到新一天的分母中。
- 读侧按
planned_sample_count和actual_sample_count共同解释结果。
4.5 主插件在线约束
单租户只指定 1 个 primary_monitoring_installation 参与自动监测。
调度前先判断该插件是否活跃:
last_seen_at <= 24h:生成当天任务last_seen_at > 24h:不生成新任务,页面沿用最近一次成功数据并提示“近期无新采样”
这条规则的目的:
- 防止设备长期离线时任务无限堆积
- 防止“未执行任务”污染覆盖率统计
- 让系统行为和单实例现实约束一致
5. 数据口径定义
5.1 顶部指标口径
所有百分比的分母统一为 实际采样成功回答数,不是计划任务数,也不是题库总数。
| 指标 | 定义 |
|---|---|
| 提及率 | mentioned_count / actual_sample_count |
| 首位提及率 | top1_mentioned_count / actual_sample_count |
| 首选推荐率 | first_recommended_count / actual_sample_count |
| 正面提及率 | positive_mentioned_count / actual_sample_count |
| 品牌可见率 | 与提及率同源,可作为 UI 别名展示 |
| 文章引用率 | cited_answer_count / actual_sample_count |
5.2 趋势图口径
趋势图展示的是按天聚合后的样本表现,不是平台真实总体份额。
每个点必须同时具备:
metric_valueactual_sample_countcoverage_rate
可选增强:
- 默认展示 7 天滚动均值
- 用户切换后可看原始日值
5.3 高频问题口径
高频问题区不再解释为“全站高频触发问题”,而是:
在当前时间窗口内,被实际采样成功次数最多的问题
推荐展示字段:
- 问题文案
- 成功采样次数
- 提及率
- 最近采样时间
5.4 引用排行口径
引用排行按模型平台展示:
- 有过可归因引用的回答数
- 引用文章数
- 引用率
若平台当日无样本或平台未登录:
- 展示为
未采样 - 不强行按
0并入分母
6. 数据模型修订
6.1 双 PostgreSQL 存储边界
V5.1 将数据按“业务配置”和“监测结果”拆到两个 PostgreSQL:
主业务 PostgreSQL
tenantsbrandsbrand_keywordsbrand_questionsarticlespublish_recordsplugin_installationstenant_monitoring_quotas
Monitoring PostgreSQL
monitoring_collect_tasksquestion_monitor_runsquestion_monitor_parse_resultsmonitoring_citation_factsmonitoring_article_url_aliasesmonitoring_*_daily
设计原则:
- 不做跨库物理外键,只保留逻辑 ID 引用。
- 监测链路的高频写入、重试、归档不影响主业务 PG。
- 读侧监测查询优先从 Monitoring PG 获取。
6.2 question_version_id 移除后的替代方案
V5 接受原系统不再维护 question_version_id,但仍然保留“输入快照不可变”原则。
替代方案:
- 在任务表和运行表写入
question_text_snapshot - 同时写入
question_hash - 历史汇总按
question_hash区分口径
这样即使 question_id 不变、文案发生修改,历史数据也不会被新文案污染。
6.3 tenant_monitoring_quotas
CREATE TABLE tenant_monitoring_quotas (
tenant_id BIGINT PRIMARY KEY REFERENCES tenants(id),
max_brands INT NOT NULL DEFAULT 1,
daily_active_question_limit INT NOT NULL DEFAULT 5,
collect_frequency VARCHAR(20) NOT NULL DEFAULT 'daily',
enabled_platforms JSONB NOT NULL DEFAULT '["deepseek","qwen","doubao"]',
primary_installation_id BIGINT REFERENCES plugin_installations(id),
task_daily_hard_cap INT NOT NULL DEFAULT 36,
plan_tier VARCHAR(20) NOT NULL DEFAULT 'free',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
建议默认值:
- Free:
daily_active_question_limit = 5,task_daily_hard_cap = 36 - Pro:
daily_active_question_limit = 10,task_daily_hard_cap = 72
说明:
tenant_monitoring_quotas放在主业务 PostgreSQL。primary_installation_id继续引用主业务库中的plugin_installations。
6.4 monitoring_collect_tasks
V5.1 使用 Monitoring PG 单表状态机进行任务租约,并用 RabbitMQ 解耦结果写入。
CREATE TABLE monitoring_collect_tasks (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
brand_id BIGINT NOT NULL,
question_id BIGINT NOT NULL,
question_text_snapshot TEXT NOT NULL,
question_hash VARCHAR(64) NOT NULL,
ai_platform_id VARCHAR(30) NOT NULL,
run_mode VARCHAR(30) NOT NULL DEFAULT 'plugin_standard',
business_date DATE NOT NULL,
planned_at TIMESTAMPTZ NOT NULL DEFAULT now(),
status VARCHAR(20) NOT NULL DEFAULT 'pending',
lease_token_hash VARCHAR(128),
leased_to_installation BIGINT,
leased_at TIMESTAMPTZ,
lease_expires_at TIMESTAMPTZ,
callback_received_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
skip_reason VARCHAR(50),
error_message TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
CONSTRAINT uk_collect_task_idempotent
UNIQUE (tenant_id, brand_id, question_id, question_hash, ai_platform_id, run_mode, business_date)
);
CREATE INDEX idx_collect_tasks_lease
ON monitoring_collect_tasks(tenant_id, status, business_date, lease_expires_at);
状态流转:
pendingleasedreceivedcompletedskippedexpiredfailed
说明:
- 任务租约状态在 Monitoring PG 中维护。
received表示 API 已接收插件结果并成功投递 MQ,但 worker 尚未完成最终入库。
6.5 question_monitor_runs
在 V5 中至少补充:
ALTER TABLE question_monitor_runs
ADD COLUMN IF NOT EXISTS tenant_id BIGINT,
ADD COLUMN IF NOT EXISTS business_date DATE,
ADD COLUMN IF NOT EXISTS run_mode VARCHAR(30),
ADD COLUMN IF NOT EXISTS question_text_snapshot TEXT,
ADD COLUMN IF NOT EXISTS question_hash VARCHAR(64),
ADD COLUMN IF NOT EXISTS provider_model VARCHAR(100),
ADD COLUMN IF NOT EXISTS request_id VARCHAR(100),
ADD COLUMN IF NOT EXISTS raw_answer_storage_key TEXT;
建议幂等键:
CREATE UNIQUE INDEX uk_monitor_run_idempotent
ON question_monitor_runs(tenant_id, brand_id, question_id, question_hash, ai_platform_id, run_mode, business_date);
建议:
question_monitor_runs落在 Monitoring PostgreSQL。- 若原始回答文本不超过阈值,可直接存库;超大原文再转对象存储。
6.6 文章 URL 归因表
为支撑“总引用数 / 文章引用率 / 引用文章数”,新增 URL 归因别名表:
CREATE TABLE monitoring_article_url_aliases (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
article_id BIGINT NOT NULL,
publish_record_id BIGINT,
platform_id VARCHAR(64),
external_article_id VARCHAR(128),
original_url TEXT NOT NULL,
normalized_url TEXT NOT NULL,
last_path_segment VARCHAR(255),
confidence VARCHAR(20) NOT NULL DEFAULT 'high',
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE UNIQUE INDEX uk_article_url_alias
ON monitoring_article_url_aliases(tenant_id, normalized_url);
7. 解析标准化与 SoV 统计模型
7.1 解析分层
V5.1 的解析分为 3 层:
- 回答层:品牌提及、首位提及、首选推荐、情感倾向
- 引用层:从回答、citation JSON、search_results 中提取 URL 事实
- 来源层:基于域名清洗和站点聚合生成 SoV 统计结果
7.2 基于 tldextract 的顶级域名清洗
为避免 www、二级域名、国家后缀等问题导致同一站点重复计数,引用归因与来源排行统一采用 Public Suffix List + tldextract 口径。
处理目标:
- 从原始 URL 中提取
subdomain / domain / suffix - 生成
registrable_domain - 生成统一站点主键
site_key - 为页面级和站点级聚合提供稳定维度
示例:
| 原始 URL | registrable_domain |
说明 |
|---|---|---|
https://www.zhihu.com/question/123 |
zhihu.com |
www 折叠 |
https://zhuanlan.zhihu.com/p/123 |
zhihu.com |
子域归并到站点 |
https://mp.weixin.qq.com/s/abc |
weixin.qq.com |
基于 PSL 提取可注册域 |
https://finance.sina.com.cn/roll/123.html |
sina.com.cn |
正确处理 com.cn |
https://sub.example.co.uk/a |
example.co.uk |
正确处理 co.uk |
推荐清洗流程:
- URL 小写化主机名
- 去掉默认端口
- 去掉 fragment
- path 做基础规范化
- host 通过
tldextract计算registrable_domain - 保存:
normalized_urlhostregistrable_domainsubdomainsuffix
7.3 monitoring_citation_facts 推荐字段
为支撑域名清洗和来源排行,建议引用事实表至少包含:
CREATE TABLE monitoring_citation_facts (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
run_id BIGINT NOT NULL,
brand_id BIGINT NOT NULL,
ai_platform_id VARCHAR(30) NOT NULL,
business_date DATE NOT NULL,
cited_url TEXT NOT NULL,
normalized_url TEXT NOT NULL,
host VARCHAR(255) NOT NULL,
registrable_domain VARCHAR(255) NOT NULL,
subdomain VARCHAR(255),
suffix VARCHAR(50),
site_key VARCHAR(255) NOT NULL,
article_id BIGINT,
publish_record_id BIGINT,
resolution_status VARCHAR(20) NOT NULL DEFAULT 'resolved',
resolution_confidence VARCHAR(20) NOT NULL DEFAULT 'high',
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_citation_facts_domain
ON monitoring_citation_facts(tenant_id, business_date, registrable_domain);
约定:
normalized_url用于页面级去重和文章归因registrable_domain用于站点级来源排行site_key默认等于registrable_domain- 如业务需要区分站群,可对特定域名做覆写映射
7.4 site_key 映射规则
默认规则:
site_key = registrable_domain
可选增强规则:
- 将
mp.weixin.qq.com、weixin.qq.com统一到weixin.qq.com - 将业务上需要区分的站群写入
site_domain_mapping - 对同集团但不同产品是否合并,必须通过配置显式决定,不靠临时规则猜测
推荐新增配置表:
CREATE TABLE site_domain_mappings (
id BIGSERIAL PRIMARY KEY,
registrable_domain VARCHAR(255) NOT NULL,
site_key VARCHAR(255) NOT NULL,
site_name VARCHAR(255) NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
7.5 SoV 统计模型
V5.1 中的 SoV 统一解释为:
在当前采样窗口内,某品牌、某站点或某文章在全部有效样本中的相对占比
必须明确分母,禁止不同口径混用。
7.6 品牌 SoV
品牌 SoV 适用于品牌曝光类页面。
定义:
brand_sov = brand_mentioned_answers / actual_sample_count
其中:
brand_mentioned_answers:成功采样回答中,提及目标品牌的回答数actual_sample_count:成功采样回答总数
这和页面上的“提及率”同源,可视为品牌在样本回答中的 Share of Voice。
7.7 引用来源 SoV
引用来源 SoV 适用于“引用来源排行”“来源平台占比”。
定义:
source_sov = source_citation_count / total_resolved_citation_count
其中:
source_citation_count:某site_key在窗口内被引用的次数total_resolved_citation_count:全部已成功解析并完成站点归类的引用次数
补充口径:
- unresolved 引用不进入分子
- unresolved 是否进入分母,要固定为“不进入”
- unresolved 单独展示占比,作为质量指标
7.8 文章 SoV
文章 SoV 用于内部文章在可归因引用中的占比。
定义:
article_sov = article_citation_count / total_article_resolved_citation_count
其中:
article_citation_count:某篇内部文章被 AI 引用的次数total_article_resolved_citation_count:全部成功归因到内部文章的引用次数
注意:
- 文章 SoV 不是品牌 SoV
- 文章 SoV 的分母不能拿全部回答数
- 若用户看的是“文章引用率”,仍然应使用
cited_answer_count / actual_sample_count
7.9 覆盖率与 SoV 的关系
覆盖率和 SoV 必须分开解释:
coverage_rate反映“今天采样够不够”SoV反映“在已采样样本里占比多少”
因此页面解释顺序应为:
- 先看覆盖率
- 再看 SoV / 提及率 / 引用率
当 coverage_rate < 40% 时:
- 允许展示 SoV
- 但必须附带低置信度提示
7.10 聚合输出建议
建议在 monitoring_citation_source_daily 和 monitoring_citation_page_daily 中增加:
citation_countcitation_sovresolved_countunresolved_countconfidence_level
这样前端可以同时展示:
- 引用次数
- SoV
- 数据质量
8. 任务协议与插件侧流程
8.1 统一为租约式协议
V5 删除 GET tasks -> POST claim 两步式协议,统一改为:
- 插件请求租约
- 服务端原子分配任务并返回
lease_token - 插件执行采集
- 插件带
lease_token回传结果 - 服务端校验归属、先写任务状态为
received并投递 RabbitMQ - Monitor Worker 异步写入运行结果、解析结果并完成任务
8.2 插件 API
POST /api/plugin/monitoring/tasks/lease
POST /api/plugin/monitoring/tasks/{id}/result
POST /api/plugin/monitoring/tasks/{id}/skip
请求头:
X-Geo-Installation-TokenX-Geo-Installation-Id
8.3 租约接口行为
租约接口建议按 PG 原子领取:
SELECT id
FROM monitoring_collect_tasks
WHERE tenant_id = $1
AND status = 'pending'
AND business_date = $2
ORDER BY planned_at ASC, id ASC
FOR UPDATE SKIP LOCKED
LIMIT $3;
服务端完成以下动作:
- 选出任务
- 生成短期
lease_token - 更新
status = leased - 写入
lease_expires_at = now() + interval '15 minutes'
8.4 插件执行策略
V5 继续复用现有插件基础设施:
但采样策略改为“小批量、固定预算”:
| 项目 | 建议值 |
|---|---|
| 心跳频率 | 15 分钟 |
| 单次租约任务数 | 2-3 |
| 单任务超时 | 60 秒 |
| 租约时长 | 15 分钟 |
| 每日硬上限 | 按套餐 36 / 72 |
8.5 任务过期与回收
定时任务每 30 分钟处理一次:
lease_expires_at < now()且状态仍为leased的任务改为expiredreceived状态超过阈值未被 worker 完成时,进入异常告警- 同一
business_date的expired任务最多重试 1 次 - 超过
business_date + 2 days的未完成任务不再重试
9. 采集、解析、聚合架构
9.1 首期简化版链路
每日 00:10 调度器生成当天任务
↓
插件后台 15 分钟心跳租约任务
↓
插件执行提问并回传结果
↓
tenant-api:校验租约 -> 标记 received -> 投递 RabbitMQ
↓
Monitor Worker:消费结果 -> 写 Monitoring PG -> 解析结果 -> 完成任务
↓
每日 06:30 聚合 Job 汇总到 monitoring_*_daily
↓
读侧 API + Redis 缓存
9.2 RabbitMQ 的职责边界
V5.1 中 RabbitMQ 只承担“结果异步化”,不承担“任务分发”。
使用 RabbitMQ 的原因:
- 插件回调接口可以快速返回,降低超时和重试风险
- 解析、引用归因、写库失败不会直接影响插件侧体验
- 方便把高频写入隔离到独立 worker
- 后续若企业版放大量级,不需要重做写链路
但 RabbitMQ 不参与以下事项:
- 不做任务租约
- 不做读侧查询
- 不强制引入准实时前端刷新
推荐队列:
monitor.result.ingestmonitor.result.dlqmonitor.aggregate.trigger
9.3 Monitoring PostgreSQL 的职责
独立 Monitoring PG 的目的不是“多一套库”,而是隔离监测链路的写放大。
承载内容:
- 任务表
- 原始回答
- 解析结果
- 引用事实
- 日聚合结果
收益:
- 主业务 PG 不承受高频插入和大文本更新
- Monitoring PG 可独立做分区、归档、VACUUM 策略
- 监测表膨胀不会影响文章、品牌、发布主链路
9.4 原始回答存储
V5.1 中抓取结果优先进入 Monitoring PG:
- 原始回答文本
- 平台响应元数据
- 引用与搜索结果原始 JSON
- 解析后的结构化字段
可选归档策略:
- 小于 64 KB 的原文直接存 Monitoring PG
- 超大原文或完整调试负载转存对象存储
- Monitoring PG 仅保留摘要、关键字段和存储路径
10. 文章引用归因策略
10.1 为什么不能只看 URL 最后一段
仅按最后一段匹配存在以下问题:
- 不同平台可能出现相同 path segment
- 同一平台 PC / H5 / 分享页 URL 可能不同
- AI 引用结果可能带参数、重定向或 canonical URL
- 同一篇文章可能存在多个可访问别名
因此 V5 的归因策略是 分层匹配 + 置信度标记。
10.2 归因顺序
normalized_url精确匹配(platform_id, external_article_id)精确匹配(domain, last_path_segment)唯一匹配- 无法唯一命中时,记为
unresolved
10.3 低置信度处理
当仅通过 last_path_segment 命中时:
- 给归因结果打
low_confidence - 可以进入趋势参考视图
- 不建议进入需要精确计费或精确归属的报表
这与 V5 的“趋势参考”定位是一致的。
11. 平台接入范围
11.1 V5 交付范围
数据模型支持 6 平台扩展,但首期交付只承诺首批 3 平台:
- DeepSeek
- 通义千问
- 豆包
11.2 页面与套餐表达
页面和套餐都必须按“当前已接入且已登录的平台”解释:
- 已接入且已登录:进入采样计划
- 已接入未登录:展示
未登录 - 未接入:展示
未接入
不得再用“全 6 平台稳定可用”作为首期对外承诺。
12. 读侧与汇总表
V5 读侧继续沿用 V3 的聚合表和缓存思路,但口径增加采样字段:
planned_sample_countactual_sample_countcoverage_rateconfidence_level
推荐所有 monitoring_*_daily 汇总表统一增加以上字段。
12.1 Dashboard composite
/api/tenant/monitoring/dashboard/composite 继续保留,但返回结构需扩展:
{
"overview": {
"mention_rate": 0.42,
"citation_rate": 0.18,
"planned_sample_count": 30,
"actual_sample_count": 21,
"coverage_rate": 0.70,
"confidence_level": "high",
"last_sampled_at": "2026-04-08T09:20:00Z"
}
}
12.2 缓存策略
读侧缓存策略可继续沿用 V3:
- composite 聚合缓存
- singleflight
- TTL 抖动
- stale-while-revalidate
但缓存失效触发点改为:
- 每日聚合完成
- 用户切换品牌 / 时间窗口
不需要为单条采样结果做准实时逐条失效。
13. 降级、告警与风险
13.1 降级策略
| 场景 | V5 行为 |
|---|---|
| 插件 24h 未活跃 | 暂停生成新任务,页面展示上次数据 |
| 平台未登录 | 该平台不进入当天计划样本 |
| 当日覆盖率低 | 页面提示“样本不足,仅供参考” |
| 某平台 adapter 失效 | 该平台展示“暂不可用”,其余平台继续 |
| URL 无法归因 | 计入 unresolved,不强行挂到文章 |
13.2 关键告警
| 指标 | 阈值 |
|---|---|
| 主插件离线时长 | > 24h |
| 日覆盖率 | < 40% |
| 单平台连续失败 | > 20 次 / 天 |
| unresolved 引用占比 | > 30% |
| 每日聚合延迟 | > 08:00 未完成 |
13.3 风险接受说明
V5 明确接受以下风险:
- 单日样本偏少导致波动大
- 插件离线导致当天无新数据
- 部分 URL 只能低置信度归因
但不接受以下风险:
- 任务重复执行导致统计翻倍
- 输入口径变更污染历史数据
- 未授权回调写入虚假监测结果
14. 实施计划
14.1 Phase 分期
| Phase | 内容 | 估时 |
|---|---|---|
| A | 双库方案落地:主业务 PG / Monitoring PG schema 与连接配置 | 4 天 |
| B | RabbitMQ 基础设施 + Monitor Worker 骨架 + DLQ | 4 天 |
| C | 插件:AI adapter 框架 + 3 平台 + 租约式任务执行 | 6 天 |
| D | 后端:租约 API、结果回调、MQ 消费、解析入库、日聚合 | 7 天 |
| E | 前端:数据追踪页补覆盖率、更新时间、置信度提示 | 4 天 |
| F | 联调、坏样本验证、口径验收 | 4 天 |
| 合计 | 29 天 |
14.2 验收标准
- 页面可展示
planned_sample_count / actual_sample_count / coverage_rate - 页面可正常展示趋势图、高频问题、引用排行
- 当覆盖率不足时,页面有明确提示
- 同一任务不会被重复计入统计
- 问题文案修改后,历史趋势不被污染
- 引用文章数可通过 URL alias 规则稳定归因,无法归因时进入 unresolved
15. V4 → V5 变更摘要
| 编号 | V4 | V5 |
|---|---|---|
| C1 | 全量监测叙事 | 采样趋势叙事 |
| C2 | Free 1 品牌 / 40 问题 | Free 3-5 个每日活跃问题 |
| C3 | Pro 3 品牌 / 40 问题 | Pro 5-10 个每日活跃问题 |
| C4 | GET + claim 两步任务协议 | 一步租约式任务协议 |
| C5 | question_version_id |
question_hash + question_text_snapshot |
| C6 | RabbitMQ + 增量聚合 | RabbitMQ 仅做结果异步化,不参与任务分发或前端准实时 |
| C7 | 准实时可见 | T+1 / 延迟可接受 |
| C8 | 仅展示百分比 | 百分比 + 采样覆盖信息 |
| C9 | 首期 6 平台叙事 | 首期只承诺 3 平台 |
| C10 | 单一业务库承载全部数据 | 主业务 PG + Monitoring PG 双库隔离 |
16. 最终建议
V5 适合当前阶段的原因不是“它最强”,而是“它和当前约束一致”:
- 和单实例插件现实相符
- 和 PRD 的 V1 边界相符
- 和用户对“趋势参考”的接受度相符
如果未来要升级到 V6,再考虑:
- 专用在线采集节点
- 企业版更高采样量
- 更细粒度的增量聚合和近实时刷新
- 更强的 URL 归因与多次重复采样校准