AI活用

Gemini API响应为空的原因:gemini-2.5-flash用thinkingBudget=0加每次5篇分批解决

Gemini API响应为空的原因:gemini-2.5-flash用thinkingBudget=0加每次5篇分批解决

早上好,我是まさきん。

我把10篇文章一次性丢给 Gemini 的 API,结果返回的正文是空的。原因和解决办法都能在官方文档里找到依据,所以记下来留个备忘。

※本文内容以发布时为准。最新条件请以官方网站为准。

POINT
  • Gemini API 的响应为空时,先看 finishReason 和 usageMetadata
  • 官方说明,输出令牌上限(maxOutputTokens)是针对包含思考令牌在内的总量
  • gemini-2.5-flash 把 thinkingBudget 设为 0 就能关闭思考(范围是 0〜24576)
  • 我把 thinkingBudget 设为 0,再把一次10篇拆成每次5篇,就跑通了
  • 模型有时会编出正文里没有的截止日期,所以日期要在后处理里和正文核对

我在做什么

我搭了一套流程,每天去抓取某个会员制网站的新文章。每篇文章“是不是优惠信息”的判断和摘要,都交给 Gemini 来做。

通知是发到家人的聊天群里。全部都推的话就没人看了,所以只保留被判定为优惠信息的内容。

模型用的是 gemini-2.5-flash。摘要和分类属于固定套路的处理,我觉得又快又便宜的模型比较合适。

一次丢10篇,正文却是空的

一开始,我把10篇新文章合并到一次请求里。因为想减少调用次数。

可是返回的响应正文是空的。并不是报错中断。响应是回来了,里面却没有内容,就是这样一种状态。

如果是报错,靠异常就能发现。空响应会悄无声息地通过,所以有点麻烦。把它嵌进固定流程时,我觉得这是第一个坑。

原因是思考也会占用输出额度

官方文档说明,Gemini 3 系列和 2.5 系列是使用“思考过程”的模型。也就是在给出回答之前,模型会在内部先做推理。

这个思考默认是开启的。按官方的说法叫“动态思考”,思考量会根据请求的复杂程度自动变化。

关键在于,这部分思考也要消耗令牌。官方写明,max_output_tokens 是包含思考令牌在内的上限。

如果在思考途中就碰到上限,finish_reason 会变成 MAX_TOKENS。此时输出要么中途被截断,要么返回为空。让模型一次思考10篇的判断,思考和输出的总量大概就容易膨胀。

注意

官方文档里还写了关于计费的提醒。即使达到上限、输出为空,已经生成的思考令牌也要计费。返回为空的状态,可能意味着既没有结果,钱却照样花出去。

返回为空时的排查表

空响应其实分好几种。我根据 API 参考文档里的字段,整理了该看哪里。

症状在响应里看哪里可能的情况处理方向
正文为空或中途截断finishReason 为 MAX_TOKENS达到了指定的最大令牌数减少思考、减少单次篇数、重新考虑上限
正文为空且思考很多usageMetadata.thoughtsTokenCount 很大思考占用了输出额度调低 thinkingBudget(2.5系列)
正文为空但原因不同finishReason 为 SAFETY 等因安全等原因停止重新检查输入内容和提示词
返回了 JSON 但内容不对finishReason 为 STOP格式正确但值有误在应用端校验值

finishReason 的 STOP 表示在自然的结束点停下。MAX_TOKENS 的定义则是达到了请求中指定的最大令牌数。

所以响应为空时,我觉得最先要看的是 finishReason。只要不是 STOP,就按正文不可用来处理,可能更稳妥。

usageMetadata 的读法

响应里会附带 usageMetadata。API 参考文档里是这样说明的。

字段含义
promptTokenCount提示词(输入)的令牌数
candidatesTokenCount生成的候选回答的令牌数合计
thoughtsTokenCount思考模型在思考上用掉的令牌数
totalTokenCount提示词+思考+候选回答的合计

合计被定义为“提示词+思考+回答”,这一点很好理解。思考和回答是作为不同的字段分别统计的。

如果思考的数字大而回答的数字小,就有可能是额度被思考占用了。把这两个数字记进日志,之后追查原因会容易得多。

thinkingBudget 的指定方法

在 2.5 系列中,用 thinkingBudget 这个参数来指定思考量。官方说明,它是给模型一个用于思考的令牌数参考值。

设为 0 可以关闭思考。设为 -1 则是动态思考。在 Python 的 SDK 里,照着官方示例写出来是这样的。

from google import genai
from google.genai import types

client = genai.Client()
response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents=prompt,
    config=types.GenerateContentConfig(
        thinking_config=types.ThinkingConfig(thinking_budget=0)
    ),
)

用 REST 调用时,要在 generationConfig 里放一个 thinkingConfig。然后在其中用数值传入 thinkingBudget。

不过官方也有一句提醒。据说根据提示词的不同,模型可能会超出预算,也可能用不满。与其当成严格的上限,不如当成参考值来看待。

各模型的 thinkingBudget 范围

范围和默认值因模型而异。我把官方文档里的表格,只挑 2.5 系列的主要模型抄了过来。

模型未指定时可指定的范围关闭思考动态思考
2.5 Pro动态思考128〜32768不可以-1(默认)
2.5 Flash动态思考0〜24576指定为 0-1(默认)
2.5 Flash Lite不思考512〜24576指定为 0-1

2.5 Pro 没法关闭思考,我觉得这是很重要的区别。如果把“在 Flash 上设为 0 的配置”原样搬到 Pro 上,前提可能就不成立了。

2.5 Flash Lite 是什么都不指定就不思考的模型。如果只是做摘要和分类,选它也是一种思路。

Gemini 3 系列用 thinkingLevel 来指定

按本文发布时的官方文档,Gemini 3 系列之后的指定方式变了。官方推荐的是 thinkingLevel。用 minimal、low、medium、high 这样的档位来指定。

2.5 系列则相反,并不支持 thinkingLevel。官方写明,2.5 系列请使用 thinkingBudget。

文档里也列出了 Gemini 3 系列的注意事项。Gemini 3.1 Pro 不能关闭思考。Gemini 3 的 Flash 和 Flash-Lite 也被说明不支持完全关闭思考。就连 minimal,官方的说法也是“并不保证关闭思考”。

也就是说,换成新模型之后,“设为 0 来关掉”这一招可能就用不了了。换模型的时候,最好事先想到需要改写配置。

先确认能不能用 2.5 系列

官方的模型列表里,对 2.5 系列有一条备注。内容是仅限过去实际使用过的用户继续使用。

备注里也写着它并非弃用,目前仍会继续通过 API 提供。不过官方建议新项目使用最新的模型。

我的流程是跑在 gemini-2.5-flash 上的。接下来要新搭的朋友,可能得先确认自己的项目里能用哪些模型。

无需签约也能获得100积分的资费模拟 用AI减轻每天的信息收集之后,也用乐天移动重新看看每月的手机费

点击后会跳转到乐天登录页面,登录后即可看到活动内容。

思考令牌的计费

价格页面上明确写着,输出的价格“包含思考令牌”。gemini-2.5-flash 那一栏也是同样的写法。

思考的指南里也有同样意思的说明。思考开启时,回答的费用是输出令牌与思考令牌的合计。

即使设置成只接收思考摘要,计费对象也仍是原始的全部思考令牌。可以理解为:实际被计入的量,可能比看得见的要多。

摘要和分类这类固定处理是每天反复运行的。即便单次很小,思考的部分会不断累积,了解这个结构总没有坏处。

结构化输出(JSON)的指定方法

如果要用程序接收判断和摘要,让模型以 JSON 返回最好处理。Gemini API 为此提供了结构化输出的机制。

按 API 参考文档,做法是在 generationConfig 里放两个字段。把 responseMimeType 指定为 application/json。同时把模式传给 responseJsonSchema。

"generationConfig": {
  "responseMimeType": "application/json",
  "responseJsonSchema": {
    "type": "object",
    "properties": {
      "is_deal": {"type": "boolean"},
      "summary": {"type": "string"},
      "deadline": {"type": "string"}
    }
  }
}

字段名是我为了说明而放的例子。参考文档里写着,传入模式时必须指定 responseMimeType。

另外,SDK 的指南里也有写法略有不同的示例。最好按自己所用 SDK 的版本,重新对照一下官方示例。

官方的最佳实践里有很重要的一句话。结构化输出能保证语法上正确的 JSON,但不保证值在语义上正确。文档写明,使用之前要在应用端做校验。

拆成每次5篇后跑通了

我实际做的处理有两项。把 thinkingBudget 设为 0。然后把一次10篇拆成每次5篇。

加上这两项之后,正文就能正常返回了。至于只做其中一项够不够,我没有分开验证。

比较项一次10篇每次5篇分批
调用次数少增加
单次输出的长度变长变短
碰到上限的风险容易变大容易变小
失败时的影响全部重来只重跑那一批
文章之间张冠李戴可能发生更容易减少

一次性处理看上去效率更高。不过一旦失败,全部都得重来。分批之后,失败的范围就被限制在那一批里。

每批几篇最合适,我想会随文章长度和输出形式而变。5篇这个数字,只是在我的用途里碰巧跑通的数字。

有时会编出正文里没有的截止日期

还有一件头疼的事,是截止日期。Gemini 有时会编出正文里根本没写的截止日期。

优惠信息的通知里,截止日期出错是很麻烦的。太早会错过机会,太晚又发现不了已经过期。

我觉得这和结构化输出的那句提醒是相通的。JSON 的形式正确,不代表值就正确。模式里有“截止日期”这一栏,模型或许就会有一股想把它填上的劲头。

日期字符串不在正文里的截止日期一律丢弃

作为对策,我加了一段后处理。思路很简单。

  1. 让 Gemini 把截止日期作为 JSON 的一个字段返回
  2. 检查与该日期对应的字符串是否出现在原文正文里
  3. 如果正文里找不到,就丢弃截止日期这个字段
  4. 作为没有截止日期的优惠信息来通知

我觉得光是拜托模型“不要编”,并不可靠。所以改成由程序端去和正文对照。

这个方法也有弱点。如果正文的写法和模型返回的写法不一样,连正确的截止日期也会被丢掉。这是一种“与其给出错误的截止日期,不如没有截止日期”的取舍设计。

嵌入固定流程时的要点

经过这次的事,我对在固定流程里加入生成式AI该怎么看,稍微理清了一些。

CHECK
  • 把空响应当作错误处理(看正文长度和 finishReason)
  • 把 usageMetadata 记进日志,以便追踪思考和输出的明细
  • 对摘要、分类这类任务,优先考虑减少思考的设置
  • 一次不要塞太多,控制在失败了也只需重跑那一批的规模
  • 模型返回的值,要和原文核对之后再用

官方的最佳实践里也有相近的例子。像事实提取、分类这类简单任务,把思考设为最少或偏低。不需要复杂推理的任务,大概也用不着深度思考。

在工作中,数字也是和出处核对之后才用的。对AI的输出也同样对待,我觉得是最让人安心的做法。

关于每天早上让AI汇总信息的事,我在让AI生成今日简报的文章里也写过。无人值守运行时的权限问题,则和claude -p 中 MCP 被拒绝的原因一文是相近的话题。

常见的失误与陷阱

把容易栽跟头的地方列一下。

第二点在官方文档里也有明确提醒。想减少费用和等待时间时,应该调低思考,而不是调小上限。把上限收紧,反而会成为回答被截断的原因。

我踩到的是第一点和第五点。API 的使用和应用版的付费套餐是两回事。应用端的价格,我整理在梳理 Google AI Pro 功能与价格的文章里。

开始之前要确认的事

给想搭类似流程的朋友,整理了一份确认清单。

我觉得第三项和第六项尤其管用。因为空响应和编造出来的值,都会悄无声息地通过。

常见问题

Q. Gemini API 的响应为空时,最先看什么?

我觉得先看 finishReason 比较好。如果是 MAX_TOKENS,就说明达到了指定的最大令牌数。再结合 thoughtsTokenCount,就能知道思考用掉了多少。

Q. 有没有不能把 thinkingBudget 设为 0 的模型?

按官方的表格,2.5 Pro 不能关闭思考。范围是 128〜32768。Gemini 3 系列是用 thinkingLevel 来指定,其中也有不支持完全关闭思考的模型。

Q. gemini-2.5-flash 的 thinkingBudget 范围是多少?

官方表格里是 0〜24576。未指定时为动态思考。0 表示关闭,-1 表示动态思考。

Q. 思考令牌也要收费吗?

要收费。价格页面上写着,输出的价格“包含思考令牌”。即使达到上限、输出为空,已生成的思考部分也会被计费。

Q. 把 maxOutputTokens 调大就能解决吗?

如果是因为碰到上限被截断,留出余量算是一个办法。不过思考量仍然很大的话,费用和等待时间都会增加。官方给出的指引是调低思考的设置。

Q. 用了结构化输出,就能防止内容出错吗?

防不了。官方写明,能保证的只到语法上正确的 JSON 为止。值在语义上是否正确并不保证。需要在应用端加入校验处理。

Q. 每批拆成几篇比较好?

我觉得没有固定的正确答案。因为会随文章长度和输出形式而变。我把10篇拆成每次5篇就跑通了,但这只是我这个用途下的结果。

Q. 关闭思考之后,判断的质量会不会下降?

我想这取决于任务内容。官方把分类和事实提取列为低思考就足够的例子。我没有用数字比较过质量的变化,在意的朋友最好拿手头的文章试一试。

参考的官方信息

总结

返回为空的原因,是思考也会占用输出的额度。把 thinkingBudget 设为 0,再拆成每次5篇,就跑通了。

话虽如此,靠配置能解决的只到“能不能返回”为止。返回的内容对不对,还得另外确认。把截止日期和正文核对的后处理,就是为此而设的。

在固定流程里用上生成式AI的朋友,不妨看一看自己是怎么处理空响应的。

无需签约也能获得100积分的资费模拟 用流程省下工夫之后,也用乐天移动确认一下通信费

点击后会跳转到乐天登录页面,登录后即可看到活动内容。

本文包含联盟营销广告。如果您通过本站链接申请相关商品或服务,我们可能会从合作企业获得报酬。此外,运营者是乐天集团的员工,也可能通过员工推荐计划获得报酬。文章内容与评价均基于运营者的真实体验与调查完成,与是否存在广告无关,但请您在阅读前了解上述关系。详情请参阅免责声明与联盟营销说明。 免责声明与联盟营销说明

本文包含机器翻译内容。正式条件请以乐天移动官方网站的多语言页面为准。

如果您对乐天移动的通信区域·信号状况有疑问,可以通过官方的 电波改善调查申请表 进行咨询。

ABOUT THE AUTHOR
まさきん

乐天集团员工·数字营销人(持有FP资格)

40岁出头,双职工家庭、四个孩子的父亲。在乐天集团担任数字营销工作的同时,也活用理财规划师(FP)资格,专注于家庭理财与资产配置。

查看简介

相关文章

RELATED
Gemini(Google AI Pro)家庭共享最多5名家人|设置步骤与共享范围 AI活用

Gemini(Google AI Pro)家庭共享最多5名家人|设置步骤与共享范围

Google AI Pro除管理员外最多可与5名家人共享。Gemini App和存储空间可以共享,YouTube Premium Lite仅限管理员,Flow的上限由全家分摊。本文根据官方帮助整理了设置步骤和儿童账号的处理方式。

2026.10.13 · 阅读约9分钟
AI订阅扣款日与记账对不上的3个原因|Claude升级后扣款日会改变 AI活用

AI订阅扣款日与记账对不上的3个原因|Claude升级后扣款日会改变

Claude在月中升级到Max时,计费周期会重置,当天成为新的扣款日。美元换算日元的汇率在数据到达发卡公司时确定,账单和记账App的同步也会晚几天。本文整理了以收据邮件为准来确定月份的5个步骤。

2026.10.13 · 阅读约10分钟
把freee会计的未处理明细改成每月一次的核销班次:每月5日7:30、分3类、最多15条交给人处理的设计 AI活用

把freee会计的未处理明细改成每月一次的核销班次:每月5日7:30、分3类、最多15条交给人处理的设计

freee会计里有大约18条未处理明细,连续6次每周检查都原封不动地留着。这里整理一下每月5日早上7:30在家里的Mac上运行的核销班次的设计,以及“能确定的部分每月合并成1个任务、拿不准的明细逐条交给人、上限15条”的界线。

2026.10.12 · 阅读约11分钟
转到乐天移动,最高可获14,000积分 无需签约也能获得100积分的资费模拟 →
立即申请 →