LLM 推理全阶段 JSON 格式输出限制方法详解
本文探讨了确保大型语言模型输出结构化 JSON 格式的三种主要策略:推理前的提示词工程、推理中的动态限制解码以及推理后的数据后处理。文章分析了 LLM 概率生成特性导致的格式错误原因,对比了 OpenAI 等厂商的方案,并提供了基于 Sglang 库的本地部署代码示例。通过实验验证,动态限制解码可实现 100% 格式合规,而提示词优化可将成功率提升至 95%。文章最后总结了各方案的优缺点及适用场景,为构建高可靠性的 AI 应用提供了技术参考。

本文探讨了确保大型语言模型输出结构化 JSON 格式的三种主要策略:推理前的提示词工程、推理中的动态限制解码以及推理后的数据后处理。文章分析了 LLM 概率生成特性导致的格式错误原因,对比了 OpenAI 等厂商的方案,并提供了基于 Sglang 库的本地部署代码示例。通过实验验证,动态限制解码可实现 100% 格式合规,而提示词优化可将成功率提升至 95%。文章最后总结了各方案的优缺点及适用场景,为构建高可靠性的 AI 应用提供了技术参考。

本文详细讨论了如何确保大型语言模型(LLMs)在推理过程中输出结构化的 JSON 格式。这对于提高数据处理的自动化程度、增强系统的互操作性至关重要,特别是在需要程序化解析模型输出的工程链路中。
对于基于大型语言模型的应用而言,确保输出能直接以结构化的 JSON 格式呈现,对于提升数据处理的自动化程度、增强系统的互操作性具有重要意义。例如,当客户需要对 LLM 的输出进行信息提取时,若输出是一个标准的 JSON 格式,将大大方便工程链路上的后处理流程;又如,LLM 在调用工具(Tool Use)或与其他智能体协作时,需要按照工具定义的要求传入正确的参数。若能保证 LLM 的输出是严格的结构化 JSON,则能保证传参正确,从而避免调用失败。
然而,在实践中,即使我们在提示词(Prompt)中反复强调要输出 JSON 结构,LLM 偶尔仍会出错。虽然'偶尔'出错的概率在单次交互中可能很低,但对于高并发、高可靠性的工程链路设计来说,这种不确定性往往是致命且麻烦的,会导致系统需要额外的容错机制或人工介入。
LLM 在推理时,是基于已经输出的上下文序列,从词汇表(Vocabulary)中预测下一个 token。预测时,模型为词汇表中的每个 token 分配一个概率分布,通过采样策略(如 Top-K, Top-P, Greedy)得到最终的预测输出。
例如,模型在输出"My name is"后,仅有 0.62 的概率输出自己的名字"Tang",即使我们在提示词中明确告诉模型自己的名字是"Tang",模型仍有 0.38 的概率输出别的名字。这种依概率采样的推理过程决定了 LLM 本质上是一个概率生成模型,不可能 100% 按确定性逻辑输出特定格式的字符串。错误的 JSON 输出(如缺少引号、括号不匹配、键名错误)导致了我们在工程链路上无法使用标准解析库(如 Python 的 json.loads)进行后续解析,因此,能 100% 严格限制 JSON 格式输出的方法非常重要。
目前业界针对 JSON 输出的解决方案主要分为以下几类:
在一个基于通义千问的 AI 教评项目场景中,JSON 格式输出对客户十分重要。因此,我们在该项目实践中由浅入深,从 LLM 推理的前、中、后三个阶段探索了限制输出 JSON 格式的方法。其中,'推理前'和'推理后'这两个阶段的方法用在了项目实践中,大大提高了 AI 教评任务中 JSON 格式的输出概率。为了进一步研究如何 100% 输出 JSON 格式,我们研究了动态限制解码技术,在'推理中'这一阶段探索并验证了基于约束解码的 100% 输出 JSON 格式方法。
在分析相关工作基础上,我们将深入讨论每阶段的方法、优劣及其实现方式,以期帮助读者掌握提升 JSON 输出概率的办法,并应用在实践中。
在提示词中加入特定的指令可提高 JSON 输出概率。以下是经过大量项目实践验证的有效技巧:
The JSON object: ...,可显著提高模型遵循格式的概率。##输出格式规范,并给出一个完整的 JSON 示例(Few-Shot Prompting)。示例应包含所有可能的字段,包括空值情况。在利用 Qwen-long 作 AI 教评的一个项目中,我们需要从教师的课堂录音文本中提取结构化的教学维度信息。采用本节中的 prompt 加上后处理方法后,输出样本基本是符合预期的结构化 JSON。JSON 正确概率从 50% 左右上升到了 95%。可见仅靠 prompt 和后处理,已经能以很高的概率使得大模型按照 JSON 格式输出。然而,在一些需要严谨输出 JSON 格式的场景(如金融交易、自动化控制),100% 严格输出 JSON 格式的方法仍值得研究。
LLM 依据已输出的词,从词汇表中预测下一个词。可以在推理过程中,动态地将词汇表中不符合 JSON 规范的 token 概率置零,从而防止输出不符合 JSON 规范的字符。这被称为'约束解码'(Constrained Decoding)或'动态限制解码'。
假设我们想让 LLM 的输出为一个城市的如下信息:
{
"name": "杭州",
"country": "中国",
"latitude": 30.27,
"population": 12000000,
"top 3 landmarks": ["西湖", "灵隐寺", "雷峰塔"]
}
如上代码块所示,在内存中定义 JSON 输出的模式 city_info_schema。LLM 每轮逐个单词输出 response,对于 JSON 的 key 值,如 "name",我们直接从内存拼接到输出字符串 response_str 中;对于 JSON 的 value,则让 LLM 通过推理产生。当用户提出问题'请填写杭州的城市信息'后,动态限制解码流程如下:
每一轮推理过程我们给定了 JSON 的'键',仅让模型推理'值'。可以进一步用正则式(Python re 库)限制我们想要的输出格式:
import 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"""\}"""
)
在推理过程中,根据正则式限制输出格式的流程如下:
如第一个键 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
显示成功连接即部署完成。客户端代码示例:
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():
(out, end=, flush=)
运行效果:试输入'杭州'和'纽约'两个城市。输出严格按照了正则式的限制,不会出现格式错误。
key 值的 token:因为 key 值是内存中定义好的,不需要由 LLM 推理而得。因此,相对于 prompt 的方式让模型输出全 JSON 的方式,节省了输出的 token 数量。(这也是为什么 OpenAI 的 JSON 模式每 token 价格有 30% 折扣的原因)在模型返回 response 后,也可以利用后处理的技术,校正 JSON 结构以提高 JSON 输出的概率。这通常作为最后一道防线。
json_repair 库,可以解决一部分模型输出 JSON 格式不规范的问题,如缺失逗号、引号不匹配等。经实践验证,json_repair 可以解决输出的 JSON 中缺少 },], 的问题,并能自动补全缺失的闭合符号。
以上介绍的三种类型的方法,可以同时使用,但需要注意不同的场景限制:
| 阶段 | 方法 | 准确率 | 部署难度 | 适用场景 |
|---|---|---|---|---|
| 推理前 | Prompt Engineering | 90%-95% | 低 | 快速原型、非关键任务 |
| 推理中 | 动态限制解码 | 100% | 高 | 生产环境、关键任务 |
| 推理后 | 后处理修复 | 95%-99% | 中 | 兜底方案、离线批处理 |
最佳实践通常是组合拳:使用 Prompt 优化基础输出,结合后处理修复小错误,对于核心业务逻辑则强制使用本地部署的动态限制解码。
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" } )
在实际应用中,可能会遇到以下问题:
max_tokens,并在后处理中检查是否闭合。确保 LLM 输出严格的 JSON 格式是实现 Agent 自动化和系统集成的重要基石。通过理解 LLM 的生成机制,合理选择 Prompt 工程、约束解码或后处理方案,开发者可以构建更加稳定可靠的 AI 应用系统。随着大模型技术的演进,未来云端 API 可能会原生支持更强大的结构化输出能力,届时本地部署的需求可能会降低,但掌握底层原理依然是工程师的核心竞争力。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online