PostHog 信号分组流水线端到端评测(Signal Grouping Eval)实战指南
发布时间:2026/9/20 4:53:43 作者:尧图编辑部 阅读量:1,286
实战指南)
数据分析后端前端数据可视化大数据【免费下载链接】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点击查看免费下载导读本文围绕 PostHog 仓库中 products/signals/eval/AGENTS.md 所定义、并由 eval_grouping_e2e.py 实现的信号分组端到端评测Signal Grouping Eval展开讲解如何用 111 条合成信号来自 48 个带标注的真值分组驱动真实的信号分组流水线量化其把海量流入信号聚类成报告Report的质量并与人工标注的分组进行对照。读完本文你将掌握该评测的完整运行方式命令行、环境变量、CLI 选项、被测流水线的四阶段架构Pre-emit → Match → Persist → Judge、六类评测实验的指标语义以及如何用 PostHog SQL 编辑器中的 HogQL 查询分析评测结果从而在自己的环境里复跑、比较模型、定位分组失败模式。一、评测目标它到底在测什么信号分组流水线的职责是把来自 Zendesk、GitHub、Linear、错误跟踪error tracking等异构来源的信号Signal实时聚类为可行动的报告Report——同一根因或同一受影响功能的信号应归入同一报告。该评测回答一个核心问题流水线聚类出的报告与人工标注的真值分组ground-truth groups相比有多接近评测的关键设计原则是真实流水线 模拟基础设施流水线是真实的LLM 查询生成、Embedding 检索、LLM 匹配、特异性验证specificity verification、摘要、安全判定、可行动性判定等全部走生产代码路径基础设施是模拟的mock.py 中的内存版EmbeddingStore替代 ClickHouse KafkaReportStore替代 Postgres使评测可以脱离外部存储快速运行、且结果可复现。信号以确定性随机顺序到达——common.py 中使用固定种子RNG_SEED 1337的随机数生成器将各分组的信号交错混排保留组内顺序的同时模拟真实世界的到达模式保证每次运行的数据流完全一致。二、被测流水线每个信号的四个阶段依据 eval_grouping_e2e.py 的run_signal_pipeline实现每个信号依次经过以下阶段1. Pre-emit发射前过滤若信号配置了摘要阈值先调用生产代码中的summarize_long_descriptions来自 emission/pipeline.py压缩过长描述再调用check_actionability判断是否可行动Claude Haiku 经由内部 LLM Gateway不可行动的信号在此被丢弃pre_emit返回None即触发signal_dropped。2. Match匹配用 LLM 生成 13 条搜索查询generate_search_queries用 OpenAI 对查询与信号分别生成 Embedding评测中固定使用text-embedding-3-small见 mock.py对每条查询做余弦相似度检索召回候选信号EmbeddingStore.search默认返回 top-10用 LLM 决定该信号应加入既有报告还是新建报告match_signal_to_report若匹配到既有报告再用 LLM 做特异性验证verify_match_specificity判断新信号与目标报告的标题、既有信号是否足够具体地属于同一问题。若特异性不足则把该信号拆分为一个新报告NewReportMatch标题取描述首行summary 标记为Split from group: ...。3. Persist持久化将信号内容 Embedding 写入内存EmbeddingStore模拟 ClickHouse 写入更新ReportStore中的报告元数据标题、信号计数与生产 workflow 的 batch 逻辑一致。4. Judge报告级判定全部信号处理完后对每个报告做 LLM 摘要安全判定judge_report_safety用于检测提示注入可行动性判定report_actionability。值得注意的是评测还会在 Pre-emit 与 Persist 之间插入生产代码中的safety_filter来自 temporal/safety_filter.py对不安全的信号直接拦截见 eval_grouping_e2e.py。三、如何运行评测3.1 运行命令# 完整运行 —— 将评测结果上报到 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评测的 pytest 配置位于 pytest.ini它约定只收集eval_*.py文件、eval_*函数与Eval*类评测不同于测试不追求 pass/fail并默认开启asyncio_mode auto与-xvs --log-cli-levelINFO等选项。3.2 必需环境变量所有变量在仓库根目录的.env中设置由 conftest.py 通过load_dotenv自动加载变量用途OPENAI_API_KEY生成 Embeddingtext-embedding-3-smallLLM_GATEWAY_URL内部 LLM Gateway 基础 URL所有 LLM 调用匹配、特异性、摘要、可行动性、安全LLM_GATEWAY_PERSONAL_API_KEYLLM Gateway 的 Bearer TokenPostHog 个人 API KeySIGNALS_EVAL_TEAM_IDLLM 成本归属cost attribution头中使用的 Team id默认1POSTHOG_PROJECT_API_KEY上报评测结果配合--no-capture可跳过POSTHOG_HOSTPostHog 实例地址默认http://localhost:8010源码层面还可以看到若未设置POSTHOG_PROJECT_API_KEYconftest 会自动创建一个 Eval Org / Eval Team 并取用其 API token见 conftest.pyLLM_GATEWAY_API_KEY会回退读取LLM_GATEWAY_PERSONAL_API_KEY。EVAL_TEAM_ID被封装为MagicMock(id...)的轻量 Team 替身供流水线辅助函数只读.id使用。3.3 CLI 选项Flag作用--limit N只处理信号流中的前 N 条信号--no-capture跳过向 PostHog 发送$ai_evaluation事件--online将捕获的结果标记为在线评测默认 offline--strategy策略模块名conftest 保留选项默认example_strategy--safe只保留安全信号并跳过 safety_filter 步骤四、源码视角评测编排与并发模型4.1 编排类EvalGroupingPipelineeval_grouping_e2e.py 中的EvalGroupingPipeline是评测中枢pytest fixture 注入posthog_client、openai_client、gateway_client、mock_temporal与 CLI 选项随后在eval_grouping_pipeline中读取信号流、按信号逐个驱动流水线、完成报告判定并捕获指标。其内部实现有几个值得注意的细节查询与 Embedding 的准备独立于锁外_preparegenerate_search_queries与全部embed调用不依赖存储状态因此可以跨信号并发执行匹配 持久化串行化_match与_persist_signal必须持有asyncio.Lockself._match_lock保证 EmbeddingStore 与 ReportStore 在加入既有报告或新建报告的决策瞬间看到一致视图失败重放任一阶段抛错时若尝试次数小于TRANSPORT_RETRIES 3按2**attempt指数退避后重放整条信号。注释明确指出断连若被静默吞掉会悄悄缩小数据集在两次运行对比时会误读为分组差异由于只有最后一步才持久化重放是安全的。4.2 并发模型文档与源码共同确认的并发边界信号以asyncio.Semaphore(MAX_CONCURRENT_RUNS)并发跑流水线MAX_CONCURRENT_RUNS 70定义于 common.pyMatch Persist 步骤被asyncio.Lock串行化报告判定阶段所有报告一次性并发执行asyncio.gather。4.3 模拟存储mock.pyEmbeddingStore内存向量存储embed()通过 AsyncOpenAI 生成真实 Embedding并写入磁盘缓存 cache/embeddings.json先写临时文件再原子替换避免中断运行留下截断文件search()做余弦距离排序返回 top-k 候选get_type_examples()为每个(source_product, source_type)返回一条示例信号供 LLM 查询生成时参考。ReportStore内存报告库维护ReportContextreport_id、title、signal_count与真值分组标签find_report_by_group_index用于找出与某真值组重叠最多的报告作为匹配正确性的判据。4.4 数据规格与真值data_spec.py 定义EvalSignalSpec单条合成信号来源、标题、正文经真实 emitter 渲染为SignalEmitterOutput与EvalGroupSpec场景、信号列表、可行动性/安全性标签。错误跟踪信号走特殊渲染路径描述格式与 cymbal 的signals.rs保持一致。真值数据在 fixtures/grouping_data.py48 个分组、111 条信号覆盖 Zendesk/GitHub/Linear/error tracking既有混合来源的同组信号例如日期选择器时区偏移一天由 Zendesk GitHub 各一条信号构成也有跨产品边界的难点场景。五、评测产出进度条与六类评测实验5.1 进度输出stderrMatching进度条逐信号推进postfix 显示processing在途与filtered被过滤/失败计数Judging进度条逐报告推进随后输出聚合结果摘要表ARI、Homogeneity、Completeness、Mean purity、Mean recall、Malicious leaked该摘要由_capture_aggregate_metrics写入 stderr见 eval_grouping_e2e.py。5.2 上报到 PostHog 的评测指标所有指标以$ai_evaluation事件上报eval_source signals-grouping事件格式见 capture.py 的capture_evaluation每个指标展开为带$ai_metric_name、$ai_score、$ai_reasoning、$ai_input、$ai_output、$ai_expected等属性的独立事件$ai_experiment_name统一加signals-grouping/前缀$ai_evaluation_type为online/offline。共五个评测实验实验粒度指标match-quality逐信号correct_match二值、correct_match_pre_specificity二值、失败模式 NONE/UNDERGROUP/OVERGROUP、query_diversity数值余弦距离、candidate_diversity数值1 − Jaccard{source}-actionability-check逐信号correct_classification二值——Pre-emit 过滤是否与真值一致grouping-quality逐报告purity、is_pure、group_recallreport-safety-check逐报告correct_classification二值——安全判定 vs 真值report-actionability-check逐报告correct_classification二值——可行动性判定 vs 真值grouping-aggregate全局ari、homogeneity、completeness、mean_purity、group_recall、malicious_leaked_rate5.3 失败模式与多样性指标的定义从_capture_match_quality源码eval_grouping_e2e.py可以看到各指标的精确定义失败模式预期应新建报告却被匹配到既有报告 OVERGROUP过度聚合预期应加入既有报告却被新建 UNDERGROUP聚合不足正确匹配 NONEquery_diversity查询 Embedding 两两余弦距离的均值0 完全相同1 正交衡量 LLM 生成查询的检索视角多样性candidate_diversity各查询候选信号集合两两之间1 − Jaccard的均值0 完全重叠1 完全不相交衡量不同查询召回结果的互补性。5.4 聚合指标解读指标含义ARI调整兰德指数剔除随机性后的聚类相似度取值 -1 到 11 表示与真值分组完全一致Homogeneity每个报告只包含来自同一真值组的信号1.0 无过度聚合Completeness某个真值组的所有信号都落入同一报告1.0 无聚合不足Mean purity每个报告中主导组信号占比的平均值Mean recall某组的信号被其最佳报告捕获比例的平均值Malicious leaked rate不安全信号未在 Pre-emit 被拦截、也未被报告安全判定拦下的比例其中malicious_leaked_rate的计算逻辑是先汇总流内所有不安全信号总数再统计被安全判定判定为安全safety_choice is True的报告中所含不安全信号数二者相除见 eval_grouping_e2e.py。六、用 HogQL 查询分析评测结果所有查询都基于$ai_eval_source signals-grouping与$ai_evaluation_type offline过滤请在 PostHog SQL 编辑器SQL Editor中运行。6.1 聚合指标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 metric6.2 匹配质量失败模式分布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 DESC6.3 特异性判定的影响对比特异性判定前后的正确性量化该环节预防过度聚合prevented overgroup/ 引发聚合不足caused undergroup/ 无影响的频率SELECT multiIf( pre.score 1.0 AND post.score 1.0, no_effect_correct, pre.score 0.0 AND post.score 0.0 AND pre.reasoning post.reasoning, no_effect_wrong, pre.score 0.0 AND post.score 1.0, prevented_overgroup, pre.score 1.0 AND post.score 0.0, caused_undergroup, pre.score 0.0 AND post.score 0.0, changed_failure_mode, unknown ) AS specificity_impact, count() AS cnt FROM ( SELECT properties.$ai_experiment_item_name AS item, properties.$ai_score AS score, properties.$ai_reasoning AS reasoning 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_pre_specificity ) pre JOIN ( SELECT properties.$ai_experiment_item_name AS item, properties.$ai_score AS score, properties.$ai_reasoning AS reasoning 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 ) post ON pre.item post.item GROUP BY specificity_impact ORDER BY cnt DESC6.4 查询与候选多样性SELECT properties.$ai_metric_name AS metric, count() AS n, round(avg(properties.$ai_score), 3) AS mean, round(min(properties.$ai_score), 3) AS min, round(max(properties.$ai_score), 3) AS max 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 IN (query_diversity, candidate_diversity) GROUP BY metric ORDER BY metric6.5 按来源统计 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_name6.6 报告级判定安全 可行动性SELECT replaceOne(properties.$ai_experiment_name, signals-grouping/, ) AS judge, count() AS total, countIf(properties.$ai_score 1.0) AS correct, round(countIf(properties.$ai_score 1.0) * 100.0 / count(), 1) AS accuracy_pct, countIf(properties.$ai_score ! 1.0 AND properties.$ai_output IN (SAFE, IMMEDIATELY_ACTIONABLE)) AS false_positives, countIf(properties.$ai_score ! 1.0 AND properties.$ai_output NOT IN (SAFE, IMMEDIATELY_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/report-safety-check, signals-grouping/report-actionability-check ) AND properties.$ai_metric_name correct_classification GROUP BY judge ORDER BY judge6.7 逐报告分组质量分布SELECT properties.$ai_metric_name AS metric, count() AS n, round(avg(properties.$ai_score), 3) AS mean_score, round(min(properties.$ai_score), 3) AS min_score, round(max(properties.$ai_score), 3) AS max_score, countIf(properties.$ai_score 1.0) AS perfect_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/grouping-quality GROUP BY metric ORDER BY metric6.8 详细的匹配失败清单用于调试SELECT properties.$ai_experiment_item_name AS item, properties.$ai_reasoning AS failure_mode, properties.$ai_input AS signal_description, properties.$ai_expected AS expected, JSONExtractString(properties.$ai_output, report) AS actual_decision 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 AND properties.$ai_score ! 1.0 ORDER BY properties.$ai_reasoning, item七、清理评测数据评测会向 ClickHouse 写入$ai_evaluation事件清理命令为 clear_eval_data.py仅在DEBUGTrue时可用默认按$ai_eval_source signals-grouping过滤并同时清理sharded_events与sharded_events_recent两张表python manage.py clear_eval_data --dry-run # 预览将删除的条数 python manage.py clear_eval_data --yes # 跳过确认直接删除 python manage.py clear_eval_data --source X # 按评测来源标签过滤从源码看--yes缺省时会交互式要求输入yes确认删除使用 ClickHouseALTER TABLE ... DELETEmutations_sync1并随后校验残留。注意该命令执行的是真实删除请先在开发/测试实例上使用--dry-run预览。八、文件结构速查文件用途eval_grouping_e2e.py测试类、流水线编排、指标捕获conftest.pypytest fixturesAPI 客户端、CLI 选项、mock temporalmock.pyEmbeddingStore内存向量库与ReportStore内存报告库capture.pycapture_evaluation()辅助函数格式化并发送$ai_evaluation事件common.py信号流生成种子 RNG、进度条、失败模式枚举、并发上限data_spec.pyEvalSignalSpec/EvalGroupSpec信号与分组规格fixtures/grouping_data.py真值48 组、111 条信号覆盖 Zendesk/GitHub/Linear/error trackingcache/embeddings.jsonOpenAI Embedding 磁盘缓存自动生成避免重复 API 调用pytest.ini评测专用 pytest 配置收集规则、Django 设置、asyncio 模式九、实战经验一份真实评测报告的读法reports/2026-09-03.md 是这套评测在真实项目中的使用范例——它对比claude-sonnet-4-5与claude-sonnet-5两代模型每个模型驱动全部 LLM 阶段各跑两轮。从该报告可以学到如何解读评测输出聚合指标看趋势、看方差同模型两轮 ARI 差 0.04与两模型均值差相当结论是在该样本量下最终分组质量打平分阶段看差异原始匹配器是两模型拉开差距的唯一环节sonnet-5 过度聚合次数约为 4-5 的一半但特异性判定在 sonnet-5 上预防 35 次过度聚合、却制造 46 次聚合不足净效果为负从而抵消了匹配器优势——这正是调优或门控特异性判定是把匹配增益转化为分组增益的杠杆这一结论的来源失败模式分布CORRECT占比约 80%85%UNDERGROUP约 1013 条、OVERGROUP约 34 条可行动性误报所有失败均为假阳性把不可行动判为可行动没有可行动信号被误丢安全指标信号安全过滤器与报告安全判定均全对恶意信号泄漏率为 0成本与延迟报告还统计 LLM 调用数、输入/输出 token、清单价成本、p50/p95 延迟并发现 sonnet-5 查询生成在 70% 的信号上触发 schema 重试返回 45 条查询而QueryGenerationResponse只接受 1 条以上但调用方保留 3 条由此催生了查询 schema 不设上限、由调用方截取前三条的修复合入方案。这类报告展示了评测的另一层价值不仅测分组质量还能横向对比模型、量化每个 LLM 阶段的成本/延迟/失败模式并指导流水线配置迭代如 thinking effort、特异性判定规则等。十、适用前提与限制评测依赖外部 APIOpenAIEmbedding与内部 LLM Gateway所有 LLM 阶段需要相应密钥与网络可达基础设施ClickHouse/Kafka/Postgres/Temporal被 mock因此不覆盖生产环境的存储一致性、消息顺序、Temporal 重试等行为报告级安全判定的真值标签来自分组数据GROUP_DATA[g].safeeval_scout_safety.py 与 experiments/ 目录还提供了针对安全过滤器对抗攻击如2026-09-safety-filter-manipulation实验的attack_fixtures.jsonl的补充评测维度结果受并发调度顺序影响锁获取顺序在运行间变化报告中两轮运行的 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点击查看免费下载相关推荐PostHog Signals 后端流水线管理命令实战信号注入、分组调度与 Scout 巡检的端到端调试PostHog Signals 后端流水线管理命令实战信号注入、分组调度与 Scout 巡检的端到端调试 导读 本文以 PostHog 仓库中 product数据分析后端前端数据可视化大数据PostHog Signals 流水线本地端到端调试指南从测试信号发射到 Temporal 工作流与 Docker 沙箱排查PostHog Signals 流水线本地端到端调试指南从测试信号发射到 Temporal 工作流与 Docker 沙箱排查 导读 当 PostHog Sig数据分析后端前端数据可视化大数据TanStack Alpine Table 分组Grouping指南从分组状态到客户端/服务端分组实战TanStack Alpine Table 分组Grouping指南从分组状态到客户端/服务端分组实战 本文是 TanStack 表格体系React T前端UI组件上一篇拯救训练效率5个技巧掌握余弦退火与线性衰减学习率调度终极指南下一篇Dify 工作流完整指南从模板到跑通10 分钟搭出你的第一个 AI 自动化应用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考