小鹏汽车综合数据监控 Skill
目标
本 Skill 用于获取小鹏汽车的综合数据,持续集成各市场、各维度的指标。目前已包含以下两大模块(其他数据待补充):
- 第一部分 · 中国市场交付周期:查询指定小鹏车型各配置版本的交付周期信息(单位:周)。数据来源:小鹏官方商城 API(
store.xiaopeng.com)。 - 第二部分 · 欧洲市场纯电动车日更数据:监控 XPENG 在欧洲披露日更数据国家的 BEV 每日上牌/交付销量,输出最近 12 个月的日更明细与环比对比。数据来源:eu-evs.com。
所有网络请求通过 scripts/ 目录下的 Node.js 脚本执行(node <script>.js),不使用 Python、curl 或其他方式。脚本目录:scripts/(相对于 skill 根目录)。
执行前先确定命中功能
收到用户问题后,先根据用户问题和上下文判断需要命中的功能列表,再根据命中的功能列表获取对应的数据。不要无差别地执行所有脚本。
功能命中规则:
| 功能 | 命中条件(满足任一即可) | |------|----------------------| | 第一部分 · 中国交付周期 | 用户提到交付周期、交付时间、提车周期、提车时间、等几周、交付等待、订车到提车、中国/国内交付等;或指定了具体车型(如 G6、GX、M03、P7)并询问交付相关话题 | | 第二部分 · 欧洲日更数据 | 用户提到欧洲销量、欧洲交付、欧洲上牌、海外销量、BEV 注册量、XPeng Europe、EU sales 等;或询问小鹏在海外/欧洲的市场表现 |
- 如果只命中一个功能,直接执行对应部分的流程。
- 如果同时命中两个功能(如"小鹏国内交付周期和欧洲销量怎么样"),分别执行两个部分的流程,各自独立获取数据后汇总展示。
- 如果无法确定命中哪个功能,使用 AskUserQuestion 询问用户想查看哪类数据。
全局执行铁律(适用于所有数据获取)
以下规则优先级最高,凌驾于各部分的具体流程之上,任何阶段都必须遵守:
- 所有 HTTP 请求一律通过
scripts/下的 Node.js 脚本发起,严禁使用 curl、Python、WebFetch、WebSearch、Bash 直接拼接 URL 或任何其他方式直接请求数据源。数据源的反爬策略、登录态、cookie 管理全部封装在脚本内,绕过脚本会导致 bot 检测触发、账号被封或拿到不一致的数据。 - 脚本失败只能"重跑同一脚本"或"把错误原样上报",不得改用替代手段。即脚本返回
ERROR|...或非零退出码时,允许间隔片刻后重跑同一脚本(最多 2~3 次);重跑仍失败则将错误信息转述给用户并停止,不得临时起意用 curl/WebFetch/Python 重新请求。 - 瞬时网络错误脚本已内置重试(socket hang up、ECONNRESET、连接超时等会在脚本内部退避重试 3 次),agent 不需要、也不应该对瞬时网络错误自行编排重试逻辑;只有当脚本输出明确的
ERROR|...时才需要 agent 介入。 - 判断脚本是否可用,只看 stdout:正常数据、
LOGIN_REQUIRED、ERROR|...都在 stdout。不要因为 stderr 有输出或退出码非零就认定脚本不可用。
第一部分:中国市场交付周期数据
脚本列表
| 脚本文件 | 用途 | 用法 |
|---------|------|------|
| fetch_car_series.js | 获取全部车型列表 | node fetch_car_series.js |
| fetch_car_versions.js | 获取指定车型的配置版本列表 | node fetch_car_versions.js <carSeriesCode> |
| fetch_delivery_period.js | 查询指定配置的交付周期 | 见下方详细说明 |
fetch_delivery_period.js 用法
该脚本根据车型类型使用不同的 API 策略:
| 模式 | 用法 | 适用车型 | 输出格式 |
|------|------|---------|---------|
| Case 1 单版本 | node fetch_delivery_period.js <carVersionCode> <carSeriesCode> | GX、M03、P7 系列 | OK\|min\|max\|carName |
| Case 2 单版本 | node fetch_delivery_period.js <carVersionCode> <carSeriesCode> | 其他车型 | OK\|min\|max\|carName |
| Case 2 批量 | node fetch_delivery_period.js <carSeriesCode> --all | 其他车型(推荐) | versionCode\|OK\|min\|max\|carName(每行一个版本) |
脚本自动根据 carSeriesCode 判断使用 Case 1 还是 Case 2。
流程步骤
步骤一:获取全部车型列表
运行 scripts/fetch_car_series.js,解析输出获取全部车型列表。
输出格式(每行一个):序号|carSeriesCode|carSeriesName
步骤二:识别用户想监控的车型
根据用户的问题识别用户想要监控哪几个(一个或多个)carSeriesCode。匹配时支持用户说车型名称(如"G6")或完整名称(如"2026款G6"),做模糊匹配。
如果用户没有提供具体车型,或提供的车型名无法匹配,则使用 AskUserQuestion 工具展示全部车型列表并让用户选择:
| 序号 | carSeriesCode | carSeriesName | |------|--------------|---------------| | 1 | GX | GX | | 2 | M03_2026 | M03 | | ... | ... | ... |
请告诉我您想查询哪些车型的交付周期?可以提供车型名称或序号,支持多个(如:1,3,5 或 GX,G7)。
步骤三:获取每个车型的配置版本列表
针对用户选中的每个 carSeriesCode,运行 scripts/fetch_car_versions.js <carSeriesCode>。
输出格式(每行一个):carVersionCode|carVersionName
步骤四:查询每个配置版本的交付周期
根据车型是否为 GX/M03/P7 系列,使用不同的查询方式。脚本会根据 carSeriesCode 自动判断。
Case 1:GX/M03/P7 系列车型
针对每个 carVersionCode,运行:
node scripts/fetch_delivery_period.js <carVersionCode> <carSeriesCode>
脚本内部逻辑:
- 请求
listSpecGroupAndSpecList?carVersionSn=${carVersionCode}获取可选配置规格列表 - 遍历每个配置组,在
specList中找到isDefault=1的默认规格,收集其carSpecificationCode - 组成排序后的
carSpecificationCode列表,作为该车型的默认配置规格(列表可以为空,表示无默认选中配置) - 请求
listCarInfoList?carVersionSn=${carVersionCode}获取 SKU 列表 - 对每个 SKU,提取其
specList中所有specCode组成列表并排序 - 找到
specCode列表与默认配置列表完全匹配的 SKU(应唯一) - 输出该 SKU 的
minDeliveryPeriod、maxDeliveryPeriod和carName
输出格式:OK|minDeliveryPeriod|maxDeliveryPeriod|carName 或 NO_DATA|0|0| 或 ERROR|0|0|
Case 2:其他车型
推荐方式(批量查询): 运行一次即可获取该车型所有版本的交付周期:
node scripts/fetch_delivery_period.js <carSeriesCode> --all
脚本内部逻辑:
- 请求
allInOne?carSeriesSn=${carSeriesCode}获取全部数据 - 从响应中提取
carSpecGroupVoMap(配置规格)和carInfoVoMap(SKU 信息),两者均以carVersionCode为 key - 对每个
carVersionCode:- 从
carSpecGroupVoMap中找到默认配置规格(同 Case 1 的匹配逻辑) - 从
carInfoVoMap中找到匹配的 SKU - 输出该版本的交付周期
- 从
输出格式(每行一个版本):carVersionCode|OK|minDeliveryPeriod|maxDeliveryPeriod|carName 或 carVersionCode|NO_DATA|0|0|
备选方式(单版本查询): 也可按版本逐一查询:
node scripts/fetch_delivery_period.js <carVersionCode> <carSeriesCode>
输出格式同 Case 1:OK|minDeliveryPeriod|maxDeliveryPeriod|carName 或 NO_DATA|0|0| 或 ERROR|0|0|
如何选择 Case
脚本自动判断,规则如下:
- Case 1:
carSeriesCode以GX、M03、P7(不区分大小写)开头 - Case 2:其他所有车型
步骤五:输出结果
以表格形式输出每个车型下的交付周期。脚本输出中最后一个 | 后的字段即为 carName,必须将完整的 carName 原样输出到表格的"车辆名称"列,不得省略或截断。
| 车型 | 配置版本 | 车辆名称 | 最短交付周期 | 最长交付周期 | |------|---------|---------|------------|------------| | GX | 1585 四驱 Max | GX 1585 四驱 Max 仰望绿 | 4周 | 6周 | | GX | 665 Max | GX 665 Max 星云白 | 6周 | 8周 |
执行约束
- 严格遵守流程:按步骤一至步骤五顺序执行,不跳过任何步骤。
- 单位为周:交付周期单位是周,不要理解为"天"或做任何转换。
- 默认配置匹配:交付周期取默认配置规格对应 SKU 的数据,不是取 SKU 列表第一个元素。
- 统一使用 Node.js 脚本:所有请求通过
scripts/下的脚本执行,不使用 curl 或 Python。 - Case 2 优先批量:对于非 GX/M03/P7 车型,优先使用
--all模式一次获取全部版本,减少 API 请求次数。 - 容错:某个车型请求失败时,输出该车型查询失败,继续查询其他车型,不中断整个流程。
- 完整输出 carName:脚本输出的最后一个字段是
carName,输出表格时必须将其完整填入"车辆名称"列,不得省略、截断或简写。
异常处理
| 异常场景 | 处理方式 | |---------|---------| | 脚本执行报错(socket hang up / 网络错误 / 非零退出码) | 先重跑同一脚本 2~3 次(间隔片刻);仍失败则将错误转述给用户并停止。严禁改用 curl/Python/WebFetch 等替代方式(见「全局执行铁律」)| | navigationBar API 请求失败 | 报告网络错误,无法继续 | | 用户提供的车型不在列表中 | 提示用户重新选择,展示完整列表 | | 配置页 HTML 中未找到版本信息 | 该车型输出"暂无配置信息" | | listSpecGroupAndSpecList / allInOne API 返回失败 | 该配置输出"查询失败",继续其他配置 | | listCarInfoList API 返回空 data | 该配置输出"N/A" | | 默认配置未匹配到任何 SKU | 该配置输出"N/A" | | listCarInfoList API 请求失败 | 该配置输出"查询失败",继续其他配置 |
第二部分:欧洲市场纯电动车日更数据
数据来源
eu-evs.com(欧洲纯电动车 BEV 注册量数据)。
重要范围说明: ALL_DAILY 视图仅汇总披露日更数据的少数欧洲国家(并非全欧洲)。也就是说,本 Skill 输出的欧洲销量数据只覆盖这些日更国家,不能代表 XPeng 在整个欧洲市场的全貌,也不应直接解读为「欧洲总销量」。
URL 模板:https://eu-evs.com/brands/XPENG/ALL_DAILY/Models-Daily/Year/${year}
页面返回 HTML 表格(id=latestDateTable),包含每个日期各车型的注册量。
脚本列表
| 脚本文件 | 用途 | 用法 |
|---------|------|------|
| xpeng_eu_daily.js | 获取最近 12 个月每日各车型交付销量明细,支持 JSON 和 markdown 报告两种输出 | node xpeng_eu_daily.js [year] [--report] [--email <email> --password <password>] |
xpeng_eu_daily.js 说明
获取指定年份的数据,自动找到最新日期,从最新月开始往前取满 12 个月,返回每个月每个日期的各车型明细和日汇总。
用法:
node scripts/xpeng_eu_daily.js [year] # 输出 JSON(含 daily/monthly_full/monthly_partial)
node scripts/xpeng_eu_daily.js [year] --report # 输出 markdown 报告(①②③ 表格,默认入口)
node scripts/xpeng_eu_daily.js [year] --email <email> --password <password>
year可选,默认当前年份--report输出 3 个 markdown 表格(月度环比 / 全月总销量 / 车型明细),供 LLM 直接展示并附加 ④ 综合分析;默认入口优先用此模式--email/--password可选,用于登录 eu-evs.com(见下方登录流程)
跨年处理(自动):12 个月通常跨越两个自然年(如最新月为 2026-06,则范围为 2025-07 至 2026-06),脚本自动获取所需年份并合并。
登录态与 bot 检测:eu-evs.com 对未登录 / 被判定为 bot / 会话失效的请求会 302 重定向到各种页面(已观察到 /bots、/login、/onlyNamed 等,后续可能继续变化)。由于成功的数据请求固定返回 200,脚本对数据页的任何 302 都视为需要登录,不再枚举重定向目标。处理逻辑如下:
- 首先尝试直接请求数据页(复用
scripts/.eu-session.json中已保存的会话) - 如果被拦截(302)且未提供凭据,向 stdout 输出
LOGIN_REQUIRED(退出码 2) - 如果提供了
--email和--password,自动执行登录流程(GET /login 获取 CSRF token → POST /login 提交凭据),登录后自动重试 - 登录成功后,会话 cookie 保存到
scripts/.eu-session.json,后续运行自动复用 - 初始取数和跨年取数两个阶段共用同一套拦截处理;已登录过则不重复登录
JSON 模式输出格式(不加 --report 时,stdout 输出单行紧凑 JSON):
{
"meta": {
"latest_date": "YYYY-MM-DD", // 最新数据日期
"latest_day": D, // 最新日期是几号(PARTIAL 截止日)
"partial_range": "1-D", // PARTIAL 对比范围
"models": ["车型1", ...], // 基准车型列表(车型名可能含逗号如 "P7,P7I")
"months": ["YYYY-MM", ...] // 12 个月,正序(最旧在前)
},
"daily": [ // 每日明细,每个日期一个对象
{"date":"YYYY-MM-DD","month":"YYYY-MM","sales":{"车型1":N,...},"total":N},
...
],
"monthly_full": [ // 全月汇总(该月所有有数据日期累加)
{"month":"YYYY-MM","days":N,"sales":{...},"total":N},
...
],
"monthly_partial": [ // 同范围汇总(仅 day ≤ latest_day,跨月公平对比用)
{"month":"YYYY-MM","days":N,"range":"1-D","sales":{...},"total":N},
...
]
}
关键说明:
- 车型用 JSON 键:通过
sales.G6、sales["P7,P7I"]访问,彻底避免列错位。 - 预汇总已内置:
monthly_partial直接给出每月 1-D 范围累加,做环比无需手动累加;monthly_full用于全月对比;daily用于单日/趋势分析。 - 跨年车型对齐:以输入年份的车型列表(
meta.models)为基准,跨年数据中缺失车型补 0,新增车型仅当出现在基准列表中才显示。
流程步骤
步骤一:运行 daily 脚本(默认 --report 模式)
默认运行 node scripts/xpeng_eu_daily.js --report(当前年份),直接获取 ①②③ 三个 markdown 表格。如果用户指定了年份(如"查看 2025 年数据"),传入年份参数:node scripts/xpeng_eu_daily.js 2025 --report。
何时用 JSON 模式(不加 --report):用户有非默认需求(某车型长期趋势、单日异常定位、工作日/周末分析、同比对比等),需要基于 daily / monthly_full 灵活计算时,去掉 --report 运行获取 JSON。
步骤一·补充:处理 LOGIN_REQUIRED(必须检测)
检测规则(强制):每次运行 xpeng_eu_daily.js 后,必须检查 stdout 是否包含 LOGIN_REQUIRED。这是脚本要求 agent 介入获取凭据的唯一信号,不得当成普通错误直接结束,必须走下面的询问流程。
信号特征:
- 出现在 stdout(不是 stderr,不要只看 stderr 或退出码)
- 退出码为 2(仅作辅助,以 stdout 字符串为准)
- 可能在初始取数阶段或跨年取数阶段出现,任意阶段出现都同样处理
触发场景:eu-evs.com 将数据页请求 302 重定向到其他页面(/bots、/login、/onlyNamed 等),都意味着需要登录。脚本对数据页的任何 302 都视为需要登录。
处理步骤:
- 使用 AskUserQuestion 询问用户的 eu-evs.com 账号邮箱和密码,并在提示中明确告知用户:
- 凭据用途与隐私承诺:邮箱和密码仅用于本次登录 eu-evs.com,不会上传到任何第三方或其他服务器,请放心提供。
- 注册安全建议:如尚未注册,建议在 eu-evs.com 注册时不要使用自己的常用密码,可使用独立的临时密码,避免主密码泄露风险。
- 如果用户反馈尚未注册,告知用户前往 https://eu-evs.com/register 注册(再次提醒不要使用常用密码),注册完成后提供邮箱和密码
- 拿到凭据后重新运行脚本,追加
--email <email> --password <password>参数 - 登录成功后会话会自动保存(
.eu-session.json),后续运行无需再传凭据
兼容兜底:若脚本输出
ERROR|BOT_BLOCKED_year_*或其他含BLOCKED字样的错误,也按LOGIN_REQUIRED同样流程处理。
步骤一·补充二:处理其他异常(原样上报)
脚本的所有信号(正常数据、LOGIN_REQUIRED、ERROR|...)统一输出到 stdout。运行脚本后,按以下优先级判断:
- stdout 包含
LOGIN_REQUIRED→ 走上方「处理 LOGIN_REQUIRED」流程,询问账密。 - stdout 包含
ERROR|LOGIN_FAILED(凭据错误)→ 告知用户邮箱或密码不正确,重新获取凭据后用--email/--password重试。 - stdout 包含其他
ERROR|...(如ERROR|HTTP_503_year_2026、ERROR|PARSE_FAILED_year_2025、ERROR|no_data_for_year_2025、ERROR|CSRF_TOKEN_NOT_FOUND等)→ 将|后的具体错误信息原样转述给用户,说明当前无法获取数据及原因,不要静默吞掉,也不要自行臆造原因。例如:ERROR|HTTP_503_year_2026→ 「eu-evs.com 返回 503,服务暂时不可用,建议稍后重试」ERROR|PARSE_FAILED_year_2025→ 「2025 年数据页面结构解析失败,数据源可能已变更」ERROR|no_data_for_year_2025→ 「2025 年暂无数据」
判断顺序很重要:先确认是否为 LOGIN_REQUIRED,再确认是否为 LOGIN_FAILED,最后才是其他 ERROR。
脚本返回数据后,按以下规则完成展示与分析。
步骤二:展示 ①②③ 表格 + 生成 ④ 综合分析
①②③ 表格:原样展示脚本输出
输出必须包含范围说明: 在展示 ①②③ 表格前后,需明确注明「以下数据仅覆盖披露日更数据的少数欧洲国家,并非 XPeng 全欧洲总销量」。该说明是必填项,不得省略,以免误导用户将数据解读为欧洲整体销量。
--report 模式输出的 3 个 markdown 表格(① 月度环比对比 / ② 全月总销量 / ③ 各车型销量明细)已由脚本预计算并格式化完成,LLM 原样展示即可,不要重新计算或改写表格数据。
脚本内部已处理:
- 环比变化量与百分比的 +/- 符号、四舍五入(保留 1 位小数)、分母为 0 标 N/A
- 当前月"月未结束"的标注
- 车型顺序按
meta.models固定,0 值保留
④ 综合分析:LLM 生成 4 条核心洞察
基于 ①②③ 表格的数据,输出 4 条核心洞察,建议覆盖以下维度:
- 整体趋势:当前月环比方向与幅度,是否延续上月走势
- 主力车型:销量最高的 1–2 个车型及其贡献率、环比表现
- 异动车型:环比变化最显著的车型(新投放放量、大幅增长或下滑)
- 结构性变化:新车型出现、产品组合迁移、市场份额相关的信号
分析必须具体引用数字(如「G6 当前月 535 辆,环比 +19.2%,贡献增量的 X%」),避免空泛描述。
步骤三:按需扩展(JSON 模式)
当用户需求超出默认 4 模块时,运行无 --report 版本获取 JSON,根据下表选择数据层级灵活计算:
| 需求 | 使用数据 |
|------|---------|
| 月度环比(1-D 同范围) | monthly_partial |
| 月度全月对比 | monthly_full |
| 某车型长期趋势 | monthly_full[].sales.<车型> 或 monthly_partial[].sales.<车型> |
| 同比/季度对比 | 基于 monthly_full 或 monthly_partial 灵活组合 |
| 单日异常定位 | daily(含每日每个车型明细) |
| 工作日 vs 周末分析 | daily(从 date 推导星期) |
执行约束
- 默认入口用
--report,不要手动计算 ①②③:--report模式输出的 3 个表格已由脚本完成所有计算与格式化(环比变化量、百分比、车型对齐、"月未结束"标注),LLM 原样展示即可,不要重新计算或改写表格数据。只有步骤三的按需扩展场景才需要从 JSON 手动计算,此时优先用monthly_partial/monthly_full,不要从daily累加。 - PARTIAL 才是公平对比:最新月尚未结束,必须用「1 号到最新日」的数据与历史月同范围对比(即
monthly_partial),不能用全月数据(monthly_full)对比。 - 日销量可为 0 或缺失:部分日期(如周末)可能没有数据,
daily数组中不会出现这些日期,这是正常现象;monthly_full/monthly_partial的days字段反映实际有数据的天数。 - 车型可能变化:不同年份车型列表可能不同(如 2026 年新增 M03、P7+、X9、F30),脚本已自动对齐,展示时以
meta.models为准。 - 单位为辆:数值为注册量(辆),不是百分比或份额。
- 百分比计算:分母为 0 时不计算百分比,标注为 N/A。
异常处理
总则:脚本所有信号(正常数据、LOGIN_REQUIRED、ERROR|...)统一输出到 stdout,agent 只需检查 stdout 即可判断后续动作,无需看 stderr 或退出码。判断优先级:LOGIN_REQUIRED → LOGIN_FAILED → 瞬时网络错误 → 其他 ERROR → 正常数据。遇到任何失败都只能重跑脚本或上报错误,不得改用 curl/Python/WebFetch 等替代方式(见「全局执行铁律」)。
| stdout 信号 | 含义 | 处理方式 |
|---------|------|---------|
| LOGIN_REQUIRED | 数据页返回 302(未登录 / bot 拦截 / 会话失效,重定向到 /bots、/login、/onlyNamed 等) | 必须使用 AskUserQuestion 询问 eu-evs.com 账号密码;未注册则引导到 https://eu-evs.com/register 注册;拿到凭据后用 --email/--password 重新运行。不得当成错误直接结束 |
| ERROR|LOGIN_FAILED | 邮箱或密码不正确 | 告知用户凭据错误,重新获取凭据后用 --email/--password 重试 |
| ERROR|BOT_BLOCKED_year_* 或其他含 BLOCKED | 拦截信号兼容兜底 | 同 LOGIN_REQUIRED 流程 |
| ERROR|HTTP_<code>_year_<y> | eu-evs.com 返回非预期状态码 | 将状态码和年份原样转述给用户;5xx 建议稍后重试,4xx 说明请求有问题 |
| ERROR|PARSE_FAILED_year_<y> | HTML 表格解析失败 | 告知用户 <y> 年数据页面结构解析失败,数据源可能已变更 |
| ERROR|no_data_for_year_<y> | 指定年份无数据 | 提示用户该年份暂无数据,建议换一年 |
| ERROR|CSRF_TOKEN_NOT_FOUND | 登录页结构变更,取不到 token | 告知用户数据源登录页结构可能已变更 |
| ERROR|LOGIN_HTTP_<code> | 登录接口异常 | 将状态码原样转述给用户 |
| ERROR|socket hang up / ERROR|connect ECONNRESET... / ERROR|ETIMEDOUT 等瞬时网络错误 | 脚本内部已退避重试 3 次仍未恢复(网络抖动、服务端瞬断) | 重跑同一脚本 2~3 次(间隔 5~10 秒);仍失败则将错误转述给用户、说明疑似网络波动并稍后再试。不得改用 curl/WebFetch/Python 等替代方式 |
| 其他 ERROR|<msg> | 未列举的异常 | 将 | 后的信息原样转述给用户,不要静默吞掉,不要臆造原因 |
| 会话过期(已保存 session 失效) | 脚本会再次输出 LOGIN_REQUIRED | 重新走登录流程 |
| 最新月无数据(月初第一天) | 输出结果可能为空 | 提示用户数据尚未更新 |
微信扫一扫