PostHog Signals 分组管线离线评估解析:从 2026-03-16 报告读懂 ARI、匹配失败模式与裁判指标
2026/9/18 12:34:41 网站建设 项目流程

PostHog Signals 分组管线离线评估解析:从 2026-03-16 报告读懂 ARI、匹配失败模式与裁判指标

【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog

导读

本文以 products/signals/eval/reports/2026-03-16.md 这份评估报告为骨架,深入解读 PostHog Signals 产品中**信号分组管线(signal grouping pipeline)**的一次离线(offline)端到端评估结果。报告中记录了 91 个合成信号、41 个 ground-truth 分组、54 份产出报告的聚类质量(ARI、同质性、完整性、纯度、组召回)、匹配失败模式分布、按来源划分的 pre-emit 可操作性检查,以及 Safety/Actionability 两个报告级裁判的准确率。读完本文,你将理解报告中每个指标的业务含义与计算口径、失败模式(尤其是 SPECIFICITY_SPLIT)背后对应的管线阶段,以及如何在本地复现这次评估并用 HogQL 查询同样的指标。

一、这份报告是什么:Signals 分组管线的离线评估

PostHog Signals 是一个将 Zendesk、GitHub、Linear 等外部工单/Issue 信号聚合为"报告(report)"的功能:多个信号如果描述同一个问题,应被聚类到同一份报告中,从而让用户一次看到问题的全貌。为了保证聚类质量,仓库在 products/signals/eval/ 下维护了一套端到端评估(end-to-end eval),其目标定义在 AGENTS.md 中:

将合成信号送入真实管线(LLM 查询生成 → 嵌入检索 → LLM 匹配 → 特异性校验 → 摘要 → 安全裁判 → 可操作性裁判),与人工标注的 ground-truth 分组对比,衡量管线把信号聚成报告的效果。

关键设计是"管线真实、基础设施打桩":用内存版EmbeddingStore替代 ClickHouse + Kafka、用ReportStore替代 Postgres(实现见 mock.py),从而在纯 Python 测试环境中跑完整链路。2026-03-16.md正是某一次离线评估产出的结果快照,包含聚合指标、匹配质量、裁判准确率等若干层面,供开发者在迭代分组逻辑时对比基线。

从文件命名看,reports/目录下还保存着 2026-03-17.md、2026-08-18.md、2026-09-03.md 等后续报告,说明这套评估是持续迭代、逐次对比的机制,本文的 03-16 报告是其中的基线记录之一。

二、本次运行的测试集与执行规模

报告开头给出了本次评估的规模信息:

  • 91 个信号(signals):由合成数据生成,来自 Zendesk、GitHub、Linear、error tracking 等来源,信号内容格式在 data_spec.py 中定义(如 Zendesk 使用subject/description字段、GitHub 使用title/body、error tracking 按 cymbal 格式渲染描述)。
  • 41 个 ground-truth 分组(groups):人工标注的"正确答案"——这些信号真实归属于哪 41 个主题分组。
  • 54 份报告(reports produced):管线最终产出 54 份报告,数量多于 ground-truth 的 41 组,说明存在过度拆分现象(下文失败模式会量化这一点)。

信号到达顺序并非按组排列,而是由 common.py 中的get_signals_stream()用固定随机种子(RNG_SEED = 1337)将各组信号交错打乱,模拟真实世界的乱序到达,同时保持组内顺序。这意味着管线必须在信号"不按主题排队"的情况下完成在线聚类,难度更接近生产环境。

每个信号经历的管线阶段

从 AGENTS.md 与 eval_grouping_e2e.py 的编排逻辑看,本次评估中每个信号依次经过以下阶段:

  1. Pre-emit:摘要长描述、做可操作性检查(actionability check,经由内部 LLM 网关调用 Claude Haiku)。不满足可操作性的信号在此被丢弃。
  2. Match:LLM 生成检索查询 → OpenAI 嵌入(text-embedding-3-small)→ 对已存信号做余弦相似度检索 → LLM 判断"并入已有报告"还是"新建报告" → 特异性校验(specificity judge)确认匹配是否过于宽泛。
  3. Persist:存储信号与嵌入,更新报告元数据。
  4. Judge:全部信号处理完后,对每份报告做摘要、安全裁判(提示注入检测)与可操作性裁判。

所有 LLM 调用统一走内部 LLM 网关(LLM_GATEWAY_URL),信号并发执行,但 match + persist 阶段由asyncio.Lock串行化,以保证嵌入库与报告库在做"并入/新建"决策时看到一致视图(并发上限MAX_CONCURRENT_RUNS = 70,定义在 common.py)。

三、聚合指标(Aggregate metrics):聚类的四个"体检项"

报告的第一张核心表是聚合指标:

MetricScore
ARI0.7059
Homogeneity0.9923
Completeness0.9065
Mean purity0.9954
Mean group recall0.6790
Malicious leaked rate0.2083 (5/24)

这些指标由 sklearn 的adjusted_rand_scorehomogeneity_completeness_v_measure等函数计算(见 eval_grouping_e2e.py 的导入),并结合报告里的定义逐项解读:

  • ARI(调整兰德指数,Adjusted Rand Index):衡量"管线聚类结果"与"ground-truth 分组"的相似度,经随机机会校正,取值 -1~1,1 为完全一致。本次 0.7059,说明聚类与人工标注的一致性处于中上水平。
  • Homogeneity(同质性)= 0.9923:每份报告里只包含来自同一个真实组的信号。越接近 1.0,说明越没有过度聚合(overgrouping)。本次表现优秀。
  • Completeness(完整性)= 0.9065:某个真实组的所有信号是否都落在同一份报告里。越接近 1.0,说明越没有欠聚合(undergrouping)。本次略低于同质性,提示存在一定程度的组被拆分。
  • Mean purity(平均纯度)= 0.9954:每份报告中主导组信号所占的平均比例,即"报告内容有多纯粹"。
  • Mean group recall(平均组召回)= 0.6790:一个真实组的信号被其最佳匹配报告捕获的比例的平均值。0.679 意味着平均约 32% 的信号没有与同组信号聚在一起——这是本次运行最薄弱的环节。
  • Malicious leaked rate(恶意信号泄漏率)= 0.2083 (5/24):24 个不安全的(恶意/提示注入)信号中,有 5 个未被安全裁判拦截而通过了管线,泄漏率 20.83%。这是安全维度的关键红线指标,后续 03-17 报告将其降到 0/24,见下文的演进对比。

从源码角度,这些指标在 AGENTS.md 中有同样的定义清单,并被作为$ai_evaluation事件中的grouping-aggregate实验捕获,用于在 PostHog 内做长期趋势监控。

四、匹配质量:失败模式的分布与 SPECIFICITY_SPLIT 的来源

报告的第二张核心表关注每个信号的匹配决策质量,本次共覆盖 104 个匹配决策:

Failure modeCount% of total
CORRECT7976.0%
SPECIFICITY_SPLIT1312.5%
UNDERGROUP65.8%
OVERGROUP65.8%

失败模式的定义

在 common.py 中定义了三个基础匹配结果枚举:

  • NONE:匹配正确(对应报告中的 CORRECT);
  • UNDERGROUP应该并入已有报告却新建了一份(欠聚合);
  • OVERGROUP加入了属于其他 ground-truth 组的报告(过度聚合)。

而报告中的SPECIFICITY_SPLIT是特异性校验阶段(specificity judge)引入的第四种状态:matcher 原本给出的匹配被特异性判断器判定为"过于宽泛"而否决/拆分,导致本应属于同一报告的信号被拆开。报告用一行专门给出了它的体量:

Total undergrouping (UNDERGROUP + SPECIFICITY_SPLIT): 19/104 (18.3%). Specificity split share of undergrouping: 13/19 (68.4%).

也就是说:本次 18.3% 的欠聚合错误中,68.4%(13/19)是由特异性判断器"过度拆分"造成的,而不是 matcher 本身没有识别出关联。这直接点出了本次运行的一个优化方向——特异性判断器的阈值/行为需要校准。

与后续报告的印证

这种"特异性判断器引入拆分"的现象并非孤例,2026-03-17.md 明确记录:特异性判断器把 14 个 overgroup 转为正确匹配,但同时引入了 5 个新的 undergroup(净 +9);2026-08-18.md 则在模型对比中发现"在 sonnet-5 上特异性判断器是净损失(84.9% → 83.7%)",因为该模型本身已很少过度聚合,判断器剩余的作用只是拆分本应合并的组。这解释了 03-16 报告中 SPECIFICITY_SPLIT 占比高、而后续迭代不断调整该阶段的原因。

检索多样性(供理解匹配质量辅助信息)

虽然 03-16 报告未列出检索多样性表,但match-quality实验本身就包含query_diversity(查询间平均余弦距离)与candidate_diversity(1 − Jaccard)两个数值指标,用于诊断"检索召回是否足够多样化"。后续报告(如 03-17 的 query_diversity 均值 0.465、candidate_diversity 均值 0.445)展示了它们的典型量级:查询中等程度多样化,不同查询召回的候选集部分重叠。

五、Pre-emit 可操作性检查:按来源的过滤质量

报告第三张表评估信号进入分组之前的可操作性过滤器({source}-actionability-check实验):

SourceTotalCorrectFailure rateFPFN
Zendesk886427.3%120
GitHub583834.5%100
Linear362433.3%60

解读要点:

  • 全部失败都是假阳性(FP):即"本应被过滤掉的不可操作信号被放行了",三个来源的 FN 均为 0——没有把真正可操作的信号误杀,这是产品体验上最要紧的底线。
  • 三个来源的失败率集中在 27%~35% 区间,说明 pre-emit 的可操作性判断对来源不敏感,瓶颈在 LLM 判断本身而非数据格式。Zendesk(工单描述)相对表现最好,GitHub Issue(34.5%)最差。
  • 从实现看,这一步对应 eval_grouping_e2e.py 中导入的check_actionability(来自 products/signals/backend/emission/pipeline.py),属于 emission 阶段的预处理,未通过即被丢弃,不会进入后续匹配。

该实验按来源拆分命名(zendesk-actionability-checkgithub-actionability-checklinear-actionability-check),指标为二值correct_classification,与 ground-truth 的可操作性标签对比。

六、报告级裁判:Safety 与 Actionability

所有信号分组完成后,管线对每份报告运行两个裁判(对应report-safety-checkreport-actionability-check实验):

JudgeTotalCorrectAccuracyFPFN
Safety544990.7%50
Actionability543564.8%190
  • Safety(90.7%):54 份报告中有 49 份被正确分类,5 个假阳性——即 5 份安全报告被误判为不安全。结合聚合指标中的恶意泄漏率 5/24,本次运行的安全护栏"有漏也有误报",后续 03-17 通过调整达到 Safety 100.0%。
  • Actionability(64.8%):54 份报告中仅 35 份被正确判定可操作性,19 个假阳性。这是本次运行准确率最低的环节,也是"报告该不该推送/展示给用户"的核心决策点,是明显的迭代目标。
  • 两个裁判的 FN 均为 0,说明没有不安全/不可操作的报告被漏判放行——错误都集中在"过于保守"方向,与 pre-emit 阶段的 FP-only 特征一致。

从实现看,报告级裁判分别对应 products/signals/backend/temporal/report_safety_judge.py(judge_report_safety,提示注入检测)与 actionability 判断,二者在 eval_grouping_e2e.py 中被逐一调用。

七、逐报告分组质量(Per-report grouping quality)

最后一张表从"单份报告"粒度给出分组质量的分布:

MetricnMeanMinMax
Purity540.9950.7501.000
Is pure5453/54 (98.1%)--
Group recall540.6790.3331.000
  • Purity 均值 0.995、最小值 0.750:绝大多数报告内容非常纯粹,但存在纯度低至 0.75 的报告(混入了 25% 的其他组信号),对应上文 OVERGROUP 错误。
  • Is pure = 53/54(98.1%):仅 1 份报告混入了不同组的信号。
  • Group recall 均值 0.679、最小值 0.333:与聚合指标中的 mean group recall 一致,是本次运行的主要短板;最差情况下一个组的信号只有 1/3 被召回,说明存在明显的欠聚合(UNDERGROUP + SPECIFICITY_SPLIT)。

综合看,本次评估的结论画像可以概括为:报告内容足够"纯"(同质性/纯度都很高),但"全"不够(完整性/组召回偏低),根因主要是特异性判断器过度拆分,其次是 matcher 自身的欠聚合

八、如何复现与继续观测:运行评估与查询指标

复现本次评估

评估入口是 eval_grouping_e2e.py,通过 pytest 运行:

# 完整运行——评估结果上报到 PostHog pytest products/signals/eval/eval_grouping_e2e.py -xvs # 快速试跑——只处理前 10 个信号,不上报 pytest products/signals/eval/eval_grouping_e2e.py -xvs --limit 10 --no-capture # 在线评估模式(结果标记为 online 而非 offline) pytest products/signals/eval/eval_grouping_e2e.py -xvs --online

需要的环境变量(配置在仓库根目录.env,自动加载)见 AGENTS.md:

VariablePurpose
OPENAI_API_KEY嵌入(text-embedding-3-small)
LLM_GATEWAY_URL内部 LLM 网关地址(匹配/特异性/摘要/可操作性/安全等全部 LLM 调用)
LLM_GATEWAY_PERSONAL_API_KEYLLM 网关的 Bearer token(PostHog 个人 API key)
SIGNALS_EVAL_TEAM_IDLLM 成本归属头使用的 team id(默认 1)
POSTHOG_PROJECT_API_KEY上报评估结果用(可用--no-capture跳过)
POSTHOG_HOSTPostHog 实例地址(默认http://localhost:8010

支持的命令行选项:

FlagEffect
--limit N只处理信号流中的前 N 个信号
--no-capture不向 PostHog 发送$ai_evaluation事件
--online将上报结果标记为 online 评估(默认 offline)

运行过程中 stderr 会输出两条 tqdm 进度条(Matching 与 Judging),随后是聚合结果汇总表,与 03-16 报告的数据结构一一对应。

用 HogQL 复现报告中的指标

评估结果以$ai_evaluation事件($ai_eval_source = 'signals-grouping'$ai_evaluation_type = 'offline')落库,AGENTS.md 提供了多段可直接在 PostHog SQL 编辑器中执行的查询。例如聚合指标:

SELECT properties.$ai_metric_name AS metric, properties.$ai_score AS score, properties.$ai_metric_description AS description, properties.$ai_reasoning AS reasoning, properties.$ai_input AS input, properties.$ai_output AS output, properties.$ai_expected AS expected FROM events WHERE event = '$ai_evaluation' AND properties.$ai_eval_source = 'signals-grouping' AND properties.$ai_evaluation_type = 'offline' AND properties.$ai_experiment_name = 'signals-grouping/grouping-aggregate' ORDER BY metric

匹配失败模式分布:

SELECT multiIf( properties.$ai_score = 1.0, 'CORRECT', properties.$ai_reasoning LIKE '%UNDERGROUP%', 'UNDERGROUP', properties.$ai_reasoning LIKE '%OVERGROUP%', 'OVERGROUP', 'UNKNOWN' ) AS failure_mode, count() AS cnt, round(count() * 100.0 / (SELECT count() FROM events WHERE event = '$ai_evaluation' AND properties.$ai_eval_source = 'signals-grouping' AND properties.$ai_evaluation_type = 'offline' AND properties.$ai_experiment_name = 'signals-grouping/match-quality'), 1) AS pct FROM events WHERE event = '$ai_evaluation' AND properties.$ai_eval_source = 'signals-grouping' AND properties.$ai_evaluation_type = 'offline' AND properties.$ai_experiment_name = 'signals-grouping/match-quality' AND properties.$ai_metric_name = 'correct_match' GROUP BY failure_mode ORDER BY cnt DESC

按来源统计 pre-emit 可操作性(对应报告第五张表):

SELECT replaceOne(properties.$ai_experiment_name, 'signals-grouping/', '') AS check_name, count() AS total, countIf(properties.$ai_score = 1.0) AS correct, countIf(properties.$ai_score != 1.0) AS failures, round(countIf(properties.$ai_score != 1.0) * 100.0 / count(), 1) AS failure_pct, countIf(properties.$ai_score != 1.0 AND properties.$ai_output = 'ACTIONABLE') AS false_positives, countIf(properties.$ai_score != 1.0 AND properties.$ai_output = 'NOT_ACTIONABLE') AS false_negatives FROM events WHERE event = '$ai_evaluation' AND properties.$ai_eval_source = 'signals-grouping' AND properties.$ai_evaluation_type = 'offline' AND properties.$ai_experiment_name IN ( 'signals-grouping/zendesk-actionability-check', 'signals-grouping/github-actionability-check', 'signals-grouping/linear-actionability-check' ) AND properties.$ai_metric_name = 'correct_classification' GROUP BY check_name ORDER BY check_name

此外还有报告级裁判、逐报告分组质量、特异性判断器影响(对比correct_match_pre_specificitycorrect_match)以及详细失败样本等查询,完整清单见 AGENTS.md 的 "HogQL queries" 一节——这正是把 03-16 这种快照报告转化为可持续监控手段的桥梁。

九、基线定位:本次运行在迭代脉络中的位置

将 03-16 报告与仓库中后续报告对比,可以更准确地定位这次运行的水平(以下数字均来自对应报告文件本身):

维度2026-03-162026-03-17说明
ARI0.7060.754+0.048
Completeness0.9070.932+0.025
Mean group recall0.6790.775+0.096
Malicious leaked5/240/24泄漏清零
Match accuracy76.0%82.1%+6.1pp
Safety accuracy90.7%100%+9.3pp
Actionability acc64.8%81.1%+16.3pp

其中 03-17 报告特别注明"Safety judge 从 90.7% 提升到 100.0%(对照 03-16)",且其match-quality表中不再出现 SPECIFICITY_SPLIT 单独列(合并进了 UNDERGROUP),说明特异性判断器行为在两次运行之间发生了调整。这正好印证了 03-16 报告最大的诊断价值:它通过 SPECIFICITY_SPLIT 的 13/19 占比,把"特异性校验过度拆分"这一根因显式暴露出来,为后续迭代提供了明确靶点

十、总结

2026-03-16 报告是 PostHog Signals 分组管线一次信息密度很高的离线评估快照,其价值体现在三个层面:

  1. 量化了管线的当前水位:ARI 0.7059、同质性 0.9923、完整性 0.9065、恶意泄漏率 5/24,以及仅 64.8% 的 Actionability 裁判准确率,构成了清晰的改进基线。
  2. 定位了主要失败模式:18.3% 的欠聚合中 68.4% 来自特异性判断器拆分(SPECIFICITY_SPLIT),而非 matcher 本身;全部可操作性错误均为假阳性、无假阴性。
  3. 沉淀了可复现、可持续的观测方式:通过 eval_grouping_e2e.py 可复跑,通过 AGENTS.md 中的 HogQL 查询可持续监控每一轮迭代。

对于任何从事"LLM 驱动的在线聚类/工单归并"类系统的工程师,这份报告连同其评估框架(真实管线 + mock 基础设施 + 固定种子信号流 + 分级指标体系)都是一个值得参考的离线评估范式。

【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询