在一篇 姊妹文章 里,我们检验了一个网关是否按真实令牌数诚实计费。这篇文章要检验 另一个承诺:名字底下的那个模型,到底是不是真的就是那个模型。转售 商可以回传一个自称 claude-sonnet-4-6 的东西,但它实际上可能是一个更小的模型、一个微调版本、一段被固定 模板包起来的提示词,或者就是真模型本身、却被悄悄砍掉了上下文窗口 和原生功能。model 字段里的字符串一模一样,可在网络上真正传输的,是截然不同的两码事。
你不必只听别人的一面之词。四个简短的测试,就能把货真价实的第一方 模型和换皮的冒牌货区分开来。它们全都不靠去问模型「你是谁」—— 因为 模型对自己的身份,是个靠不住的叙述者。要直接探测的,是 能力。
模型造假的四种手法
- 调包。 在旗舰模型的名字底下,端出一个更便宜、更小的模型。运行成本最低, 在简单提示词上也最不容易被发现。
- 模板代理。 你的提示词在抵达模型之前,被塞进一套固定的脚手架里 —— 这会改变 模型的行为,而且 还会用你根本没写过的文字,把你的令牌账单注水撑大。
- 截断的上下文窗口。 号称有 200K 上下文,实际上却 截断成其中一小部分,悄悄丢掉长输入的中间一段。
- 被阉割的功能。 工具调用、视觉或提示词缓存被拿掉 或造假,于是除了纯聊天以外的一切都会退化。
测试 1 —— 上下文窗口
把一个事实藏进一篇很长的文档深处,再让它找回来。货真价实的 200K 上下文模型能取回它;被截断的降级货则会在输入时报错,或者丢掉 中间一段:
# test_context_window.py
# 被换在这个名字底下的降级模型,根本撑不住它宣称的上下文长度。
# 把一个事实藏进一篇很长的文档深处,再让它把这个事实找回来。
from openai import OpenAI
client = OpenAI(api_key="sk-brievio-...", base_url="https://api.brievio.com/v1")
needle = "The launch code is HORIZON-7741."
filler = ("This sentence is filler. " * 9000) # 约 5 万个令牌的噪声
haystack = filler + "\n\n" + needle + "\n\n" + filler
resp = client.chat.completions.create(
model="claude-sonnet-4-6",
messages=[
{"role": "system", "content": "Answer only from the document."},
{"role": "user", "content": haystack + "\n\nWhat is the launch code?"},
],
max_tokens=20,
)
print(resp.choices[0].message.content) # 真货会回答:HORIZON-7741
# 被截断的降级代理,要么在长输入时直接报错,要么悄悄丢掉中间一段、
# 回一句「我不知道」。把填充内容塞到超过模型宣称的窗口(比如 200K 模型
# 就塞超过 150K 令牌),看看它会在哪里崩掉。测试 2 —— 原生工具调用
发起一次工具调用,然后检查 tool_calls。真模型会回传一个 结构化的调用;只是假装支持工具的换皮货,则会回传 null,并把一坨 JSON 塞进文本里:
# test_tools.py —— 是原生工具调用,还是冒牌货?
resp = client.chat.completions.create(
model="claude-sonnet-4-6",
messages=[{"role": "user", "content": "What's the weather in Tokyo? Use the tool."}],
tools=[{
"type": "function",
"function": {
"name": "get_weather",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}},
},
}],
tool_choice="auto",
)
msg = resp.choices[0].message
print("tool_calls:", msg.tool_calls) # 真货会回传:结构化的 get_weather(city="Tokyo")
# 只是假装支持工具的换皮代理会回传 tool_calls=None,
# 改成把一坨 JSON 当成纯文本硬塞进 message.content。这就是破绽所在。测试 3 —— 视觉
发一张你早就知道内容的图片,让模型把它读出来。被降级成纯文本的 模型办不到 —— 它会产生幻觉,或者直接报错:
# test_vision.py —— 它真的「看得见」吗?
resp = client.chat.completions.create(
model="claude-sonnet-4-6",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Reply with only the exact text shown in this image."},
{"type": "image_url", "image_url": {"url": "https://your-host/known-text.png"}},
],
}],
max_tokens=30,
)
print(resp.choices[0].message.content) # 真货会回答:图片里的文字
# 被降级成纯文本的模型读不出来 —— 它会产生幻觉、在 image 部分报错,
# 或者干脆无视它。请用一张你早就知道内容的图片。测试 4 —— 缓存与账单
第四项检查,是从那篇 令牌注水文章 借来的:把同一段很长的前缀发两次,确认第二次时 cached_tokens 不为零,并且确认你的 prompt_tokens 和你实际发出的文字相符。模板代理在这两点上都会失败 —— 它没法缓存 一段被自己改写过的前缀,而且还会把包装层也一起算进账单。模型的 真实性和计量表的诚实度,是结伴而行的;请把它们放在一起检查。
把它们串起来
货真价实的模型,四项全过:它撑得住完整上下文、回传真正的工具 调用、读得懂图片、会缓存前缀,并且按你发出的令牌数计费。换皮或 降级的货,至少会在其中一项上崩掉 —— 通常是那些造假成本最高的项目 (长上下文、视觉)先出问题。在你接入一个网关时,把这整套测试跑 一遍;日后只要觉得某个模型的回答悄悄变差了,就再跑一遍。这里出现 的退步(regression),正是无声降级现形的时刻。
诚实的基准线
Brievio 通过一线云端通道,路由货真价实的第一方模型 —— Claude 经由 AWS Bedrock、Gemini 经由 Google Vertex —— 完整的上下文窗口、原生 工具调用、视觉与提示词缓存,全都原封不动地直通而过;而且你请求的 是哪个模型,拿到的就是哪个模型。把上面所有测试都拿来对着 Brievio 跑一遍,它应该都能干干净净地通过。 模型目录 列出了每个模型真实的能力与上下文长度,而 文档 则展示了这里用到的请求的确切格式。
「它是不是真模型」和「计量表说的是不是实话」—— 这两个问题,值得拿 去问任何一个 AI 网关,包括 Brievio 自己在内。两者都只要大约一分钟 就能得到答案。动手问吧。