别再直接 `json.loads` 了!AI 返回的 JSON 坑位指南

01. 成就感背后的"生产事故"

当你第一次成功让模型返回一个完美的 JSON 结构时,那种"代码终于受控"的成就感溢于言表。但如果你直接在代码里写下 print(data['title']),那么恭喜你,你已经为未来的生产事故埋下了伏笔。

在 AI 工程中,有一个残酷的现实:模型返回 JSON,并不代表程序可以无条件信任它。


02. 模型会给 JSON 挖哪些坑?

即便你用了最强的 GPT-4 或 Claude 3,模型依然会偶尔"掉链子"。常见的异常场景包括:

1. 结构性"幻觉"

你要求返回一个数组,模型可能因为上下文太长,返回了一个被截断的字符串,或者干脆在 JSON 前后加了句"这是你要的结果:"。

  • 后果json.loads() 直接抛出 ValueErrorJSONDecodeError

2. 字段"失踪案"

模型可能会漏掉你认为"必填"的字段,或者自作聪明地修改了键名(比如把 user_name 改成了 username)。

  • 后果 :程序访问时触发 KeyError

3. 类型"变色龙"

最典型的例子:你期待 tags 是一个数组 ["A", "B"],模型却返回了逗号分隔的字符串 "A, B"

  • 后果 :下游的 .map()foreach 逻辑直接崩溃。

03. 核心观念:AI 输出是"不可信输入"

在传统工程中,我们对用户提交的表单、第三方接口的返回都会进行严格的校验。AI 输出本质上也是一种"外部输入",而且是比第三方接口更不稳定、更不可控的输入。

优秀的 AI 工程师不相信"概率",只相信"防御"。


04. 实战:如何优雅地"接住"模型输出?

不要只写 json.loads。一个工业级的解析流程应该是这样的:

❌ 试玩版代码(极脆)

python 复制代码
response = get_ai_response(prompt)
data = json.loads(response)
print(data['tags'][0]) # 万一 tags 是字符串?万一 data 是空?

✅ 工程版代码(稳健)

python 复制代码
def safe_parse_tags(ai_output: str):
    try:
        data = json.loads(ai_output)
        
        # 1. 结构校验
        if not isinstance(data, dict):
            return []
            
        # 2. 字段与类型强校验
        tags = data.get('tags')
        if isinstance(tags, list):
            return tags
        elif isinstance(tags, str):
            # 这里的"防御"体现为:即便模型给错了类型,我们也尝试修复它
            return [t.strip() for t in tags.split(',')] 
            
        return [] # 兜底逻辑
    except (json.JSONDecodeError, Exception):
        return [] # 彻底失败时的安全降级(降级思维)

05. 进阶:引入 Schema 验证

在复杂的 AI 项目中,手动写 isinstance 太痛苦了。业界标准的做法是引入 Pydantic (Python)或者 Zod(TypeScript)。

python 复制代码
from pydantic import BaseModel, Field, validator
from typing import List

class ProductSchema(BaseModel):
    title: str
    price: float
    tags: List[str] = Field(default_factory=list)

    @validator('tags', pre=True)
    def handle_tags_string(cls, v):
        if isinstance(v, str):
            return [t.strip() for t in v.split(',')]
        return v

通过 Schema,你可以把"不确定"的模型输出,强行约束为"确定"的程序对象。这就是从"调包"到"工程"的跃迁。


06. 结语:工程感的起点

很多人问:会调 API 就算 AI 工程师了吗?

我的回答是:当你开始不再迷信模型输出,而是像对待任何"不可信输入"一样去解析、校验和兜底时,你才算真正开始了 AI 工程化的修行。

一句话总结:结构化输出解决的是"模型怎么说",而结构化消费解决的是"程序怎么活"。


讨论区:你在解析 AI 返回的 JSON 时遇到过哪些离谱的"幻觉"?你是怎么做兜底的?欢迎交流!


本文首发于掘金,记录前端开发者向 AI 工程转型的防御性编程实践。

相关推荐
小和尚同志4 小时前
AI 自动化测试探索(二):Chrome-devtools MCP
人工智能·e2e·aigc
冬奇Lab6 小时前
Workflow 系列(02):设计范式——四层架构、三种 Context 传递模式与确认门设计
人工智能·agent·工作流引擎
冬奇Lab6 小时前
每日一个开源项目(第145篇):Trellis - 把项目记忆、规范和任务上下文持久化进代码仓库
人工智能·开源·资讯
有道AI情报局6 小时前
Harness即产品
人工智能·agent
罗西的思考7 小时前
机器人 / 强化学习】HIL-SERL:人类在环驱动的具身智能进化框架
人工智能·算法·机器学习
lichenyang4538 小时前
Docker 学习笔记(一):为什么需要镜像、容器和仓库?
前端
kyriewen8 小时前
别再对着 TypeScript 报错发呆了:我把 10 个最常见的红色波浪线翻译成了人话
前端·javascript·typescript
IT_陈寒8 小时前
SpringBoot自动配置的坑,我的API突然就404了
前端·人工智能·后端
笃行3508 小时前
从零到上线:用 EdgeOne Makers + CodeBuddy 搭一个「对账核对员」AI Agent
人工智能