Solon v3.9.5

snack4 - Json 流式读取与结构修复

</> markdown
2026年3月18日 上午10:41:14

在处理 LLM(大语言模型) 实时输出或 NDJSON(服务端推送流) 时,开发者经常面临两个挑战:一是数据以“流”的形式分批到达;二是数据流可能由于中断或截断导致 JSON 结构不完整。

snack4JsonReader 针对这些场景深度优化,提供了高效的流式读取与智能结构修复能力。

1、流式读取

核心场景:

  • LLM 分块输出:大语言模型分块输出 JSON 数据
  • NDJSON 数据:换行分隔的 JSON 格式(或没有换行),如 {"a":"a"}{"a":"a","b":"b"}
  • 大型 JSON 文件:避免一次性加载到内存

接口:

JsonReader reader = new JsonReader(inputStream); // or json

// 读取下一个 JSON 块
ONode node = reader.readNext();

// 使用迭代器遍历(推荐)
for (ONode item : reader.iterableNext()) {
    // 处理每个 JSON
}

// 读取最后一个 JSON 块
ONode last = reader.readLast();

应用示例:

String ndjson = "{\"name\":\"Alice\"}\n{\"name\":\"Bob\"}\n{\"name\":\"Charlie\"}";

// 迭代器方式(推荐)
for (ONode item : new JsonReader(ndjson).iterableNext()) {
    System.out.println(item.get("name").val());
}
// 输出: Alice, Bob, Charlie

// 逐个读取
JsonReader reader = new JsonReader(ndjson);
ONode node;
while ((node = reader.readNext()) != null) {
    System.out.println(node.val());
}

2、结构修复

启用方式

Options opts = Options.of(Feature.Read_AutoRepair);
JsonReader reader = new JsonReader(json, opts);

修复示例

输入修复结果
{"flag": tru{"flag": true}
{"a":{"b":{"c":1{"a":{"b":{"c":1}}}
[1,2,3,[1,2,3]
{"a":{"a":null}

代码示例

// LLM 输出不完整的 JSON
String incomplete = "{\"flag\": tru";  // true 没写完

Options opts = Options.of(Feature.Read_AutoRepair);
JsonReader reader = new JsonReader(incomplete, opts);
ONode node = reader.readLast();
System.out.println(node.toJson());
// 输出: {"flag":null}

// 深层嵌套未闭合
String broken = "{\"data\":{\"items\":[";
Options opts2 = Options.of(Feature.Read_AutoRepair);
JsonReader reader2 = new JsonReader(broken, opts2);
ONode node2 = reader2.readLast();
System.out.println(node2.toJson());
// 输出: {"data":{"items":[]}}

3、组合使用

流式解析 + 自动修复,处理复杂的 LLM 混合输出:

String mixed = "{\"name\":\"test\"}{\"name\":\"test\",\"broken\": tru";

Options opts = Options.of(Feature.Read_AutoRepair);
JsonReader reader = new JsonReader(mixed, opts);

for (ONode node : reader.iterableNext()) {
    System.out.println(node.toJson());
}
// 输出: {"name":"test"}
//       {"broken":null,"ok":"yes"}