跳到主要内容

13 篇博文 含有标签「自动化」

查看所有标签

飞书 Playwright + Doc Parser 文档下载

· 阅读需 3 分钟
Bowen Zhang
本文作者

必需前置条件

本技能是 Playwright MCP + Doc Parser MCP 的组合实现,二者缺一不可:

  • Playwright MCP:复用已登录的飞书浏览器会话,读取 Wiki 目录树、节点层级和 Wiki token。
  • Doc Parser MCP:解析飞书文档正文、下载 Markdown 及图片。批量下载阶段必须调用其 submit_and_download_with_images 能力。

使用前必须先安装并配置 Doc Parser MCP。安装参考: https://li.feishu.cn/wiki/HoSbwwOt7iLGlZkPGKQcsTNin0f

如果 Doc Parser MCP 未安装、未配置或不可用,应先停止下载并提示用户完成安装;不要改用 lark-cli、飞书 OpenAPI、手工复制或其他解析方式替代。

适用范围

使用本技能把飞书 Wiki 下的全部或指定文档下载到本地,并保留知识库原有层级。目录读取必须通过 Playwright MCP 完成,文档解析和下载必须通过 Doc Parser MCP 完成。

工作流程

  1. 复用 Playwright MCP 中已经登录飞书的浏览器会话。不要随意新建未登录浏览器;如果页面跳到登录页,先重新连接已登录会话。
  2. 打开用户提供的 Wiki 地址,等待左侧目录树完成渲染。只处理用户指定 Wiki 子树,不要把其他空间或搜索结果混入任务。
  3. 从 DOM 收集目录节点的标题、层级位置和 Wiki token。优先使用以下选择器:
    • 节点:div.workspace-tree-view-node
    • 标题:.workspace-tree-view-node-content
    • 层级:data-node-pos
    • 标识:data-node-uid 中的 wikiToken
  4. 只展开目标节点的后代。记录每个节点的原始 pos、标题、token 和父子关系;不要只依赖当前可见文本,因为折叠节点可能尚未出现在 DOM 中。
  5. 根据 data-node-pos 生成本地目录。常见位置如 2,0,0,0 应从索引 3 开始映射,前面的 Wiki 根节点索引不应创建成本地目录。每篇文档使用独立目录,Markdown 和图片保存在该目录内。
  6. 先安全删除本次目标输出目录,再开始全量刷新。确认解析后的绝对路径位于用户指定根目录内,禁止删除其他路径。
  7. 对每个节点调用 Doc Parser 的 submit_and_download_with_images
    • resourceUrihttps://<飞书域名>/wiki/<wikiToken>
    • outputDir:该节点对应的本地目录
    • pollInterval:通常为 5 秒
    • timeout:按文档大小设置,至少覆盖正常解析和图片下载时间
  8. Doc Parser 通常会在 outputDir 下创建 docs-* 临时目录。任务成功后,将临时目录中的最终内容移动到节点目录的预期位置,并删除临时目录;失败时保留错误信息,不把临时目录当作最终结果。
  9. 所有节点完成后执行结果校验,汇总成功、失败、重复名称、缺少 Markdown、图片数量和残留临时目录。

目录映射规则

  • 使用 pos 的路径索引建立父子关系,而不是按遍历顺序猜测目录。
  • 同一父节点下出现同名文档时,按稳定顺序命名为 标题标题 (2)标题 (3);后缀只作用于真正同名的兄弟节点。
  • 不能因为递归遍历了很多子节点,就把父目录错误命名为 标题 (10)
  • 不能把不同节点合并到同一个目录,也不能静默覆盖同名文档。
  • Windows 文件夹名中的非法字符统一替换为 _,同时保留原始标题用于日志和校验。
  • 每个文档目录至少应包含一个 Markdown 文件;图片应保留为相对路径,避免 Markdown 中出现失效的临时绝对路径。

Playwright 读取示例

const nodes = await page.locator('div.workspace-tree-view-node').evaluateAll(items =>
items.map(node => ({
pos: node.dataset.nodePos || '',
uid: node.dataset.nodeUid || '',
title: node.querySelector('.workspace-tree-view-node-content')?.textContent.trim() || ''
}))
);

const tokenFromUid = uid => uid.match(/wikiToken=([^&]+)/)?.[1] || '';

实际执行时应先确认目录已展开、节点数量稳定,再保存 pos、标题和 token。若 token 不在 data-node-uid,点击对应文档后从当前地址提取 /wiki/<token>,仍然只通过 Playwright 完成。

失败处理

  • 登录失效:停止提交下载任务,重新连接已登录 Playwright 会话后再继续。
  • 单篇文档失败:记录 pos、标题、token、目标目录和错误,继续处理其他节点,最后集中重试失败项。
  • 目录数量异常:重新展开目标子树并重新采集,不要依据不完整列表执行全量删除或下载。
  • 出现重复目录或覆盖迹象:停止后续写入,检查同名兄弟的稳定后缀和 pos 映射,再从干净目标目录重跑。
  • Doc Parser 超时:提高该节点的 timeout 后重试;不要把未完成的 docs-* 目录标记为成功。

完成校验

至少检查以下项目:

  • Playwright 采集的文档节点数与成功下载的 Markdown 数量一致,或明确列出失败节点。
  • 每个预期节点都有正确的本地目录,目录层级与 pos 映射一致。
  • 同名文档均有稳定后缀,且没有误覆盖、误合并或父目录异常后缀。
  • Markdown 中的图片引用有效,统计图片总数并抽查相对路径。
  • 目标根目录下没有残留 docs-*、日志、临时下载目录或空的错误目录。

最终报告简要列出输出根目录、节点总数、成功/失败数、Markdown 数、图片数和需要人工处理的节点。

Vanna Fuxi SQL(伏羲数据问答)

· 阅读需 2 分钟
Bowen Zhang
本文作者

基于已部署的 Vanna AI SQL 问答服务(伏羲环境)接口:

  • POST https://vanna-ai-sql-api-ontest.inner.chj.cloud/ask

当用户询问“伏羲上的数据”时(例如“我想查伏羲上的张博文准驾等级”“帮我查伏羲里某人的驾驶证信息”),使用本 skill 调用该接口并整理结果后回复用户。

触发场景(给模型看的)

当满足以下任意条件时,优先考虑使用本 skill:

  • 用户明确提到“伏羲”“伏羲上的数据”“伏羲系统”“Vanna SQL 问答”等。
  • 用户用自然语言问与驾驶/准驾等级/人员车辆信息等相关的问题,并你知道这些数据在伏羲库里。

示例触发语句:

  • “我想查伏羲上的张博文准驾等级”
  • “帮我看看伏羲里某个驾驶人的违规记录”
  • “用 Vanna 那套 SQL 问答帮我看下这个人近期的驾驶情况”

调用方式

使用 exec 工具调用 Node.js 脚本:

python {baseDir}/scripts/ask.py "<自然语言问题>"

其中:

  • <自然语言问题> 直接使用用户的问题文本,例如:
    我想查伏羲上的张博文准驾等级

脚本会:

  1. https://vanna-ai-sql-api-ontest.inner.chj.cloud/ask 发送 POST 请求。

  2. 请求体 JSON 结构遵循后端 QuestionRequest 模型:

    {
    "question": "我想查伏羲上的张博文准驾等级",
    "visualize": false,
    "allow_llm_to_see_data": true,
    "model": null
    }
  3. 得到形如 QuestionResponse 的 JSON:

    • success: 是否成功
    • question: 实际问句
    • sql: 生成并执行的 SQL
    • data: 查询结果(列表,元素为对象)
    • explanation: 对 SQL / 结果的解释(如果有)
    • 其他辅助字段(visualization, data_markdown, error, execution_time 等)
  4. 将完整 JSON 输出到标准输出。

对话流程建议

  1. 检查用户问题是否属于伏羲数据范围:

    • 如果只是一般业务咨询,不需要查库,则按普通对话处理。
    • 如果需要真实数据(例如“准驾等级”“近半年违章次数”等),用本 skill。
  2. 调用脚本:

    python {baseDir}/scripts/ask.py "<用户原始问题>"
  3. 读取脚本输出的 JSON,按以下规则总结回答给用户(用中文):

    • 如果 success == false 或有 error 字段:
      • 告知用户“伏羲查询失败”,简要给出错误信息(避免泄露敏感内部栈信息)。
    • 如果 success == truedata 有内容:
      • 简要说明:你已经调用伏羲 SQL 问答接口并成功返回结果。
      • 若有 sql 字段且非空,请把生成的 SQL 展示给用户(可用代码块包裹)。
      • 结合 datasql/explanation,提炼用户最关心的信息:
        • 对于“准驾等级”类问题,只强调相关字段(例如某人的准驾等级、证件状态等)。
        • 如有多行数据,说明筛选条件(例如按最新记录、或者全部罗列)。
    • 尽量用自然语言解释,必要时可附上一小段表格或项目符号列表。
  4. 如有歧义(例如伏羲数据里有多个同名“张博文”):

    • 向用户说明存在同名记录。
    • 给出区分字段(如身份证号尾号、所属部门等),请用户补充信息后再调用一次接口。

注意事项

  • 本 skill 假定远端接口已经在伏羲环境正确配置并可访问。
  • 如遇网络故障 / 5xx 等错误,先向用户说明是“后端服务不可用或网络异常”,再视情况建议稍后重试。
  • 不要在对话中泄露完整内部 URL 日志,只说明是调用了“伏羲 SQL 问答接口”。

SSP 车辆管理 - 从 prod 迁移车辆到 testtwo

· 阅读需 2 分钟
Bowen Zhang
本文作者

📖 不知道怎么获取 x-chj-gwtoken?看这里! 👉 飞书文档 - 获取 x-chj-gwtoken 操作指南(含截图步骤)

核心原则:优先通过接口操作。 流程:先查 prod 获取原车数据(需 x-chj-gwtoken)→ 再到 testtwo 还原创建(无需鉴权)。

环境信息

环境域名鉴权
prod(licar)https://api-hmi-default-private-front.chehejia.com需要 x-chj-gwtoken
testtwohttps://bcs-jedi-stub-service.testtwo.k8s.chehejia.com无需鉴权

域名可通过环境变量覆盖(默认使用上表中的值):

  • VEHICLE_SYNC_PROD_URL:prod 环境域名
  • VEHICLE_SYNC_TESTTWO_URL:testtwo 环境域名

快速开始

# 安装依赖
pip install -r requirements.txt

# 直接提供 x-chj-gwtoken 运行(推荐)
python scripts/sync.py <VIN> --token "your-x-chj-gwtoken"

# 不提供 x-chj-gwtoken 运行(会提示输入)
python scripts/sync.py <VIN>

获取 x-chj-gwtoken

不知道怎么获取 x-chj-gwtoken?查看飞书文档 👉 获取 x-chj-gwtoken 操作指南(含截图)

x-chj-gwtoken 有过期时间,如果迁移过程中报 401/403,重新获取一次即可。

工作流程

1. [prod] 查询车辆基础信息 → vehSeriesNo、vehVariableModelNo、purpose
2. [prod] 查询车辆配置字 → vehicleConfigCode(HU 功能配置字)
3. [prod] 查询车辆设备信息 → SN、ICCID
4. [testtwo] 同步车辆基础信息(mes/vehicle-info/licar/sync)
5. [testtwo] 同步拓扑信息(mes/topology-info/sync)
6. [testtwo] 创建 HU 功能配置字(config-code/create)
7. [testtwo] 绑定设备(devices/bind)
8. [testtwo] 更新车辆展示信息(update-veh-info)
9. 验证结果

执行步骤(供 Claude 使用)

1. 确认参数

先问用户以下信息,缺什么问什么:

如果用户提供了 VIN 和 x-chj-gwtoken,直接进入第 2 步。 如果用户只给了 VIN,先问 x-chj-gwtoken,并告知去飞书文档查看获取方式。

2. 检查 Python 环境

python --version

确认 Python 3.10+ 可用。

3. 安装依赖

cd "docs/skill/车云平台数据同步-prod-to-testtwo"
pip install requests

4. 运行同步脚本

python scripts/sync.py <VIN> --token "<token>"

如果用户没有提供 x-chj-gwtoken 参数,会交互式提示输入。

5. 向用户报告结果

  • 成功:显示迁移完成 + 车辆信息摘要
  • 失败:显示具体失败步骤 + 错误信息

参数说明

参数必填说明
VIN目标车辆 VIN(位置参数)
--tokenx-chj-gwtoken,不传则交互式输入

故障排查

问题原因解决
401 Unauthorizedx-chj-gwtoken 过期重新获取 x-chj-gwtoken
未找到车辆VIN 不存在于 prod确认 VIN 是否正确
同步失败网络或服务异常重试,或检查 testtwo 服务状态

AOSP APK 签名

· 阅读需 2 分钟
Bowen Zhang
本文作者

使用 scripts/sign.py 调用签名平台接口完成一次完整签名流程:上传 APK、创建后台任务、轮询任务状态,成功后返回签名文件地址。

使用 scripts/download.py 携带 Artifactory Basic Auth 下载 signed_url 返回的签名 APK。

快速开始

python scripts/sign.py path/to/app.apk \
--platform SS4 \
--signature-type platform \
--key-source releasekey \
--user-name fengyubiao

脚本成功时输出 JSON,重点字段为:

{
"status": "completed",
"task_id": "...",
"signed_url": "https://...apk.signed"
}

必填参数与环境变量

脚本读取以下环境变量:AOSP_SIGNATURE_BASE_URLAOSP_SIGNATURE_USER_NAMEARTIFACTORY_USERNAMEARTIFACTORY_PASSWORD

参数默认值说明
apk待签名 APK 本地路径
--user-nameAOSP_SIGNATURE_USER_NAME签名平台用户 LDAP 名称
--platformSS4SS3SS4
--signature-typeplatform签名类型,默认平台签名
--key-sourcereleasekey密钥来源
--base-urlAOSP_SIGNATURE_BASE_URL 或平台正式域名签名平台地址
--interval5轮询间隔,单位秒
--timeout1800最大等待时间,单位秒
--request-timeout300单次 HTTP 请求超时时间,单位秒

当前 Skill 不要求 Cookie,也不会主动发送 Cookie。签名平台需要在当前内网环境可直接访问。

$env:AOSP_SIGNATURE_USER_NAME = "fengyubiao"
python scripts/sign.py .\app-release.apk --platform SS4

下载签名 APK:

$env:ARTIFACTORY_USERNAME = "你的 Artifactory 用户名"
$env:ARTIFACTORY_PASSWORD = "你的密码或 Token"
python scripts/download.py `
"https://artifactory.example/artifactory/path/app.apk.signed" `
--output .\app-release.apk.signed

脚本使用流式写入,先保存为 .part 临时文件,下载完成后再替换目标文件;认证失败、网络失败或中断时会清理临时文件。

下载参数:

参数默认值说明
--usernameARTIFACTORY_USERNAMEArtifactory 用户名
--passwordARTIFACTORY_PASSWORDArtifactory 密码或 Token
--timeout600下载请求超时时间,单位秒
--chunk-size1048576流式下载块大小,单位字节

工作流

  1. 检查 APK 文件存在且扩展名为 .apk
  2. /api/apk/sign 发送 multipart form-data 请求,字段为 fileplatformsignature_typekey_sourceuser_name
  3. 从响应中读取 task_idstatus=accepted 表示任务已进入后台队列,不代表签名完成。
  4. 轮询 /api/tasks/stats/summary?user_name=... 获取总体 signing、completed、failed 状态,用于进度日志。
  5. 轮询 /api/tasks/list?user_name=...,按返回的 task_id 精确匹配当前任务。
  6. status=completedsigned_url 非空时立即返回 signed_url
  7. status=failed 或达到超时时抛出明确错误,并保留 task_id 方便人工排查。

不要按文件名或列表第一条任务匹配;同名 APK 可能存在多个历史任务,必须使用创建接口返回的 task_id

鉴权说明

HAR 只用于确认接口字段和响应结构,不要复制其中的 OAuth code、access token、refresh token 或 Cookie。当前实现不处理 Cookie;若接口返回 401/403,应确认服务端是否已开放内网匿名访问。

相关接口

详细请求/响应字段见 [references/api.md](#)。脚本仅使用 Python 标准库,无需安装第三方依赖;依赖说明见 [requirements.txt](#)

常见问题

  • accepted:任务已创建,继续轮询,不要立即当作成功。
  • signing:签名处理中,继续等待。
  • completedsigned_url 为空:视为异常,返回错误并提示检查平台任务详情。
  • failed:输出 error_message,不要重复自动提交同一个 APK,除非用户明确要求重试。
  • 列表接口没有当前 task_id:可能是任务尚未入库,等待后重试;超过超时后失败。

完整流程 - 从 prod 迁移车辆到 testtwo 并推送应用

· 阅读需 4 分钟
Bowen Zhang
本文作者

一站式编排:检测是否存在 → 添加车辆 → 添加白名单 → 切换云端环境 → 批量推送应用。 本 skill 是编排层:把各叶子能力按顺序串联,判断点必须询问用户;具体接口操作由各子 skill 完成。

流程概览

Step 1 [检测] testtwo 查询车辆是否存在 → 存在则跳过 Step 2
Step 2 [添加] 不存在时:prod 查询 → testtwo 添加车辆 + 绑定设备
Step 3 [白名单] 通过飞书机器人罗伯特添加 X01 白名单(线上 + 线下)
Step 4 [切环境] ⚠ 询问用户是否需要切换云端环境(prod → testtwo)
Step 5 [推送] ⚠ 询问用户是否需要批量推送(按车型选 OTA 测试分组)

前置条件

⚠ 本 skill 是编排层,依赖同市场发布的 3 个子 skill。需与本 skill 一起安装,否则 flow.py list 会显示「缺」,流程无法执行。

1. 安装依赖(插件市场)

本 skill 与子 skill 都发布在插件市场 lixiang-skills-marketplace,先添加并刷新市场,再按名称安装:

# 添加插件市场(首次执行)
/plugin marketplace add https://gitlab.chehejia.com/ai-market/lixiang-skills-marketplace.git

# 刷新市场,拉取最新插件列表
/plugin marketplace update lixiang-skills-marketplace

# 按名称安装(直接写插件名,不要带 lixiang-skills-marketplace@ 前缀)
/plugin install cheyun-vehicle-migrate-prod-to-testtwo-push
/plugin install cheyun-vehicle-sync-prod-to-testtwo
/plugin install cheyun-lark-robert-whitelist-env
/plugin install cheyun-amp-batch-push-app

# 安装完成后执行,使插件生效
/reload-plugins

以下 4 个插件在本流程中的作用与入口脚本:

市场中的名称在本流程中的作用入口脚本
cheyun-vehicle-migrate-prod-to-testtwo-push本编排 skill(主流程)flow.py
cheyun-vehicle-sync-prod-to-testtwoStep 1~2 检测/添加车辆sync.py
cheyun-lark-robert-whitelist-envStep 3~4 白名单/切换环境send.py
cheyun-amp-batch-push-appStep 5 批量推送push.py

2. 运行所需凭据

条件说明
x-chj-gwtokenStep 1~2 查询/同步需要(从 licar.chehejia.com F12 Network 复制)
lark-cli + 飞书群Step 3~4 需要(需先加入罗伯特所在飞书群并 lark-cli auth login
AMP CookieStep 5 需要(testtwo 登录 cookie,见子 skill 说明)

子 skill 一览

步骤子 skill入口脚本
1~2 检测/添加cheyun-vehicle-sync-prod-to-testtwosync.py --token …
3 白名单cheyun-lark-robert-whitelist-envsend.py whitelist <VIN>
4 切换/查询环境cheyun-lark-robert-whitelist-envsend.py switch-env / query-env
5 批量推送cheyun-amp-batch-push-apppush.py add <VIN…> --group …

每个子 skill 都是独立可安装的 skill,本 skill 只负责编排,不重复实现。

驱动命令

# 打印完整 5 步流程与命令(推荐先跑这个)
python scripts/flow.py plan <VIN...>

# 打印某一步的说明与命令
python scripts/flow.py step <1..5> <VIN...>

# 校验子 skill 是否就位
python scripts/flow.py list

执行步骤(供 Claude 使用)

汇总结论:把 flow.py 输出的命令复制执行;每步完成向用户汇报后再进下一步。

  1. 确认 VIN 列表(17 位,多台空格/逗号分隔)
  2. flow.py plan <VIN...> 拿到完整清单与命令
  3. Step 1~2 迁移:确认 x-chj-gwtoken(没有就引导用户从 licar F12 复制,见 cheyun-vehicle-sync-prod-to-testtwo 的飞书文档),运行 sync.py <VIN> --token <token>;若车辆已存在会提示,跳过添加
  4. Step 3 白名单:确认 lark-cli 可用且已进群,运行 send.py whitelist <VIN>(无论什么车型都按 X01;线上+线下都要)
  5. Step 4 切换环境必须询问用户是否需要切换(车辆可能不在线,切了无意义);需要则运行 send.py switch-env <VIN> prod testtwo
  6. Step 5 批量推送必须询问用户是否需要推送;需要则按车型选组(X04B=3000742,X04C=3000743,或 push.py groups --name <关键字> 查),运行 push.py add <VIN...> --group <名称或id>
  7. 收尾汇报:每台车的迁移/白名单/环境/推送结果汇总给用户

判断点(必须询问用户,不要自动执行)

判断点原因
Step 4 是否切换云端环境车辆可能不在线,切换了无意义,由用户判断车辆状态
Step 5 是否批量推送属额外操作,需用户确认

参考文档

内容位置
迁移/检测/添加车辆接口cheyun-vehicle-sync-prod-to-testtwo 技能说明
白名单/切换环境cheyun-lark-robert-whitelist-env 技能说明
测试分组查询接口docs/查询测试分组.md
AMP 登录 Cookie 获取飞书文档 获取AMP登录Cookie操作指南

故障排查

问题原因解决
flow.py list 显示「缺」子 skill 目录缺失按上文安装依赖,装完执行 /reload-plugins
/plugin install lixiang-skills-marketplace@xxx 报 Marketplace not found当前 CLI 不支持 市场名@插件名 写法去掉前缀直接 /plugin install xxx
迁移报 401/403x-chj-gwtoken 过期重新获取并传入;见 sync skill 飞书文档
白名单发送失败/找不到群未进群 / token 过期先通过邀请链接进群,再 lark-cli auth login
推送报 code 240420AMP Cookie 过期重新登录 testtwo AMP 复制最新 Cookie

车辆应用配置(huapp-config)

· 阅读需 2 分钟
Bowen Zhang
本文作者

为指定 VIN 车辆逐条写入应用内部配置(huapp-config):设置应用打开时的首页路由homeRouteName)和截图悬浮按钮showScreenshotFab)开关。 内网接口,无需鉴权,不需要登录 Cookie,可单台或批量调用。

应用不一定都要配 huapp-config —— 只有需要在应用内部做额外设置(首页路由、截图悬浮按钮)的 app 才需要。纯批量加 VIN 到测试分组请用「批量推送」skill。

环境信息

接口https://fuxi-ai-webapp-conversation-01.inner.chj.cloud/api/huapp-config
鉴权无(内网接口)

接口地址可通过环境变量 AMP_HUAPP_CONFIG_URL 覆盖。

默认参数

参数默认值说明
--app-codecom.fuxi.x11mediatest目标应用包名
--home-routeX04cMediaTestDrive_AccelDecelPitch应用打开时的首页路由
截图悬浮按钮showScreenshotFab = true默认开启,--no-fab 关闭

快速开始

# 安装依赖
pip install -r requirements.txt

# 为单台车配置(默认参数)
python scripts/configure.py HLX32B141T1026801

# 指定 app_code、首页路由,并关闭截图悬浮按钮
python scripts/configure.py HLX32B141T1026801 --app-code com.fuxi.x11mediatest --home-route X04cMediaTestDrive_AccelDecelPitch --no-fab

# 批量配置多台
python scripts/configure.py HLX32B141T1026801 HLX34B160T1303448

执行步骤(供 Claude 使用)

  1. 确认参数:VIN(17 位,多台用逗号/空格分隔)、--app-code(默认 com.fuxi.x11mediatest)、--home-route(默认同前)、截图悬浮按钮开关(默认开)
  2. 确认必要性:只有该 app 需要在应用内部做设置时才配置;不了解可询问用户
  3. 运行 python scripts/configure.py <VIN...> [...]
  4. 报告:每台输出 [成功]/[失败] 与汇总「成功 N/总数」;失败项可单独重跑

参数说明

参数必填说明
vins一个或多个 VIN
--app-code应用包名(默认 com.fuxi.x11mediatest
--home-route首页路由名(默认 X04cMediaTestDrive_AccelDecelPitch
--no-fab关闭截图悬浮按钮(默认开启)

故障排查

问题原因解决
单台 [失败]内网接口不可达 / VIN 无效确认在内网环境运行、VIN 为 17 位;可单独重跑该 VIN
返回非 0 code业务异常(参数/app_code 不对)查看失败信息里的 msg,核对包名与参数

批量推送应用到车辆(AMP)

· 阅读需 3 分钟
Bowen Zhang
本文作者

把 VIN 车辆批量添加到 OTA 应用市场运营平台(AMP)的应用测试分组。 纯 Python 实现,不依赖浏览器;接口 + Cookie 鉴权。 车辆应用配置(huapp-config)已拆分为独立 skill「cheyun-amp-huapp-config」:需要配置首页路由/截图悬浮按钮等应用内部设置时用那个 skill,本 skill 只做批量加 VIN。

环境信息

环境接口域名登录页状态
testtwo(开发测试)https://ota-app-market-web.testtwo.k8s.chehejia.comhttps://amp.testtwo.chehejia.com✅ 已接入
prod(生产)https://ota-app-market-web.prod.k8s.chehejia.comhttps://amp.chehejia.com⏳ 接口地址待确认,暂未接入

域名可通过环境变量覆盖:

  • AMP_PUSH_TESTTWO_URL:testtwo 接口域名

testtwo 环境需要登录态。code=240420 表示登录失效。获取 Cookie 方式:

  1. 浏览器登录 https://amp.testtwo.chehejia.com
  2. F12 → Network → 勾选 Fetch/XHR,再按接口域名过滤:ota-app-market-web.testtwo.k8s.chehejia.com;刷新页面或操作一下页面(如触发一次查询)
  3. 复制该请求 Request Headers 里的 Cookie 整串(形如 k1=v1; k2=v2
  4. 通过 --cookie 传入;脚本会保存到 settings.json,下次可省略

Cookie 会过期,报 240420 时重新复制一份即可;可用 --clear-cookie 清除已保存的 cookie。

📖 获取 Cookie 的详细图文步骤见飞书文档:获取AMP登录Cookie操作指南

测试分组解析规则(重要)

--group 参数支持两种写法,脚本自动处理:

用户输入处理方式
数字 id,如 3000742直接作为分组 id 使用
名称/关键字,如 L6试驾调用分页查询接口(/ota/v1/app/market/web/app/test/group/page)按名称模糊匹配
匹配到 1 个自动取该分组
匹配到 多个打印候选列表,提示用户用 --group <数字id> 重新指定(退出码 2)
匹配不到报错,提示先运行 groups --name <关键字> 查看可用分组 id

名称模糊匹配和平台查询的结果一致;拿不准时先运行 groups 子命令确认 id。

快速开始

# 安装依赖
pip install -r requirements.txt

# 按名称查测试分组(返回 id)
python scripts/push.py groups --name L6 --cookie "k1=v1; k2=v2"

# 批量添加 VIN 到测试分组
python scripts/push.py add HLX32B141T1026801 HLX34B160T1303448 --group L6试驾_HU_SS3_台架 --cookie "k1=v1; k2=v2"

# 需要配置车辆应用配置(huapp-config)时,用独立 skill「cheyun-amp-huapp-config」

命令说明

groups:查询测试分组

python scripts/push.py groups [--name <关键字>]
  • 不传 --name 列前 50 条全部分组;传了就按名称模糊匹配
  • 输出包含:id、名称、类型、状态、已关联 VIN 数、说明

add:批量添加 VIN 到测试分组

python scripts/push.py add <VIN> [<VIN> ...] --group <名称或id>

流程:解析分组 → batchAdd(一次性把多个 VIN 加入测试分组)。

需要配置 huapp-config(车辆应用配置,如首页路由、截图悬浮按钮)时,改走独立 skill cheyun-amp-huapp-config,两者分开执行,按需选择。

执行步骤(供 Claude 使用)

  1. 确认参数:拼 VIN(17 位,多台用逗号/空格分隔)、分组(名称或 id)、Cookie(优先已保存的;无则按上文引导获取)
  2. 环境:当前仅 testtwo;如用户明确需要 prod,说明接口地址待确认,暂不可用
  3. 运行:可先 push.py groups --name <关键字> 确认分组 id,再 push.py add ...
  4. 报告:batchAdd 返回 code;多分组歧义时把候选列表展示给用户让其选 id
  5. 按需配置:如果用户还需要配置应用内部设置(首页路由/截图悬浮按钮),再引导用 cheyun-amp-huapp-config skill

参数说明

参数必填说明
vins一个或多个 VIN(add 子命令)
--group测试分组名称或数字 id(add 子命令)
--name分组名称关键字(groups 子命令)
--cookie登录 Cookie,不传则读已保存的
--clear-cookie清除已保存的 cookie 后退出

故障排查

问题原因解决
code 240420Cookie 过期 / 未登录重新登录 https://amp.testtwo.chehejia.com 并复制最新 Cookie
匹配到多个测试分组--group 名称过于模糊按提示用 --group <数字id> 重新指定
未匹配到分组名称不对 / 分组被删先运行 groups --name <关键字> 确认 id
batchAdd 返回业务异常VIN 无效 / 分组状态异常查看返回 msg;确认 VIN 为 17 位、分组已启用
需要配置应用内部设置应是 huapp-config 场景改用独立 skill cheyun-amp-huapp-config

OTA 应用升级数据查询(App Market / AMP)

· 阅读需 3 分钟
Bowen Zhang
本文作者

查询车辆在各应用市场运营平台(AMP)环境下的 OTA 应用升级记录(已安装 / 未安装及版本号)。 纯 Python 实现,不依赖 Playwright 浏览器,通过接口 + 登录 Cookie 鉴权。 应用不写死:VIN 与应用(appid)均由用户输入

环境信息

环境接口域名登录页编号段示例(com.fuxi.x11mediatest)
prod(生产)https://ota-app-market-web.prod.k8s.chehejia.comhttps://amp.chehejia.com1000181
testtwo(开发测试)https://ota-app-market-web.testtwo.k8s.chehejia.comhttps://amp.testtwo.chehejia.com3000170

域名可通过环境变量覆盖(默认使用上表中的值):

  • OTA_QUERY_PROD_URL:prod 接口域名
  • OTA_QUERY_TESTTWO_URL:testtwo 接口域名

两个环境都需要登录态。code=240420 表示登录失效。获取 Cookie 方式:

  1. 浏览器登录对应环境的登录页(prod:https://amp.chehejia.com,testtwo:https://amp.testtwo.chehejia.com
  2. F12 → Network → 勾选 Fetch/XHR,再按接口域名过滤:ota-app-market-web.prod.k8s.chehejia.com(prod)/ ota-app-market-web.testtwo.k8s.chehejia.com(testtwo);刷新页面或操作一下页面(如触发一次查询)
  3. 复制该请求 Request Headers 里的 Cookie 值(形如 k1=v1; k2=v2
  4. 通过 --cookie 传入;脚本会保存到 settings.json,下次可省略

Cookie 会过期,报 240420 时重新复制一份即可;可用 --clear-cookie 清除已保存的 cookie。

📖 获取 Cookie 的详细图文步骤见飞书文档:获取AMP登录Cookie操作指南

appid 转换规则(重要)

queryPage 接口要求平台数字 appId(如 prod 1000181 / testtwo 3000170),不能直接传包名

脚本对用户输入的 --appid 自动处理:

用户输入处理方式
数字,如 1000181 / 3000170直接作为平台 appId 传入
包名,如 com.fuxi.x11mediatest自动调用应用列表枚举接口/ota/v1/app/market/web/common/queryAppList)转为当前环境的数字 appId
中文名子串,如 智能底盘同上,按应用列表模糊匹配
不传查询该车辆全部应用

转换走的目标枚举接口与环境一致:选 --env prod 用 prod 的 app 列表,选 --env testtwo 用 testtwo 的 app 列表。若不匹配会明确报错并提示相近应用。

快速开始

# 安装依赖
pip install -r requirements.txt

# 查询全部应用(prod,需 Cookie)
python scripts/query.py HLX34B160T1303448 --cookie "k1=v1; k2=v2"

# 按包名查某个应用(自动转平台 appId)
python scripts/query.py HLX34B160T1303448 --appid com.fuxi.x11mediatest --cookie "k1=v1; k2=v2"

# 按平台数字 appId 查,并指定 testtwo 环境
python scripts/query.py HLX32B141T1026801 --appid 3000170 --env testtwo --cookie "k1=v1; k2=v2"

# 输出原始 JSON
python scripts/query.py HLX34B160T1303448 --appid com.fuxi.x11mediatest --json

执行步骤(供 Claude 使用)

1. 确认参数

缺什么问什么:

  • VIN:要查询的车辆 VIN(必填)
  • appid:应用。可选。用户直接给包名/中文名/数字均可;不给则查询全部
  • 环境:默认 prod;如需 testtwo 让用户明确指定
  • Cookie:优先用已保存的;失效时引导用户按上文重新复制

2. 检查 Python 环境 & 安装依赖

python --version # 3.10+
pip install -r requirements.txt

3. 运行查询脚本

python scripts/query.py <VIN> [--appid <appid>] [--env <prod|testtwo>] [--cookie "<cookie>"]

4. 向用户报告结果

  • 查到数据:按表展示各行的包名、屏幕、当前/目标版本、升级状态、安装判定、事件时间
  • 未查到:说明该 VIN 在所选环境无该应用升级记录(多数属于未推送/未安装)

返回字段与安装判定

字段说明
code0 成功;240420 登录失效
currentInternalVersion当前版本号(数字),0 表示未装
targetInternalVersion目标版本号
upgradeStatus升级状态码,50 = 升级成功
upgradeStatusName状态文字:升级成功、升级中、下载中、等待升级 等
screenName屏幕位置:中控 / 副驾 / 后排
appPackageName应用包名
eventTime事件时间

已安装判定upgradeStatus == 50currentInternalVersion > 0 → 已安装;否则未完成。

参数说明

参数必填说明
VIN目标车辆 VIN(17 位)
--appid应用:包名 / 中文名 / 平台数字 appId;包名自动转平台 appId;不传查全部
--env环境,prod(默认)或 testtwo
--cookie登录 Cookie,不传则读已保存的
--page-size每页条数(默认 20)
--json输出原始 JSON
--clear-cookie清除已保存的 cookie 后退出

故障排查

问题原因解决
code 240420Cookie 过期 / 未登录重新登录对应环境并复制最新 Cookie
未找到应用 xxx包名/应用名在该环境不存在用应用列表枚举接口确认,或直接用数字 appId
匹配到多个应用输入过于模糊改成完整包名,或直接给平台数字 appId
totalCount: 0该 VIN 无该应用升级记录属于未推送/未安装;可去掉 --appid 查全部

🚀 车云收尾"两件套":切云端环境 + OTA 批量推 App —— 一个编排 Skill 一次串通

· 阅读需 5 分钟
Bowen Zhang
本文作者

一句话摘要: 上一轮我安利过"从 prod 迁车到 testtwo",这次是接续它的编排层 Skill——把「检测 → 添加 → 白名单 → 切换云端环境按车型批量推送 App 到 OTA 测试分组」5 步串成一条线。其中最磨人的两件收尾活:切环境(prod ↔ testtw)和 App OTA 推送,终于不用再跨 AMP / 飞书机器人 / 云端平台人肉一遍。


你是否也被这两件"收尾活"烦着

把车搬进 testtwo、加好白名单,你以为完了——真正磨人的是两个收尾动作

  • 切换云端环境:车得上测试环境联调,结果它云端环境还挂在 prod,联调各种连不上;得去跟飞书机器人「罗伯特」发命令切环境,发完还不知道切没切成,再查一遍;
  • 添加 App 的 OTA 推送:要推了,打开 AMP,按车型挑 OTA 测试分组——组号又长又难记(X04B=3000742、X04C=3000743……),记不住还得回头查,一台一台手点,点错就推到别人的测试环境。

这两件事有规则、纯手工、跨平台,还极其容易错。正适合交给 Claude Code。

所以我把迁移、白名单、切环境、批量推送四个叶子能力串成一个编排 Skill:一句人话触发,5 步一条龙跑完,中间该你拍板的节点自动停下来问你。


一、这个 Skill 是什么:编排层,把 4 个子能力按序串起来

不自造接口,而是站在 4 个已发布的子 Skill 之上,把一条「完整流程」按顺序编排执行:

flow.py plan <VIN...>
├─ Step 1 检测:testtwo 里车是否已存在
├─ Step 2 添加:prod 查原车 → testtwo 建车 + 绑定设备(存在则跳过)
├─ Step 3 白名单:飞书机器人罗伯特加 X01(线上 + 线下)
├─ Step 4 ⚠ 切环境:prod ↔ testtwo(本 Skill 核心新增)
└─ Step 5 ⚠ OTA 推送:选机型测试分组,批量推 App(本 Skill 核心新增)
步骤动作子 Skill入口
1~2检测 / 添加车辆cheyun-vehicle-sync-prod-to-testtwosync.py
3X01 白名单(线上+线下)cheyun-lark-robert-whitelist-envsend.py whitelist
4切换云端环境同上send.py switch-env / query-env
5批量推送 App 到 OTA 分组cheyun-amp-batch-push-apppush.py add / groups

一整条流程 = flow.py 编排 + 4 个子 Skill。只装主 Skill 不装叶子,flow.py list 会显示「缺」,流程跑不了。


二、两件"新增"到底省了什么

场景 A:切换云端环境(Step 4)

以前(约 5~10 分钟,跨两个界面): 找到车 → 判断它目前在 prod 还是 testtwo → 去飞书给机器人罗工发「切环境」命令 → 等回 → 切完再回云端平台查一次确认「现在到底在哪」→ 不在预期里再回头切一遍。

现在: 一行命令(或一句话)就切,切完回读确认在哪个环境:

python send.py switch-env <VIN> prod testtwo # 从 prod 切到 testtwo
python send.py query-env <VIN> # 随时查当前在哪个环境

一句话:「切环境」从『发命令 + 手工回查』变成『一条命令 + 自动确认』。

为什么这个判断点必须先问你: 车可能处于离线。车不在线的时候切换没有意义——是否切由你根据车辆状态拍板,Skill 不做主。

场景 B:批量推送 App 到 OTA 测试分组(Step 5)

以前(一台车 8~15 分钟): 打开 AMP → 输入 VIN → 找到该车型对应的测试分组号(组号要在各分组里翻,因为 X04B=3000742、X04C=3000743 这种编码要死记)→ 把 App 推进分组 → 重复 N 台。

现在:

push.py add VIN1 VIN2 VIN3 --group 3000742 # 多辆车一次批量推
push.py groups --name X04B # 记不住组号?按关键字搜

一句话:「批量推送」从『反复挑组 + 手打组号』变成『一次点名、按机型分组一把推进去』。


三、两个"判断点":它知道什么时候该闭嘴

把流程做成「一门到底」最大的顾虑是自动过头。所以切环境和推送两队都设成了询问点——只问你不自动跑

  • Step 4 为什么问? 车不在线的时候切了等于白切,车辆在不在只有你掌握实况。
  • Step 5 为什么问? 推送是额外操作,推错会误伤测试环境其他同学,必须你确认。

一句话:AI 把能自动的自动掉,把该由你拍板的还给你——这正是它敢『一条龙』的底气。


四、怎么装上、怎么用起来

安装(一条命令串,4 个一起装)

/plugin marketplace add https://gitlab.chehejia.com/ai-market/lixiang-skills-marketplace.git
/plugin marketplace update lixiang-skills-marketplace

/plugin install cheyun-vehicle-migrate-prod-to-testtwo-push
/plugin install cheyun-vehicle-sync-prod-to-testtwo
/plugin install cheyun-lark-robert-whitelist-env
/plugin install cheyun-amp-batch-push-app

/reload-plugins

或到 AI Market 详情页复制安装命令发给 ClaudeCode 机器人即可。

运行所需凭据:

凭据用在怎么拿
x-chj-gwtokenStep 1~2 查/同步 prodlicar.chehejia.com 的 F12 → Network
lark-cli + 进飞书群Step 3~4 白名单/切环境先进罗伯特所在飞书群,再 lark-cli auth login
AMP CookieStep 5 批量推送testtwo 登录浏览器 Copy 最新 Cookie

用法:一句话 / 命令

需求这么说
先看整条流程与命令(推荐先跑)flow.py plan <VIN...>
看某一步怎么执行flow.py step <4/5> <VIN...>
检查子 Skill 是否就位flow.py list
直接开跑「把这辆车迁到 testtwo,切环境,再推到测试分组」或 flow.py run <VIN...>

五、提示与避坑

问题信号解法
子 Skill 没装齐flow.py list 显示「缺」补装完整 4 个插件,再 /reload-plugins
x-chj-gwtoken迁移报 401/403重新从 licar F12 复制一份
白名单发不出去找不到群聊/发送失败先进罗伯特所在飞书群,再登录
推送报错code 240420AMP Cookie 过期,重登 testtwo 替换

别背组号:push.py groups --name <关键字> 帮你搜,X04B=3000742、X04C=3000743 这种事让它记。


适合谁 / 不适合谁

🎯 推荐:

  • 天天在 prod ↔ testtwo 之间切云端环境的测试同学
  • 要给一批车做 OTA 推送、还要按车型分组的
  • 想省"切环境回查 + 背组号"这种纯枯燥操作的人

⚠️ 谨慎:

  • 对云端环境 / OTA 分组关系还不太熟的——先跑 flow.py plan 看清单
  • 对"自动推送"还没把握——Step 5 有刹车点,先手动跑几回确认

下一步规划

  • 📅 支持 VIN 列表文件:CSV 批量 100 台,统一汇总报告
  • 📅 流程日志落盘:每步可回溯,排查不用重跑
  • 📅 凭证改走环境变量:token/cookie 集中管理,不散在命令里

结语

「切环境 + OTA 批量推送」这两件收尾活,是我在车云测试里最想交出去的两件事。 它们不是难,是碎、是重复、是不小心就错。把规则的部分交给编排,把判断的部分留给自己,这台车云测试的日常才算真的顺了下来。

装好之后,在 Claude / LiClaw 里说一句就行:

「把这台车迁到 testtwo,切个环境,再推到 X04B 测试分组」

🚗 完整编排 Skill:https://ai-market.chehejia.com/?page=skills&skill=ckqpipedmzv0phihh4el


Skill 质量检查(skill-quality-check)

· 阅读需 3 分钟
Bowen Zhang
本文作者

检查 skill 目录是否符合上传应用市场的质量标准,兼容输出接近内部评估接口的预检信息(SKILL.md 质量 / 脚本静态分析 / 模拟运行 / 一致性 / 兼容性 / skill 类型 / 沙箱可执行性 / Token 估算 / 安全发现)。 本检查器将 __pycache__ 编译缓存目录及其中的编译产物文件如实判为垃圾文件,不再排除。

检查维度(对齐正式报告)

维度检查内容
SKILL.md 质量目录/SKILL.md 存在、frontmatter 键与 YAML、name(长度/kebab-case/与目录名一致)、description(存在/≤1024/50-500/触发词数量)、正文行数、脚本布局、无不当目录、scripts/ 内容合规、assets/ 内容合规、垃圾/临时文件、根目录非标准文件、路径风格(正斜杠)、引用文件是否存在、引用嵌套深度、目录结构总评
脚本静态分析scripts/ 下每个 .py 脚本:语法正确;存在外部调用(requests/subprocess 等)时必须设置 timeout
模拟运行实际执行每个脚本:--help 正常退出(退出码 0、无堆栈);传入非法参数时优雅报错(退出码非 0、无 Traceback、有错误提示)
一致性代码中的环境变量均在 SKILL.md 文档中提及;requirements.txt 必须存在;所有第三方 import 均在 requirements.txt 中声明
兼容性Python 3.10+ 运行时、Claude Code/OpenClaw 兼容性预检
内部接口预检--json 输出 company_compatible,包括 skill 类型、外部依赖、沙箱可执行性、Token 估算、依赖/环境变量一致性和安全发现

快速开始

# 全量扫描 skills 项目根目录下所有 skill
python scripts/checker.py

# 指定一个或多个 skill 目录逐个检查
python scripts/checker.py cheyun-vehicle-cloud-online-status
python scripts/checker.py ../foo-skill ../bar-skill

# 覆盖扫描根目录、关闭模拟运行、JSON 输出
python scripts/checker.py --root D:/path/to/skills --no-run
python scripts/checker.py --json

--json 输出中的 company_compatible 是本地静态预检,不会访问公司服务端,也不能替代最终上传检测;它的字段和严重级别尽量贴近 AI Market 返回结构。

参数说明

参数说明
dirs要检查的 skill 目录(位置参数,可多个);缺省扫描根目录下所有含 SKILL.md 的目录
--root <dir>覆盖扫描根目录(默认 D:\bowen\project\skills
--no-run关闭「模拟运行」,只做静态检查(零副作用)
--json输出 JSON 结果(供自动化脚本使用)

执行步骤(供 Claude 使用)

1. 确认参数

  • 目标:检查某个具体 skill,还是全量扫描?缺省即全量扫描。
  • 是否要模拟运行:默认开启;若用户担心副作用或目标目录含会真实发送消息/调接口的脚本,可加 --no-run

2. 运行检查器

python scripts/checker.py [skill_dir...] [--no-run]

3. 解读报告

  • 每个 skill 一行 [目录名] 整体得分 xx | 全部通过 / 有 N 项未通过,各维度给出分类得分。
  • [PASS] 通过;[LOW ] 次要问题(如触发词缺失、assets 混入非资源文件);[MED ] 中等问题(如垃圾文件、语法错误、缺超时、依赖未声明)。
  • 有未通过项时,把对应项的 明细 逐条反馈给用户并给出修复建议。

4. 常见修复

问题修复
垃圾/临时文件(明细含 __pycache__ 缓存目录)删除该缓存目录后复查(运行脚本后必现,上传前再清一次;用 rm -rf 删除即可)
scripts/ 内容合规(存在非脚本文件)把模板等移入 scripts/ 下专用的模板子目录,其余非 .py 文件移出 scripts/
description 长度不足 50补充触发词与能力描述,扩展 description
触发词数量检查: 0 个在 description 末尾加 当用户提到"xxx"时触发(引号内为触发词)
存在外部调用但未设置超时给 requests/subprocess 调用补 timeout= 参数
未声明的依赖: xxx在 requirements.txt 补一行 xxx==版本(纯标准库则写 # Pure standard library…
出现堆栈跟踪脚本顶层需 if __name__ == "__main__": 包裹 try/except Exception 优雅退出
引用文件是否存在(正文引用了磁盘上不存在的路径)把正文中反引号内的路径改成真实存在的相对路径,或用描述性措辞,不要写成本就不存在的路径字符串(如示例、通配符、占位目录)

故障排查

问题原因解决
未在 … 下找到含 SKILL.md 的 skill 目录扫描根目录下没有带 SKILL.md 的目录传入 dirs 指定目标,或用 --root 指定正确根目录
模拟运行报错/超时目标脚本依赖特定环境或交互输入--no-run 跳过模拟运行
结果中 __pycache__ 反复出现每次运行脚本都会生成编译缓存上传前删除 scripts/ 下的 __pycache__ 目录,并注意本检查器运行后自身也会生成缓存
Python 3.10 以下依赖 list[str] 等新语法升级到 Python 3.10+