PostHog MCP Analytics 意图聚类实战指南:从 Agent 目标聚类到工具可发现性诊断
【免费下载链接】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
意图聚类(Intent Clustering)是 PostHog MCP Analytics 中回答"Agent 到底想用 MCP 做什么、做得成不成"的核心能力:它把 Agent 调用工具时携带的自由文本$mcp_intent向量化后按语义相似度分簇,再从"调用工具"的视角反转出一个工具中心视图,回答"我的工具被 Agent 找到了吗、和谁竞争、服务得怎么样"。本文将以 PostHog 开源仓库中products/mcp_analytics/skills/exploring-mcp-intent-clusters/SKILL.md为骨架,结合 intent_clustering.py 的源码实现,完整讲解快照结构、两个 MCP 工具的调用工作流、可发现性分析方法、覆盖率读法与重新计算的工程细节。
什么是意图聚类:从"调了哪个工具"到"想达成什么目标"
聚类流水线读取 Agent 每次工具调用($mcp_tool_call事件)上携带的自由文本$mcp_intent(Agent 用自然语言陈述的目标),对其进行向量化嵌入(embedding),并将语义相近的目标归入同一簇。它回答的是"人们在尝试做什么,并且做成没有?"(what are peopletryingto do, and does it work?),而不是"哪个工具被调用了"。
其归因(attribution)是按调用(per call)进行的:每一次调用都被记到它自己携带的 intent 名下;没有携带 intent 的调用则继承同一会话中最近一次出现的 intent(last observation carried forward,LOCF)。因此一个工具的计数反映的是它实际服务的目标,而不是会话开场白。每个簇携带自己的工具分布(tool distribution)、调用次数与错误率。
快照还附带一个工具中心视图(tool-centric pivot),反转回答同一个问题:对于给定的工具,是哪些 intent 在驱动它的使用?Agent 多久能找到它?它和谁竞争?
与工具质量(tool quality)和会话(sessions)这类最终聚合$mcp_tool_call的指标不同,聚类需要 embedding 计算,无法用 SQL 表达,因此由两个类型化 MCP 工具基于一个持久化的快照(stored snapshot)提供。
两个核心工具
| 工具 | 用途 |
|---|---|
posthog:mcp-analytics-intent-clusters-retrieve | 拉取项目最新的聚类快照 |
posthog:mcp-analytics-intent-clusters-recompute | 触发一次异步重新计算 |
从 tools.yaml 可以看到两者的注册差异:retrieve只读、幂等(readOnly: true、idempotent: true),需要mcp_analytics:read权限;recompute可写、非幂等,需要mcp_analytics:write权限,且requires_ai_consent: true(重算会驱动 embedding 服务产生外部调用,需要 AI 使用同意)。两者都挂在mcp-analyticsfeature flag 下,url_prefix为/mcp-analytics。
工作流一:读取当前聚类快照
posthog:mcp-analytics-intent-clusters-retrieve {}返回的快照包含status、last_computed_at、computed_with(embedding 模型、聚类参数与样本覆盖率百分比)、一个clusters数组、一个tools数组(工具中心视图)以及tool_overlaps。
簇(cluster)字段解读
每个簇携带以下字段:
label:簇的标签(取簇内 medoid,即离质心最近的 intent 文本);intent_count/call_count/error_count/error_rate_pct;routing_entropy:该簇工具分布的归一化香农熵,取值 [0, 1];tool_distribution:该目标路由到哪些工具,含每个工具在簇内的占比与各自的错误率;sample_intents:簇内代表性 intent 样本(每条簇最多 3 条);switches:出错调用后紧接着换用另一个工具的记录——这是"Agent 把这些工具搞混了"的最强证据;self_retries:出错调用后紧接着用同一个工具重试的记录——说明该工具的错误信息没能帮助 Agent 自我纠错。
从 intent_clustering.py 的build_snapshot可以看到这些字段的精确生成方式:label取 medoid intent(_medoid_index,按余弦距离取最接近质心的样本);tool_distribution按调用量降序排列并计算pct与每个工具的error_rate_pct;sample_intents取簇内频率最高的前 3 条。簇最终按call_count降序排序,且只有调用量最高的前MAX_SNAPSHOT_CLUSTERS = 100个簇(见 constants.py)会被持久化进快照,computed_with.n_clusters保留的是全部簇数量,供 UI 说明实际找到了多少簇。
如何阅读簇
- 按
call_count排序阅读,回答"Agent 主要在做什么"; - 按
error_rate_pct阅读,回答"哪些目标在失败"——某个簇的错误率高,指向一类工具服务得很差的目标(a class of agent goals the tools serve badly)。
routing_entropy描述簇内工具使用的分散程度:低熵意味着一个目标稳定地映射到一个工具;高熵意味着 Agent 在为该目标四处寻找正确的工具(通常是能力缺失的信号)。源码中_routing_entropy的实现在 intent_clustering.py:它计算工具分布的香农熵并除以log(工具数)归一化,单工具簇熵为 0。
工作流二:用工具中心视图回答"我的工具可被找到吗"
tools数组中的每个条目携带:
clusters:该工具服务的 intent 簇列表,每个簇条目含:capture_pct:该工具在簇调用中的份额;rank:该工具在簇内按调用量的排名;top_competitor:最强的竞争工具及其份额;description_fit:工具描述与簇质心之间的余弦相似度;在描述尚未被捕获前为null。注意:工具条目只携带cluster_id,不携带簇自身的 label 或总量——需要按 id 与顶层clusters数组 join。
n_clusters_served:该工具总共服务的簇数量。工具条目列表是有上限的(默认MAX_CLUSTERS_PER_TOOL = 20),因此在说"这个工具服务 N 个 intent"之前,必须先用这个字段核对真实数量。discovery_rate_pct:在被抽样的会话中,$mcp_tools_list目录里广告过该工具的会话里,实际调用它的比例;当该工具在不足 5 个被广告的会话中出现时(MIN_ADVERTISED_SESSIONS = 5,见 intent_clustering.py),该值为null(样本太小,视为噪声)。contested_score:工具各簇的按调用量加权的平均熵——衡量该工具的 intent 与其他工具被拆分的频率。
可发现性失败模式的判读
- 高
description_fit+ 低capture_pct= 可发现性失败:Agent 本应为了该目标找到这个工具,却选了别的东西; - 低
description_fit+ 高capture= 描述低估了工具实际做的事(description undersells what the tool actually does)。
tool_overlaps列出在相同 intent 上竞争的成对工具;用sessions_with_both对比sessions_with_either来区分工作流(两个工具在同一会话里配合使用)与混乱(会话二选一)。从源码看,contested_calls是每个簇上min(calls_a, calls_b)的累加,即两个工具"都有可能接走的调用量"(compute_tool_overlaps),对对的会话计数则从calls_by_session中直接统计;配对展开是 O(n²) 的,所以每个簇只取调用量最高的前MAX_OVERLAP_TOOLS_PER_CLUSTER = 20个工具进入配对,且配对数量上限MAX_CONFUSION_PAIRS = 50。
引用数字前先读覆盖率
computed_with中的以下字段决定了你能多严肃地引用这些数字:
sampled_sessions/session_coverage_pct:语料占整个时间窗口的比例;advertisement_coverage_pct:限制了可发现率能"看到"的范围——只有观测到 tools-list 目录的会话才会进入可发现率的分母,而 exec-wrapper 模式下会话只广告 wrapper 工具,因此按工具的发现率是在全目录(full-catalog)会话上测得的。
从 build_snapshot 的meta组装可以看到完整的覆盖率字段清单:session_coverage_pct、intent_coverage_pct(窗口内携带 intent 的调用占比)、imputed_call_pct(LOCF 继承的调用占比)、unattributed_call_pct、corpus_call_coverage_pct、advertisement_coverage_pct、description_coverage_pct,以及sampling_warning——它明确声明:每工具捕获率与可发现率是样本统计量(sample statistics),不是总体真实值,因为快照来自按工具分层抽样的会话(per-tool floors,主导工具被设上限)。
computed_with不是完整性检查
computed_with并不对一切负责。只有顶层工具与重叠对的上限会通过dropped_tools和dropped_overlap_pairs报告丢弃量;每个簇内的列表是静默截断的(MAX_SWITCHES_PER_CLUSTER = 10、MAX_SELF_RETRIES_PER_CLUSTER = 5),所以看到一个簇显示 10 条 switches 或 5 条 self-retries,应理解为"至少这么多",而非"恰好这么多"。工具的簇条目同样被截断,但那里n_clusters_served给出了真实数量。
聚类只看事件,不读会话摘要
聚类只读取事件。按需生成的会话摘要(MCPSession.intent,即 "generate intent" 写入的内容)被刻意排除:摘要描述的是整个会话,把它摊到该会话的每次调用上,正是逐调用语料(per-call corpus)要消除的错误归因。因此,一个只有摘要 intent、从未在事件上记录过 intent 的会话不会出现在任何簇中——检查intent_coverage_pct看窗口内因此被遗漏的比例,需要时直接读会话摘要(见 exploring-mcp-sessions)。
工作流三:处理空快照或过期快照
- 空 / 空闲且无簇(
status: idle,clusters: []):还没有运行过任何一次聚类。触发一次重算(见下),并告诉用户它在后台计算。 last_computed_at过期:建议重新计算。
注意 empty_snapshot 的细节:一个"流量很大但没有任何可归因 intent"的窗口,与一个"完全没有流量"的窗口,返回的空快照并不相同——前者intent_coverage_pct会如实给出"0% 的调用携带 intent"这个可行动的信息,后者则全是null。
工作流四:触发重新计算
posthog:mcp-analytics-intent-clusters-recompute {}该调用立即返回status: computing(HTTP 202),实际工作在后台运行。随后轮询posthog:mcp-analytics-intent-clusters-retrieve直到status回到idle(完成)或error。不要阻塞等待——告诉用户一分钟后再来问。
重算在工程上受到节流:每个项目同一时刻只允许一次运行;已在计算中时再收到 202 只是确认了进行中的那次运行。后台的真实执行是一个 Temporal 工作流:管理命令 cluster_mcp_intents.py 用于手动端到端验证,它会启动一次DailyIntentClusteringWorkflow执行并等待其完成,再打印快照(--team-id必填,--lookback-days默认用任务默认值 7 天,--raw输出原始 JSON)。流水线本身由 intent_clustering.py 顶部的 docstring 说明:它是一个个纯函数(pure functions),每个阶段都可独立测试,Temporal activity 负责编排并持久化结果——因为算法是整个特性风险最高的部分,保持纯函数可以在不触碰 ClickHouse、Postgres 或 embedding 服务的情况下验证算法。
底层流水线:从采样到快照的五步
从源码可以还原完整的重算链路(每一步都有对应的纯函数与 SQL):
- 分层采样(stratified sampling):
sample_corpus_sessions用cityHash64(session_id)做确定性伪随机排序采样(L220-L229),保证可复现、可复用 embedding 缓存;fetch_tools_by_session+stratify_session_ids+select_corpus_sessions确保低/中流量工具(logs/tracing/metrics)不被主导工具(exec/scout)的流量"抹掉"——每个工具至少保留MIN_SESSIONS_PER_TOOL = 400个会话(约等于把捕获率读到 ±5% 的统计下限),而任何工具贡献的调用不超过MAX_CALLS_PER_TOOL = 1500,语料总预算MAX_CORPUS_SESSIONS = 6000。 - 归因(attribution):
build_call_corpus逐调用把 intent 归属到调用,缺失时 LOCF 继承同会话最近的 intent,并按频率截取前DEFAULT_TOP_N_INTENTS = 1000条(L682-L759)。 - 嵌入(embedding):
embed_texts_async用text-embedding-3-small-1536模型(EMBEDDING_MODEL,L59),intent 以"User intent: "前缀、工具描述以"Tool description: "前缀分别缓存(MCPIntentEmbeddingCache),并发上限EMBED_CONCURRENCY = 20;嵌入失败逐条吞掉但记录聚合告警。 - 聚类:
cluster_embeddings使用 sklearn 的AgglomerativeClustering,余弦距离 + 平均链接(average linkage),距离阈值DEFAULT_DISTANCE_THRESHOLD = 0.2(越小簇越紧、簇数越多,是用户可调的旋钮),不产生噪声哨兵(L985-L1007)。 - 快照组装:
build_snapshot聚合出簇、工具中心视图、重叠对与computed_with元信息,作为一个 JSONB blob 持久化到 Postgres(MCPIntentClusterSnapshot模型,迁移见 0004_mcpintentclustersnapshot.py),SNAPSHOT_VERSION = 2。
每个阶段都有对应测试:见 test_intent_clustering.py。前端聚类界面在 frontend/clustering/MCPAnalyticsClustering.tsx,包含簇面板、工具中心面板与重叠表等组件。
构造 UI 链接
- 意图聚类页面:
https://app.posthog.com/project/<project_id>/mcp-analytics/intent-clustering
实用提示
- 簇的好坏取决于
$mcp_intent覆盖率:如果很少有调用携带 intent,簇会稀疏。可用下面的 HogQL 快速交叉核对覆盖率(在$mcp_tool_call上):
countIf(toString(properties.$mcp_intent) != '')- 高
error_rate_pct+ 高routing_entropy的簇是最强的"这些工具服务不好这个目标"信号,值得深入查看它的sample_intents和tool_distribution。 - 重算被节流为每个项目一次运行;计算中再次收到 202 只是确认进行中的运行。
- 采样诚实性:
computed_with.sampled = true、corpus_strategy = "stratified_by_tool",任何下游在使用每工具的捕获率/可发现率时必须警告这是平衡样本(balanced sample)而非总体统计。
相关技能
- exploring-mcp-tool-quality——每工具的错误率与延迟;
- exploring-mcp-sessions——intent 背后的单个运行明细。
【免费下载链接】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),仅供参考