关于 ae-migrate-tracking-code
ae-migrate-tracking-code 是面向已有第三方埋点代码的迁移技能,可将受支持的 SDK 调用整理为中间表示并映射到 AE。它覆盖从扫描调用点到协调计划生成与代码插入的流程。
主要功能
- 01识别受支持的第三方分析 SDK
- 02提取事件、身份与属性调用点
- 03追踪封装函数的调用位置
- 04将扫描结果整理为中间表示
- 05协调埋点计划与 AE 代码插入
适用场景
- 01将 Firebase Analytics 埋点切换到 AE
- 02把 Amplitude 事件迁移到 AE
- 03在保留原 SDK 时新增 AE 埋点
- 04扫描现有代码并整理迁移映射
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ thinkingaiagenticengine/ ae-cli --skill ae-migrate-tracking-code安装后在 Claude Code 中输入/ae-migrate-tracking-code确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/ae-preset-properties.mdir.mdmapping-framework.mdreferences/providers/amplitude.mdfirebase.mdga4.mdmixpanel.mdREADME.mdsensors-data.md详细介绍
ae-migrate-tracking-code
对话语言:本文档使用英文,但所有面向用户的输出都必须使用用户输入的语言。 用户输入英文 → 用英文回复;用户输入中文 → 用中文回复;用户输入日文 → 用日文回复。 如果不确定,则默认使用英文。 这适用于所有输出:章节标题、阶段名称、提示词、代码注释等。 ⚠️ 重要:许多提供商适配器文档包含中文术语说明。阅读这些文档并回答使用英文或日文的用户时,请将标题和注释翻译成用户使用的语言。 不要在英文或日文回复中照搬本文档中的中文内容。
术语表
| 中文 | English | Notes |
|---|---|---|
| 埋点迁移 | Tracking Migration | 将现有第三方 SDK 埋点调用转换为 AE SDK 调用 |
| 源 SDK | Source SDK / Provider | 项目中已有的第三方 SDK(Firebase、Amplitude 等) |
| 调用点 | Call Site | 源 SDK 调用(logEvent / setUserId / setUserProperty / Identify) |
| 归一化中间表示 | IR (Intermediate Representation) | 与提供商无关的已提取调用点转储 |
| 映射 | Mapping | 源事件/属性 → AE 事件/属性的转换 |
| 切换 | Switch | 将源调用替换为 AE track(),并移除源 SDK |
| 双写 / 新增 | Add / Dual-write | 保留源 SDK,并同时添加 AE track() |
| 依赖标识 | Dependency Identifier | 切换模式下用于移除源 SDK 的包/模块名称 |
| 自动采集事件 | Auto-track Event | 源 SDK 自动采集的事件(例如 session_start) |
| 公共属性 | Super Property | 自动附加到每个事件的属性。⚠️ AE 中正确的中文术语是“公共属性”或“公共事件属性”。绝不能将“Super Property”翻译为“超级属性”——这不是有效的 AE 术语。 |
| 用户属性 | User Property | 设置在用户资料上的属性 |
| 用户体系 | User Identity System | AE 中的 distinct_id / account_id 策略 |
触发条件
当用户提出以下请求时触发:“将 Firebase 埋点迁移到 AE / 用 ThinkingAI 替换 Amplitude / 我的项目已经有 Firebase/Amplitude 埋点,将其切换到 AE SDK / 在现有分析工具旁新增 AE 埋点”等,例如:把当前工程里的 xx SDK 切换到数数、把已有埋点用数数实现一遍、用数数替换 xx SDK、集成数数并参考已有的 xx SDK 埋点。
目标 AE SDK 也可能称为:数数 / 数数 SDK / ThinkingAI / ThinkingAI SDK / Agentic Engine / Agentic Engine SDK / AE / AE SDK——它们指的是同一个 SDK。触发信号是“已有的第三方源 SDK + 迁移/切换/替换/实现一遍”,或者“集成/接入数数,并参考已有的 xx SDK 埋点”。单纯接入数数 SDK / 加数数埋点,但没有源 SDK,属于从零开始的场景——应使用 ae-generate-tracking-code,而不是此技能。
范围:此技能仅处理代码库——扫描现有第三方埋点调用(阶段 0/1)。如果没有包含第三方埋点的源代码(只有产品文档/描述),请勿使用此技能;应改用 ae-generate-tracking-plan + ae-generate-tracking-code。将历史数据导入 AE 属于离线数据迁移工作,不在此技能的范围内——此技能只切换实时客户端/服务端 SDK,同时保留用户 ID 以及事件/属性名称,使新数据能够与导入的数据合并。
此技能负责协调端到端的迁移,但不会重复实现以下两个现有技能:
- 方案生成/上传 → 移交给
ae-generate-tracking-plan(代码库路径)。 - AE SDK 代码插入 → 移交给
ae-generate-tracking-code(插入模式),并使用迁移映射提供插入位置,而不是通过 grep 查找发现业务触发点。
提供方注册表(可扩展)
核心部分与提供方无关。每个第三方平台对应一个适配器文件。要支持新的提供方,请在 references/providers/ 下添加一个适配器,并在下方添加一行——不要修改此 SKILL.md。
| 提供方 | 适配器 | 覆盖的平台 | 检测模式(摘要) |
|---|---|---|---|
| Firebase Analytics | references/providers/firebase.md | Web v8/v9、Android、iOS、Flutter、React Native、Unity、C++ | firebase/analytics、firebase.analytics()、FirebaseAnalytics、FIRAnalytics、Analytics.logEvent(iOS Swift)、FirebaseAnalytics.instance |
| Amplitude | references/providers/amplitude.md | Web legacy(amplitude-js)、Browser 2.x、Node、Python、Go、Java、Android、iOS、React Native、Flutter、Unity | amplitude-js、@amplitude/analytics-browser、@amplitude/analytics-node、amplitude.init、amplitude.getInstance()、amplitude.logEvent、amplitude.track、Identify、服务端导入(from amplitude import、analytics-go、com.amplitude:java-sdk) |
| Sensors Data(神策) | references/providers/sensors-data.md | Web、Android、iOS、Harmony、macOS/tvOS、C++、React Native、Flutter、Unity、Unreal、Cocos2d-x、小程序(微信/其他)、QuickApp、APICloud、uni-app、Weex、Egret、LayaAir,以及服务端 SDK(Java/Python/Go/Node/PHP/Ruby/C/.NET/Lua) | sensorsdata.min.js、sensors.init、sensors.track、SensorsDataAPI、SensorsAnalyticsSDK、profileSet、setProfile(legacy)、服务端 sa-sdk-*(Python/Go/Node/PHP/Ruby/C/.NET/Lua) |
| Mixpanel | references/providers/mixpanel.md | JavaScript、Node、Python、Go、Java、Ruby、PHP、Android、iOS、Swift、React Native、Flutter、Unity | mixpanel-browser、mixpanel.init、mixpanel.track、mixpanel.identify、mixpanel.people、MixpanelAPI、mixpanel.NewApiClient(Go)、Mixpanel::Tracker(Ruby)、Mixpanel::getInstance(PHP)、mp.track / people_set(Python) |
| Google Analytics 4 | references/providers/ga4.md | Web(gtag.js / dataLayer)、Measurement Protocol(服务端) | gtag('event'、gtag('config'、gtag('set'、dataLayer(仅当同时存在 gtag(/G- 时才属于 GA4)、G-XXXXXXX、Measurement Protocol mp/collect |
适配器契约(每个适配器必需的字段)定义于 references/providers/README.md。
支持范围:仅支持上面列出的提供方/平台(以及各适配器 Recognition 部分中的平台表格)。未列出的内容不在范围内,本技能不予支持——不要为未列出的平台编造映射。
阶段 0 — 检测来源 SDK 和版本
- 定位项目及其包/依赖清单(
package.json、build.gradle、Podfile、pubspec.yaml、*.csproj等),以及源代码导入项。 - 与上方注册表匹配。阅读匹配适配器的 Recognition 部分,确认提供方并确定版本变体:
- Firebase:区分 v8 命名空间形式与 v9 模块化形式(Web),以及 Android/iOS/Flutter 原生形式。
- Amplitude:区分 legacy(
getInstance().logEvent)与 SDK 2.x(amplitude.track/@amplitude/analytics-browser)。
- 如果存在多个提供方,列出它们并询问用户先迁移哪一个(每次运行迁移一个提供方,映射更清晰)。例外——GA4 和 Firebase Analytics 属于同一数据流:GA4 是 Firebase 的 Web 层(同一个测量 ID 既是 GA4 媒体资源,也是 Firebase 项目)。如果同一项目中同时存在
gtag(...)和logEvent(...),它们不是两个提供方——应合并为一次迁移运行:一次扫描、一个draft.json/mapping.json,并对共享的事件 / 属性 / 用户 ID 名称执行一次去重。切勿为一个 Google 数据流生成两份草稿。 - 如果没有匹配的注册表项,但存在跟踪代码 → 展示找到的调用,询问用户提供方名称,并根据
references/providers/README.md,在继续之前请用户提供文档/代码片段,以收集最小化适配器。
阶段 1 — 将调用点提取到 IR
根据适配器的 Recognition 模式,扫描项目中的四类调用:
- 事件调用:
logEvent(...)/track(...)及其参数/属性。 - 身份调用:
setUserId(...)/identify(...)/login(...)。 - 用户属性调用:
setUserProperty(...)/setUserProperties(...)/Identify操作。 - 超级属性调用(常见事件属性):
register(...)/registerSuperProperties(...)(Mixpanel、Sensors Data)/setDefaultEventParameters(...)(Firebase)。将其记录为kind: super_property,并保留完整的props映射——不要误读为用户属性(参见mapping-framework.md§6)。Amplitude 和 GA4 没有此类 API。
将每个调用点记录为 file:line、调用类型、事件/参数值(字面量或通过阅读周边代码解析的变量名)。按照 references/ir.md 将规范化后的转储写入 .ae-cli/migration/scan.json。
包装层解析(反向调用图追踪)——实际项目几乎不会在每个业务事件中直接调用源 SDK,而是会将其包装在分析辅助函数中(trackEvent(name, props) → mixpanel.track(name, props))。简单的 grep 只能看到包装函数中唯一的 SDK 调用(事件名称 = 参数 → 会得到 resolved:false),从而遗漏所有真实业务事件。因此,当 SDK 调用的事件名称是一个函数参数(运行时变量从外层函数的参数传入)时,不要立即记录为 resolved:false:
- 找出外层函数
F——仅当F的唯一作用是将该参数转发给 SDK 调用时,才将其视为分析包装函数。如果事件名称来自局部逻辑/表达式,而非参数,则它不是包装函数——按常规将该调用点记录为resolved:false。 - grep 查找
F的所有调用者。将每个使用静态事件名称的调用者解析为普通调用点:kind根据F所转发到的 SDK 调用推断(event / identity / user_property),event_name取自调用者的字面量或常量参数,source_call= 调用者的调用行,file= 调用者的文件,via_wrapper=F的名称。 - 使用动态事件名称的调用者仍记为
resolved:false。如果没有找到调用者(包装函数被外部调用,或使用动态分派),则退回到将包装函数自身的 SDK 调用记录为一个resolved:false调用点。 - 将
F本身记录在 scan.json 顶层的wrappers数组中(参见references/ir.md)——它是追踪的关键节点,不是迁移目标。
自动跟踪说明:源 SDK 自动采集的事件(例如 Firebase 的 session_start、first_open、screen_view)不是调用点。请在阶段 2 中根据适配器的 Auto-track decision 表进行处理,不要在此处处理。
阶段 2 — 映射到 AE(编写 draft.json + mapping.json)
- 阅读
references/mapping-framework.md(通用算法)和提供方适配器(差异)。 - 对每个提取出的事件:映射到 AE 事件(使用 snake_case 名称;需要前向兼容时则使用原样名称——
mapping-framework.md§1;display_name使用用户的语言);将每个参数映射为带类型的 AE 属性;并应用适配器中的命名约束(保留前缀、特殊字符、长度上限)。 - 应用去重和提升规则:同一属性出现在 3 个或更多事件中 → 公共事件属性(超级属性);预设的
#属性永远不会成为超级属性。显式超级属性调用点(register/setDefaultEventParameters)也应放入draft.json的common_event_properties池中——参见mapping-framework.md§6。 - 将身份映射到 AE
login(accountId)(account_id_sourceuser_account);如果需要与导入的历史数据保持前向兼容,则还要保持访客 ID 连续性(初始化时调用setDistinctId/identify)——参见mapping-framework.md§4。用户属性操作根据适配器的映射表,映射到 AEuser_set/user_setOnce/user_add/user_append/user_unset。超级属性调用映射到setSuperProperties({...})(静态公共事件属性),参见mapping-framework.md§6。 - 根据调用点所在位置确定每个事件的
platform(应用代码 → 客户端;后端 → 服务端)。 - 请用户确认迁移模式(参见下方“模式”),并确认历史来源平台数据是否已(或将)离线导入 AE——这将决定根据
mapping-framework.md§1 采用前向兼容命名,以及根据 §4 保持访客 ID 连续性。导入本身属于离线数据迁移工作,不在范围内;此技能只切换实时 SDK——然后:- 编写
.ae-cli/migration/mapping.json(来源位置 → AE 事件 + 模式决策,结构见references/ir.md)。 - 按 AE 计划架构编写
.ae-cli/draft.json(与ae-generate-tracking-plan生成的架构相同),以便计划技能可直接使用。
- 编写
展示映射摘要表,并在继续之前取得用户的 ok。
阶段 3 — 生成并上传追踪计划
将工作移交给 ae-generate-tracking-plan,使用已生成的代码库信息和 draft:
ae-cli tracking plan draft --in .ae-cli/draft.json --out .ae-cli/draft.xlsxae-cli tracking plan validate --in .ae-cli/draft.json --fix- 根据计划技能确定 AE 主机、登录信息和 projectId,然后运行
ae-cli tracking plan upload ...(上传前询问用户;根据该技能的冲突检测决定追加还是替换)。
阶段 4 — 插入 AE SDK 代码(切换或添加)
将工作移交给 ae-generate-tracking-code(插入模式),但插入位置取自 .ae-cli/migration/mapping.json,而不是通过 grep 发现业务触发点:
- 客户端/服务端平台和语言已在
draft.jsonmeta 中;按该技能的方式确定 APP_ID / SERVER_URL。 - 对于每个映射后的 AE 事件,插入点均为 mapping.json 中记录的原始调用点。
switch模式(替换)——高风险,删除前必须确认: - 删除任何内容前,明确列出将删除的内容(源代码调用点,以及适配器 Dependency identifiers 中的源 SDK 依赖),并征得用户同意后再删除。
- 在同一位置将源
logEvent/track调用替换为 AEtrack(...)调用;移除现已不再使用的源导入。 - 将来自模块常量的事件名内联:在 AE
track(...)调用中直接写出 snake_case 字面名称(必须与// @tracking <event_name>标记一致)。删除常量定义前,先在整个项目中搜索其名称——模块常量通常会被多个文件导入、传入服务端报告,或在测试中断言。只有当迁移后的调用点是它仅有的引用时,才移除该常量(此时它属于死代码);否则保留。不要保留仅供迁移后的调用使用的常量。 - 使用适配器的 Dependency identifiers 移除源 SDK 依赖(例如
firebase/analytics、@amplitude/analytics-browser)。 - 移除无用的包装函数:当通过某个包装函数解析出的所有调用点都已执行
replace时,该包装函数便成为死代码——将其删除(并移除现在不再使用的源导入)。如果该包装函数所在文件中没有其他内容,则删除该文件。(add模式会保留包装函数——它仍为源 SDK 提供数据——并在每个业务调用点添加 AE 调用。) - 类似地,将身份识别/用户属性调用转换为
login(...)/用户属性调用;将超级属性调用转换为setSuperProperties({...}),并放在原调用点(绝不可提前移位——源代码中register的位置决定了值何时可用,例如登录后;参见mapping-framework.md§6)。
add 模式(双写):
- 保留源调用,不做修改;紧邻其前后添加 AE
track(...)调用(遵循周围代码的风格)。 - 保持两个 SDK 相互独立——两个方向都如此。 双写意味着对每个提供方/每个 SDK(Firebase、Amplitude、Sensors Data、Mixpanel、GA4 等)分别执行两次独立写入,而不是受源 SDK 状态控制的 AE 写入:
- AE
track()/login()/用户属性/setSuperProperties()调用绝不能嵌套在源 SDK 的可用性检查、提前返回或错误处理路径中——例如放在if (!analytics) return之后、isSupported()检查之后,或源代码的try/catch之内。如果源调用位于此类保护逻辑之后,应将 AE 调用移出,使其无条件执行。 - 为每个 SDK 的写入分别设置自己的
try/catch:源 SDK 故障(不可用、isSupported() === false或抛出错误)绝不能阻止 AE 写入;AE 故障也绝不能阻止源 SDK 写入(或导致其崩溃)。 - 保护逻辑必须涵盖源 SDK 的全部故障情形,而非仅一种异常类型。已有的范围过窄的捕获(例如 Python 中针对 400 验证错误的
except ValueError,或 Java 中的catch (IllegalArgumentException))不能作为独立性保护——其他故障(未配置 API 密钥导致RuntimeError、网络/超时)仍会逃逸,并在 AE 写入前导致崩溃。应扩大捕获范围以涵盖所有异常,执行 AE 写入,然后重新抛出源异常,以保持原有的状态/错误语义(400/503)不变。 - 每个 SDK 的初始化也要分别设置自己的
try/catch,以免某个 SDK 在加载时被卸载或禁用(初始化抛出错误/缺少模块)导致另一个 SDK 中断。无论哪个 SDK 被卸载或禁用,两个写入都必须继续正常工作。 - 混合运行中的每个
add/add_after/add_before条目也都适用上述要求。
- AE
- 保留源 SDK 依赖;只添加 AE SDK 依赖。
异步调用点 — 源调用使用
await等待(React Native / Flutter 中的await analytics().logEvent(...),以及某些await mixpanel.track(...))会返回 Promise,但 AE 客户端的track()/login()/ 用户属性 /setSuperProperties()调用是同步的: switch:移除被替换调用上的await— 等待同步 AE 调用会触发 lint 警告,且不会改变任何行为。如果源调用位于try/catch中,且catch处理的是源 SDK 的 Promise 拒绝(网络重试、离线回退、错误报告),则该拒绝分支会随源 SDK 一并消失:移除现已无用的catch逻辑;如果try块中只剩 AE 调用,则将try/catch简化为直接调用 AE(AE 同步错误随后遵循代码技能的 Code Style:在switch模式下明确暴露)。绝不要为了保持结构一致,给 AE 调用套上虚构的async/await。add:原样保留源调用的await和try/catch,并将 AE 调用放在该代码块之外,不使用await,按上述独立性规则放入单独的try/catch。
两种模式都遵循代码技能的插入规则:从 wiki 主文档获取 SDK 初始化信息(绝不猜测导入语句)、预先检查 git 状态、批量 Edit 并检查语言风格、添加 // @tracking <event_name> 注释前缀。
用户属性 append / unset(ae_call = user_append / user_unset):这两种操作不在计划的 update_type 枚举中(仅包含 user_set / user_setOnce / user_add),因此不会进入 draft.json — 在草稿中,其 update_type 写为 user_set(占位符)。在代码插入时,按映射中的 ae_call 直接输出 AE SDK 调用(user_append → userAppend,user_unset → userUnset),并从 wiki 主文档读取真实的方法签名(绝不猜测)。
**⚠️ add 模式覆盖代码技能中“Do NOT add try/catch”的 Code Style 规则。**该规则适用于单 SDK 场景(全新插入 / 切换完成后的 switch):只有一个 SDK 时,明确暴露错误才是目的,因此初始化 / 跟踪错误必须抛出,而不能被吞掉。双写则相反 — 上述“每个 SDK 各自使用 try/catch”规则同样适用于生成的 AE 代码:
- AE 初始化必须采用相同的保护方式(使用独立的
try/catch/ 可用性检查),确保 AE SDK 加载失败时绝不会在加载时抛出,也不会导致源 SDK 停止运行。 - 绝不要输出加载时捕获 SDK、导致其引用永久为
undefined并在每次调用时抛错的代码(例如包装器中的var ta = window.TA;)— 缺少 AE SDK 时,每次调用都必须是空操作,而不能导致业务逻辑或源 SDK 写入崩溃。 switch模式不适用此覆盖:切换完成后 AE 是唯一的 SDK,因此完全遵循代码技能的 Code Style(错误仍须明确暴露)。
阶段 5 — 验证
沿用代码技能的验证流程:
ae-cli auth status/ 确认当前主机;添加 / 选择调试设备。- 触发迁移后的事件,并查询
ae-cli tracking debug-data list。 - 在
add模式下,验证 AE 数据与仍在运行的源 SDK 数据;在switch模式下,确认源 SDK 已完全移除且 AE 数据正常流入。
模式
| 模式 | 是否保留源 SDK? | AE 调用位置 | 依赖项变更 |
|---|---|---|---|
switch | 移除 | 替换源调用 | 移除源依赖,添加 AE 依赖 |
add | 保留 | 添加在源调用旁边 | 仅添加 AE 依赖 |
在阶段 2 询问用户要使用哪种模式。**默认使用 add(双写):在确认提示中将 add 作为推荐选项。**将 switch 视为非默认的破坏性选项——只有用户明确表示想要完全切换时才提供,且绝不要将其标记为推荐选项。
分阶段/混合运行:mode 是运行级默认值,但每个映射条目都有自己的 action(replace 与 add_after/add_before),并且以每个条目的 action 为准。switch 运行仍可将选定条目保留为 add_after,用于分阶段推出(例如,现在切换 identity + sign-up,同时在验证数据期间让 purchase 保持双写)。在这种情况下:替换后的文件会移除源 SDK,双写文件会保留源 SDK,且只有在完全切换(每个条目都是 replace)时才会移除源 SDK 依赖。请参阅 references/ir.md §mapping.json 和 mapping-framework.md §8。
⚠️
switch具有破坏性(高风险):它会删除源跟踪调用、对应的导入以及源 SDK 依赖。默认情况下绝不要删除旧代码。删除任何内容前,必须明确告知用户将移除哪些内容(调用点 + 依赖项)并获得用户确认;在阶段 4 即将删除前还必须再次确认,即使用户已在阶段 2 选择switch。
禁止事项
- 猜测 AE SDK 导入/包名——始终通过
ae-generate-tracking-code阅读 wiki 主文档(references/sdk-index.md)。 - 将事件/属性名称修改为偏离 AE 方案的名称(
snake_case、已注册名称)。 - 将源 SDK 自动跟踪事件迁移为手动
track()调用——应按适配器将其映射到 AE 自动跟踪开关,或直接舍弃。 - 在
add模式下,将 AE 的track()/login()/用户属性调用嵌套在源 SDK 的可用性检查、提前返回或try/catch中;也不得让任一 SDK 的初始化不受保护,或使用范围过窄、仅捕获特定异常类型的代码保护源 SDK 写入,导致源 SDK 故障仍可能在 AE 写入前引发崩溃——对于每个提供方,双写都必须保持为两次独立写入(每个 SDK 各自使用try/catch,包括初始化,并覆盖完整的故障范围),以确保一个 SDK 故障或被卸载时不会影响另一个。 - 跳过阶段 2 的映射摘要确认。
- 将
user_append/user_unset写入draft.json的update_type(方案枚举仅包含user_set/user_setOnce/user_add)——追加/取消设置应保留在mapping.json的ae_call中,并在阶段 4 直接输出。 - 在任何面向用户的输出中,将 “Super Property” 翻译为“超级属性”。
- 在 git-status 预检查(插入模式)之前编写源代码或 AE 代码。
- 编辑提供方适配器,将特定提供方逻辑加入核心代码——新增提供方时只能新增适配器文件。
- 未在删除前立即明确警告用户并获得确认,就删除源跟踪代码或移除源 SDK 依赖(
switch模式)。
内部参考
references/ir.md— 规范化 IR 架构(scan.json/mapping.json)。references/mapping-framework.md— 与提供方无关的映射算法。references/ae-preset-properties.md— AE#预置属性及系统字段的权威列表(只有这些#名称会被摄取)。references/providers/README.md— 适配器约定及如何添加提供方。references/providers/firebase.md— Firebase 适配器。references/providers/amplitude.md— Amplitude 适配器。references/providers/sensors-data.md— Sensors Data(神策)适配器。references/providers/mixpanel.md— Mixpanel 适配器。references/providers/ga4.md— Google Analytics 4(gtag.js/Measurement Protocol)适配器。