Gemini JSON输出截断?3档修复策略 + 生产兜底方案一次搞定
【免费下载链接】generative-aiSample code and notebooks for Generative AI on Google Cloud, with Gemini Enterprise Agent Platform项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai
你满心欢喜地json.loads()模型返回的结果,JSONDecodeError直接拍在脸上。打印原文一看,JSON 在数组中间戛然而止——典型的 Gemini JSON输出截断。我在 generative-ai 仓库里把定位、修复、兜底整理成了一套可直接抄的打法。
数据解析一旦失败,下游收到的就是一串坏消息。
展示错乱只是最轻的代价,第一步先看清楚 JSON 是怎么断的。
快速诊断:你的 JSON 到底是怎么被截的
| 截断表现 | 触发条件 | 判断依据 |
|---|---|---|
数组写到一半断掉,缺]和} | 输出撞上模型 token 上限 | finish_reason为MAX_TOKENS |
| JSON 闭合后拖着一段解释文字 | 自由文本模式夹带"私货" | 报错位置在 JSON 结束符之后 |
| 函数参数缺字段、嵌套结构残缺 | 调用参数体过大 | args对不上你定义的 schema |
让模型一次枚举几百条记录的,大概率是 token 上限问题。
输出"看着挺全"但解析失败的,先怀疑自由文本里的解释性文字。
三档修复策略(按复杂度递进)
三档是递进关系:从改一行配置,到改输出形式,再到改生成流程,哪档够用就用哪档。
第一档:调参快修
输出体积只略超默认上限的话,给模型更多书写空间就够了。
from google.genai import types # 把 max_output_tokens 顶到模型上限,给 JSON 留足空间 resp = client.models.generate_content( model="gemini-2.0-flash", contents="生成 100 个产品的 JSON 数组,只返回数据", config=types.GenerateContentConfig( max_output_tokens=8192, # gemini-2.0-flash 的输出上限 temperature=0, # 压低随机性,输出更稳 ), )⚠️ 上限是模型的上限(gemini-2.0-flash 为 8192),参数顶到头也写不出更多 token,再截断就得换输出形式。
JSON 在上限处照样断尾,说明调参解决不了——得让模型别再"写作文"。
第二档:结构化输出锁格式
让模型填表而不是作文:用 FunctionDeclaration 描述你要的 JSON 结构,再用 ANY 模式强制它调用output_json。仓库里的 forced_function_calling 示例 有完整实现,照着抄就能跑。
from google.genai import types cfg = types.ToolConfig( # ANY 模式:强制按 schema 回结构化调用 function_calling_config=types.FunctionCallingConfig( mode=types.FunctionCallingConfigMode.ANY, allowed_function_names=["output_json"])) resp = client.models.generate_content( model="gemini-2.0-flash", contents="生成产品列表并以 JSON 返回", config=types.GenerateContentConfig(temperature=0, tools=[types.Tool(function_declarations=[output_json_schema])], tool_config=cfg)) data = resp.function_calls[0].args # 参数已是结构化数据⚠️ schema 是契约:字段留成松散 object,模型仍有发挥空间;嵌套大数组时参数照样可能撞上 token 上限。参数设计可参考 function_calling_data_structures 示例。
这一档只解决了"形状"问题。单次要几千条记录时,函数参数本身会爆,只能把任务拆开。
第三档:分片生成拼大图
超大数据一次调用装不下,就把任务拆批:每批单独调用、单独校验,最后在自己代码里拼完整数据。
from google.genai import types def generate_large_json(client, total=5000, chunk=500): items = [] for i in range(0, total, chunk): # 一批一批要,控制每批输出在 token 上限内 resp = client.models.generate_content( model="gemini-2.0-flash", contents=f"生成第 {i} 到第 {i+chunk-1} 条产品数据,只返回 JSON 数组", config=types.GenerateContentConfig(max_output_tokens=8192), ) items.extend(safe_parse_json(resp.text)) # 先校验再合并 return {"total": len(items), "data": items}⚠️ 分片拿延迟和成本换稳定:批次越多调用越贵,合并时务必核对主键不重复、总条数不缩水。
生成侧稳了之后,最后的安全网在解析侧。
生产环境兜底
三档全做了,生产链路仍需最后一道保险:解析包一层,别让一次截断搞崩整条链路。
import json def safe_parse_json(text): try: return json.loads(text) except json.JSONDecodeError: # 常见截断:尾部缺 } 或 ],逐个尝试补齐 for suffix in ("}", "]", "}]"): try: return json.loads(text.rstrip() + suffix) except json.JSONDecodeError: continue # 修不好就返回兜底结构,交给上层决策 return {"error": "JSON 解析失败", "raw": text}补括号只能救"尾部截断"。
字段值本身被截断的(价格写到19就断了)修不了,只能靠重试兜住。
- 解析失败自动重试,分片尺寸调小一档
- 降级返回兜底结构,不直接抛异常
- 原始输出落日志,接入告警通知
避坑速查清单
- 检查 max_output_tokens 是否顶到模型上限
- 把 temperature 设为 0 压低随机性
- 用 ANY 模式强制函数调用出结构化结果
- 超大数组拆分片,每批输出控制在上限内
- JSON 解析包 try/except 加修复逻辑
- 核对 finish_reason 是否撞上 token 上限
- 解析失败时记录原始输出并告警
【免费下载链接】generative-aiSample code and notebooks for Generative AI on Google Cloud, with Gemini Enterprise Agent Platform项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考