这篇不聊融资、不画饼,就是讲一个我自己遇到的小痛点,以及怎么顺手做成了一个能用的工具。源码没开源,但架构思路和工程上的取舍都可以聊聊。
一、背景:中转站这行,水有点浑
从 2023 年开始,AI API 中转/代理服务一下子冒出来一大堆。搜一下能找到几十家,个个都喊着"官方同源""低价直连""无限额度"。
但真掏了钱,问题就来了:
- 模型到底是不是真的? 嘴上说是
gpt-4o,返回的到底是 OpenAI 原版,还是拿个小模型套壳糊弄人? - Key 填进去能不能用? 端点通不通、要不要先充值才能测试、报错信息是不是故意藏着掖着?
- 延迟和稳定性怎么样? 宣传页写着"20ms 直连",实际跑一次推理要 8 秒,连流式都不支持。
- 最关键的是:没有一个中立的第三方,能在你掏钱之前先帮你验验货。
社区里也不是没人讨论,但基本都是零散的吐槽、过期的跑分截图,或者让你先把 Key 托管给某个监控平台——这本身又是一次信任让步。
所以我就动手做了 APICheck:在把钱交给任何一家中转站之前,先自己亲手验证一下,它到底能不能用、模型是不是真的。
二、为啥不直接用现成的?
我一开始也找了一圈现成方案,最后发现都不太对味:
- 长期监控类的 SaaS:要注册、要托管你的 Key、要长期跑任务。我就想"点一下,马上知道现在这个端点行不行",犯不着把密钥交出去。
- 各种跑分/排行榜:数据来源不透明,很多看起来就是宣发稿,你根本不知道它测没测、怎么测的。
- 自己写脚本测:能写,但每次换端点都要改参数、对着 JSON 看半天,非技术的同事根本用不了。
最后给自己定了三条原则,后面所有技术选型都是围着这三条转的:
- 不托管密钥:检测在你授权下,针对你提供的端点发一次真实请求,结束后不留存任何业务数据。
- 单次就能验证:不要什么长期大盘,就要"此刻这一发"的结果,点完直接看。
- 老老实实说清楚边界:排行是人工维护的参考,不是实时监控;检测是快照,不是承诺。
说起来有意思,第三条反而成了这个项目最核心的东西。市面上的工具都在往满了吹,我反而觉得把"能做什么、不能做什么"写在第一屏更重要。
三、APICheck 到底是个啥
一句话:一个 AI API 中转站的单次检测平台,外加一份人工维护的服务商参考排行。
解决的就是接入前那一步验证的问题:
- 这个 API 能不能用?Key 填进去会不会打水漂?
- 号称的
gpt-4o/claude是真模型还是套壳? - 几十家中转站,哪家相对更稳、更透明?
目前主要两块功能:
1. 单次 API 检测
把端点和 Key 粘贴进去,立刻发起一次真实请求,验证连通性和基本可用性,然后出一份可读的报告:端点状态、模型真实性、延迟、连通结果。
2. 人工维护的服务商参考排行
我们结合公开信息、社区反馈和抽样检测,定期人工整理一份服务商榜单,覆盖稳定性、透明度、合规这些维度。就是个选型参考,不是什么"唯一真理"。
四、一次检测具体是怎么跑的
核心思路其实很朴素:用你给的端点,发一个我们专门设计的探针请求,然后看返回里都藏着什么信息。
下面是一段原理示意代码(不是生产环境的),主要是讲清楚思路,线上实现比这个复杂得多:
// 核心思路:发一次真实探针请求,做基础校验 async function probe(endpoint: string, apiKey: string, claimedModel: string) { const t0 = Date.now(); const res = await fetch(`${endpoint}/v1/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}`, }, body: JSON.stringify({ model: claimedModel, messages: [{ role: 'user', content: '用一句话解释量子纠缠,并给出一个只有真实 GPT-4 才会犯的典型错误示例。' }], stream: false, }), }); const latency = Date.now() - t0; if (!res.ok) return { ok: false, status: res.status, latency }; const data = await res.json(); // 校验 1:协议兼容 —— 返回是不是标准 OpenAI 兼容的 choices[0].message.content const content = data?.choices?.[0]?.message?.content; // 校验 2:计费字段 —— usage.prompt_tokens / completion_tokens 齐不齐 const hasUsage = !!data?.usage?.completion_tokens; // 校验 3:模型字段有没有被改(有些套壳会篡改 model 字段) const echoedModel = data?.model; return { ok: true, latency, hasUsage, echoedModel, contentLen: content?.length ?? 0 }; }
"模型真实性"不是什么玄学,就是几个可观测维度交叉验证出来的:
- 协议一致性:返回符不符合 OpenAI / Anthropic 兼容的 schema?字段缺东少西往往就是二次封装的信号。
- 探针 prompt:用只有特定模型才能稳定答对(或者稳定答错)的问题,看响应对不对得上这个模型的"风格边界"和知识边界。
- 计费与延迟分布:
usage字段合不合理、流式格式标不标准、首字延迟是不是离谱。 - 异常指纹:套壳站常见的特征——模型字段被篡改、思考链格式乱、函数调用能力缺失之类的。
强调一下:这些判定都是"参考性"的,不是司法鉴定。我们从来不说自己能"100% 识别套壳",这既是科学上的诚实,也是不想误导用户。
五、关于数据口径和边界:做技术产品得有点诚实
这一节是我最想聊的——做减法有时候比做加法更需要勇气。
很多同类产品首页都写着"实时排行榜""全网监控""权威认证"。我没这么干,原因很实在:
- 单次检测结果只反映"检测那一刻"这个端点的表现。网络和供应商状态随时在变,说成长期承诺就是骗人。
- 服务商排行是人工维护的,参考了公开资料、社区反馈和抽样检测。更新有周期,不可能等于实时状态。
- 我们不对排行的绝对准确性或者任何商业决策后果做担保。它应该是个参考起点,不是唯一依据。
把边界写清楚,短期看像是"自曝其短",长期反而能建立信任:用户知道你哪里靠谱、哪里只是参考,用起来反而更放心。
六、技术选型:为啥选了这一套
公开的、不涉及敏感信息的技术概览如下:
| 层 | 选型 | 原因 |
|---|---|---|
| 前端 | React + TypeScript + Vite(SSG) | 首屏快、利于 SEO;类型安全能减少线上问题 |
| 后端 | Node.js + tRPC | 前后端共享类型,省掉接口文档和联调的麻烦 |
| 数据库 | PostgreSQL | 稳定、schema 演进成熟(用 Drizzle ORM 管迁移) |
| 网关 / 反代 | Nginx + Caddy | 静态托管 + HTTPS 终止,部署省事 |
| 部署 | Docker Compose | 一套配置本地跑通、服务器直接复刻 |
说几个具体的工程取舍:
- 用 tRPC 不用 REST:检测报告、排行这类结构化数据,前后端共用 TS 类型,改一处编译期就能把不兼容的地方拦住。
- 用 SSG 不用纯 CSR:官网大部分是静态内容(介绍、排行展示),预渲染后首屏直接出,对 SEO 和弱网环境都友好。
- 优先轻量:没搞什么重型微服务,单体 Node 服务 + 网关足够支撑当前规模,复杂度可控。
出于安全和商业考虑,服务器地址、环境变量、密钥、内部架构和部署脚本就不公开了。上面这套是"思路级"的分享,照着搭一个同类工具问题不大。
七、最后说两句
做这个项目最大的收获其实不是多了个工具,而是验证了一件事:大家都在往满了承诺的时候,老老实实把边界说清楚,反而成了一种稀缺的竞争力。
做技术产品,尤其是 To B 类的工具,诚实其实是最高效的策略——用户知道你哪里能做到、哪里只是参考,反而敢放心用。后面有时间的话,打算再写一篇聊聊探针设计的具体细节,以及套壳站识别上踩过的一些坑。
