一、前言
虽然现在大部分LLM都已经可以支持输出上万个Token了。但是,我们在实际业务落地的时候,还是会经常遇到LLM不按照我们规定的格式输出的情况。
特别是我们需要输出的结果具备结构化,方便我们继续执行下游任务的情况。
由于json格式天生亲近纯文本,所以想让LLM结构化输出的时候,一般都是输出为json,然后将json抽取出来,转化为字典,继续做下游任务。
但是有很多原因,会导致我们无法得到完整的json输出。
二、输出半截Json的几种情况
2.1 输出超过了LLM支持Token的上线
- 输入的上下文过长,导致留给输出的位置太少,LLM无法给出完整的答案,从而json只输出了一半就结束了。
- 任务太过复杂,使用CoT技术,让LLM输出的中间思考过程太多,导致LLM没有太多的空间输出最终的结果。要么没有得到最终的结果,要么结果只输出了一半就停止了
2.2 敏感词拦截LLM的输出
为了防止LLM被滥用,输出不恰当的内容。不同的地区,对敏感的内容不一样,因此在对外输出结果时,一般都会根据所在地的不同情况,进行敏感词过滤或者拦截。就如同前几年,Meta搞出了一个有犯罪倾向的AI一样,在全世界都是不被允许的。
所以,当你的llm不受控制的输出敏感内容时被截胡,输出半截子结果也是会存在这种情况。
2.3 不能严格遵守指令
这种情况更为普遍。再牛的LLM也有打盹的时候,不能保证一定按照你的格式要求输出。
我们经常遇到,在输出json的时候,经常会遇到一下情况:
- 丢失关键的标点符号;例如:
{"question":你好吗!}
没有双引号,是无法完整的解析这个输出的。 - 标点符号,没有出现在正确的位置;例如:
{"question":"你好吗!" ,"answer":"我很好"}
中间的标点符号是全角,不是半角,也会导致json输出失败。 - 还有很多种情况,就不一一列举,下面介绍一下如何解决这类问题。
三、一个开源的解决方案
遇到上述三个问题,通常有三种方法解决:
- 补全json:主要针对json答案输出一半的情况,也就是将半截json不全成完整的json格式,使其具备json解析的条件。
- 修正json:主要针对json答案中标点缺失或者标点不正确的情况
- 丢弃部分json内容:主要针对json中一些无法顾虑到的特殊情况,保留正常的内容,丢弃不规范的内容。
3.1 streaming-json-py的解决方案
这是一个开源的解决方案,并且提供了
- streaming-json-go`
- streaming-json-py
- streaming-json-js
三种编程语言,可以满足不同环境下的需求。
下面看一下实战效果
pip install streamingjson
lexer = streamingjson.Lexer() # append your JSON segment lexer.append_string('{"a":') # complete the JSON print(lexer.complete_json()) # will print `{"a":null}` # append more JSON segment lexer.append_string('[tr') # complete the JSON again print(lexer.complete_json()) # will print `{"a":[true]}`
这个开源的方案重点是在补全json
替代方案:修复无效JSON字符串,解决 LLMs 生成的 JSON 数据中可能出现的格式错误。
四、改进的一个方案
我们自己改进的方案,主要通过检测json中标点符号的缺失和错误性,来纠正json格式,然后,辅助补全json来实现的,最后通过提取json部分的内容,来获得结构化的结果
举两个例子:
output = '''你需要的答案是```jsonn{"question":"2024年奥运会在哪里举办?"n,n"answer":“巴黎n'''
这里有三个错误:
,
是中文,无法正确解析巴黎
有个引号错误,有个引号缺失- 缺少三引号和
}
最终完美纠正了上述的错误,并且正确的输出
{'question': '2024年奥运会在哪里举办?', 'answer': '巴黎'}