免费模型接口在并发下可能返回429、截断JSON或延迟突增,文章提供速率限制、响应结构、漂移和预算四个维度的测试方法。
免费模型端点在测量其速率限制、响应结构、漂移和预算之前,不适合自动化——而不是测量其可用性。
失败模式很常见。免费端点返回一次 200,于是你把它接到了一个任务上。后来,在并发场景下,它返回 429、截断的 JSON body 或突然的延迟峰值。你的流水线不知道这些区别,对错误输出照常执行。
之前这个账号的文章覆盖了模型响应之后的关卡:比对文件系统、权限矩阵、缓冲流式 JSON、只读 SQL。这篇文章把检查点提前了。这是一个预检接收探测,在所有这些关卡生效之前运行。
一种相关的设置是 MonkeyCode 的免费模型访问和免费服务器选项。声明:本文是 MonkeyCode 产品推广的一部分准备的。这两个可用性声明是运营方提供的,不代表对特定模型、配额、可用性或延迟的保证。不要从营销页面上假设任何这些。
200 状态码不是接收标准。探测检查四个信号:
速率结构 —— 在返回 429 之前有多少请求成功,以及是否存在 Retry-After。
响应结构 —— 端点在多次调用中是否返回了承诺的 JSON 字段。
漂移 —— 相同的 prompt 在短时间内是否改变了结构或延迟。
预算 —— 输入和输出的 token 数量,以便估算实际任务的成本。
这些不是质量检查。它们不会告诉你模型是否擅长编码或推理。它们只告诉你这个端点是否适合自动化。
下面的脚本只使用 Python 标准库。它假设是一个非流式的 JSON 端点,带有 chat 风格的 messages 字段:
import json, os, time, urllib.error, urllib.request
from concurrent.futures import ThreadPoolExecutor
ENDPOINT = os.environ.get("FREE_ENDPOINT", "")
API_KEY = os.environ.get("FREE_API_KEY", "")
PROMPTS = [
[{"role": "user", "content": 'Return JSON with keys "ok" and "summary".'}],
[{"role": "user", "content": 'Return JSON with keys "ok" and "summary" for another topic.'}],
[{"role": "user", "content": 'Return JSON with keys "ok" and "summary".'}],
]
def call(prompt, timeout=20):
payload = {
"messages": prompt,
"temperature": 0,
}
# Only include response_format if the endpoint documents it.
# payload["response_format"] = {"type": "json_object"}
req = urllib.request.Request(
ENDPOINT,
data=json.dumps(payload).encode(),
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
method="POST",
)
start = time.monotonic()
result = {"status": None, "data": None, "latency": None, "retry_after": None}
try:
with urllib.request.urlopen(req, timeout=timeout) as r:
result["status"] = r.status
result["data"] = json.loads(r.read().decode())
result["latency"] = time.monotonic() - start
except urllib.error.HTTPError as e:
result["status"] = e.code
result["data"] = {"error": e.read().decode()[:200]}
result["latency"] = time.monotonic() - start
result["retry_after"] = e.headers.get("Retry-After")
except Exception as e:
result["data"] = {"exception": type(e).__name__}
result["latency"] = time.monotonic() - start
return result
def shape_ok(result):
try:
content = result["data"]["choices"][0]["message"]["content"]
return result["status"] == 200 and isinstance(content, str) and bool(content)
except Exception:
return False
def shape_check():
return [call(p) for p in PROMPTS]
def rate_check(concurrency=3, rounds=2):
def worker(_):
return call(PROMPTS[0])
with ThreadPoolExecutor(max_workers=concurrency) as ex:
return [f.result() for f in [ex.submit(worker, i) for i in range(concurrency * rounds)]]
def budget_check(results):
total_in = 0
total_out = 0
for r in results:
usage = r.get("data", {}).get("usage", {})
total_in += usage.get("prompt_tokens", 0)
total_out += usage.get("completion_tokens", 0)
return {"input_tokens": total_in, "output_tokens": total_out}
if __name__ == "__main__":
results = shape_check()
print("shape_ok:", [shape_ok(r) for r in results])
rate_results = rate_check()
print("status:", [r["status"] for r in rate_results])
print("latency_ms:", [round((r["latency"] or 0) * 1000) for r in rate_results])
print("budget_estimate:", budget_check(results + rate_results))
从环境变量设置 ENDPOINT 和 API_KEY,不要写在文件里。
如果端点拒绝 response_format,删除该字段,改用 JSON 解析器验证返回的字符串。
运行一次 shape_check,然后用接近真实工作负载的并发量运行 rate_check。
budget_check 只在响应包含 usage 对象时有效。许多免费端点不暴露它;把缺失视为未知,而不是零。
这是一个模板,不是基准结果。它没有在当前配额下运行过。
运行前先设定阈值。它们取决于你的任务。
不要复制这些数字。你的免费层可能允许一个并发请求或二十个。自己测量。
通过探测不代表模型是安全的。免费端点可能:
返回结构正确但内容错误的 JSON。
通过结构检查但幻觉出一条命令。
在探测后有一个短暂的冷却期。
明天改变 schema。
在关卡之前运行这个探测,而不是替代它们。早期的关卡仍然决定输出可以触碰什么。
还要随时间测量漂移,而不是只测一次。一次性接收探测在端点处于空闲窗口时可能产生假阳性。在两个不同时间点运行它,或者将当前运行与保存到小 JSON 文件中的上一次运行进行比较。
漂移记录示例:
{
"checked_at": "2026-08-15T10:00:00Z",
"requests": 10,
"non_200": 0,
"median_latency_ms": 842,
"shape_ok": 10
}
如果下一条记录跃升到 8 个 non-200 或 2400 ms 中位延迟,在流水线启动之前就停止它。
你需要硬 SLA 或生产级密钥。
你在合规或安全关键领域。
你期望免费层是稳定和版本化的。
你想评估模型质量。这个探测测量的是传输,而不是推理。
对于这些情况,带有合同的付费或专用端点才是正确的工具。
免费模型端点通过通过预检探测来赢得自动化的位置,而不是靠一次 curl 响应。先测量速率结构、响应结构、漂移和 token 预算。然后把输出交给现有的关卡。
如果你在使用 MonkeyCode 的免费模型或服务器选项,在把它连接到任何可以写入或消费的东西之前,先运行这个探测。