简介:本文围绕免费大模型 API 的实际调用展开,系统梳理了免费模型识别、额度与限流验证、空返回排查及参数配置等关键问题。通过可复现的实测方法,帮助开发者避开“名字带 flash 却收费”“接口调通却返回空”等常见陷阱,建立一套稳定可靠的免费模型兜底调用方案。
在很多个人项目和小型应用中,出于成本考虑,开发者常常会在主链路之外挂一个免费的大模型 API 作为兜底。当付费主模型出现额度耗尽、服务波动或临时限流时,兜底模型可以保证功能不至于完全不可用。
然而,“免费”两个字背后往往藏着大量隐性成本。最近在为一个副项目接入某云厂商的免费模型时,我随手多试了几个公开渠道提到的模型 ID,结果发现好几处与公开说法对不上:
flash,看起来像轻量免费版,实际调用却提示余额不足;这些问题如果不提前摸清,很容易在线上环境里造成“看似成功、实则无输出”的静默故障。于是花了一个下午,把该厂商文档和公开资料里提到的免费模型挨个真调了一遍,把额度、限流、返回格式、报错信息全部记录下来。本文是一份调用手册,不是模型评测。文中的数字均为特定时间点的实测结果,脚本思路附在文末,读者可自行复现。
需要先说明范围:我手上只有一家云厂商的可用密钥,所以只有它是真调的。 另外两家的状态只是顺手记录,未做完整验证,不替它们打包票。
一上来就遇到一个坑:该厂商的模型列表接口 /models 并不能列出免费模型。
curl https://api.example.com/v4/models \-H "Authorization: Bearer $KEY"
返回的是一串付费主力模型,比如 glm-4.5、glm-4.6、glm-4.7、glm-5、glm-5-turbo、glm-5.1、glm-5.2 等,一个 flash 都没有。如果你照着这个接口去找免费模型,会一无所获。免费模型的 ID 只能从官方文档或公开资料里翻出来,再逐个验证。
把公开资料里提到过的免费模型 ID 全试了一遍,实测结果如下:
| 模型 ID | 能否调用 | 耗时 | 说明 |
|---|---|---|---|
| glm-4-flash | ✓ | 0.7–1.7s | 最稳,适合日常主力 |
| glm-4-flash-250414 | ✓ | 0.7s | 同上,带日期版本号 |
| glm-4-flashx | ✗ | — | 报余额不足,不免费 |
| glm-4.5-flash | ✓ | 18–42s | 旧 ID 仍能调通 |
| glm-4.7-flash | ⚠ | 7–10s | 能用,但十次六次被限流 |
| glm-z1-flash | ✓ | 5.5–6s | 推理模型 |
| glm-4v-flash | ✓ | 1.1s | 图像理解 |
| glm-4.1v-thinking-flash | ✓ | 1.9s | 图像推理 |
其中 glm-4-flashx 要单独拎出来说。 它的名字长得跟 flash 几乎一模一样,很多汇总文章把它列进免费清单,实际调用却返回:
{"error":{"code":"1113","message":"余额不足或无可用资源包,请充值。"}}
多一个 x,就要钱。账户里没有余额时,它一次都跑不通。这类“名字相近但计费策略不同”的模型,是免费 API 使用中最容易踩的坑之一。
这是实际项目里踩过的坑,而且踩了之后得出了一个错误结论,一直挂到今天。
现象是这样的:调用 glm-4.5-flash 或 glm-4.7-flash,HTTP 状态码 200,不报错,但 choices[0].message.content 是空字符串。当时的结论是“这个思考模型有问题,别用,换 glm-4-flash”。
这次挨个试才发现,模型本身没问题,是调用参数不对。同一个模型、同一个问题,只改 max_tokens:
// 请求 A:max_tokens 过小{"model": "glm-4.5-flash","messages": [{"role": "user", "content": "请解释什么是幂等性"}],"max_tokens": 8}// 返回:content 为空字符串,finish_reason 为 length// 请求 B:max_tokens 合理{"model": "glm-4.5-flash","messages": [{"role": "user", "content": "请解释什么是幂等性"}],"max_tokens": 512}// 返回:正常内容
原因在于,部分推理型模型在正式输出内容之前,会先消耗一部分 token 做内部推理。如果 max_tokens 设置得过小,推理阶段还没结束,token 预算就被耗尽,最终返回的 content 就是空的,而 finish_reason 往往是 length。这属于参数配置问题,而不是模型故障。
实践建议:
max_tokens 不要设得过小,建议至少 256 起步,推理模型建议 512 以上。content 是否为空,还要看 finish_reason。如果为 length,说明被截断,需要调大 max_tokens。免费模型并不是无限可用,限流策略因模型而异。实测中:
glm-4-flash 和 glm-4-flash-250414 最稳定,连续调用基本不触发限流;glm-4.7-flash 虽然能用,但十次里大约六次会被限流,返回 429 或类似错误;glm-4v-flash、glm-4.1v-thinking-flash 调用耗时较短,但同样受免费额度约束。限流的表现形式通常有两种:一是直接返回 429 状态码;二是返回 200 但内容为错误提示。前者容易识别,后者容易被忽略,需要在业务层做统一封装。
应对策略:
finish_reason,便于后续分析。下面是一个简化的调用封装思路,重点在于统一处理空返回、限流和重试:
import timeimport requestsdef call_free_model(prompt, model="glm-4-flash", max_retries=3):url = "https://api.example.com/v4/chat/completions"headers = {"Authorization": f"Bearer {KEY}"}payload = {"model": model,"messages": [{"role": "user", "content": prompt}],"max_tokens": 512}for attempt in range(max_retries):try:resp = requests.post(url, json=payload, headers=headers, timeout=30)if resp.status_code == 429:time.sleep(2 ** attempt)continuedata = resp.json()content = data["choices"][0]["message"]["content"]finish = data["choices"][0].get("finish_reason")if not content or finish == "length":# 空返回或截断,视为失败time.sleep(1)continuereturn contentexcept Exception:time.sleep(2 ** attempt)return None # 全部失败,交由上层降级
关键点有三个:识别 429 并退避重试、识别空返回并视为失败、最终失败时返回 None 交由业务层处理。
免费大模型 API 确实可以用于兜底,但需要把它当作一个“有脾气”的依赖来对待。核心结论如下:
flash 不等于免费,glm-4-flashx 就是典型反例,多一个字母就要收费。max_tokens 设置过小有关,需结合 finish_reason 判断。finish_reason 都是排查问题的关键信息。把这些问题提前摸清,免费 API 才能真正成为可靠的兜底方案,而不是线上故障的隐藏来源。