比价站不先比价,先给报价打可信度标签,PriceAI 怎么处理灰产数据
- 可信度分级:通过 effective_status、freshness_status、confidence 等多维字段评估报价可信度,非简单二分
- 最低价准入:先过滤缺货、过期、低可信度报价,再在可信报价中排序,避免异常低价误导
- 五层架构:从接入层到展示决策层,形成脏数据到可信报价的治理链路,核心是可信度治理层
- 采集调度:支持 15 种采集器类型,通过限流、熔断、价格解析正则与灰产站点协商式获取数据
- 风险预检:用户反馈驱动的欺诈、售后问题标记,要求图片证据防恶意差评,自动剥离 AFF 参数
你在淘宝搜「ChatGPT Plus 代充」,第一页蹦出来十几家,价格从 89 到 199 都有。点进去看,有的是月卡短期号,有的是荷兰 iDEAL 渠道号,有的是共享账号,还有的根本不告诉你交付方式,只写「低价稳定」。你不知道哪个真有货,哪个是过期报价,哪个买完第二天号就没了。
这不是一个简单的比价问题。把所有价格摆出来排个序,是最容易的做法,也是最坑用户的做法,因为灰产报价里混着缺货、过期、隐藏、欺诈。PriceAI 这个项目有意思的地方在于,它面对的是一堆结构混乱、可信度参差的数据,却没有选择当个「排序器」,而是先做了一件更脏更累的事,给每一条报价打上可信度标签。
大家好,我是若风。今天拆一下 PriceAI 这个 1692 Star 的开源项目,看看它怎么治理 AI 订阅和 API 这片灰色的价格信息。
它到底在治理什么
一句话,PriceAI 是个 AI 订阅和模型 API 的购买前比价工具。但这句描述太轻,没说清它真正解决的问题。
真正难的不是「拿到价格」,而是「判断这条价格能不能信」。同一个 Claude Pro,官网是 20 美元一个月,某个卡网报价 35 块人民币,另一个卡网报价 60 块,中间差出来的不仅是利润空间,还有完全不同的风险。35 块那个可能是共享号,60 块那个可能是独享成品号,也可能两个都是骗子。
PriceAI 把这件事拆成了四个独立的模块,官方订阅、卡网订阅、官方 API、中转 API。这四个东西的风险边界完全不一样,官方订阅是价格基准,卡网订阅要看交付方式和现货,官方 API 看文档和额度,中转 API 必须额外关注倍率和上游来源。它没有把这四类混在一个列表里排序,这点很关键。
为什么这么分?因为如果混在一起,用户会默认「便宜的就是好的」,而实际上不同来源的风险根本不可比。把官方正价、卡网代充、中转 API 放同一张表里按价格升序,等于在鼓励用户去踩最危险的坑。
可信度分级才是核心机制
这是整个项目最值得拆的部分。PriceAI 没有把「最低价」当成最高目标,它先解决的是「这条报价能不能进最低价计算」。
打开 supabase/migrations/20260507120500_offer_freshness.sql 这个迁移文件,能看到它给每条原始报价(raw_offers)加了 6 个状态字段,source_status、effective_status、freshness_status、verified_at、expires_at、confidence。这不是简单的「有货/没货」二分法,是一套多维度的状态机。
最核心的是 effective_status 这个字段的判定逻辑。一条报价要被判定为 available(可用),必须同时满足四个条件,状态不是 out_of_stock、价格不为空、URL 不为空、且时间没过期。只要有一条不满足,就会被降级为 unavailable、stale 或 low_confidence。
这里的 low_confidence(低可信度)状态特别有意思。看 SQL 里的 case when 分支,它会区分数据来源,如果来源是 public_json(公开结构化接口),可信度只有 0.55,如果是其他采集方式,反而是 0.90。乍看反直觉,公开接口反而更不可信?想一下就通了,公开 JSON 接口意味着任何人都能批量拉取和伪造,而需要解析 HTML 或走浏览器采集的站点,数据被篡改的成本更高。这个判定不是拍脑袋,是踩过坑之后的工程权衡。
再看 freshness_status,它把报价新鲜度分成 fresh(10 分钟内)、aging(10 到 30 分钟)、stale(30 分钟到 2 小时)、expired(超过 2 小时)四档。在卡网这种价格和库存随时变化的场景里,一条 2 小时前的报价,基本等于历史数据,不该参与实时最低价计算。
最低价不是排序,是准入
很多人会以为比价站的核心是排序算法,谁便宜谁排第一。PriceAI 在 public_product_offer_pagination.sql 里给出了不同的答案。
它定义了一个叫 availability_rank 的字段,逻辑是这样的,只有当一条报价状态不是缺货、价格有值、URL 有值、effective_status 不在 unavailable/stale/failed 里、freshness_status 不是 expired、且 expires_at 没过期,它的 availability_rank 才是 0,否则是 1。排序时 0 排在 1 前面。
翻译一下,它做的不是「按价格排序」,而是「先把不可信的报价挡在门外,再在可信报价里排价格」。这是一道准入门槛,不是排序权重。缺货的、过期的、低可信度的报价,无论价格多低,都不会出现在「最低价」位置。
这个设计决策背后是一个很清醒的认知,在灰产数据里,一条异常低价往往是风险信号而不是优惠。把异常低价推到最前面,等于把用户推向最危险的渠道。
五层架构串起整条治理链路
把上面这些散落的机制拼起来,PriceAI 的整体架构其实是一条从脏数据到可信报价的治理链路。
最上面是接入层,200+ 卡网渠道按技术形态分成 15 种 collector_kind,collectors.json 里能看到 kami 卡密类 29 个 host、dujiao 独角数卡 16 个 host,加上用户提交和站点资料两条人工入库通道。
第二层是采集调度层,collect-prices.mjs 在这里做限流和熔断,每次最多抓 20 个商品、间隔 15 秒、连续 3 次 403 就冷却 5 分钟,价格解析靠 PRICE_VALUE_PATTERN 正则兼容千分位、货币符号、后缀三种格式。
第三层是标准化归类,catalog.ts 的 canonicalCatalog 把混乱的商品标题归一成标准商品,api-transit-normalization.ts 在这一层顺手剥掉 URL 里的 AFF 跟踪参数。
第四层是整条链路的核心,可信度治理层。offer_freshness.sql 的状态分级、freshness_status 的新鲜度衰减、confidence 的来源可信度值、trust-risk.ts 的风险预检,全部集中在这层。availability_rank 这道准入门槛就立在这里,决定哪些报价有资格参与最低价计算。
最底下是展示决策层,四个模块前端加独立的模型检测服务,最终把核验过的信息展示出来,并把用户引导回原站做最终确认。
15 种采集器,一种调度框架
讲完判定逻辑,来看数据是怎么进来的。PriceAI 的采集层不是一个大爬虫,是一个支持 15 种 collector_kind 的调度框架。
看 config/collectors.json 这个配置文件,它把卡网站点按技术形态分类,kami(卡密类自动发货)、dujiao(独角数卡)、shopApi(店铺商品接口)、genericHtml(通用 HTML 解析)、xiaoheiwan、opensoraHtml 等等。每个 host 对应一种采集方式,不是见站就抓,是先识别它的技术栈再选对应的解析器。
这种设计的好处是扩展性强。新增一个卡网,只要判断它是独角数卡还是卡密系统,就能复用已有的解析逻辑,不用从零写爬虫。坏处也很明显,维护成本高,卡网一旦改版,对应的解析器就得跟着改。
再看 scripts/collect-prices.mjs 里的调度细节。它定义了一堆防止把对方站点打死的参数,DEFAULT_LIANDONG_SHOP_BULK_LIMIT 设成 20,每次最多抓 20 个商品,DEFAULT_LIANDONG_SHOP_BULK_DELAY_MS 是 15 秒,两批之间停 15 秒,还有 DEFAULT_LIANDONG_SHOP_HTTP_403_THRESHOLD 设成 3,连续 3 次 403 就触发熔断冷却 5 分钟。
这些数字说明作者很清楚自己在干什么,这不是在自己服务器上抓数据,是在跟一堆灰产卡网「协商式」地拿数据,既要拿到,又不能把对方打挂,更不能触发对方的风控把自己 ban 掉。
价格解析这一步也有讲究。看 collect-prices.mjs 开头的 PRICE_VALUE_PATTERN,它用正则同时匹配三种价格格式,带逗号千分位的(1,299)、带货币符号的(¥129)、带后缀的(129 元)。灰产站点的商品标题格式极其混乱,有的把价格写在标题里,有的写在规格里,有的混着销量和库存号,这个正则是在大量脏数据上迭代出来的。
风险预检把欺诈和描述不符单独拎出来
可信度分级之外,还有一层风险预检。看 src/lib/trust-risk.ts 这个文件,它定义了一个 HIGH_RISK_FEEDBACK_REASONS 集合,包含 aftersales_shipping(售后发货问题)、fraud(欺诈)、bad_source(来源不良)三类。
这三类是用户反馈驱动的。当一条报价被多次标记为欺诈或售后问题,它会被单独标记为高风险,即使价格再低也不会被推到前面。而且 FEEDBACK_IMAGE_EVIDENCE_REQUIRED_REASONS 要求,对于这几类反馈,用户必须上传图片证据才能提交,防止恶意差评把竞争对手的报价刷下去。
这是一个很现实的设计。灰产市场没有第三方担保,用户反馈是唯一的风控信号源,但反馈本身也会被滥用。要求图片证据,是在「鼓励真实反馈」和「防止反馈武器化」之间找平衡。
中转 API 那边还有一层独立的治理。src/lib/api-transit-normalization.ts 里有个 TRACKING_PARAMS 集合,在用户提交中转站 URL 时,会自动剥掉 aff、ref、referral、utm_ 前缀这些跟踪参数。这个细节值得停下来想一想,它防止的不是爬虫,是用户在提交站点资料时,无意中把带 AFF 参数的推广链接提交进来,让 PriceAI 变成免费的导流工具。
这个项目的边界和局限
诚实地说,PriceAI 的设计思路很清醒,但它的边界也很明显,有些是它自己承认的,有些是源码里藏着的。
第一个是 bus factor。整个仓库贡献者只有 1 人,这是 gh api contributors 返回的真实数字。一个聚合 200+ 渠道、跑着 100 多个 Supabase 迁移、维护 15 种采集器的项目,只有一个人在维护,这种集中度就是最大的风险。作者一旦停更,采集器会一个个失效,数据会越来越旧,最后变成一个空壳。
第二个是采集的天花板。看 collectors.md 里明确写着「不绕过验证码、登录墙、WAF 或平台风控」。这意味着需要登录才能看价格的站点、有 Cloudflare 防护的站点、需要人机验证的站点,PriceAI 都拿不到数据。README 里说聚合 200+ 渠道,但 collectors.json 里实际配置的 host 只有 80 多个,这个数字差距来自哪里,可能是有些渠道走用户提交而不是自动采集,也可能是部分渠道已经下线但 README 没更新。无论哪种,都说明「200+」是个理想值,实际自动覆盖的渠道比宣传的要少。
第三个是 license 的限制。PriceAI 不是常规的开源协议,gh api license 返回 NOASSERTION,README 里写得很清楚,允许学习和本地自用,但「未经书面授权,不允许将 PriceAI 或修改版作为公开网站对外运营」,也不允许接入广告或 AFF。这是个源码可见但商业受限的协议,想 fork 出来做竞品的人要先想清楚。对比一下,它依赖的检测服务 fork 自 canarybyte/veridrop,那个项目是 AGPL-3.0,真正的传染性开源,PriceAI 自己反而比上游更保守。
第四个是它不担保。这一点 README 里反复说,api-transit-station-admission.md 里也写明「正式上架不等于 PriceAI 推荐」。PriceAI 只负责把信息展示出来让你核验,不承担任何渠道的售后责任。这意味着即使它把某条报价标成「可信」,你买完被骗了,它也没有任何义务。这是个理性的边界,但对抱有「PriceAI 推荐的就是安全的」期待的用户来说,可能会失望。
它给了一个可以复用的判断框架
拆完 PriceAI,我最想提炼的不是它的技术栈,Next.js 加 Supabase 加 Cloudflare Workers 没什么特别,而是它面对「脏数据」时的处理思路。
我把它叫「可信度先于价格」模式。当你处理的数据源质量参差不齐,尤其像灰产数据这种天然不可信的场景,不要急着做排序和推荐,先给每条数据打上多维度的可信度标签,把不可信的数据挡在核心决策之外。这个模式可以迁移到很多场景,招聘网站的真实薪资核验、二手房平台的价格真实性判断、甚至评论系统的刷榜检测,核心都是同一个问题,当数据可以被伪造时,排序算法做得再精致也是在地基上盖楼。
PriceAI 做对的一件事是,它承认自己处理的是灰产数据,并且把这个「承认」写进了系统设计的每一层,从 SQL 字段到采集调度到风险预检。它没有假装自己是个中立的比价工具,而是诚实地把自己定位成「购买前的参考」,不担保、不收款、不包装。
这种诚实,在处处是软文的 AI 工具市场里,本身就是一个稀缺品。如果你正在做需要聚合第三方数据的产品,或者正在评估 AI 订阅和 API 的获取成本,PriceAI 的源码值得读一遍,不是为了抄它的代码,是为了学它怎么跟脏数据共处。
评论互动