当前位置:首页 > 文章列表 > 科技周边 > 人工智能 > Go 调用大模型时结构化 JSON 仍要校验:Schema、拒答和截断响应的最小防线

Go 调用大模型时结构化 JSON 仍要校验:Schema、拒答和截断响应的最小防线

来源:17golang原创 2026-07-20 17:47:44 0浏览 收藏

接口已经要求大模型返回 JSON,线上却仍然出现了“能解析、不能入库”的记录:分类字段拼写错误、数组内容被截断,甚至模型直接返回了拒答文本。处理这类问题时,Go 服务不该只调用一次 json.Unmarshal 就把结果直接传给数据库,而要把响应状态、JSON 结构和业务语义分成三道独立的检查环节。

严格 JSON Schema 主要解决「数据形状是否符合事先约定」的问题,不会帮你判断请求是否触发拒答、输出内容是否完整,也不保证字段里的业务数值完全正确;Go 侧至少要保留状态检查、结构解析和业务校验三层防线。

要点速览

  • 先判断响应是否正常结束,以及是否存在拒答或空内容的情况。
  • json.Unmarshal 只负责校验 JSON 语法和字段类型,不负责枚举值合法性与内容长度校验。
  • 业务校验失败时保留原始请求 ID,禁止半成品数据直接写入存储。
  • 流式响应要等完成事件或明确的结束状态返回后,再拼接得到最终的完整 JSON。

先分清:Schema 约束和业务规则不是一回事

结构化输出能让模型更稳定地贴合开发者给出的 JSON Schema 要求,例如要求返回 titleprioritylabels 三个字段。官方说明也明确提到,严格 Schema 只覆盖标准 JSON Schema 的一部分规则;请求可能因为安全原因返回拒答,也可能在达到输出长度上限前被截断,字段值本身仍可能不符合业务要求。

放到 Go 服务的实现逻辑里,可以先画出一条清晰的边界:

  • 响应层:校验 HTTP 状态、请求 ID、完成状态、拒答相关字段。
  • 结构层:校验 JSON 是否完整,字段类型是否和预先定义的 Go 结构体匹配。
  • 业务层:校验优先级范围、标签数量、标题长度和所有业务必填字段。

结构化 JSON 从模型响应到业务校验的三层检查:拒答、解析、规则

最小实现:用 Go 结构体挡住半成品数据

先定义专属的业务对象,不要用 map[string]any 接住所有返回字段。结构体可以把类型错误尽早暴露出来,也方便后续串联对应的业务规则检查。

package review

import (
    "encoding/json"
    "errors"
    "fmt"
    "strings"
)

type Review struct {
    Title    string   `json:"title"`
    Priority int      `json:"priority"`
    Labels   []string `json:"labels"`
}

func ParseReview(raw []byte) (Review, error) {
    var out Review
    if len(strings.TrimSpace(string(raw))) == 0 {
        return out, errors.New("empty model content")
    }
    if err := json.Unmarshal(raw, &out); err != nil {
        return out, fmt.Errorf("invalid review json: %w", err)
    }
    if err := out.Check(); err != nil {
        return out, err
    }
    return out, nil
}

func (r Review) Check() error {
    title := strings.TrimSpace(r.Title)
    if title == "" || len([]rune(title)) > 80 {
        return errors.New("title is empty or too long")
    }
    if r.Priority  3 {
        return fmt.Errorf("priority %d is outside 1..3", r.Priority)
    }
    if len(r.Labels) > 5 {
        return errors.New("too many labels")
    }
    return nil
}

这里的关键不是写了多少条校验规则,而是校验失败时绝不返回「看起来还能用」的对象。调用方拿到错误后,要把请求 ID、模型状态和原始响应写入隔离日志,交给人工或者后续补偿流程处理。

把响应状态检查放在 JSON 解析之前

很多线上误判都来自检查顺序错误:服务看到一段字符串能被正常解析,就当成模型返回的最终结果。更稳妥的做法是先读接口的外层响应字段,再把最终文本交给 ParseReview

type ModelEnvelope struct {
    RequestID string `json:"id"`
    Status    string `json:"status"`
    Refusal   string `json:"refusal"`
    Content   string `json:"content"`
}

func AcceptEnvelope(e ModelEnvelope) error {
    if e.Refusal != "" {
        return fmt.Errorf("model refusal: %s", e.Refusal)
    }
    if e.Status != "completed" {
        return fmt.Errorf("response is not completed: %s", e.Status)
    }
    if strings.TrimSpace(e.Content) == "" {
        return errors.New("completed response has no content")
    }
    return nil
}

completed 只是示例状态名,实际接入时要以你所用接口的官方响应字段为准,不要把某一家 API 的字段名直接当成所有模型服务的通用协议。

流式返回:最后一段分片不等于完整 JSON

流式接口会把内容拆成多段事件逐步返回。中途断开时,前半段内容可能已经长得很像完整 JSON,但缺少结尾的闭合括号;如果代码在每个分片到达时都尝试入库,截断的数据就会混入正常业务记录。

正确的处理边界是:分片内容只写入内存缓冲,收到明确的完成信号后再调用一次 ParseReview 做统一解析。如果连接断开、完成状态缺失或者内容长度超过业务阈值,直接进入失败处理分支。对流式 JSON 做「每个分片独立解析」通常没有实际意义,因为字符串、数组和转义字符都有可能跨分片拆分。

Go 流式模型响应的缓冲与完成门禁:分片拼接、完成状态、业务校验、入库

三个容易漏掉的边界场景

拒答不是格式错误

拒答内容可能是完全合法的字符串,甚至外层响应状态仍然显示正常。它应该单独标记为「模型未提供有效业务结果」,不要伪装成 JSON 解析失败,也不要直接拿默认空对象继续往下走流程。

截断不是低优先级告警

达到输出上限时,模型可能只返回 JSON 的前半段内容。就算这段残缺内容偶然能被解析,也要结合完成状态和响应元数据综合判断;没有明确的结束信号,就不要把结果视为可正常落库的有效数据。

合法值不代表正确值

{"priority":2} 在语法和类型上都没有问题,但它是否符合当前工单的风险等级,仍要由业务规则或者后置人工审核决定。严格 Schema 不能替代实际业务逻辑的事实核对。

落库前的最后一道校验门

实际服务可以把三个阶段的错误统一封装成可观测事件,但不要把它们混成一个笼统的「AI 调用失败」。建议至少记录 request_id、接口状态、完成状态、解析错误类型、业务校验错误和重试次数这些维度的信息。入库动作只接收已经通过 AcceptEnvelopeParseReview 的对象。

如果业务允许配置重试,重试条件也要做限制:网络中断、明确的临时服务错误可以发起重试;拒答、字段语义冲突和连续截断这类场景更适合直接送入隔离队列。重试前要保留完整的原始响应,方便后续定位问题根源是模型侧、提示词侧还是调用层出了问题。

相关问题

JSON Schema 严格模式能保证字段内容真实吗?

不能。它只能约束结构和类型,字段值仍可能不符合业务事实,需要额外加规则校验、数据库核对或者人工审核环节。

能不能只用 map[string]any 接模型返回结果?

临时做技术探索可以,生产链路不建议。结构体加显式校验的模式更容易发现字段改名、类型变化与空值这类隐性问题。

流式输出什么时候可以写入数据库?

收到接口定义的完成信号、拼接出来的完整内容通过 JSON 解析,并且所有业务规则校验全部通过之后。任一条件缺失都应该先把数据做隔离处理。

模型返回拒答时应该重试吗?

先确认拒答原因。安全类拒答不适合盲目重复请求;如果是临时网络或服务波动错误,再依据接口状态和预设重试策略处理。

小结

Go 接入大模型时,把 Schema 当成第一道护栏就够了,后面仍需要响应状态检查、完整性判断和业务语义校验。代码量不需要很大,但每道门都要有明确的失败处理逻辑:不返回半成品数据、不吞掉原始响应、不把合法 JSON 误当成完全正确的业务数据。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
浏览器长任务怎么排查:用 PerformanceObserver 定位 50ms+ 主线程卡顿浏览器长任务怎么排查:用 PerformanceObserver 定位 50ms+ 主线程卡顿
上一篇
浏览器长任务怎么排查:用 PerformanceObserver 定位 50ms+ 主线程卡顿
Go 1.26.5 和 1.25.12 发布:crypto/tls、os 修复后,生产服务怎么判断升级窗口
下一篇
Go 1.26.5 和 1.25.12 发布:crypto/tls、os 修复后,生产服务怎么判断升级窗口
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • ljg-skills -
    ljg-skills
    ljg-skills 是李继刚开源的 AI 技能与提示词集合,面向大模型使用者整理了一批可复用的 prompt、角色设定和任务技能模板,适合用于学习提示词设计、搭建个人 AI 工作流和沉淀团队常用智能体能力。
    4590次使用
  • MELO音乐 - AI 音乐生成平台,支持多模态创作能力
    MELO音乐
    MELO音乐是一站式AI视频与音乐制作助手,对标suno, udio的高品质体验。提供伴奏生成、原创写词、无损导出、哼唱识曲、混音变声等全套音频与短视频编辑工具。无论是流行Kpop、电音说唱、民谣古风、摇滚儿歌还是商用轻音乐,MELO为你免费谱曲,轻松做同款!
    4237次使用
  • UniScribe - AI 免费在线音视频转文字平台
    UniScribe
    UniScribe 是一款 AI 音视频转文字与内容整理工具,支持上传音频、视频文件或粘贴 YouTube 链接,自动生成转写文本、摘要、思维导图和关键问题,并支持多格式导出,适合会议记录、课程学习、访谈整理和内容创作复盘。
    4195次使用
  • 剧云 - 免费 AI 智能中文剧本创作平台
    剧云
    剧云是专业中文剧本创作平台,安全稳定运行十余年,集成AI编剧、剧本医生审核、人物小传、剧情关系图、大纲编写、多人协作、Word导入导出、版权管控功能,数据安全防护,轻松高效创作剧本。
    4415次使用
  • 万象有声 - AI 一站式有声内容创作平台
    万象有声
    万象有声,一个专为有声创作者打造的新一代智能有声内容创作平台。平台提供专业的智能拆章、智能画本编辑、AI配音、AI生成音效、后期制作、智能对轨、智能审听等有声创作全流程工具,可以帮助创作者高效、低成本创作出引人入胜的有声作品。立即体验,让有声书制作更简单!
    4371次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码