原创

GLM-4.7-Flash 结构化 JSON 输出实测:Node.js 解析、校验与重试

生产环境对比“只靠提示词”和 response_format JSON 模式,解释 Markdown 围栏、answer 外层、content 为空等问题,并给出 Node.js 解析、分类白名单、字段校验和有限重试实现。

GLM API 实战专题 · 第 3/3 篇查看专题目录 →

一句话结论

使用 GLM-4.7-Flash 做文章分类、AI 摘要或数据提取时,不要只在提示词里写“只输出 JSON”。本站生产环境实测发现,这种方式可能返回 Markdown 代码围栏,导致 JSON.parse 直接失败。启用 response_format: { type: "json_object" } 能得到合法 JSON,但仍要验证字段结构和业务取值。

如果你还没有完成模型接入,请先看 GLM-4.7-Flash API 配置与实测;需要多个模型容错时,可继续阅读 Node.js 多模型轮询与故障切换。

两种方式的真实对比

测试时间为 2026 年 8 月 13 日,环境为本站生产服务器 Node.js 20 容器,模型为 glm-4.7-flash,关闭思考模式。

调用方式 HTTP 延迟 能否直接 JSON.parse 实际表现
只用提示词要求 JSON 200 1995 ms 否 返回了 Markdown 代码围栏
response_format JSON 模式 200 1547 ms 是 返回合法 JSON,但增加了 answer 外层

这说明接口成功、语法合法和字段符合预期是三件不同的事。JSON 模式解决的是语法问题,不会自动保证对象结构完全符合你的程序。

正确的 Node.js 请求方式

const response = await fetch(
  'https://open.bigmodel.cn/api/paas/v4/chat/completions',
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${process.env.ZHIPU_API_KEY}`,
    },
    body: JSON.stringify({
      model: 'glm-4.7-flash',
      messages: [
        {
          role: 'system',
          content: '你是文章分类器。必须输出有效 JSON。',
        },
        {
          role: 'user',
          content: '将文章分到允许分类中,并给出不超过3个标签。',
        },
      ],
      response_format: { type: 'json_object' },
      thinking: { type: 'disabled' },
      temperature: 0.2,
      max_tokens: 300,
    }),
    signal: AbortSignal.timeout(30_000),
  },
);

if (!response.ok) {
  throw new Error(`模型请求失败:${response.status}`);
}

const payload = await response.json();
const content = payload.choices?.[0]?.message?.content;
if (!content) throw new Error('模型返回内容为空');

const result = JSON.parse(content);

系统提示词中仍应明确要求 JSON。智谱官方文档说明 JSON 模式会返回有效 JSON,但程序不能因此跳过后续校验。

为分类结果做业务校验

假设网站只允许四个分类:

const allowedCategories = new Set([
  'AI 开发教程',
  'AI 工程实践',
  'AI 工具与应用',
  '行业观察',
]);

function validateClassification(value) {
  const candidate = value.answer ?? value;
  if (!candidate || typeof candidate !== 'object') {
    throw new Error('分类结果不是对象');
  }
  if (!allowedCategories.has(candidate.category)) {
    throw new Error(`不允许的分类:${candidate.category}`);
  }
  if (!Array.isArray(candidate.tags)) {
    throw new Error('tags 必须是数组');
  }
  const tags = candidate.tags
    .filter(tag => typeof tag === 'string')
    .map(tag => tag.trim())
    .filter(Boolean)
    .slice(0, 3);
  return { category: candidate.category, tags };
}

这里兼容了实测出现的 answer 外层,但更稳妥的做法是使用 JSON Schema 校验库,并把允许分类动态写进提示词。

兼容已有的 Markdown 输出

旧提示词或其他模型可能继续返回代码围栏。迁移期间可以做一次保守清理:

function parseModelJson(text) {
  const cleaned = String(text)
    .trim()
    .replace(/^```jsons*/i, '')
    .replace(/s*```$/, '');
  return JSON.parse(cleaned);
}

不要用正则从任意长文本中贪婪截取第一对花括号,这容易把解释文字或嵌套对象截坏。解析失败时应保留脱敏后的原始输出用于排查,然后有限重试或进入人工审核。

AI 摘要应该校验哪些字段

日报或文章摘要不应只检查“有内容”。至少验证:

  • intro 是非空字符串,并限制最大长度;
  • highlights 是数组,条数符合后台配置;
  • 每条精选包含标题、摘要和来源 ID;
  • 来源 ID 必须存在于本次抓取数据,避免模型编造链接;
  • 分类必须属于网站的固定分类集合;
  • 输出中不能包含 API Key、后台 Token 等敏感信息。

当某一字段不合格时,优先让模型只修复该字段,而不是重新生成整篇日报。这样更节省 Token,也减少已经合格内容发生变化。

为什么 content 有时是空的

开启思考模式后,模型可能先把 Token 用在 reasoning_content。如果 max_tokens 太小,最终 content 可能为空。分类、标签和固定结构提取通常不需要复杂推理,可以关闭思考模式;如果必须开启,则同时检查 reasoning_content、finish_reason 和 Token 用量。

重试策略

以下情况可以重试一次:网络超时、临时 5xx、JSON 被截断。以下情况不应该原样重试:提示词没有给出允许字段、分类集合不完整、Schema 与程序代码不一致。后者必须先修正请求,否则多模型轮询只会重复产生错误结果。

建议每次请求记录:配置模型、响应模型、HTTP 状态、finish_reason、解析结果、Schema 校验结果、延迟和 Token 用量。日志中不要写入 API Key,也尽量避免保存包含个人信息的完整正文。

适合本站后台的落地流程

  1. 抓取阶段只保存原始数据,不调用模型;
  2. AI 总结阶段使用 JSON 模式生成结构化结果;
  3. 服务端解析并执行字段、分类和来源 ID 校验;
  4. 校验失败只重试一次,并显示实际使用模型;
  5. 仍失败则保留抓取数据,允许管理员重新总结;
  6. 通过后再写入日报或文章库,避免半成品覆盖旧内容。

最终建议

GLM-4.7-Flash 的 JSON 模式适合自动分类、摘要和字段提取,但它只是可靠链路的一环。生产环境应同时使用明确提示词、response_format、关闭不必要的思考、服务端 Schema 校验、允许值集合和有限重试。只有这些步骤全部通过,模型输出才能安全落库。

常见问题

response_format 能保证字段完全正确吗?

不能。它主要保证 JSON 语法有效,模型仍可能增加外层对象、遗漏字段或返回不允许的分类,因此服务端必须继续做 Schema 和白名单校验。

为什么提示词要求 JSON 仍会返回代码围栏?

自然语言约束不是协议约束,模型可能按常见写作格式包裹 Markdown。应使用 JSON 模式,并为旧输出提供有限的代码围栏清理。

JSON 解析失败后应该重新生成整篇内容吗?

优先只重试失败字段或结构修复。整篇重新生成会增加 Token 成本,也可能改变已经合格的内容。

实测与内容说明

实测记录

  • 2026-08-13,生产服务器 Node.js 20 容器测试
  • 仅提示词模式返回 Markdown 围栏,JSON.parse 失败
  • response_format=json_object 返回合法 JSON,实测延迟 1547 ms

参考资料

内容版本 1.1 · 审核:推荐智能手记 · 计划复审:2026-09-13