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_url="http://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_url="http://localhost:8080/v1", api_key="local-gateway-key" # 这里填的是你在 .env 里设置的 LOCAL_API_KEY ) response = client.chat.completions.create( model="gpt-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( model="gpt-4o-mini", messages=[{"role": "user", "content": "讲个冷笑话"}], stream=True ) 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( model="gpt-4o-mini", base_url="http://localhost:8080/v1", api_key="local-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 是一个值得拉下仓库跑一遍的项目。它的核心思路——适配器模式加统一网关——在未来很长一段时间内都不会过时。免费额度这个东西不会永远存在,但这种"把分散资源收拢成一个统一入口"的思维方式,放到任何涉及多服务集成的场景里都有价值。我自己的做法是:把它当作一座桥,免费额度在的时候就享受低成本的便利,额度万一哪天没有了,桥上的流量随时可以切回付费通道。