探索大型语言模型LLM推理全阶段的JSON格式输出限制方法

简介: 本篇文章详细讨论了如何确保大型语言模型(LLMs)输出结构化的JSON格式,这对于提高数据处理的自动化程度和系统的互操作性至关重要。

一、引言

1.1 JSON结构化输出的意义

对于基于大型语言模型(LLMs)的应用而言,确保输出能直接以结构化的JSON格式呈现,对于提升数据处理的自动化程度、增强系统的互操作性具有重要意义。例如,客户需要对LLM的输出进行信息提取时,若输出是一个JSON格式则会大大方便工程链路上的后处理;例如,LLM在调用工具(或其它智能体)时,需要按照工具要求传入正确的参数,若能保证LLM的输出是结构化的JSON,则能保证传参正确,从而正确调用工具。

然而,在实践中,即使我们在提示词中反复告诉模型要输出JSON结构,LLM还是偶尔出错。虽然“偶尔”出错的概率很低,但对于工程链路的设计来说,是致命且麻烦的。

1.2 LLM为何不能严格输出JSON

LLM在推理时,基于已经输出的句子,从词汇表中预测下一个词。预测时,为词汇表中的每个词分配一个概率,通过采样得到预测输出,如图1所示。例如,模型在输出"My name is"后,仅有0.62的概率输出自己的名字"Tang",即使我们在提示词中告诉了模型自己的名字是"Tang",模型也有0.38的概率输出别的名字。

image.png

图1. LLM推理的预测概率示意

因此,这个依概率采样的推理过程决定了LLM不可能100%按要求输出JSON格式。错误的JSON输出导致了我们在工程链路上无法作后续的解析,因此,能100%严格限制JSON格式输出的方法非常重要。


1.3 友商方案

  • OpenAI JSON Mode

推出于2023年12月份,基于提示词优化,用户仍需要在提示词中给出JSON示例,不能保证严格100%输出JSON。

  • Kimi JSON Mode

近期推出。类似OpenAI的 JSON Mode,用户仍需要在提示词中给出JSON示例,不能保证严格100%输出JSON。

  • OpenAI Structured Outputs

推出于2024年8月份,根据用户给出的JSON示例,严格保证100%输出JSON格式。

https://openai.com/index/introducing-structured-outputs-in-the-api/

                                                                                        image.png


图2. OpenAI输出JSON格式的方法,橙、黄、绿分别代表提示词优化、微调、动态限制解码法的JSON输出准确率

(动态限制解码法准确率为100%)

二、前中后三阶段的优化策略

Motivation: 在一个基于通义千问的AI教评项目场景中,JSON格式输出对客户十分重要。因此,我们在该项目实践中由浅入深,从LLM推理的前、中、后三个阶段探索了限制输出JSON格式的方法。其中,“推理前”和“推理后”这两个阶段的方法用在了项目实践中,大大提高了AI教评任务中JSON格式的输出概率。为了进一步研究如何100%输出JSON格式,我们借他山之石,研究了OpenAI的Structured Outputs方法,在“推理中”这一阶段探索并验证了基于动态限制解码的100%输出JSON格式方法。

在分析相关工作基础上,我们将深入讨论每阶段的方法、优劣及其实现方式,以期帮助读者掌握提升JSON输出概率的办法,并应用在实践中。

2.1 推理“前”:Prompt Engineering

(以下提示词来自大量项目实践验证)。

在提示词中加入这句话“The JSON object:json”可提高JSON输出概率。(别问,问就是大量实践总结的经验~)。

在提示词中给出"##输出格式规范",并给出JSON示例```json ... ```。


## 输出格式规范:
```json
[{
  "name":"<评价维度>",
  "mentions":"< 提及次数 >",
  "references":[{
    "time":"<发言时间>",
    "text":"<原文内容>"}]}]
```

The JSON object:json

【实践】

在利用Qwen-long作AI教评的一个项目中,我们需要从教师的课堂录音文本中提取结构化的教学维度信息。采用本节中的prompt加上2.3中的JSON后处理方法后,输出样本基本是符合预期的结构化JSON。JSON正确概率从50%左右上升到了95%。可见仅靠prompt和后处理,已经能以很高的概率使得大模型按照JSON格式输出。然而,在一些需要严谨输出JSON格式的场景,100%严格输出JSON格式的方法仍值得研究。

【优势】

实施简便,无需模型架构调整,可以大幅提高输出JSON的概率。

【不足】

高度依赖于人工设计的prompt,灵活性受限。不能100%输出JSON。

2.2 推理“中”:基于动态限制解码实现100%输出JSON

【原理】

LLM依据已输出的词,从词汇表中预测下一个词,可以在词汇表中将不符合JSON规范的词概率置零,从而防止输出不符合JSON规范。(原理偏复杂,可跳过本节直接看结论)。假设我们想让LLM的输出为一个城市的如下信息:


city_info_schema=[{
  "name":"城市名",
  "country":"城市所属国家",
  "latitude":"城市纬度",
  "population":"城市人口(千万)",
  "top 3 landmarks":["知名景点1","知名景点2","知名景点3"]
}]

如上代码块所示,在内存中定义JSON输出的模式city_info_schema。LLM每轮逐个单词输出"response",对于JSON的"key"值,如"name",我们直接从内存拼接到输出字符串"response_str"中;对于JSON的"value",则让LLM通过推理产生。当用户提出问题“请填写杭州的城市信息”后,动态限制解码流程如下:

image.png

图3. 动态限制解码法示意图。其中只有绿色词是LLM的推理产生。

上图展示了动态限制解码的工作流程,每一轮推理过程我们给定了JSON的“键”,仅让模型推理“值”。可以进一步用正则式(Python re库)限制我们想要的输出格式:


city_regex = (
    r"""\{\n"""
    + r"""  "name": "[\w\d\s]{1,16}",\n"""
    + r"""  "country": "[\w\d\s]{1,16}",\n"""
    + r"""  "latitude": [-+]?[0-9]*\.?[0-9]{0,2},\n"""
    + r"""  "population": [-+]?[0-9]{1,9},\n"""
    + r"""  "top 3 landmarks": \["[\w\d\s]{1,16}", "[\w\d\s]{1,16}", "[\w\d\s]{1,16}"\]\n"""
    + r"""\}"""
)

在推理过程中,根据正则式限制输出格式的流程如下:

image.png

图4. 动态限制解码法的”推理-限制-采样-拼接”流程


如第一个键"key"对应的"name",我们用正则式限制其必须输出16个字以内的英文,则"杭"的概率由于不符合正则式要求,预测概率置零,模型一定会按照我们的要求输出。

由于动态限制解码技术需要我们有冻结模型解码过程、改变词汇表采样概率、改变模型输入的权限,目前在线的API接口。

不支持编写动态限制解码算法。但是可以在本地部署模型以实现动态限制解码。

【实践】

在PAI平台的免费体验DSW(NVIDIA A10)上本地部署Qwen2-7B-Instruct实现动态限制解码。基于开源的sglang库,可快速部署动态限制解码算法。


pip install --upgrade pip
pip install "sglang[all]"
# Install FlashInfer CUDA kernels
wget "https://modelscope.oss-cn-beijing.aliyuncs.com/resource/flashinfer-0.1.2%2Bcu121torch2.3-cp310-cp310-linux_x86_64.whl"
pip install flashinfer-0.1.2+cu121torch2.3-cp310-cp310-linux_x86_64.whl
modelscope download --model=qwen/Qwen2-7B-Instruct --local_dir ./Qwen2-7B-Instruct
python3 -m sglang.launch_server --model-path Qwen2-7B-Instruct --port 30000

                                                                            image.png

图5. sglang框架下的千问模型本地部署成功示意图

显示上图即部署成功。

###导入库
import json
import time
from sglang import set_default_backend, RuntimeEndpoint
import sglang as sgl
from sglang.test.test_utils import (
    add_common_sglang_args_and_parse,
    select_sglang_backend,
)
from sglang.utils import dump_state_text, read_jsonl
##定义“限制模型输出的正则式”
city_regex = (
    r"""\{\n"""
    + r"""  "name": "[\w\d\s]{1,16}",\n"""
    + r"""  "country": "[\w\d\s]{1,16}",\n"""
    + r"""  "latitude": [-+]?[0-9]*\.?[0-9]{0,2},\n"""
    + r"""  "population": [-+]?[0-9]{1,9},\n"""
    + r"""  "top 3 landmarks": \["[\w\d\s]{1,16}", "[\w\d\s]{1,16}", "[\w\d\s]{1,16}"\]\n"""
    + r"""\}"""
)
## 将正则式应用在输出范式中
@sgl.function
def chat_example(s,question):
    s += sgl.system("You are a helpful assistant.")
    # Same as: s += s.system("You are a helpful assistant.")

    with s.user():
        s += question

    s += sgl.assistant_begin()
    s += "Answer: " + sgl.gen("json_output", max_tokens=256, regex=city_regex)
    s += sgl.assistant_end()
## 设置Qwen2的本地通信端口,上图设置为port30000
set_default_backend(RuntimeEndpoint("http://localhost:30000"))
## 捕捉用户输入
state = chat_example.run(
    question=input("请输入城市名:"),
    # temperature=0.1,
    stream=True
)
## 打印必然的JSON输出结果
for out in state.text_iter():
    print(out, end="", flush=True)

运行效果:试输入“杭州”和“纽约”两个城市。输出严格按照了正则式的限制。

image.png

image.png

图6. 基于动态限制解码的JSON格式输出结果。

【优势】

  • 100%严格输出JSON格式,甚至是任意正则式可以定义的格式。
  • 在输出的JSON中,节省了输出"key"值的token:因为"key"值是内存中定义好的,不需要由LLM推理而得。因此,相对于prompt的方式让模型输出全JSON的方式,节省了输出的token数量。(这也是为什么OpenAI的JSON 模式每token价格有30%的折扣的原因)。

【不足】

  • 必须本地部署LLM。


2.3 推理“后”:JSON数据后处理

在模型返回response后,也可以利用后处理的技术,校正JSON结构以提高JSON输出的概率。

  • JSON Repair库

Python 的json_repair库,可以解决一部分模型输出JSON格式不规范的问题。


from json_repair import loads #pip install json_repair
import json

if __name__ == '__main__':
    
    bad_string= '''
[
            {
                "foo": "Foo bar baz",
                "tag": "foo-bar-baz"
            },
            {
                "中文": "foo bar foobar foo bar baz.",
                "标签": "foo-bar-foobar"
            }
        ]
'''
    
    parsed_json = loads(bad_string)
    json_str = json.dumps(parsed_json,ensure_ascii=False)
    print(json_str)

经实践验证,json_repair可以解决输出的JSON中缺少"},],"的问题。


  • 随机种子控制:可改变LLM推理的seed, 在不同的seed下输出以减少出错概率。

三、总结与展望

以上介绍的三种类型的方法,可以同时使用,但需要注意不同的场景限制:

【前、中、后三阶段方法总结】

image.png

【彩蛋】

qwen-max-0919、qwen-max-latest、qwen-plus、qwen-plus-0919、qwen-plus-latest、qwen-turbo-0919、qwen-turbo-latest以及qwen2.5系列模型已支持结构化输出JSON。(设置response_format = { "type": "json_object" } ),可去阿里云百炼平台上进行体验哦~~


👉阿里云百炼详情了解可点击此官网链接:阿里云百炼官网介绍

👉阿里云百炼控制台页面可点击此链接直接进入阿里云百炼控制台


欢迎大家在评论区交流探讨调用阿里云百炼的体验与经验 。如果您在体验过程中有遇到什么问题需要我们解答,可以在评论区中留言探讨或是加入我们的官方支持群(群号:77600022533)进行交流反馈!


相关实践学习
如何快速体验知识检索增强应用
在应用广场中您可以挑选智能体API应用、官方预置完整工程链路的知识检索增强(RAG)应用、流程编排应用,以及官方最佳实践的写作应用妙笔等,通过应用快速将通义千问系列等大语言模型能力接入到业务解决方案中。
相关文章
|
7月前
|
人工智能 自然语言处理 物联网
RoSA: 一种新的大模型参数高效微调方法
随着语言模型不断扩展到前所未有的规模,对下游任务的所有参数进行微调变得非常昂贵,PEFT方法已成为自然语言处理领域的研究热点。PEFT方法将微调限制在一小部分参数中,以很小的计算成本实现自然语言理解任务的最先进性能。
187 1
|
21天前
|
缓存 算法 关系型数据库
MIT韩松团队长上下文LLM推理高效框架DuoAttention:单GPU实现330万Token上下文推理
麻省理工学院韩松团队提出DuoAttention框架,旨在提高大型语言模型(LLM)处理长上下文的效率。该框架通过区分检索头和流式头,仅对检索头应用全键值缓存,减少内存消耗和计算时间,同时保持模型长上下文处理能力。实验结果显示,DuoAttention在多种模型架构上显著提升了推理效率,为LLM的实际应用提供了新可能。
47 14
|
1月前
|
自然语言处理 开发者
多模态大模型LLM、MLLM性能评估方法
针对多模态大模型(LLM)和多语言大模型(MLLM)的性能评估,本文介绍了多种关键方法和标准,包括模态融合率(MIR)、多模态大语言模型综合评估基准(MME)、CheckList评估方法、多模态增益(MG)和多模态泄露(ML),以及LLaVA Bench。这些方法为评估模型的多模态和多语言能力提供了全面的框架,有助于研究者和开发者优化和改进模型。
107 5
|
1月前
|
人工智能 自然语言处理
重要的事情说两遍!Prompt复读机,显著提高LLM推理能力
【10月更文挑战第30天】本文介绍了一种名为“问题重读”(Question Re-reading)的提示策略,旨在提高大型语言模型(LLMs)的推理能力。该策略受人类学习和问题解决过程的启发,通过重新审视输入提示中的问题信息,使LLMs能够提取更深层次的见解、识别复杂模式,并建立更细致的联系。实验结果显示,问题重读策略在多个推理任务上显著提升了模型性能。
58 2
|
1月前
|
JSON 人工智能 算法
探索LLM推理全阶段的JSON格式输出限制方法
文章详细讨论了如何确保大型语言模型(LLMs)输出结构化的JSON格式,这对于提高数据处理的自动化程度和系统的互操作性至关重要。
|
2月前
|
机器学习/深度学习 自然语言处理 算法
通过RAG增强大模型回答原本无法回答的问题
RAG(检索增强生成)是一种结合信息检索和文本生成技术的方法,旨在提升大规模语言模型处理特定问题的能力。通过先从大量文档中检索相关信息,再利用这些信息生成更准确的答案,RAG特别适用于需要最新数据或专业知识的场景,如医疗咨询、法律建议等。此方法不仅提高了答案的质量和准确性,还增强了系统的可扩展性和适应性。随着技术进步,RAG有望在更多领域发挥重要作用。
51 2
|
5月前
|
自然语言处理
AIGC使用问题之GPT-1如何优化目标函数,如何做模型微调
AIGC使用问题之GPT-1如何优化目标函数,如何做模型微调
|
5月前
LLM用于时序预测真的不行,连推理能力都没用到
【7月更文挑战第15天】LLM在时序预测上的应用遇挫:研究显示,大型语言模型在多个实验中未显优势,甚至被简单注意力层替代时效果不变或更好。预训练知识未能有效利用,处理时序依赖性不足,且在小样本学习中未见提升。[链接:](https://arxiv.org/pdf/2406.16964)**
96 2
|
6月前
|
机器学习/深度学习 人工智能 自然语言处理
揭秘In-Context Learning(ICL):大型语言模型如何通过上下文学习实现少样本高效推理[示例设计、ICL机制详解]
揭秘In-Context Learning(ICL):大型语言模型如何通过上下文学习实现少样本高效推理[示例设计、ICL机制详解]
揭秘In-Context Learning(ICL):大型语言模型如何通过上下文学习实现少样本高效推理[示例设计、ICL机制详解]
|
7月前
|
缓存 人工智能 自然语言处理
LLM 大模型学习必知必会系列(三):LLM和多模态模型高效推理实践
LLM 大模型学习必知必会系列(三):LLM和多模态模型高效推理实践
LLM 大模型学习必知必会系列(三):LLM和多模态模型高效推理实践