AIREITER

22 个平台、241 条命令:我为什么没有做统一响应模型

最后更新: 2026-07-31 06:26:05

要从二十多个平台抓取公开数据,第一反应通常是先做抽象:设计一个统一的 Post、一个统一的 User,再把各平台响应映射进去。bilibili 视频、tiktok 视频、zhihu 回答、linkedin 帖子,看起来无非都是“内容加作者”。刚接入三四个平台时,这套设计很顺手;但等平台数量来到二十多个,它就会变成最难绕开的负担。

最终我没有做统一模型。面对二十多个平台、两百多条命令,真正经得住扩展的反而是看似笨拙的做法:每个平台各管各的。

统一模型是怎样一步步失效的

它并不是突然崩掉的。大约接到第八个平台时,Post 上已经挂满十几个可选字段:有的平台有弹幕数,有的平台没有;有的平台“发布时间”是精确到秒的时间戳,有的平台则是一句“3 days ago”。等到二十多个平台,这层模型已经名存实亡。它不会报编译错误,却不再替你节省任何工作:下游代码在读取每个字段前,都得先判断“这个平台到底有没有填它”;判断逻辑比直接读原始响应还长;所谓统一层反而成了干活时必须绕开的障碍。

写入侧也一样。每接入一个新平台,都要回头修改这套模型,把新字段硬塞进原本为旧平台设计的格子里。

一个平台,就是一个独立的限界上下文

真正可持续的拆法恰好相反:不要抽象统一模型,让每个平台独立负责自己的领域。在目录结构中,每个平台都是一个 <platform>_reverse/ 上下文,只负责四件事,不向外借出:

  • 参数校验。这个平台的 id 长什么样,哪些参数组合合法,只有它自己最清楚。

  • 通信协议。是直接发 HTTP,还是要跑一段本地 JS 签名;该请求哪个域名、带哪些请求头,都是平台私有细节。

  • 签名逻辑。不同平台的签名机制差异很大,硬塞进一个共享 signer,只会养出一个充斥 if-else 的怪物。

  • 响应规范化。把原始响应整理为该平台自己拥有的结构,而不是某个全局统一结构。

第四点最容易被误解。“没有统一模型”不等于“不做规范化”。每个平台当然都要规范化,只是目标结构由平台自己定义,而不是被强行塞进共享模型。真正应该统一的范围,仅限于确实是同一个东西的地方:同一平台内两个接口共用一套帖子结构,这完全合理,因为它们确实对应同一个领域对象。错误在于把平台内部的统一,硬扩展为跨平台统一。

共享层只放真正跨平台的能力

什么该进入共享层?不是那些表面上相像的东西,而是对所有平台而言行为确实一致的能力。我的共享层只有三项:

  1. 接口读模型。从各平台的 argparse 声明中生成统一的能力目录。这里统一的是命令如何被发现、如何被描述,而不是命令返回什么数据。前者确实跨平台,后者仍然属于平台私有领域。(“声明即接口”这一思路,见接口即代码一文。)

  2. 本地回环传输。带认证的请求统一经由本地 WebSocket 会话服务转发;它对所有平台一视同仁,也不会碰任何平台的业务字段。

  3. 分发入口。识别平台,把命令交给对应上下文,仅此而已。

判断标准很简单:一个能力要进入共享层,就必须在每个平台上都以同样方式工作。传输、分发、接口描述生成满足这个条件;而“一条内容”在 bilibili 和 linkedin 上的行为完全不同,因此不该放进去。“看起来像”是抽象最大的陷阱:两个视频表面上很像,于是你想统一它们;但表面相似不等于行为相同。把前者误当成可共享的领域模型,正是统一模型最终失效的根源。

命令分布决定了抽象是否划算

还在犹豫要不要做统一模型?看一眼真实的命令数量分布,答案就很清楚了。22 个平台、241 条命令,而且分布极不均衡:

平台

命令数

tiktok

34

bilibili

26

linkedin

18

zhihu

18

douyin

17

xiaohongshu

16

其余 16 个平台

各 1 到 13 条

排名前六的平台合计 129 条命令,已经超过总数的一半;另一半则分散在 16 个长尾平台中,其中很多只有两三条命令,有些甚至只有一条。

这种分布直接决定了抽象的经济账:统一模型的成本是固定的——每个接入方都要填字段、判空、想办法绕过模型的限制;收益却按平台分摊。对于一个只有两三条命令的长尾平台,抽象带来的收益甚至是负数,因为为了塞进统一模型而写的适配代码,比它所有业务代码加起来还长。

不要为尚未存在的实现预留抽象

顺着这个分布,还能得出一条规则:只有一种实现时,不要预留抽象。某个平台目前只有一套实现,就别为了“以后可能有第二套”先建 repository、factory 或 interface 层。新增一个平台,只需新增一个 <platform>_reverse/ 上下文,没必要先去改共享基类。

接口层的价值在于让多个实现可以互换;只有一个实现时,它的收益为零,维护成本却是正的。为不存在的第二种实现预留位置,和为不存在的跨平台共性预留位置,本质上是同一个错误。跨语言迁移时,这一点再次得到了验证:旧 registry 的几百条命令中,有一批被明确留在未迁移状态,没有留下 stub,也没有兼容代理。因为空壳的成本高于缺口:它会让后来的人误以为那里真的有东西。预留抽象也是如此。

让模型做跨平台规范化,也要给它平台上下文

“按平台拆分、不做统一模型”这套思路,用在模型规范化上同样成立。把二十多个平台的原始响应整理成可分析结构时,很自然会想到交给模型处理;而最常见的错误也和代码层完全一样:先定义一个统一 Schema,再把每个平台的原始 JSON 丢进去,附上一句“映射到这个 Schema”。

这会失败。模型并不知道 bilibili 的播放量字段和 tiktok 的播放量字段是否真是同一回事;强迫它向最低公分母 Schema 靠拢,要么会丢掉某个平台依赖的字段,要么会把字段半对半错地填进去。

正确做法是按平台提供上下文:告诉模型“这是 bilibili,这些字段分别代表什么,我希望该平台整理成这样的结构”。一次只规范化一个平台,跨平台合并交给分析层处理。整个过程可以拆成几步,每一步对模型的能力要求都不同:

步骤

所需能力

选择

model id

阅读单个平台完整原始响应的结构

长上下文,能一次容纳完整响应和字段说明

Kimi K3

kimi-k3

确定规范化边界:哪些字段真正跨平台,哪些是平台特有字段

强推理能力,能抵抗过度统一

Claude Opus 5

claude-opus-5

按平台批量提取字段,逐项映射

成本低,可高并发执行数百到数千次调用

Claude Sonnet 5

claude-sonnet-5

解释两个平台同名字段为何无法对齐

中等推理能力,能结合字段说明差异

GPT-5.6 Sol

gpt-5.6-sol

第二步是唯一一个换模型后结果会明显不同的环节。它考验的是:你能不能承认两个字段其实不是同一回事。这和算法家族识别中的反证部分是同一个问题:较弱的模型会顺着你“统一”的暗示走,较强的模型则会指出边界在哪里。

真正的门槛是切换成本

这四个层级来自三个厂商,对应三套 SDK、三种认证方式、三类错误格式。为了在不同步骤之间切模型而重写三遍客户端,显然不划算;于是多数人会从头到尾只跑一个层级,常常还会在“确定边界”这一步用了只会压平差异的模型,最终又构建出一个在二十多个平台上失效的 Schema。

AIReiter 把这一层抹平了:一个 key、一个兼容 OpenAI 的接口,背后覆盖四个层级;只要修改请求体里的 model 字段,就能切换模型。

# Set the normalization boundary: the reasoning tier
curl https://aireiter.com/api/v1/chat/completions \
  -H "Authorization: Bearer $AIREITER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-opus-5",
    "messages": [{"role": "user", "content": "<one platform response sample + have it mark which fields are platform-specific>"}]
  }'

# Extract fields per platform in bulk: change the model field, leave the rest
#   "model": "claude-sonnet-5"
# Field-difference attribution:
#   "model": "gpt-5.6-sol"

如果你已经在使用 OpenAI SDK,只需把 base_url 指向 https://aireiter.com/api/v1,其他地方无需改动。使用 Anthropic SDK 时,则用同一个 key 请求 POST /api/v1/messages。

价格方面,Claude 模型按官方定价七折,GPT 模型半价,Kimi K3 也可以使用同一个 key 调用。折扣正好覆盖主要成本:按平台批量提取字段是调用最密集的一步,二十多个平台、每个平台数百到数千条记录,每条记录一次调用,使用价格最低的 Sonnet 后还能再享七折。用 Kimi K3 阅读完整长响应时,单次输入也有数十万 token,同样是一笔成本。至于负责划定边界的推理层,调用次数很少,成本几乎可以忽略。

  • 获取 API key

  • 免注册试用:先手动跑一份平台响应,看看模型是如实标出差异,还是急着把它们压平,再决定是否接入流程。

结语

跨平台采集时,统一一个 Post/User 模型是最自然的第一反应。小规模时它很顺手,但平台扩展到二十多个后必然失效:成本固定、收益按平台分摊,而命令数量又呈现极强的长尾分布。能长期维持的方案,是一个平台一个限界上下文,各自负责参数校验、协议、签名和响应规范化。共享层只保留在所有平台上确实行为一致的内容——传输、分发、接口描述生成——而不去容纳那些只是表面相似的领域模型;也不为单一实现或并不存在的共性预留抽象。

模型处理也是同一句话:带着平台上下文做规范化,不要给它套统一 Schema;跨平台合并只在分析层进行。完整的四阶段工作流会更详细地介绍这四层模型如何分工。而当它们通过一个统一接口接入后,切换成本就不再是不用它们的理由。