Gemma 4的MoE和Dense版本对相同prompt展现截然相反的行为。这是LLM模型选择和prompt工程的深度案例,提示不同架构的本质差异。
Gemma 4 挑战:撰写关于 Gemma 4 的参赛文章
更新——2026-05-21:评论区的反馈促使我将 max_tokens 从 400 提高到 4096,并重新进行了测试。本文中关于架构影响的论述,大部分其实源于 token 预算不足这个 bug——只要给予足够的预算,Dense 模型在所有场景中都能恢复正常。后续文章:我提高了 Gemma 4 的 Token 上限,Dense 模型不再拒绝回答。
TL;DR:我运营着一个面向阿拉伯语商家的 AI 销售聊天机器人。我想知道,Gemma 4 能否在面向客户的回复环节取代 GPT-4o-mini。我通过真实的生产聊天路由器,在六个阿拉伯语客户场景中测试了两个 Gemma 4 变体——260 亿参数的混合专家模型(40 亿激活参数)和 310 亿参数的 Dense 模型——并将它们与 GPT-4o-mini 和 GPT-4o 进行了对比。第一轮中,两个 Gemma 变体真正的失败模式并不是幻觉,而是不愿作答——该搜索时拖延,该明确说出名称时却含糊其辞。因此在第二轮中,我添加了三条仅针对 Gemma 的提示词规则。MoE 模型转向了有依据的回答;Dense 模型则转向了假阴性式拒绝——明明答案就在上下文中,却声称“我们没有那个”。相同的指令、两种架构、截然相反的方向。我认为自己调优的是架构,而不是模型规模。
我的平台是一个面向阿拉伯语电商的多租户聊天路由器。客户消息传入后,一个小型的 gpt-4o-mini 路由调用会决定是搜索商品,还是仅进行对话;如果执行了搜索,第二次调用会根据搜索结果编写面向客户的回复。
直到上周,这个回复调用仍被硬编码为 gpt-4o-mini。我接入了一个按对话选择模型的功能,这样每次运行之间唯一变化的,就是将检索数据转化为阿拉伯语文本的模型。路由器、资料提取、议价改写、经过翻译的商品摘要——为了公平比较,这些部分仍全部使用 gpt-4o-mini。Gemma 只负责撰写最终回复。披露这种混合技术栈非常重要;Gemma 并没有运行完整的流水线。
我将生产环境中的精品店克隆成了一家测试商店——共有 34 件商品,所有 schema 字段都填充完整(尺码、颜色、材质、目标价格/底价、AI 摘要、嵌入向量);数据库中的规范语言为英语,提供服务时会在运行时翻译成阿拉伯语。配送政策的原文确实是:
“加沙和约旦河西岸订单满 100 美元免运费。标准配送时间为 2~4 个工作日。”
这个细节稍后很重要。
六个阿拉伯语客户场景:
四个模型、六个场景。每种模型与场景组合运行一次。这是探索性测试,不是统计实验——24 轮对话只能反映一种信号形态,不能算作基准测试。对于需要后续重复测试的部分,我会明确指出。
以下是这些模型及其 API ID:
gemma-4-26b-a4b-it——a4b 后缀符合 Google 对混合专家模型变体中激活参数数量的命名惯例(总计 260 亿参数,其中 40 亿参数处于激活状态)
gemma-4-31b-it——没有激活参数后缀,是 Dense 模型
这个命名细节,正是本文余下内容所要讨论的主题。
我尝试在 Google API 上禁用思考模式。我发送了 generationConfig.thinkingConfig = { thinkingBudget: 0, includeThoughts: false }。API 返回 HTTP 400:"Thinking budget is not supported for this model."。于是我移除了这项配置。
这意味着:我无法控制 Gemma 4 是否会在回答前进行推理,也没有遥测数据能告诉我它是否这样做了。我的响应解析器会过滤标记为 thought: true 的部分,并防御性地移除 <think>…</think> 块,但这两个过滤器触发时都不会记录日志。接下来展示的回复都不包含可见的思考草稿——但我无法告诉你,它们是否曾包含后来被静默移除的隐藏思考草稿。
因此,下面的延迟比较在一种意义上是公平的:我比较的是客户实际使用各模型 API 端点时会体验到的结果。但如果把它视为纯粹的推理性能比较,那就不公平——gpt-4o-mini 默认不会执行扩展推理;Gemma 4 则可能会进行一定程度的推理,而我无法将其禁用。延迟差距一部分来自推理性能差异,另一部分也可能来自是否进行思考的差异。在这个端点上,我无法进一步区分二者。
如果你继续阅读,请记住这个前提。
开始测试时,我原以为 Gemma 会捏造价格、地点和 SKU 名称。这也是人们对非英语聊天场景中中小型开放模型的普遍看法。
但数据比这更有意思。
延迟方面存在鸿沟。GPT-4o-mini 和 GPT-4o 在 7~14 秒内就能回答。Gemma 4 26B 的响应时间为 28~77 秒,其中 77 秒出现在涉及数学计算和配送的场景。Gemma 4 31B 在成功完成的场景中耗时 30~43 秒。
商品目录依据方面的表现让我很意外。下面两个例子,在检查商店配置之前,我差点把它们写成 GPT 在幻觉控制上的胜利:
场景 4。客户询问一笔 240 谢克尔的订单是否免运费。Gemma 26B 回答:“只有金额超过 100 美元的订单才能免运费,配送范围为加沙和约旦河西岸。”我读到这句话时,以为它凭空编造了这些地理范围。但并没有。这就是商店 shipping_info 字段中的原文。Gemma 的回答比我预期的更有依据。
场景 3。客户想要一套婚礼西装和一块银色手表。Gemma 31B 说出了两套具体西装及其价格:“Azure Charm Tailored Suit,350 美元;Executive Blue Suit,400 美元。”我以为它在编造带品牌名的 SKU。实际上并不是——数据库中确实存在这些记录,而且 GPT-4o-mini 也说出了它们的名称。
第一轮中,Gemma 真正的失败模式比“它会产生幻觉”更加具体:
Gemma 26B 在场景 2 中停滞了。客户询问是否有 L 码的白衬衫。商店里有三件。模型没有将它们列出来,而是说:“让我问问店主,稍后回复你。”搜索结果明明就在它的上下文中,它却选择推迟回答,而不是直接列出来。
Gemma 26B 在场景 3 中含糊其辞。它为婚礼西装推荐了“两个很棒的选择”,却没有说出具体名称。31B 给出了明确答案,它却十分模糊。
Gemma 31B 偶尔会出错——在推理压力场景中,它曾返回一次 HTTP 500,甚至还没生成候选答案。
在 Gemma 的全部十二次运行中,推理过程都没有以可见形式泄露出来。
第一轮得到的教训并不是“Gemma 会捏造内容”,而是:
失败模式不是幻觉,而是不愿作答。
正是这句话促使我开始了第二轮测试。
OpenAI 的技术栈没有增加任何内容。目的就是在 Gemma 侧进行一次受控的前后对比。
对于 Gemma,我在 callChatModel 分发器中添加了一个分支。当解析出的提供商为 "google" 时,请求发出前会发生三项变化:
function augmentForGoogle(
params: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming
): OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming {
const messages = [
{ role: "system", content: GEMMA_AR_FRAME },
...params.messages,
];
return {
...params,
messages,
temperature: Math.min(params.temperature ?? 0.7, 0.3),
max_tokens: Math.max(params.max_tokens ?? 0, 400),
};
}
GEMMA_AR_FRAME 是一个由四行内容组成的 system 块,会被添加到现有提示词栈的最前面:
你是一家在线商店的销售代表,正在回复一位阿拉伯客户。
使用巴勒斯坦阿拉伯语方言,以一条简短消息作答。不要写开场白,也不要显示推理过程。
绝对不要编造上述数据中未提及的价格、商品名称、政策或地点。
如果客户询问的商品不在目录中,请如实说“我们没有那个”,并从现有商品中推荐一个替代选项。
最终回复中不要包含内部推理过程,也不要出现英语句子。
总计三项改动:在前面添加以阿拉伯语为优先的框架、将 temperature 上限设为 0.3、将 max_tokens 下限设为 400。大约 25 行代码。OpenAI 调用与第一轮逐字节完全一致。
我一次性修改了三项内容。我无法告诉你究竟是哪一项发挥了作用——要确定这一点,至少还需要进行三轮消融实验。下文描述的是这些改动的综合效果。
变化最明显的是场景 2——商品搜索。
第一轮,Gemma 4 26B(MoE):
يا هلا! من عيوني، خليني أتأكدلك إذا متوفر عنا قميص أبيض بمقاس L حالياً. رح أسأل صاحب المحل وأرجعلك فوراً عشان أضمنلك إنه...
翻译:“你好!让我确认一下,我们现在是否有 L 码的白衬衫。我会问问店主,然后马上回复你……”
停滞。三件白衬衫就在提示词中,模型却拒绝使用这些信息。
第二轮,Gemma 4 26B,同一个模型、同一家商店、同一条客户消息:
يا هلا! موجود عنا Urban Cool Striped Shirt بـ $65، وBordeaux Heritage Shirt بـ $80، وUrban Stripes Classic Shirt بـ $95...
三个真实的 SKU,真实的价格。这些增强措施并没有给模型提供任何新数据——数据一直都在那里。它只是改变了模型在两条路径都可选时的选择:是拖延,还是明确作答。
场景 3 中,26B 也呈现出相同的变化方向。第一轮:“提前恭喜你!这里有两个很棒的选择,肯定会让你惊艳……”(没有名称)。第二轮:“银色手表我们没有,但我们有适合婚礼的西装,比如 Azure Charm Tailored Suit 和 Executive Blue Suit……”(如实拒绝了手表需求,并说出了真实西装的名称)。
然后我在 Gemma 4 31B(稠密模型)上运行了相同的第 2 轮。
第 1 轮,Gemma 4 31B,场景 2:
يا هلا فيك! من عيوني، عندنا خيارات بتجنن بمقاس L وباللون الأبيض: Urban Cool Striped Shirt بـ 65 شيكل، Bordeaux Heritage Shirt...
三个真实产品、真实价格,约 30 秒。第 1 轮两个 Gemma 变体中最好的场景 2。
第 2 轮,相同模型、相同商店、相同客户消息:
والله يا غالي حالياً ما عندنا قميص أبيض مقاس L. اعذرني، ما في شي متوفر من هاد الموديل حالياً.
翻译:"天哪,亲爱的,我们目前没有尺码 L 的白色衬衫。抱歉,这个款式目前没有库存。"
这是错的。商店有三件白色 L 号衬衫。搜索结果就在 31B 的上下文中。模型拒绝了。
指令"如果客户询问目录中没有的东西,请诚实地说'我们没有那个'"——同一条指令推动 MoE 走向有根据的认可——推动稠密模型走向没有根据的拒绝。它应用了规则的拒绝部分,却没有先搜索规则适用的数据。
31B 上的第 2 轮也产生了六次运行中的两次 HTTP 500 错误——都在 11 秒内,在任何候选生成前。26B 上的第 2 轮产生了零个错误。在相同增强提示下的可靠性差距是 0 / 6(MoE)vs 2 / 6(稠密)。
列按轮次而非按模型分组——因此两个第 2 轮列并排放在一起,MoE vs 稠密的分歧一眼可见。
延迟 p95:GPT-4o-mini 14s · GPT-4o 13s · 26B R1 77s · 31B R1 76s · 26B R2 49s · 31B R2 41s。
场景 5(观望压力测试)没有区分任何东西——每个模型都在价值上表现出来,拒绝了惊慌折扣。保留在矩阵中作为回归检查;这行在本文中是填充,但它是框架没有精选样本的证据。
横向阅读矩阵:稠密第 2 轮列是我如果只测试过 MoE 就会发货的那个。
标准的解读会是"较大的模型过度拟合了指令"。这是一个可能的解释。但架构差异就在模型 ID 中,它给出了一个更清晰的机制。
在稠密模型中,每个参数对每个 token 都是激活的。遵循指令在整个前向传播中均匀推动。像"拒绝目录中没有的"这样的前置规则对每个层的每个输出 token 都在范围内。当规则有歧义时——先搜索,如果不存在则拒绝——稠密模型的均匀激活没有"先检查"的独立阶段,所以规则解析成单一行为。在我的增强下,该解析倾向于拒绝。
在混合专家模型中,路由在前向传播主导前为每个 token 选择一小部分参数。路由意味着不同的 token 可以在生成中期接入不同的参数子集——所以模型在 MoE 中有架构插槽用于切换子行为,而稠密前向传播中没有。"检查数据,然后如果不存在则拒绝"的序列在 MoE 中有地方存放,在稠密中没有。(我在这里要小心:这不是说有一个"检索专家"和一个"拒绝专家"——MoE 中的专家是学习到的表示,不映射到人类可读的任务类别。该声明是结构性的,而非功能性的。)
我没有可引用的可解释性研究。这是数据拟合的假设,不是证明。它预测什么,以及接下来值得测试的东西:
在稠密模型上运行相同的六个场景,指令的正面部分在前("列出数据中每个匹配的产品"),负面部分在后。如果稠密场景 2 的假阴性消失,问题是指令顺序与稠密激活的相互作用,而非架构本身。
用相同的增强运行一个更小的稠密 Gemma(2B 或 7B 变体,如果有的话)。如果较小的稠密也拒绝,失败与密度成比例。如果较小的稠密列出了衬衫,它与参数计数单独成比例。
在不同的 MoE(Mixtral 变体)和不同的稠密(Qwen 32B 稠密)上尝试相同的增强。如果 MoE/Dense 分歧在各种系列中重复,该机制是通用的。
如果你运行过类似的东西,我想听听。
按发现的新颖性排序,而非成本的大小:
变体特定的提示词调整是开源模型发货的基础。这是故事中我没想到要写的部分。没有"一个提示词用于 Gemma 4"。帮助 MoE 变体的改动会破坏稠密变体。如果你在为聊天界面在开源模型变体之间选择,你不是在选择模型——你是在为每个变体选择一条提示词调整维护通道。这是闭源模型产品(GPT-4o-mini、Claude Haiku)不收费的隐藏持续成本。
Google API 上的延迟是一个鸿沟。Gemma 26B 28–77s,31B 30–43s,对比 GPT-4o-mini 的 7–14s。交互式聊天在这些数字下不会发货。无论是推理时间、强制推理时间还是路由开销,客户看到的是墙上时钟都是一样的。
增强提示下稠密变体的方差非零。31B 第 2 轮 6 次运行中 2 次 HTTP 500 是阻塞性的,不只是慢。MoE 变体在相同提示中 0/6 错误。
对于我的用例——负载下的阿拉伯语电商聊天——GPT-4o-mini 继续在生产中。Gemma 4 26B(MoE)是我见过最强的非英文客户聊天开源候选,但延迟和按变体调整表面需要收紧后才能发货。Gemma 4 31B(稠密)需要在有根据的检索任务上修复拒绝偏差后才能使用。
我认为我是在调整架构,而非规模。
那就是来自 TL;DR 的那条线,重写后我没有更尖锐的了。我为"Gemma"设计的干预——三个规则和一个温度改变——击中了两个不同的架构并产生了两个不同的失败翻转。我认为我在控制的变量是模型。我实际上在控制的变量是模糊指令与我没有命名的架构之间的相互作用。
如果你在为非英文聊天界面对开源模型进行基准测试,从这里取走两件事:
在真实产品数据上运行,在你的真实聊天路由器中,用真实客户形状的提示。针对合成人物的脚本基准不会捕获 MoE vs 稠密分歧——两个 Gemma 变体在隔离中"看起来像 Gemma"。分歧针对带有真实歧义的真实目录显示。
仔细阅读模型 ID。gemma-4-26b-a4b-it 和 gemma-4-31b-it 看起来像"同一系列的两个尺寸"。a4b 后缀是它们不是的信号。如果你的提示取决于多步骤指令遵循——先搜索,在不存在时拒绝——架构比参数计数更重要。
我仍在为面向客户的回复使用 GPT-4o-mini。聊天机器人仍然是巴勒斯坦阿拉伯语。发货仍然是加沙和约旦河西岸,订单超过 100 美元。衬衫仍然是真实的。
这周改变的是我写下一个提示词的方式。不是"对于 Gemma"。对于 Gemma 的架构。模型是系统中最小的变量。模型下的架构是我遗漏的。