ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

FreeLLMAPI实战:聚合34家免费大模型API的统一网关方案

FreeLLMAPI实战:聚合34家免费大模型API的统一网关方案 FreeLLMAPI 这个项目我是真服气的。事情起因很简单我手头有个小工具需要调用大模型但预算又抠所以盯上了各家厂商的免费额度。结果注册了七八家平台之后我发现能用是能用但根本没法用——每家 API 地址不一样鉴权方式不统一消息格式各有各的怪癖代码里塞了五六个 SDK 的适配逻辑最后自己都看不下去了。所以当我看到 FreeLLMAPI 这个开源项目时第一反应是这不是把我心里那点破事儿全给解决了嘛。标题里那句话已经很直白了把 34 家免费额度聚成一个 /v1 端点。但你如果以为这只是个简单的 API 转发工具那就小看它了。这个项目的价值不在聚合两个字而在它处理免费额度这个特殊对象时的一系列设计取舍。第 3 期我就拿它开刀把它到底做了什么、怎么做的、用起来有哪些坑讲透。1. 先聊痛点34 家免费额度为什么让你又爱又恨大模型厂商给免费额度的习惯这几年已经成了一种固定获客手段。你去看各家平台的开发者后台基本都能翻到类似的促销逻辑注册就送 API 额度、按请求数给免费层、限时试用金、还有专门针对开源项目和学生的扶持计划。光我自己的账号矩阵里就躺着 OpenAI 早期注册送的额度、Google Gemini API 的免费层限制、Anthropic 的新用户试用金、以及国内智谱、DeepSeek、通义这些平台慷慨的 token 包。单独拿出来看每一个都挺香的合在一起看问题就大了。第一个问题是地址和协议的混乱。OpenAI 用的是 OpenAI 风格接口Google 有自己的一套Anthropic 的消息结构又完全不同国内很多厂商虽然声称兼容 OpenAI 格式但真实响应里的字段细微差别照样能让你多写几十行兼容代码。你表面上集成了 34 家实际上是给自己造了 34 个小爹每一个都有自己的脾气。第二个问题更恶心密钥管理和额度追踪。免费 key 不像付费 key 那样可以放心地在多个环境里共享。一个免费 key 并发一高就会触发限流限流了你还不知道是触发了 RPM 限制还是 TPM 限制或者干脆被风控判定为滥用。更别提各家给免费额度的计量方式还不一样——有的是按 token 计费有的是按请求次数有的只在特定模型上生效。你在代码里写死一个 key然后祈祷它别在半夜悄悄耗尽这体验谁能顶得住第三个问题是占比最重的这些免费额度高度分散资源利用率极低。有些平台送的额度只够跑几百次小模型请求单独为它写一套对接代码完全划不来。但如果是通过一个统一入口做自动调度每次请求自动挑最合适的、最便宜在这个场景里是免费剩余量最充分的那一家34 家的剩余额度就能拼出一个相当可观的总资源池。这就好像钱包里全是零零碎碎的钢镚儿单个看买不了什么全倒出来数一数就能换顿大餐了。FreeLLMAPI 做的事情正是把你心里要是能有个东西帮我统一管这些免费额度就好了的念头变成了一个能跑起来的服务。它不替代任何上游厂商而是在你和 34 家模型服务中间加了一层调度员。2. 项目拆解FreeLLMAPI 的架构逻辑与技术选型这个项目最核心的设计思路用一句话概括就是对外是 OpenAI 兼容端点对内是插件化 Provider 调度。2.1 Provider 适配器机制磨平 34 家差异的关键先看整体结构。我翻了代码之后发现项目并不是把 34 家厂商的 API 调用逻辑一股脑塞进一个大的 request handler 里而是抽象出了一层Provider接口。每一家厂商对应一个独立的适配器负责完成以下几件事把统一的请求格式转化为该厂商要求的消息格式处理该厂商特有的鉴权方式比如自定义 header、动态 token、API-Key 在不同位置的传递将该厂商的响应内容标准化成统一的 Completion 输出结构上报本次请求实际消耗的 token 数量或配额变化。这个思路其实不新鲜标准适配器模式但放在这个项目里非常合适。因为 34 家服务商的差异不是字段名不同这种表面的问题而是 API 风格本身的分叉。有 OpenAI 兼容系、Claude 消息系、Gemini 生成内容系、国产模型各自的方言系。没有这一层适配模块之间根本没法对话。2.2 请求路由与负载均衡的调度规则有了适配层接下来就要解决这次请求发给谁的问题。项目的调度策略不是随机挑一家而更像是一个带权重的轮询机制。权重由两个维度决定一是该 Provider 当前的剩余免费额度估算二是你配置的基础权重。具体逻辑你可以这样理解每个 Provider 在配置里有一个weight参数默认值为 1。调度时项目会先过滤掉不可用的 Provider比如健康检查失败、额度已耗尽、超过单日调用上限然后在剩余可用 Provider 之间做加权随机。这意味着用得少的 Provider 并不会因为权重低就永远吃灰只要它还在可用列表里就有机会被抽中。在额度估算上项目对每个 Provider 存储了一个简单的配额状态包括今日已调用次数、估算已消耗 token 数、以及你设置的最大配额。当某个 Provider 的请求失败并返回配额相关错误时适配器会将该 Provider 标记为暂不可用并进入一个冷却时间。这个机制避免了拿一个已经耗尽的 key 反复重试的尴尬。2.3 统一 /v1 端点与 OpenAI 兼容设计对外暴露的端点部分设计得更讨巧。项目直接实现了 OpenAI 的/v1/chat/completions路径和请求/响应结构。也就是说你能用任何支持自定义 base_url 的 OpenAI SDK、客户端工具直接接入它。这意味着什么意味着你现有的代码里如果用的是OpenAI(api_key..., base_urlhttp://localhost:8080/v1)这种写法替换成这个项目只需要改一个 base_url 和 api_key。你甚至可以把它接入到 LangChain、Flowise、Dify 这类只认 OpenAI 兼容地址的编排工具里去。项目服务端在拿到请求后会根据你请求里 model 字段的值来决定路由策略。这里有个很贴心的设计你可以在配置里建立模型映射表把统一的模型别名映射到不同厂商的真实模型名。比如你定义一个fast别名映射到三家不同平台快模型那么调度层会在三家之间做负载均衡。如果你用的是普通模型名如gpt-4o-mini调度层会尽量路由到有对应模型可用的 Provider 上。2.4 为什么选中这个技术栈再说实现语言。FreeLLMAPI 使用的是 Node.js/TypeScript配合轻量级 Web 框架搭建服务端。这一点我认为选得非常对路。原因有三第一LLM 生态里的 SDK 基本都是 JS 和 Python 双修做一个连接器项目使用 JS 生态对接上游 API 非常方便很多 Provider 官方就维护了 Node 版 SDK第二Node.js 的异步 IO 模型天然适合做转发网关IO 密集型场景下表现好而 API 聚合层就是一个典型的 IO 密集型服务第三TypeScript 的接口抽象能力让 Provider 适配器这类模式落地非常舒服。3. 把服务跑起来部署步骤与核心配置说明聊完架构直接上手跑一遍。项目提供了 Docker Compose 编排这是我最推荐的方式省去本地环境依赖的坑。先克隆仓库然后编辑配置最后 compose up 即可。3.1 Docker Compose 部署全流程git clone https://github.com/freellmapi/freellmapi.git cd freellmapi cp .env.example .env # 编辑 .env填入你的服务端口、管理密钥等基础信息 docker compose up -d跑起来之后默认会在8080端口监听。你可以先用 curl 验证健康检查curl http://localhost:8080/v1/models正常情况下会返回一个模型列表内容取决于你后续在配置文件里添加的 Provider 和模型映射。如果这一步返回空列表说明你的 Provider 配置还没生效或者配置文件路径不对。没有 Docker 的情况项目也支持裸机运行需要 Node.js 20 环境执行npm install之后npm run start即可。但我仍然推荐 Docker 方式因为项目依赖的配置文件、状态存储目录、日志输出都能和宿主机隔离升级版本时不用操心依赖冲突。3.2 配置文件里最需要关注的几个字段项目的主配置文件是config.yaml用 YAML 格式维护对新手友好。里面最核心的段落是providers。每个 Provider 配置块大体长这样providers: - id: openai_free type: openai apiKey: sk-xxxx baseUrl: https://api.openai.com/v1 models: - id: gpt-4o-mini mapping: gpt-4o-mini weight: 1 maxRequestsPerDay: 500 maxTokensPerDay: 200000 healthCheckPath: /v1/models几个字段解释一下id是 Provider 在系统内的唯一标识日志和配额统计里都会用到type对应项目内置的适配器类型比如openai、anthropic、gemini、zhipu、deepseek等apiKey是你在厂商平台申请的密钥models是该 Provider 下可用的模型列表其中id是对外暴露的模型名mapping是实际请求上游时使用的真实模型名maxRequestsPerDay和maxTokensPerDay是相对保守的额度限制设置建议设得比你实际领取的免费额度略低一些。因为各家平台的免费额度计量往往有延迟你这边看到的消耗和厂商后台记录的可能存在偏差留出 10% 的余量能避免被误伤风控。3.3 配额统计的实现方式与避坑思路项目对每日额度的统计并不是实时地查询各家厂商的后台接口实际上大部分厂商根本没有公开的额度查询 API而是采用本地计数与上游响应反馈相结合的估算方式。本地计数就是在每次请求成功后解析响应里的usage字段如果上游返回的话累加到该 Provider 当天的 token 消耗记录里。如果上游不返回 usage 信息项目会基于请求的输入输出文本长度做一次估算。这种方式的误差是必然存在的但作为还剩多少能用的参考已经足够。你真正要留意的一个坑是本地计数和厂商后台的计数口径往往不一致。有些平台按总 token 算有些按计费 token 算有些把缓存命中的 token 也计入免费额度有些则不计。所以不要在下班后盯着本地仪表盘的数字和厂商后台对账你会发现怎么都对不上。更好的方式是把maxTokensPerDay设为厂商免费额度的 70%-80%用硬限制兜底而不是追求精确预测。4. 把 /v1 端点接到你自己的工具链里服务端跑起来之后使用体验就非常顺滑了。这一步我要重点演示如何接入到主流工具尤其是当你已经有现成代码时改造量极小。4.1 OpenAI SDK 直接改地址就能用如果你用的是 Python 的 openai 库接入方式如下from openai import OpenAI client OpenAI( base_urlhttp://localhost:8080/v1, api_keylocal-gateway-key # 这里填的是你在 .env 里设置的 LOCAL_API_KEY ) response client.chat.completions.create( modelgpt-4o-mini, messages[ {role: system, content: 你是一个帮助用户总结文章内容的助手。}, {role: user, content: 请帮我总结这段内容...} ] ) print(response.choices[0].message.content)关键的改动只有一行base_url。api_key这里已经不再是某家厂商的真实密钥而是网关自己的访问凭证。这样做还有个额外好处你的业务代码里不需要再保管多家厂商的 key密钥统一收口到网关配置里降低了泄露风险。4.2 支持流式输出的对接逻辑很多聚合类项目做流式输出时容易翻车因为不同厂商的流式格式差异比普通响应更大事件名、字段名、结束标记五花八门。FreeLLMAPI 在这一点上处理得比较完整。适配器层会把上游的流式事件解析出来重新拼装成 OpenAI 风格的 SSE 流再按data: [DONE]标准结束。所以客户端代码里只要是按 OpenAI SSE 格式解析的都能直接使用流式。示例写法stream client.chat.completions.create( modelgpt-4o-mini, messages[{role: user, content: 讲个冷笑话}], streamTrue ) for chunk in stream: if chunk.choices and chunk.choices[0].delta.content: print(chunk.choices[0].delta.content, end)4.3 给 LangChain 等编排工具用的技巧我实测了把它接入 LangChain 的情况。LangChain 的ChatOpenAI类支持传入自定义base_url所以只需要from langchain_openai import ChatOpenAI llm ChatOpenAI( modelgpt-4o-mini, base_urlhttp://localhost:8080/v1, api_keylocal-gateway-key )之后 LLM 调用、Agent 的推理链路、Tool Calling 都能正常走。当然前提是你选的 Provider 上游模型本身支持函数调用或工具调用。如果某个免费模型的工具调用能力较弱你会看到工具调用结果解析失败或返回空。这种情况下建议在模型映射表里将这类任务固定路由到支持工具调用的模型而不是交给自动调度。5. 实测中踩过的坑免费额度聚合没有想象中那么优雅这个项目跑了小一个月我把实际使用中遇到的几个典型问题整理出来。这些都是你在文档里看不全、但动手一定会撞上的东西。5.1 各家限流参数差异导致的假健康问题项目内置的健康检查机制是定时向每个 Provider 发送一个轻量级请求比如/v1/models来判断该 Provider 是否可用。但实测中我发现一个漏洞健康检查通过不代表实际调用能成功。有一家厂商的健康检查接口非常宽容任何时候都返回 200但实际调用 Chat Completion 时会在高并发下疯狂返回 429。反过来另一些平台的模型列表接口偶尔会因网络波动返回 502但实际推理接口却没任何问题。处理方案是两手抓一方面不要完全信任健康检查结果要在适配器里针对 HTTP 429/503 这类限流状态码进行独立的熔断处理连续失败 N 次后自动摘除该 Provider 一段时间另一方面对 FreeLLMAPI 中已有的重试逻辑建议在客户端也做一层重试兜底这样即使网关选到了一个即将触发限流的 Provider客户端也能通过重试拿到成功响应而不是直接报错到用户面前。5.2 关于免费额度的三个常见误解第一个误解免费额度是永久的。实际上大部分厂商的免费赠送都有有效期有的一个月有的三个月。过期之后 key 不会失效但会开始扣费如果你没有绑定支付方式则直接报错。我遇到过注册了一堆平台半年后跑起来一看好几个 key 静默失效调度器还傻乎乎地往那边发请求。第二个误解免费 key 可以无限并发测试。真相是免费层对 RPM每分钟请求数和 TPM每分钟 token 数的限制往往比付费层苛刻得多。你在代码里做了并发为 50 的批量任务很可能直接触发限流然后被厂商风控盯上连正常请求都受影响。这也是为什么我在配置里一直强调要把 maxRequestsPerDay 设得保守宁可用完换下一家也不要一次性把 key 打爆。第三个误解所有 Provider 的额度消耗都能被准确统计。前文已经说过本地计数和厂商计费口径不一致这个不只是在免费场景下存在付费场景也一样。所以当你看到仪表盘显示今日剩余 12000 token时心里要有数这只是一个估算值不是精准读数。5.3 不要把敏感数据喂给免费端点这一点我必须单独拎出来说因为它太容易被忽略了。你在 FreeLLMAPI 里配置的每一个免费 key对应的都是第三方厂商的服务。这些服务的隐私政策、数据处理条款、数据留存时间完全不一样。有的平台明确写着会用你的输入数据做模型优化有的平台虽然没有明说但也没有承诺不使用。所以如果你的业务涉及用户隐私数据、商业机密、未公开的代码绝对不要通过这个项目的聚合入口发给免费模型。这不是 FreeLLMAPI 的问题而是免费额度本身的边界。付费 API 同样存在数据使用条款问题但至少你和厂商之间有合同约束免费额度往往连这层保障都没有。我的建议是给这个网关划一条清晰的使用边界。比如只用来做代码片段解释、格式转换、草稿生成、娱乐对话这类低敏感任务。生产环境的核心链路还是用正规付费 API或者私有化部署的模型。6. 从 FreeLLMAPI 到通用网关这类项目的价值边界看完了部署和使用最后聊聊这个项目对开发者的真正启示。6.1 对个人开发者最实在的三个价值点价值一盘活碎片资源。把分散在各家平台的免费额度统一调度起来确实能支撑起不少轻量级应用场景。我现在的个人自动化脚本、临时数据分析、文本分类任务都是通过它免费跑的一个月下来省下的 API 开支不算多但胜在省心。价值二密钥集中管理的思路。就算你全部使用付费 API把多把 key 集中在一个网关里统一管理、统一记账、统一限额也比散落在各个业务代码里安全得多。这个项目的配置格式和管理思路可以直接借鉴到公司内部工具链里去。价值三Provider 适配器的代码风格。项目的适配器代码很规范如果你想在自己的项目里接入多家大模型厂商直接读它的源码比看各家 SDK 文档要快得多。它把各家 API 的差异点都浓缩在了一个文件里是很好的学习样本。6.2 基于这个项目可以做的两个拓展方向方向一加一层本地模型路由。现在很多开发者手头都有本地部署的 Ollama、vLLM 之类的推理服务。如果能把本地模型也注册成一个 Provider然后在模型映射表里配置规则让高并发、低敏感请求优先走本地把免费额度作为溢出的补充那整个网关的可用性和成本控制还能上一个台阶。方向二做一个单页的使用面板。项目本身带了简单的状态接口但如果你想给团队用最好在网关前面加一个简单的 Web 面板展示每个 Provider 的配额消耗、成功率、平均延迟。这个面板的数据来源可以直接从网关的统计接口拉不需要改动原项目写一个小服务接上去就行。从个人开发者的角度来讲FreeLLMAPI 是一个值得拉下仓库跑一遍的项目。它的核心思路——适配器模式加统一网关——在未来很长一段时间内都不会过时。免费额度这个东西不会永远存在但这种把分散资源收拢成一个统一入口的思维方式放到任何涉及多服务集成的场景里都有价值。我自己的做法是把它当作一座桥免费额度在的时候就享受低成本的便利额度万一哪天没有了桥上的流量随时可以切回付费通道。
返回列表