SkillPay 接入实录:我用 HTTP 402 让 AI Skill 在对话里收钱

📂 技术工具 📝 2549 字 ⏱️ 6 min

写过 Skill 的人大概都有过这个瞬间——花两周磨出来一份,逻辑、话术、边界条件反复调过,发到社区,过两天看到有人复制走,改个名字换成自己的头像重新发了一遍。

我不打算抱怨抄袭,开源社区本来就这样。但想把这件事当产品做,靠"发文件"是不行的:文件一旦离开你的服务器,它就不再是你的了。

这几天我把自己天天在用的三个心理咨询 Skill 挂上了 SkillHub 的 SkillPay,标价 ¥1.99/次。链路跑通了,坑也踩够了,今天一并写出来。

SkillPay 到底改了什么

普通 Skill 的本质是可下载的源文件:prompt、模板、脚本,谁拿到谁就能跑,也能改。SkillPay 换了个思路——它卖的是一台你控制的后端服务,SKILL.md 只是一张"调用说明书"。

官方给的说法是:按次计费、单次价格商家自定、平台暂不收取技术服务费,支持微信和支付宝双渠道,收益按渠道规则实时结算。个人实名认证并开通收款能力就能接,不是只有企业能做。

最关键的一点是交互:支付确认发生在对话里,用户不用跳出 Agent 去扫码跳页面。你看不到"付款成功"的站外页面,只看到 AI 停了一下,然后继续干活。

整条链路就是一个 402

技术上说穿了不复杂,核心是 HTTP 402 这个躺了三十年的状态码终于被用上了。

用户本地 AI(skill)
   ↓ POST /api/counsel,不带凭证
服务端 → 402 + Payment-Needed(Base64URL 账单)
   ↓ 用户扫码授权
skill 带 Payment-Proof 重试原请求
   ↓
服务端 verify 验付 → 生成内容 → fulfillment.confirm 履约 → 200

账单里带这些字段:out_trade_no、amount、currency、resource_id、pay_before、seller_signature、seller_sign_type(RSA2)、seller_unique_id。签名串按 key 字典序把 amount, currency, goods_name, out_trade_no, pay_before, resource_id, seller_id, service_id 用 k=v&k=v 拼起来,只拼非空字段,RSA-SHA256 签完再 base64。

四个硬规则,写在官方文档里,也写在服务端的校验里:

  1. 金额以服务端账单为准,SkillHub 页面上标的价只是展示
  2. pay_before 过期后一律拒绝,除了"履约进行中",其他都要重新下单
  3. 同一个 trade_no 不能跨订单复用
  4. 履约只允许一次

买家那侧其实不用自己写代码:npx -y @alipay/agent-payment@latest install 装完会得到一个 alipay-bot,402-buyer-pay 负责付,402-query-payment-status 负责查单并自动回执履约。我的脚本只做编排,零密钥、绝不代付——状态不明先查单,不重复下单。

我踩的四个坑

坑一:沙箱金额永远是 0.01。 沙箱的 service_id 固定是 api_mock_service_id,账单金额按这个 mock 服务的登记价走,跟你 .env 里配的 PRICE=1.99 无关。我一开始盯着沙箱账单上的 0.01 怀疑自己价格没生效,白查了半小时。

坑二:不能留"跳过验签"的开关。 我本来想加个 SKIP_VERIFY 环境变量方便本地调试,后来发现官方预检明确会查这个——沙箱和生产必须走同一套控制流,存在能绕过的分支直接过不了。删掉。

坑三:推理模型的思维链也吃 max_tokens。 服务端要 LLM 返回结构化 JSON,我把输出预算设成 4096 觉得绰绰有余。结果换了带推理的模型之后,思维链先把预算吃光,最后返回的 content 是空的。服务端报 empty_content,我盯了半天 prompt 才发现问题在预算。现在默认 16384,换模型先评估这个数。

坑四:JSON 会偶发不合法。 采样波动,同一份 prompt 跑十次有一次多个逗号。服务端现在的策略是自动把温度从 0.4 降到 0.1 重试一次,两次都失败才返回 RESOURCE_GENERATION_FAILED。这个我在沙箱里真触发过一次,重试就过了——所以"重试一次"不是保险,是必需品。

三个产品,一套后端

这块是我最满意的设计。

心理咨询这件事,亲密关系、情绪、亲子三个场景的记录结构和分析框架高度重合:都是建档 → 每日记录事实 → 周小结 → 看趋势 → 必要时做一次深度梳理。差别只在 prompt 和模板。

所以我没做三个服务端,而是做了一个,请求体加一个可选字段 lens:

技能包lens免费能力付费 ¥1.99/次
心桥relationship(默认)关系建档、每日记录、周小结、趋势深度分析
心绪mood情绪档案、四栏记录、周小结深度梳理
心苗parenting家庭沟通档案、亲子观察、周小结深度梳理

账单商品名按 lens 取,金额、resource_id、service_id 共用;系统提示词按 lens 选文件。未知 lens 直接 400,不传就落到默认值——老客户端不改也能用。

三个产品,一份运维。 订单库是同一个 SQLite,better-sqlite3 是单写者模型,所以 pm2 只能单实例 fork,不能开 cluster。这个约束在扩容时会疼,但现阶段不是问题。

为什么是心理咨询

说点私心的。

这套"先记录、再观察、必要时深度分析"的方法,我自己用了很久。它有个前提:你别指望 AI 替你决定人生。所以我把能力切成了两半——

免费的那半是记录和趋势:今天发生了什么、你当时怎么反应、这周和上周比是往上还是往下。这些不需要付费,也不该付费。

付费的那半只有一件事:一次更深入的判断。定性现在是什么状态、哪些是信号哪些是你的解读、接下来该做什么、什么话不能说。

还有一条我写死在流程里:危机不走付费。自伤、自杀念头、暴力、虐待、涉及孩子的伤害信号——出现这些,直接转介专业机构和热线,不推销分析,不做关系技巧建议。这条不是免责声明,是产品底线。

三个 Skill

  • 心桥 · 亲密关系与情感咨询(heartbridge-counsel v1.0.1,AI 评分 4.7)— 婚姻、恋爱、冷战、沟通
  • 心绪 · 情绪记录与深度梳理(moodbridge v1.0.1,4.7)— 情绪日记、内耗、焦虑、触发源
  • 心苗 · 亲子沟通与养育梳理(parentbridge v1.0.0,4.6)— 亲子冲突、写作业、青春期

在 SkillHub 搜英文 slug 就能找到,或者直接装:

skillhub install heartbridge-counsel --namespace user_53f23a66
skillhub install moodbridge --namespace user_53f23a66
skillhub install parentbridge --namespace user_53f23a66

一点判断

SkillPay 现在还是早期,可用的 skill 不多,很多还停留在"把免费工具标个价"的阶段。但方向我认:AI 时代的知识产品,交付物应该是"可调用的能力",不是"可复制的文件"。

文件会被抄走,服务不会。

如果你也在写 Skill,问自己一句:你的价值在 SKILL.md 里,还是在服务器上? 答案如果在前者,那它迟早会变成别人的。