Smart Skill Matcher · 托管付费版(Hosted PaySkill Edition)
> 中英双语文档 | Bilingual (中文 / English)
目录 | Table of Contents
- 快速开始(3 步跑通)
- 定位
- 触发时机与触发示例
- 包内文件与运行形态
- 调用约定
- 端到端示例
- 错误码与用户可见提示
- 异常与降级
- 常见问题 FAQ
- 反模式(请勿这样用)
- 故障排查
- 接口参考
- 推荐引擎与一键安装
- 版本变更
- 隐私与合规
1. 快速开始 | Quick Start
> 目标:3 步走通「出账 → 支付 → 拿到推荐结果」。
前置条件
| 项 | 要求 |
|---|---|
| 运行环境 | Node.js >= 18(依赖全局 fetch / AbortController);或 Python 3.8+(仅用标准库,无第三方依赖) |
| 沙箱环境变量 | SKM_API_BASE 【必填】 后端 Base URL(形如 https://<appid>-<hash>.ap-shanghai.tencentscf.com,路由直挂域名根) |
| 可选环境变量 | SKM_API_KEY(仅 /market、/team、/orders 等内网接口需要;/recommend 是公开计费点,不配也照常走 402) |
第 1 步:发起首次调用 → 拿到 402 账单
node skillhub-payskill/call.js "帮我做一份销售数据可视化看板"
# 或
python skillhub-payskill/call.py "帮我做一份销售数据可视化看板"
预期输出(节选,金额与订单号为示例值):
{
"ok": false,
"status": 402,
"stage": "pay",
"error": "payment_needed",
"bill": {
"protocol": {
"out_trade_no": "SKM_1759027200000_a1b2c3d4",
"amount": "0.01",
"currency": "CNY",
"resource_id": "skill-recommend",
"pay_before": "2026-09-28T22:20:00+08:00",
"seller_signature": "<RSA2 签名,Base64URL>",
"seller_unique_id": "<商家唯一标识>"
}
}
}
> 402 不是故障,是计费点:表示"这次推荐需要先付费"。
第 2 步:完成支付,取回 Payment-Proof
把上一步的 bill 交给支付宝 AI 付(AI 按量付费)完成用户支付;支付成功后取得 Payment-Proof(Base64URL 文本)。
第 3 步:携带凭证重试 → 拿到 TOP-5 推荐
# 推荐用 stdin 传入,避免 Payment-Proof 进入 shell 历史
echo "<你的Payment-Proof>" | node skillhub-payskill/call.js "帮我做一份销售数据可视化看板"
预期输出(节选):
{
"ok": true,
"status": 200,
"stage": "complete",
"tradeNo": "2026092822001...",
"data": {
"ok": true,
"intent": {
"category": "data-analysis",
"category_name": "数据分析",
"keywords": ["销售数据可视化看板", "数据分析", "数据可视化", "报表"],
"market_source": "https://api.skillhub.cn"
},
"degraded": false,
"recommended": [
{
"name": "<技能名>",
"slug": "<slug>",
"source": "market",
"category": "data-analysis",
"categoryName": "数据分析",
"description": "<技能描述>",
"tags": ["<标签>"],
"matchScore": 0.87,
"hot": 12,
"downloads": 4800,
"installs": 1200,
"homepage": "https://skillhub.cn/skills/<slug>",
"matchReason": "命中关键词:数据、可视化;分类匹配:数据分析;市场热度:4.8k 下载 / 1.2k 安装"
}
],
"trade_no": "2026092822001...",
"out_trade_no": "SKM_1759027200000_a1b2c3d4",
"already_fulfilled": false,
"fulfillment_confirmed": true
}
}
> 到这一步,整条链路已经跑通:402 出账 → 支付 → 验付 → 交付 → 履约回执。
> 推荐结果带 slug 与 homepage,可直接一键安装(见第 13 节)。
2. 定位 | Positioning
中文:本技能为云端托管版。匹配算法、市场数据与定价策略在云端,算法本身不公开;但随包提供可读、可运行、可审计的协议适配层(skillhub-payskill/ 目录),包含完整的入参校验、错误处理、重试、幂等逻辑与付费后一键安装。收到任务后,把用户需求与已安装技能清单上报云端,云端依次完成 12 分类意图识别 → 关键词同义扩展 → 多次市场检索合并 → 意图排序,返回 TOP-5 语义推荐(附分类、热度、主页与匹配理由);每次成功推荐消耗 SkillHub 套餐 1 次。
English: A hosted / closed-source-algorithm edition. Matching runs in the cloud; the readable, runnable protocol adapter ships in-package with full validation, error handling, retry, idempotency and one-click install after payment. The cloud pipeline performs 12-category intent inference → keyword expansion → multi-query market search → intent ranking, returning TOP-5 semantic recommendations with category, popularity, homepage and match reasons; each successful recommendation consumes 1 credit.
3. 触发时机与触发示例 | When to Invoke
会触发
| 场景 | 用户话术示例 |
|---|---|
| 新建任务 / 新会话时做技能匹配决策 | "帮我做一份销售数据看板"、"我想分析这份 Excel" |
| 询问该用什么技能 / 插件 / 工具 | "有没有适合做 PPT 的技能?"、"这个需求该用什么工具?" |
| 需要跨平台语义推荐、市场热榜或同类对比 | "最近有什么热门的效率工具?"、"A 和 B 这两个技能哪个更合适?" |
不会触发
| 场景 | 说明 |
|---|---|
| 纯知识问答 / 闲聊 | "今天几号?"、"解释一下什么是向量检索" |
| 用户已明确指定技能 | "用 xx 技能帮我处理" —— 直接执行,无需匹配 |
| 与技能选型无关的代码/文档任务 | 例如"帮我修这个 bug",应直接进入开发流程 |
4. 包内文件与运行形态 | Package & Architecture
包内文件清单(发布包 skill-matcher-payskill-1.2.0/)
├── SKILL.md ← 本文档(技能说明与协议参考)
├── SkillHub_上架与定价.md ← 上架与定价说明
├── pricing.json ← 价格档位声明
├── references/
│ └── categories.md ← 12 分类体系与匹配引擎参考(渐进式披露)
├── docs/
│ └── SKILLHUB_上架部署指南.md ← 部署与发布手册
└── skillhub-payskill/ ← 协议适配层(可读 / 可运行 / 可审计)
├── call.js / call.py ← SkillHub 沙箱统一入口(CLI + 模块导出 + 一键安装子命令)
└── a2m-pay.js / a2m_pay.py ← A2M 402 协议客户端(校验 / 错误处理 / 重试 / 幂等 / 付费后安装)
边界说明
- 不公开的部分:匹配算法(分类推断 / 关键词扩展 / 检索排序)、市场数据库、定价与计费策略 —— 均在云端,不在包内。
- 公开的部分:客户端协议适配层源码随包提供,可逐行审计其入参校验、超时、重试、错误码、幂等实现,以及付费后的一键安装逻辑。
- 运行形态:SkillHub 云端沙箱;本地无匹配能力,能力全部来自后端
recommend-api。 - 分类体系参考:
references/categories.md描述 12 个一级分类与匹配引擎的外部可观测行为,供需要理解结果来源时阅读。
5. 调用约定 | Calling Convention
- 基础地址:
SKM_API_BASE(由沙箱环境变量注入,不随包分发、无兜底默认值) - 鉴权:
/recommend为 A2M 协议端点,公开可达(买家侧 Agent 不持有商家内网 Key);访问控制由支付墙承担(无凭证 → 402 出账)。/market、/team、/orders需请求头Authorization: Bearer <API_KEY>。- 客户端 Key 为可选:未配置
SKM_API_KEY时不会本地阻断,直接发起请求走 402 计费。 - 失败重试:
runWithRetry(...)(JS)/run_with_retry(...)(Python)对可重试错误做有界指数退避;402 与 4xx 参数错误立即返回。重试始终使用同一 Payment-Proof,后端订单幂等,不会重复计费或重复交付。 - 运行环境:JS 端 Node >= 18;Python 端仅用标准库。
- 关于异步通知:AI 按量付费(A2M)没有支付宝回调商家的异步通知机制。协议全链路均为商家主动出站调用(
payment.verify验付 →fulfillment.confirm履约回执)。对账依赖本地订单落库 + 支付宝商家中心对账单;POST /notify仅作为内部补单 / 对账修正入口保留,不是支付宝回调地址。
支付宝 AI 付(A2M 402)流程
POST /recommend(无Payment-Proof)→HTTP 402,Payment-Needed响应头携带 Base64URL 账单(含out_trade_no / amount / currency / resource_id / pay_before / seller_signature(RSA2) / seller_unique_id)- 智能体把账单交给支付宝,用户支付后取得支付凭证
POST /recommend(带Payment-Proof,含payment_proof / trade_no / client_session)→ 后端验付通过返回 TOP-5 推荐,并异步发送履约回执
通用按量付费语义映射(SkillHub 标准支付闭环 ↔ 支付宝 A2M 协议)
| 阶段 | 语义 | A2M 对应实现 |
|---|---|---|
probe |
探测:检查是否已持有效支付凭证 | 检查 Payment-Proof → alipay.aipay.agent.payment.verify 验付 |
pay |
支付:下发账单等待用户支付 | HTTP 402 + Payment-Needed 账单(含金额/订单号/RSA2 签名) |
complete |
完成:验付通过后交付资源 | 返回推荐资源 + alipay.aipay.agent.fulfillment.confirm 履约 |
ack |
回执:订单幂等确认,防重复交付 | 订单状态机 pending → paid → fulfilled(Redis 持久化,幂等) |
6. 端到端示例 | End-to-End Examples
示例 A:首次调用,拿到 402 账单
node skillhub-payskill/call.js "帮我做一份销售数据可视化看板"
{
"ok": false,
"status": 402,
"stage": "pay",
"error": "payment_needed",
"bill": {
"protocol": {
"out_trade_no": "SKM_1759027200000_a1b2c3d4",
"amount": "0.01",
"currency": "CNY",
"resource_id": "skill-recommend",
"pay_before": "2026-09-28T22:20:00+08:00",
"seller_signature": "<RSA2 签名>",
"seller_unique_id": "<商家唯一标识>"
}
},
"detail": "{\"error\":\"payment_required\",\"message\":\"请先完成支付\"}"
}
接下来做什么:把 bill.protocol 交给支付宝 AI 付完成支付。
示例 B:携带凭证重试,拿到推荐结果
echo "<你的Payment-Proof>" | node skillhub-payskill/call.js "帮我做一份销售数据可视化看板"
{
"ok": true,
"status": 200,
"stage": "complete",
"tradeNo": "2026092822001...",
"data": {
"ok": true,
"intent": { "category": "data-analysis", "category_name": "数据分析", "keywords": ["…"], "market_source": "https://api.skillhub.cn" },
"degraded": false,
"recommended": [
{ "name": "<技能名>", "slug": "<slug>", "source": "market", "category": "data-analysis", "categoryName": "数据分析", "description": "<描述>", "tags": ["<标签>"], "matchScore": 0.87, "hot": 12, "downloads": 4800, "installs": 1200, "homepage": "https://skillhub.cn/skills/<slug>", "matchReason": "命中关键词:数据、可视化;分类匹配:数据分析" }
],
"trade_no": "2026092822001...",
"out_trade_no": "SKM_1759027200000_a1b2c3d4",
"already_fulfilled": false,
"fulfillment_confirmed": true
}
}
字段含义
| 字段 | 含义 |
|---|---|
intent |
云端意图识别结果:category / category_name(12 分类之一)、keywords(扩展后的检索词)、market_source(实际市场源;降级时为 local-fallback) |
degraded |
true 表示市场检索不可用,结果来自云端本地兜底库(不含 slug / 主页,无法一键安装) |
recommended[] |
TOP-5 推荐(按契合度降序,同档按 hot 降序) |
recommended[].source |
installed(已安装)/ market(市场推荐)/ local-fallback(降级兜底) |
recommended[].slug |
技能唯一标识,用于一键安装(降级兜底时为空) |
recommended[].category / categoryName |
分类键与中文名(见 references/categories.md) |
recommended[].matchScore |
归一化匹配度(0~1,最高 1.00) |
recommended[].hot |
市场热度值(下载/安装对数压缩后的整数) |
recommended[].downloads / installs |
市场下载量 / 安装量(原始计数) |
recommended[].homepage |
技能市场主页链接(降级兜底时为空) |
recommended[].matchReason |
可读匹配理由(命中关键词 / 分类匹配 / 热度) |
already_fulfilled |
true 表示该笔订单此前已交付(幂等命中,未重复计费) |
fulfillment_confirmed |
true 表示履约回执已确认 |
示例 C:网络中断与自动重试
const { runWithRetry } = require("./skillhub-payskill/call.js");
// 仅对可重试错误(网络错误 / 429 / 5xx / 502 履约回执失败)做有界指数退避
const r = await runWithRetry("帮我做一份销售数据看板", [], proof, 3, 500);
console.log(r.status, r.error, r.attempts);
{ "ok": false, "status": 0, "stage": "probe", "error": "network", "retryable": true, "message": "请求超时", "attempts": 3 }
行为说明:最多 3 次尝试,退避间隔 0.5s → 1s → 2s;三次仍失败则原样返回最后一次结果,由调用方决定是否提示用户稍后重试。
示例 D:订单对账(服务商自查)
curl -H "Authorization: Bearer $SKM_API_KEY" \
"$SKM_API_BASE/orders?limit=20&status=fulfilled"
返回 orders[](含 out_trade_no / status / amount / trade_no / created_at / paid_at / fulfilled_at)与 summary(fulfilled 笔数、fulfilled_amount 合计金额)。status 取值 pending | paid | fulfilled:paid 表示钱已到账但资源未交付(异常需排查),fulfilled 表示已交付。
示例 E:健康检查(免鉴权探活)
curl "$SKM_API_BASE/health"
用于发布前 / 排障时确认后端存活,不产生任何费用。
7. 错误码与用户可见提示 | Error Codes
客户端返回的 error 字段与后端返回的 reason / code 字段,含义与处置如下。
error / code |
触发条件 | HTTP | 用户会看到什么 | 建议动作 | 自动重试 |
|---|---|---|---|---|---|
config_missing |
沙箱未注入 SKM_API_BASE |
500 | "未配置 SKM_API_BASE:请在 SkillHub 沙箱环境变量注入后端 Base URL…" | 运维补齐环境变量后重试 | 否 |
bad_request |
入参缺失 / 超长 / 凭证含非法字符 | 400 | "缺少 user_input" / "user_input 过长(上限 4000 字符)" / "Payment-Proof 含非法字符(应为 Base64URL 文本)" | 修正入参后重试 | 否 |
network |
连接失败 / DNS 失败 / 建连或读体超时 | 0 | "请求超时" 或底层网络错误信息 | 检查网络与后端可用性;用 runWithRetry 自动退避重试 |
是 |
payment_needed |
无有效凭证(正常计费点) | 402 | 返回账单(金额 / 订单号 / 有效期)+ 引导支付 | 交给支付宝 AI 付完成支付,带 Payment-Proof 重试 |
否 |
reason: bad_proof / proof_invalid |
凭证非法或已失效 | 402 | 账单 + reason |
重新支付取得新凭证 | 否 |
reason: order_not_found |
凭证对应的订单不存在 | 402 | 账单 + reason |
用最近一次出账的订单凭证;必要时重新出账 | 否 |
reason: order_expired |
账单已过 pay_before |
402 | 账单 + reason |
重新发起出账,取新账单支付 | 否 |
reason: order_not_usable / not_active |
订单状态不可用(已关闭/已退款等) | 402 | 账单 + reason |
重新出账 | 否 |
reason: amount_mismatch |
支付金额与账单不符 | 402 | 账单 + reason |
严格按账单 amount 支付 |
否 |
reason: trade_no_mismatch |
凭证交易号与订单不匹配 | 402 | 账单 + reason |
使用同一订单的凭证,勿混用 | 否 |
reason: resource_mismatch |
凭证资源标识与订单不匹配 | 402 | 账单 + reason |
使用同一订单的凭证 | 否 |
reason: missing_* |
凭证缺少必要字段 | 402 | 账单 + reason |
凭证不完整,重新支付 | 否 |
reason: verify_failed / gateway_error |
支付宝网关验付失败 / 网关异常 | 402 | 账单 + reason |
稍后重试;持续出现请联系服务商 | 否 |
http_401 / unauthorized |
内网接口未带 Bearer,或 Key 不在白名单 | 401 | 401 | 仅内网接口需配置 SKM_API_KEY;/recommend 无需 Key |
否 |
http_400 |
后端参数校验失败 | 400 | 后端 message |
按提示修正请求 | 否 |
http_404 |
路径不存在(多为 Base URL 配错) | 404 | 404 | 检查 SKM_API_BASE 是否直挂域名根、未多带前缀 |
否 |
http_429 |
触发限流 | 429 | 429 | 退避重试 | 是 |
http_5xx |
后端异常 | 5xx | 5xx | 退避重试;持续出现请联系服务商 | 是 |
FULFILLMENT_CONFIRM_FAILED |
资源已生成,但履约回执发送失败 | 502 | 502 + code |
用同一 Payment-Proof 重试即可,不会重复计费 |
是 |
bad_json |
200 但响应体无法解析为 JSON | 200 | 无结构化结果 | 联系服务商排查网关 | 否 |
> 「自动重试」= runWithRetry / run_with_retry 会自动退避重试的错误类别。
hint 字段(展示层):经 call.js / call.py 的 CLI 调用失败时,输出会在原结果上附加一个 hint 字段 —— 上表「用户会看到什么 + 建议动作」的中文合并文案。纯查表、不参与请求、不改动任何协议语义;库调用(require / import 后直接调 run)返回结构不受影响。
{
"ok": false,
"status": 500,
"stage": "probe",
"error": "config_missing",
"message": "未配置 SKM_API_BASE:…",
"hint": "未配置 SKM_API_BASE:请在 SkillHub 沙箱环境变量注入后端 Base URL(形如 https://<appid>-<hash>.ap-shanghai.tencentscf.com),运维补齐后重试。"
}
8. 异常与降级 | Failure Handling & Degradation
> 本节说明异常发生时会发生什么,以及不会发生什么。
| 异常场景 | 客户端行为 | 用户可见结果 | 是否自动恢复 |
|---|---|---|---|
| 网络不可达 / DNS 失败 | 标记 retryable,交由 runWithRetry 退避重试 |
"请求超时" 或网络错误信息 | 是(最多 3 次尝试) |
| 建连成功但响应体慢速滴流 | 超时覆盖「建连 + 读体」全程,超时内主动放弃 | 按网络错误上报(可重试),不会永久挂起 | 是 |
| 后端 5xx / 429 | 标记 retryable,退避重试 |
5xx / 429 | 是 |
| 履约回执失败(502) | 标记 retryable,用同一凭证重试 |
502 + FULFILLMENT_CONFIRM_FAILED |
是(订单幂等,不重复计费) |
| 沙箱环境变量缺失 | 直接返回 config_missing,不发出任何请求 |
明确的配置指引文案 | 否(需运维补齐) |
| 响应体异常大 | 按 1 MB 上限截断读取,防内存耗尽 | 按截断内容解析 | 否 |
| 服务端返回重定向 | 不跟随,直接失败 | 网络类错误 | 否(避免支付凭证被转发到第三方主机) |
| 支付凭证非法字符 / 超长 | 本地拦截,不发出请求 | "Payment-Proof 含非法字符" | 否 |
| 云端服务不可用 | 无本地兜底,如实失败 | 明确的错误码与提示 | 否(等待服务恢复) |
降级原则
- 诚实降级,不伪造结果:匹配能力全在云端,云端不可用时返回错误,不会返回本地猜测的假推荐。
- 失败可解释:每个失败都有稳定的
error/reason码与人类可读message,不做"静默失败"。 - 计费安全:重试复用同一
Payment-Proof,服务端订单状态机pending → paid → fulfilled保证不重复计费、不重复交付。 - 凭证不落盘:
Payment-Proof全程不写日志、不写文件、不进命令行参数(优先环境变量 / stdin)。
9. 常见问题 FAQ
Q1. 需要安装什么?要额外装规则文件吗?
不需要。本技能是云端托管版,只需在 SkillHub 侧配置沙箱环境变量 SKM_API_BASE(必填),无需本地安装规则文件或依赖包。
Q2. 一定要配 API Key 吗?
不必。/recommend 是公开计费点,买家侧不持有商家内网 Key。仅当你要调用 /market、/team、/orders 等内网接口时,才需要配置 SKM_API_KEY。
Q3. 为什么第一次调用返回 402?是报错吗?
不是报错,是计费点。402 表示"这次推荐需要先付费",响应头 Payment-Needed 里带着账单(金额、订单号、有效期、RSA2 签名)。按《快速开始》第 2、3 步支付后重试即可。
Q4. 钱扣了但没拿到结果,怎么办?
先看返回的 status / reason:若是 502 FULFILLMENT_CONFIRM_FAILED,说明资源已生成、只是履约回执失败 —— 用同一 Payment-Proof 重试即可拿到结果,不会重复计费。若是 402,说明凭证未被接受,按 reason 提示处理。仍无法解决时,用 GET /orders(Bearer)核对订单状态。
Q5. 会重复计费吗?
不会。同一 Payment-Proof 对应同一订单,服务端状态机 pending → paid → fulfilled 幂等;重复提交会命中 already_fulfilled: true 并直接返回既有结果。
Q6. 可以离线使用吗?
不可以。本技能不含本地匹配算法,必须联网调用后端 recommend-api。后端不可用时会如实报错,不会返回本地假结果。
Q7. 可以换成我自己的后端吗?
可以。把 SKM_API_BASE 指向你自己部署的 recommend-api(保持 /recommend、/market 等路由与 A2M 402 协议一致)即可。
Q8. 超时多久?重试几次?
默认超时 30 秒(覆盖建连与读体全程),可用非机密环境变量 SKM_TIMEOUT_MS 覆盖。runWithRetry 默认最多 3 次尝试,退避 0.5s → 1s → 2s,仅对可重试错误生效。
Q9. 支持哪些运行环境?
JS 端需 Node.js >= 18(依赖全局 fetch / AbortController);Python 端仅用标准库,Python 3.8+ 可用。
Q10. 为什么只返回 5 个推荐?
TOP-5 是计费点约定的交付粒度(按 matchScore 降序、同分按 hot 降序)。需要更多候选时可多次调用。
Q11. 为什么不公开源码?
匹配算法、市场数据与定价策略属服务商核心资产,运行在云端。但协议适配层源码随包提供(skillhub-payskill/),你可以逐行审计它的校验、超时、重试、错误码与幂等实现。
Q12. 输入有什么限制?
需求文本 ≤ 4000 字符;已安装技能清单 ≤ 200 条;技能字段单值 ≤ 200 字符;单个技能对象键数 ≤ 50。超限会返回 400 bad_request 且不发出请求。
Q13. 怎么对账?
两条线交叉核对:① SkillHub 后台调用量;② 你的云函数 POST /recommend 访问日志 + GET /orders 订单账本(pending / paid / fulfilled)。二者应一一对应。
Q14. 怎么确认后端还活着?
GET /health(免鉴权、不计费)。
Q15. 触发不了怎么办?
本技能在「新建任务 / 新会话做技能匹配」「询问该用什么技能」时触发。若你的任务已明确指定技能,或属于纯知识问答,则不会触发——这是预期行为(见第 3 节)。
Q16. 推荐结果里的分类是怎么来的?
云端按 12 个一级分类的意图词做命中统计,命中最多者胜出(见 references/categories.md)。无命中时不强行归类,category 为空串,排序退化为纯词面相关度 + 热度。
Q17. 推荐结果能直接安装吗?
能。结果带 slug 时,用 call.js install <slug> --agent <你的Agent>(或 --dir <绝对路径>)即可装进当前 Agent 的 skills 目录。安装是付费后的本地动作,不额外计费。若结果处于降级状态(degraded: true),则无 slug、不能安装。
Q18. 一次调用会检索多次,会多扣费吗?
不会。多次市场检索都发生在同一次付费调用内部,一次调用 = 一次计费;检索次数与计费次数无关。
Q19. 结果里的热度(hot)和下载量是实时值吗?
downloads / installs 为检索时抓取的市场原始计数,hot 为下载/安装对数压缩后的整数值。检索结果在云端有进程内缓存(默认 5 分钟),因此短期内可能看到相同数值。
10. 反模式(请勿这样用) | Anti-Patterns
| 反模式 | 为什么危险 | 正确做法 |
|---|---|---|
把 Payment-Proof 写进日志、文件、工单或聊天记录 |
支付凭证泄露,可能被他人重放 | 仅内存中传递;经环境变量 SKM_PAYMENT_PROOF 或 stdin 传入 |
把 Payment-Proof 作为命令行参数 |
会留在 shell 历史与进程列表 | 用 stdin 管道或环境变量 |
并发重放同一 Payment-Proof 期望多次交付 |
订单幂等,只会交付一次;并发反而可能触发限流 | 串行调用;重复提交命中 already_fulfilled |
把 SKM_API_BASE 写死在代码里或提交到仓库 |
内部地址与账号标识随代码扩散 | 一律从环境变量读取;缺失时显式报错 |
| 用生产凭证打沙箱网关,或反之 | 验签必然失败(verify_failed) |
沙箱/生产两套凭证体系严格隔离 |
| 绕过 402 直接改后端或伪造凭证 | 违反计费协议,订单状态机将拒绝 | 老老实实走「出账 → 支付 → 验付」 |
| 把内网 Bearer Key 下发给终端用户 | 内网接口被越权调用 | 内网 Key 只留在服务端/沙箱侧 |
| 把它当通用搜索引擎或大模型 | 它只做技能推荐,不做通用问答 | 通用问答交给对应模型 |
| 塞超长需求文本(> 4000 字符) | 请求被本地拦截返回 400 | 先精简需求再提交 |
把推荐结果的 name 当 slug 传参安装 |
名称含空格/中文,会被 slug 白名单拒绝(bad_slug) |
使用结果里的 slug 字段原值 |
用相对路径作为 --dir |
安装位置不确定,可能落到意料外的目录 | 一律传绝对路径 |
| 在降级结果上尝试一键安装 | degraded: true 时无 slug,安装必然失败 |
待市场检索恢复后重试,或手动在市场检索 |
11. 故障排查 | Troubleshooting
| 症状 | 可能原因 | 处置 |
|---|---|---|
500 config_missing |
沙箱未注入 SKM_API_BASE |
在 SkillHub 沙箱环境变量注入后端 Base URL 后重试 |
404 |
SKM_API_BASE 多带了路径前缀 |
改为直挂域名根(如 https://<appid>-<hash>.ap-shanghai.tencentscf.com),不带 /recommend-api |
401 出现在 /market、/orders |
未带 Bearer 或 Key 不在白名单 | 配置 SKM_API_KEY,并与云端 API_KEYS 保持一致 |
| 反复 402(带凭证仍 402) | 凭证与订单不匹配 / 已过期 / 金额不符 | 读返回的 reason 字段定位;必要时重新出账取新账单 |
402 之后拿不到凭证 |
用户未完成支付,或支付渠道返回失败 | 确认支付已完成;重新走第 2 步 |
network / "请求超时" |
网络抖动或后端不可用 | 用 runWithRetry 重试;先 GET /health 探活 |
502 FULFILLMENT_CONFIRM_FAILED |
履约回执发送失败(资源已生成) | 用同一 Payment-Proof 重试,不会重复计费 |
| 调用成功但结果为空 | 需求文本过短或已安装技能清单为空 | 补充更具体的需求描述 |
| 技能完全不触发 | 任务已明确指定技能,或属纯知识问答 | 属预期行为,见第 3 节 |
degraded: true 且无主页链接 |
市场检索源不可用(网络 / 接口异常) | 稍后重试;后端可用 GET /health 探活,云端可临时用兜底库维持 |
install_failed / cli_missing |
SkillHub CLI 未安装或未登录、网络异常 | 先 skillhub --version 确认 CLI;必要时用 --install-cli 安装 CLI |
| 安装成功但 Agent 未识别 | 装到了错误的 skills 目录 | 用 --dir 指定当前 Agent 的 skills 绝对路径 |
12. 接口参考 | API Reference
| 方法 | 路径 | 鉴权 | 计费 | 说明 |
|---|---|---|---|---|
| POST | /recommend |
公开(支付墙) | 是 | 语义推荐(A2M 402 验付后交付 TOP-5) |
| POST | /notify |
公开(RSA2 验签) | 否 | 内部补单 / 对账修正入口(非支付宝回调;A2M 无异步通知) |
| GET | /market |
Bearer | 否 | 市场热榜 / 同类对比 |
| POST | /team |
Bearer | 否 | 团队共享技能库(ToB 专属) |
| GET | /orders |
Bearer | 否 | 订单账本查询(支持 out_trade_no / trade_no / status / limit) |
| GET | /health |
免鉴权 | 否 | 健康检查 |
13. 推荐引擎与一键安装 | Matching Engine & One-Click Install
> 本节描述付费交付结果的来源与付费后的落地动作。匹配引擎全部运行在云端(recommend-api),
> 客户端不参与计算;分类体系与打分细则见 references/categories.md。
13.1 匹配引擎(云端)
推荐由四步流水线生成,全部发生在同一次付费调用内部(一次调用 = 一次计费,不因检索次数增加而多扣):
| 步骤 | 说明 |
|---|---|
| ① 意图识别 | 按 12 个一级分类的意图词做命中统计,命中最多者胜出,无命中则不强行归类 |
| ② 关键词扩展 | 原始需求 + 同义/上位词词典 + 分类兜底词,去重后最多 6 个检索词 |
| ③ 多次市场检索 | 取扩展词前 4 个各检索一次,并按分类热度补一轮,并发 + 合并去重;带进程内缓存 |
| ④ 意图排序 | 词面相关度(名称/标签/描述/分类)× 2 + 热度分,输出 TOP-5 |
- 降级:市场检索全部失败时改用云端本地兜底库,返回
degraded: true(无slug/ 主页,不能一键安装)。 - 缓存:检索结果进程内缓存(默认 5 分钟),降低外部接口压力、提升 P95;不影响结果正确性。
13.2 一键安装(付费后动作)
推荐结果带 slug 时,可用客户端内置的安装能力把技能装进当前 Agent 的 skills 目录:
# CLI:装到指定 Agent 约定目录
node skillhub-payskill/call.js install <slug> --agent cursor
# 或显式指定绝对路径(推荐,最稳妥)
node skillhub-payskill/call.js install <slug> --dir "C:/Users/me/.cursor/skills"
# 未装 SkillHub CLI 时顺带安装(--cli-only,不装默认技能)
node skillhub-payskill/call.js install <slug> --agent cursor --install-cli
// 模块 API
const { installSkill } = require("./skillhub-payskill/call.js");
const r = await installSkill("<slug>", { agent: "cursor" });
// 或 await installSkill("<slug>", { dir: "/abs/path/to/skills" })
支持的 --agent 约定目录
--agent |
skills 目录(相对用户主目录) |
|---|---|
cursor |
.cursor/skills |
claude-code / claude |
.claude/skills |
codex |
.codex/skills |
windsurf |
.codeium/windsurf/skills |
gemini-cli / gemini |
.gemini/skills |
workbuddy |
.workbuddy/skills |
nanobot |
.workspace/skills |
> 未列出的 Agent 请用 --dir 指定 绝对路径。
安全约束(客户端源码可审计)
- slug 白名单:仅允许
[a-z0-9][a-z0-9._-]{0,80},拒绝一切 shell 元字符。 - 目录校验:
--dir必须是绝对路径且不含引号 / 换行 / NUL。 - 不落 shell 拼接:调用外部命令使用参数数组(
execFile/subprocess),不做字符串拼接。 - 不参与计费:一键安装是付费推荐之后的本地动作,不发起任何计费请求、不触碰
Payment-Proof。
安装相关返回码
error |
触发条件 | 处置 |
|---|---|---|
bad_slug |
slug 为空或含非法字符 | 使用推荐结果里的 slug 原值 |
bad_dir |
--dir 非绝对路径 / 含非法字符,或 --agent 未识别 |
改用绝对路径或受支持的 --agent |
cli_missing |
未检测到 SkillHub CLI | 传 --install-cli(或 autoInstallCli: true),或先执行官方安装脚本 |
cli_install_failed |
CLI 安装脚本执行失败 | 检查网络;或手动安装 CLI 后重试 |
install_failed |
skillhub install 返回非 0 |
读 message / stderr 定位(网络、磁盘权限、slug 不存在等) |
14. 版本变更 | Changelog
v1.2.0(2026-10-11)
- 增强(云端匹配引擎):推荐由「朴素关键词匹配」升级为四步流水线 ——
12 个一级分类推断 → 关键词同义扩展 → 多次市场检索合并去重 → 意图排序,输出 TOP-5。 - 新增(云端):接入 SkillHub 公开市场检索(
GET /api/skills,无需鉴权),带进程内缓存(默认 5 分钟)
与降级兜底(检索失败回落本地库并标记degraded)。 - 新增(输出增强):推荐结果新增
slug/category/categoryName/downloads/installs/
homepage/matchReason字段,并新增顶层intent(分类 + 扩展关键词)与degraded。 - 新增(客户端一键安装):
call.js/call.py新增install子命令,
a2m-pay.js/a2m_pay.py新增installSkill/install_skill(slug 白名单 + 目录校验 + 参数数组调用,不落 shell 拼接)。 - 新增(展示层):
call.js/call.py交付结果新增可读推荐列表(匹配理由 / 分类 / 热度 / 主页 / 安装命令)。 - 新增(文档):
references/categories.md—— 12 分类体系与匹配引擎的渐进式披露参考。 - 兼容性:A2M 402 计费链路、价格档位、
/recommend契约(新增字段为向后兼容的追加)均无破坏性变化;
pending → paid → fulfilled订单状态机与幂等语义不变。
v1.1.3(2026-09-29)
- 文档(本轮主要变更):面向 SkillHub 评测报告重构文档结构 —— 新增目录、快速开始、端到端示例、
错误码与用户可见提示、异常与降级、FAQ、反模式、故障排查、触发示例共 9 个章节。 - 文档:修正"不提供源码"的表述歧义 —— 明确「匹配算法在云端不公开」与「协议适配层随包提供、可读可审计」
是两个不同范围,避免被误读为"包内无可运行代码"。 - 文档:补充包内文件清单与推荐结果字段说明(
matchScore/hot/source/already_fulfilled)。 - 增强(展示层):
call.js/call.py在 CLI 输出中新增「错误码 → 中文提示 + 建议动作」映射,
排障时无需查文档即可读懂失败原因。 - 兼容性:后端接口契约、A2M 402 协议、计费点与价格均无变化;无需重新部署云函数。
v1.1.2(2026-09-28)
- 修复(阻断级):Python 模块
a2m-pay.py更名为a2m_pay.py。原连字符文件名无法被import,
导致沙箱 Python 入口call.py直接ModuleNotFoundError起不来。 - 修复:
sandbox_pay_demo.js去掉SKM_API_KEY硬校验,无 Key 也能演示公开计费点的 402 出账。 - 新增:客户端
runWithRetry/run_with_retry有界指数退避重试(仅对可重试错误生效,复用同一 Payment-Proof)。 - 新增:服务端
GET /orders订单账本查询(Bearer 保护),用于 A2M 无回调场景下的对账。 - 优化:
ack幂等缓存加上限(FIFO 淘汰),避免长驻 Agent 进程内存无界增长。 - 优化:
run()空输入返回结构与callRecommend对齐(含status/stage),调用方分支不再拿到undefined。 - 优化:Python 端错误响应体按上限完整读入后再解析,避免截断导致
code/reason丢失。 - 安全:客户端入参边界加固——支付凭证做字符集与长度校验(防 HTTP 头注入),需求文本 ≤ 4000 字符、
技能清单 ≤ 200 条、字段单值 ≤ 200 字符、单对象键数 ≤ 50,超限直接返回 400 且不发出请求;响应体按 1 MB 上限读取;
不跟随 HTTP 重定向,避免支付凭证被转发到第三方主机。 - 健壮性:请求超时覆盖「建连 + 读体」全程——服务端只回响应头、再慢速滴流响应体时,
客户端会在超时内放弃并按可重试的网络错误上报,不会永久挂起。 - 安全:客户端不再内置后端地址兜底值,
SKM_API_BASE改为必填,缺失时返回500 config_missing
并给出配置指引(不再静默请求写死的域名);凭证类参数不再引导经命令行传入,优先环境变量 / stdin。 - 文档:明确客户端 Key 可选、重试语义、运行环境要求;澄清 A2M 无支付宝异步通知机制;
随包文档去除内部服务地址与账号标识。
15. 隐私与合规 | Privacy & Compliance
- 本技能不内置、不上传任何用户凭据、私有密钥、支付宝应用私钥或内部地址。
- 仅在触发匹配时,将必要的需求文本与已安装技能元数据(name/description/tags)上报云端用于推荐;
支付凭证仅在验付环节按协议使用,不落盘、不进日志、不写临时文件。 - 示例使用占位符,请勿在自定义配置中写入真实敏感信息。