理解使用JsonOutputParser时的JSONDecodeError
我刚开始接触输出解析器,发现它们在正常工作时非常有用。不过,我遇到了一个问题,就是有时候我的程序会报错,这个错误似乎和我使用的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 的响应时,它会返回原始的解析错误,也就是你收到的错误信息。
接下来的建议步骤
- 记录下 LLM 返回的原始响应,看看实际返回的是什么字符串。
- 在这个时候,最可能的做法就是重新尝试调用 LLM,或者将错误信息返回给最终用户。
- 有可能 LLM 的响应实际上是“部分可以解析为 JSON”的(也就是说,可能有一些边缘情况被遗漏了)。如果是这样,你可能需要考虑在单元测试中添加一个新的测试案例,并更新
parse_partial_json()
的实现。