前言

最近在做一个项目,需要调用各种大模型API来生成结构化数据。本来以为很简单,让大模型输出JSON格式就行了,结果发现这是个大坑!

不管是GPT、Claude还是国产大模型,经常会输出一些格式不完整的JSON:

  • 有时候少个括号
  • 有时候字符串没闭合
  • 有时候直接截断了
  • 有时候还会在JSON前面加一些"思考过程"

每次都要手动处理这些错误,实在太麻烦了。于是我决定写个工具来自动修复这些问题。

遇到的典型问题

1. 最常见:缺少结尾括号

{"name": "张三", "age": 30, "skills": ["Go", "Python"

这种情况特别常见,特别是当模型输出被截断时。

2. 键缺少引号

{name: "张三", age: 30}

有些模型会输出这种JavaScript风格的对象,但这不是合法的JSON。

3. 字符串未正确闭合

{"message": "他说:"这是一个测试", "status": "ok"}

当字符串中包含引号时,经常会出现这种问题。

4. 深度嵌套结构错误

{"user": {"name": "张三", "profile": {"email": "test@example.com", "tags": ["tag1", "tag2"

嵌套越深,出错的概率越大。

5. 多JSON对象流被截断

{"event": "start", "id": 1}{"event": "update", "id": 1, "data": {"status": "processing"

当模型输出多个JSON对象时,经常在中间被截断。

解决方案

经过一番研究,我决定用Go语言写一个专门的JSON修复工具。主要思路是:

  1. 智能解析:逐字符分析JSON结构,理解当前的解析状态
  2. 上下文推断:根据已解析的内容推断缺失的结构
  3. 容错处理:对各种异常情况进行兼容处理
  4. 格式化输出:修复后输出标准的JSON格式

核心实现思路

状态机设计

我设计了一个状态机来跟踪JSON解析的状态:

type ParseState int

const (
    StateStart ParseState = iota
    StateObject
    StateArray
    StateString
    StateNumber
    // ... 其他状态
)

智能修复逻辑

func repairJSON(input string) (string, error) {
    // 1. 预处理:去除非JSON前缀
    cleanInput := removeNonJSONPrefix(input)
    
    // 2. 逐字符解析,维护状态栈
    stack := make([]ParseState, 0)
    
    // 3. 遇到错误时智能修复
    // 4. 返回修复后的JSON
}

使用效果

安装使用

go get github.com/qdxiao/llmjsonrepair

简单示例

package main

import (
    "fmt"
    "log"
    "github.com/qdxiao/llmjsonrepair/pkg"
)

func main() {
    // 原始的错误JSON
    malformedJSON := `{"name": "张三", "age": 30, "skills": ["Go", "Python"`
    
    // 修复并返回格式化的JSON字符串
    repairedJSON, err := pkg.Repair(malformedJSON)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("修复后的JSON:")
    fmt.Println(repairedJSON)
    
    // 直接解析为Go数据结构
    data, err := pkg.Loads(malformedJSON)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("解析后的数据: %+v\n", data)
}

修复效果对比

修复前:

{"name": "张三", "age": 30, "skills": ["Go", "Python"

修复后:

{
  "name": "张三",
  "age": 30,
  "skills": [
    "Go",
    "Python"
  ]
}

实际应用场景

1. 大模型API调用

// 调用大模型API
response := callLLMAPI("请生成用户信息的JSON")

// 直接修复并解析,不用担心格式问题
userData, err := pkg.Loads(response)
if err != nil {
    log.Printf("修复失败: %v", err)
    return
}

// 正常使用数据
fmt.Printf("用户姓名: %s\n", userData.(map[string]interface{})["name"])

2. 批量数据处理

// 处理多个可能有问题的JSON
jsonList := []string{
    `{"id": 1, "name": "用户1"`,  // 缺少结尾括号
    `{id: 2, name: "用户2"}`,     // 键缺少引号
    `{"id": 3, "name": "用户3"}`, // 正常JSON
}

for i, jsonStr := range jsonList {
    data, err := pkg.Loads(jsonStr)
    if err != nil {
        log.Printf("第%d个JSON修复失败: %v", i+1, err)
        continue
    }
    fmt.Printf("第%d个用户: %+v\n", i+1, data)
}

性能表现

经过测试,这个工具在处理各种错误JSON时表现不错:

  • 修复成功率:对常见错误类型的修复成功率达到95%以上
  • 性能:单个JSON修复耗时通常在1ms以内
  • 内存占用:相比原始JSON大小,内存开销很小

局限性和注意事项

  1. 极度损坏的JSON:如果JSON损坏程度太严重,可能无法修复
  2. 语义理解:工具只能修复格式问题,无法理解JSON的业务语义
  3. 复杂嵌套:对于特别复杂的嵌套结构,修复效果可能不理想

总结

通过这个工具,我基本解决了大模型输出JSON格式错误的问题。现在在项目中使用大模型API时,再也不用担心JSON格式问题了。

如果你也遇到类似的问题,可以试试这个工具。当然,最好的解决方案还是在prompt中明确要求模型输出标准JSON格式,但有个兜底的修复工具总是好的。

项目地址

GitHub: https://github.com/qdxiao/llmjsonrepair

欢迎大家试用和反馈!如果觉得有用的话,给个star支持一下~


相关技术标签: #Go语言 #JSON解析 #大模型 #API开发 #数据处理

遇到问题欢迎交流讨论!

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐