Sentry 前端埋点数据查询实战:基于 Amplitude MCP 的事件发现与查询工作流
本文以 Sentry 仓库中 Agent 技能文档 references/amplitude-mcp.md 为核心,完整讲解如何通过 Amplitude MCP(Model Context Protocol)回答"有多少人使用某功能"这类产品数据问题:从一次性连接配置、Amplitude 项目发现,到 search、get_properties、query_dataset 的完整调用链,并结合 static/app/utils/analytics/ 下的事件定义源码,说明事件名(eventName)是如何从代码一路流入 Amplitude 的,以及 MCP 未连接时如何用代码库兜底。
读完本文,你将掌握:
- Amplitude MCP 的连接方式与
claude.ai Amplitude工具的发现流程; - 一套可复用的"找事件 → 查属性 → 跑查询 → 报结果"四步工作流,含完整参数示例;
- Sentry 前端埋点事件从
trackAnalytics到 Amplitude 的完整链路(事件键 → 事件名映射 → 双通道上报),以及为什么 Reload-only 事件在 Amplitude 里搜不到; - 常见数据问题(页面浏览量、点击量、漏斗、留存)到 Amplitude 查询参数的映射表。
一、前置知识:Sentry 的埋点事件如何进入 Amplitude
在讲 MCP 查询之前,先理解查询目标——Amplitude 中的事件名——在 Sentry 代码里长什么样。这一点决定了为什么 search 要按 eventName 搜索,以及为什么有些事件搜不到。
Sentry 前端所有埋点都经由统一入口 trackAnalytics 发出。它由工厂函数 makeAnalyticsFunction 基于"事件键 → Amplitude 显示名"的映射表生成,定义在 analytics.tsx:
// static/app/utils/analytics.tsx
interface EventParameters extends CommandPaletteEventParameters, /* …几十个领域事件类型 */ {}
const allEventMap: Record<string, string | null> = {
...commandPaletteEventMap,
...feedbackEventMap,
...issueEventMap,
...seerAnalyticsEventsMap,
/* … */
};
export const trackAnalytics = makeAnalyticsFunction<EventParameters>(allEventMap);
makeAnalyticsFunction.tsx 的核心逻辑是:调用 trackAnalytics('issue_details.seer_opened', params) 时,先查 eventKeyToNameMap[eventKey] 得到 eventName,再与 eventKey 一起打包传给 rawTrackAnalyticsEvent。每个业务域在 static/app/utils/analytics/ 下维护一份 {domain}AnalyticsEvents.tsx 文件,同时定义事件参数类型(*EventParameters)和名称映射表(*EventMap)。例如 Seer / Autofix 域:
// static/app/utils/analytics/seerAnalyticsEvents.tsx
'issue_details.seer_opened': 'Issue Details: Seer Opened', // 在 workflowAnalyticsEvents.tsx 中定义
'seer.explorer.session_created': 'Seer Explorer: Session Created',
注意:
issue_details.*这批事件实际定义在 workflowAnalyticsEvents.tsx,映射值为'issue_details.seer_opened': 'Issue Details: Seer Opened'——这正是本文后面所有 MCP 查询示例使用的事件名。
三通道事件管线
事件发出后走的是 GetSentry 的 override 实现 rawTrackAnalyticsEvent.tsx,它决定了事件最终到达哪些分析后端:
| 目的地 | 触发条件 | 使用字段 | 查询方式 |
|---|---|---|---|
| Reload(内部后端) | 只要传了 eventKey 就上报 |
eventKey |
Redash |
| Amplitude | eventName 非空 且 organization_id 可解析 |
eventName |
Amplitude UI 或 MCP |
| Pendo | 与 Amplitude 相同 | eventName |
Pendo |
源码中有两处关键门槛值得注意(rawTrackAnalyticsEvent.tsx):
if (eventKey) {
const reloadData = { user_id: ..., org_id: organization_id, allow_no_schema: true, ...data };
trackReloadEvent(eventKey, reloadData); // 总是上报 Reload
}
if (eventName && organization_id !== undefined) {
trackAmplitudeEvent(eventName, organization_id, dataWithUrl, {time});
trackPendoEvent(eventName, data);
}
- 事件名映射为
null的事件不会进 Amplitude。这类事件是"Reload-only"的内部高频指标,因此在 Amplitude 的search里搜不到它们——这是后文"MCP 无结果时回退 grep"这条兜底规则的根本原因之一。 - 缺少
organization上下文的事件也发不到 Amplitude(organization_id === undefined时直接跳过)。所以调用trackAnalytics时传入organization是事件进入 Amplitude 的前提。
再看 trackAmplitudeEvent.tsx 的最终落点:它先检查 ConfigStore.get('enableAnalytics') 开关,然后 Amplitude.setUserId 设置用户、Amplitude.setGroup('organization_id', ...) 在组织切换时更新分组,最后 Amplitude.track(event_type, data, eventOptions) 发出事件。也就是说,Amplitude 里的用户维度是 Sentry 用户 ID,组织维度是 organization_id group——查询"独立用户数"(uniques + countGroup: "User")时统计的就是这个 userId。
一个真实的埋点调用示例,来自 Issue 详情页侧边栏的"Open Autofix"按钮 autofixSection.tsx:
<Button
size="md"
icon={<IconSeer />}
variant="primary"
onClick={openSeerDrawer}
analyticsEventKey="issue_details.seer_opened"
analyticsEventName="Issue Details: Seer Opened"
analyticsParams={{
group_id: group.id,
autofix_exists: true,
has_root_cause: hasRootCause,
has_pr: hasPullRequests,
mode: 'explorer',
referrer,
}}
/>
按钮通过声明式 props(analyticsEventKey / analyticsEventName / analyticsParams)触发同一个 issue_details.seer_opened 事件。这条链路——声明式 props → trackAnalytics → override → Amplitude.track——就是本文后续 MCP 查询的对象。
二、一次性配置:连接 Amplitude MCP
如果 Amplitude MCP 尚未连接(调用 mcp__claude_ai_Amplitude__* 工具会不可用),按以下三步完成连接:
- 在 Claude Code 中运行
/mcp; - 在列表中选择 "claude.ai Amplitude";
- 通过 Sentry SSO 完成认证。
连接成功后,mcp__claude_ai_Amplitude__* 系列工具(get_context、search、get_properties、query_dataset、query_chart 等)即可在会话中调用。
三、发现 Amplitude 项目:get_context
所有 Amplitude 工具调用都需要 projectId。发现方式:
- 调用
get_context,找到 Sentry 组织及其下属项目列表; - 找到
sentry.io这个产品对应的项目,取其appId; - 把这个
appId作为后续所有 Amplitude 工具调用(get_properties、query_dataset等)中的projectId使用。
这一步只做一次,同一会话内可复用。
四、发现工作流:四步回答"有多少人做了 X"
当用户问出"多少人做了 X?""有人在用 Y 吗?"这类问题时,按以下四步执行。
步骤 1:找到事件(Find the Event)
用 search 按关键词搜索事件。queries 支持多个关键词并行搜索,entityTypes 限定为 EVENT,search_goal 用自然语言说明搜索意图:
mcp__claude_ai_Amplitude__search({
queries: ["seer", "autofix"],
entityTypes: ["EVENT"],
limitPerQuery: 20,
search_goal: "Find events related to the seer feature on issue details"
})
返回结果就是 Amplitude 里的事件名(eventName),即各事件映射表里的值,例如 "Issue Details: Seer Opened"。
如果 search 没有返回任何结果,回退到 grep 代码库(对应第一节讲的两类"Amplitude 盲区":null 映射的 Reload-only 事件、以及尚未接入 Amplitude 的事件):
grep -rn "seer\|autofix" static/app/utils/analytics/ --include="*.tsx"
Sentry 的领域事件文件都集中在 static/app/utils/analytics/ 目录下,按功能域命名(seerAnalyticsEvents.tsx、workflowAnalyticsEvents.tsx、feedbackAnalyticsEvents.tsx 等),grep 该目录即可覆盖绝大多数前端事件定义。
步骤 2:获取事件属性(可选)
当用户需要按某个属性过滤或分组(比如按平台、按入口来源)时,先取该事件的属性列表:
mcp__claude_ai_Amplitude__get_properties({
propertyType: "event",
projectId: "<projectId>",
eventType: "Issue Details: Seer Opened"
})
返回该事件已上报的所有属性名。属性名应与代码中 analyticsParams 的键对应——以上述 Autofix 按钮为例,返回结果里应能看到 group_id、has_root_cause、has_pr、mode、referrer 等键。
步骤 3:查询数据(Query the Data)
对临时性(ad-hoc)分析需求,使用 query_dataset 构造事件分段查询。以"最近 30 天有多少独立用户打开过 Seer"为例:
mcp__claude_ai_Amplitude__query_dataset({
projectId: "<projectId>",
definition: {
type: "eventsSegmentation",
app: "<projectId>",
name: "Seer Opens Last 30 Days",
params: {
range: "Last 30 Days",
events: [{
event_type: "Issue Details: Seer Opened",
filters: [],
group_by: []
}],
metric: "uniques",
countGroup: "User",
groupBy: [],
interval: 1,
segments: [{ conditions: [] }]
}
}
})
参数要点:
| 参数 | 作用 |
|---|---|
range |
时间范围,如 "Last 30 Days" |
events[].event_type |
步骤 1 找到的 Amplitude 事件名(eventName) |
events[].filters |
按事件属性过滤,属性名来自步骤 2 的 get_properties |
metric |
聚合指标:uniques(独立用户)或 totals(总量) |
countGroup |
计数维度,"User" 表示按用户去重 |
groupBy |
需要按属性/时间分桶时填写 |
segments[].conditions |
用户段条件,空数组表示不限 |
如果用户提供的是已存在的图表 ID 或 URL,则改用 query_chart 直接取数,无需重新拼装查询定义。
步骤 4:汇报结果(Report Results)
- 明确说明使用了哪个事件名、查询了哪个时间范围;
- 默认报告独立用户数(uniques)而非总事件量,除非用户明确要求总量;
- 当数字缺乏上下文时,主动提议按属性(平台、组织等)做拆解。
五、常见查询模式速查表
文档将高频的自然语言问题映射为固定的指标与事件模式,可直接套用:
| 用户问题 | 指标 | 事件类型模式 |
|---|---|---|
| "有多少人浏览 X 页面?" | uniques |
"Page View: ..." |
| "X 按钮有多少次点击?" | totals |
"Feature: Button Clicked" |
| "从 X 到 Y 的漏斗是什么?" | 漏斗 | 使用 type: "funnels" 并传入有序事件 |
| "人们会回到 X 吗?" | 留存 | 使用 type: "retention" |
对应到 query_dataset 的 definition:前两种仍用 type: "eventsSegmentation",只改 metric(uniques / totals)与事件名;后两种则把 type 换为 "funnels"(events 按转化顺序排列)或 "retention"。
六、搜索现成的 Dashboard 与 Chart
当用户要的不是原始数据,而是"给我看看 Seer 的仪表盘"时,用 search 指定 DASHBOARD / CHART 实体类型:
mcp__claude_ai_Amplitude__search({
queries: ["seer dashboard", "autofix metrics"],
limitPerQuery: 10,
entityTypes: ["DASHBOARD", "CHART"]
})
找到后可以直接打开链接,或将其 ID 交给 query_chart 取数。
七、MCP 未连接时的代码库兜底
Amplitude MCP 是"锦上添花"的加速器;没有它时,仓库本身就是完整的事件字典。兜底流程:
- grep 事件文件找 Amplitude 名称:在各
{domain}AnalyticsEvents.tsx的事件映射表(*EventMap)里找eventName值,例如grep -rn "Seer Opened" static/app/utils/analytics/; - 向用户报告事件键(eventKey)与 Amplitude 名称(eventName)的对应关系,让用户可以在 Amplitude UI 中手动检索——事件键是
issue_details.seer_opened这类 snake_case 键,Amplitude 名称是Issue Details: Seer Opened这类 Title Case 字符串,两者一一对应; - 建议用户连接 Amplitude MCP 以便直接查询:运行
/mcp→ 选择 "claude.ai Amplitude"。
八、实践要点与排错
结合源码,使用这套工作流时有几个容易踩坑的点:
search搜不到 ≠ 事件不存在。映射值为null的 Reload-only 事件(SKILL.md 中的事件管线说明 指出其"too expensive for Amplitude")不会出现在 Amplitude 搜索中,此时必须走 grep 兜底,并通过事件键去 Redash(Reload 侧)查询。projectId与app字段填同一个值。query_dataset示例中projectId(顶层)与definition.app都填get_context得到的sentry.io项目appId。- 计数口径先看
countGroup。"多少人"用metric: "uniques"+countGroup: "User";"多少次"用metric: "totals"。trackAmplitudeEvent.tsx 中Amplitude.setUserId(user?.id ?? null)说明 User 维度对应 Sentry 用户 ID,同一用户跨组织切换时organization_idgroup 会随之更新。 - 事件是否真的会发到 Amplitude,取决于调用点传没传
organization。从源码结构看,rawTrackAnalyticsEvent在organization_id === undefined时跳过 Amplitude 通道(rawTrackAnalyticsEvent.tsx),因此查询结果偏少时,除了核对事件名,还应检查埋点调用点的组织上下文是否完整。 - 本地调试埋点:在浏览器
localStorage设置DEBUG_ANALYTICS = 1,makeAnalyticsFunction.tsx 与 rawTrackAnalyticsEvent.tsx 都会console.log出完整的事件参数,便于在跑 MCP 查询前确认eventName与属性值。
小结
这套工作流的价值在于把"产品数据问题"转化为一条确定的工具链:get_context 拿 projectId → search 找事件名(无果则 grep static/app/utils/analytics/)→ get_properties 看可过滤属性 → query_dataset / query_chart 取数 → 以"事件名 + 时间范围 + 独立用户数"的口径汇报。理解了 Sentry 埋点"事件键 → 名称映射 → Reload/Amplitude/Pendo 三通道"的底层管线后,Amplitude 查询结果的每个数字都能回溯到具体的一次 trackAnalytics 调用,查询与代码互为印证。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00