理解使用JsonOutputParser时的JSONDecodeError

0 投票
1 回答
54 浏览
提问于 2025-04-13 15:43

我刚开始接触输出解析器,发现它们在正常工作时非常有用。不过,我遇到了一个问题,就是有时候我的程序会报错,这个错误似乎和我使用的JsonOutputParser有关,下面是一个简化的错误信息:

JSONDecodeError
JsonOutputParser.parse_result(self, result, partial)
156 # Parse the JSON string into a Python dictionary
--> 157 parsed = parser(json_str)
159 return parsed
122 # If we got here, we ran out of characters to remove
123 # and still couldn't parse the string as JSON, so return the parse error
124 # for the original string.
--> 125 return json.loads(s, strict=strict)

根据这篇帖子,这个问题可能是因为“剩余的令牌不够,无法完全生成我的输出”,这和上面的错误信息有点关系:

122 # If we got here, we ran out of characters to remove

不过我不太明白这是什么意思,也不知道该怎么解决。

有没有人遇到过这个问题,能给我一些建议吗?我得承认我有点困惑,尤其是这个错误并不是每次都会出现,只在我运行脚本的每隔一次才会发生。

1 个回答

1

查看一下 单元测试,可以帮助你理解 JsonOutputParser.parse_partial_json() 是怎么工作的。

TEST_CASES_PARTIAL = [
    ('{"foo": "bar", "bar": "foo"}', '{"foo": "bar", "bar": "foo"}'),
    ('{"foo": "bar", "bar": "foo', '{"foo": "bar", "bar": "foo"}'),
    ('{"foo": "bar", "bar": "foo}', '{"foo": "bar", "bar": "foo}"}'),
    ('{"foo": "bar", "bar": "foo[', '{"foo": "bar", "bar": "foo["}'),
    ('{"foo": "bar", "bar": "foo\\"', '{"foo": "bar", "bar": "foo\\""}'),
    ('{"foo": "bar", "bar":', '{"foo": "bar"}'),
    ('{"foo": "bar", "bar"', '{"foo": "bar"}'),
    ('{"foo": "bar", ', '{"foo": "bar"}'),
]


@pytest.mark.parametrize("json_strings", TEST_CASES_PARTIAL)
def test_parse_partial_json(json_strings: Tuple[str, str]) -> None:
    case, expected = json_strings
    parsed = parse_partial_json(case)
    assert parsed == json.loads(expected)

parse_partial_json() 这个函数的作用是尝试解析那些不合法的 JSON 字符串,它会不断地从字符串中去掉字符,直到能够解析出一个合法的 JSON 字符串。

{"foo": "bar", "bar"  # original LLM response

is truncated to...

{"foo": "bar"}        # valid JSON response

这是一种尽力而为的方法,用来处理来自大型语言模型(LLM)的不合法 JSON 响应。我们知道,LLM 返回的结果不一定是合法的 JSON。当这个函数无法解析 LLM 的响应时,它会返回原始的解析错误,也就是你收到的错误信息。

接下来的建议步骤

  1. 记录下 LLM 返回的原始响应,看看实际返回的是什么字符串。
  2. 在这个时候,最可能的做法就是重新尝试调用 LLM,或者将错误信息返回给最终用户。
  3. 有可能 LLM 的响应实际上是“部分可以解析为 JSON”的(也就是说,可能有一些边缘情况被遗漏了)。如果是这样,你可能需要考虑在单元测试中添加一个新的测试案例,并更新 parse_partial_json() 的实现。

参考资料:

  1. JsonOutputParser.parse_partial_json() (GitHub)
  2. JsonOutputParser.parse_partial_json() 单元测试 (GitHub)

撰写回答