跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
PythonAI算法

LLM 推理全阶段 JSON 格式输出限制方法详解

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

KernelLab发布于 2025/2/7更新于 2026/6/220 浏览
LLM 推理全阶段 JSON 格式输出限制方法详解

导读

本文详细讨论了如何确保大型语言模型(LLMs)在推理过程中输出结构化的 JSON 格式。这对于提高数据处理的自动化程度、增强系统的互操作性至关重要,特别是在需要程序化解析模型输出的工程链路中。

一、引言

1.1 JSON 结构化输出的意义

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

然而,在实践中,即使我们在提示词(Prompt)中反复强调要输出 JSON 结构,LLM 偶尔仍会出错。虽然'偶尔'出错的概率在单次交互中可能很低,但对于高并发、高可靠性的工程链路设计来说,这种不确定性往往是致命且麻烦的,会导致系统需要额外的容错机制或人工介入。

1.2 LLM 为何不能严格输出 JSON

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 格式输出的方法非常重要。

1.3 现有方案对比

目前业界针对 JSON 输出的解决方案主要分为以下几类:

  • OpenAI JSON Mode:推出于 2023 年 12 月,基于提示词优化,用户仍需要在提示词中给出 JSON 示例,不能保证严格 100% 输出 JSON,存在格式错误风险。
  • Kimi JSON Mode:近期推出,类似 OpenAI 的 JSON Mode,用户仍需要在提示词中给出 JSON 示例,同样不能保证严格 100% 输出 JSON。
  • OpenAI Structured Outputs:推出于 2024 年 8 月,根据用户给出的 JSON Schema,通过后端约束解码技术,严格保证 100% 输出符合 Schema 的 JSON 格式。

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

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

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

2.1 推理'前':Prompt Engineering

在提示词中加入特定的指令可提高 JSON 输出概率。以下是经过大量项目实践验证的有效技巧:

  1. 明确指定格式:在提示词中加入这句话The JSON object: ...,可显著提高模型遵循格式的概率。
  2. 提供输出规范:在提示词中给出##输出格式规范,并给出一个完整的 JSON 示例(Few-Shot Prompting)。示例应包含所有可能的字段,包括空值情况。
  3. 设置温度参数:将模型的 temperature 设置为 0 或非常低的值(如 0.1),以减少随机性,增加确定性输出。
【实践案例】

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

【优势】
  • 实施简便,无需修改模型架构或部署环境。
  • 可以大幅提高输出 JSON 的概率,适合对实时性要求不高但成本敏感的场景。
【不足】
  • 高度依赖于人工设计的 prompt,灵活性受限,维护成本高。
  • 不能 100% 输出 JSON,仍需配合校验逻辑。
2.2 推理'中':基于动态限制解码实现 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"""\}"""
)

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

  1. 推理:模型计算下一个 token 的概率分布。
  2. 限制:根据正则表达式过滤掉不符合当前上下文的 token。
  3. 采样:在剩余的合法 token 中进行采样。
  4. 拼接:将选定的 token 加入输出流。

如第一个键 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():
    print(out, end="", flush=True)

运行效果:试输入'杭州'和'纽约'两个城市。输出严格按照了正则式的限制,不会出现格式错误。

【优势】
  • 100% 严格输出 JSON 格式,甚至是任意正则式可以定义的格式。
  • 在输出的 JSON 中,节省了输出 key 值的 token:因为 key 值是内存中定义好的,不需要由 LLM 推理而得。因此,相对于 prompt 的方式让模型输出全 JSON 的方式,节省了输出的 token 数量。(这也是为什么 OpenAI 的 JSON 模式每 token 价格有 30% 折扣的原因)
【不足】
  • 必须本地部署 LLM。无法直接使用云端 API。
  • 增加了推理延迟,因为每一步都需要进行正则匹配和概率调整。
  • 对显存有一定要求,需加载完整模型权重。
2.3 推理'后':JSON 数据后处理

在模型返回 response 后,也可以利用后处理的技术,校正 JSON 结构以提高 JSON 输出的概率。这通常作为最后一道防线。

  • JSON Repair 库:Python 的 json_repair 库,可以解决一部分模型输出 JSON 格式不规范的问题,如缺失逗号、引号不匹配等。

经实践验证,json_repair 可以解决输出的 JSON 中缺少 },], 的问题,并能自动补全缺失的闭合符号。

  • 随机种子控制:可改变 LLM 推理的 seed,在不同的 seed 下多次重试输出,以减少出错概率。这在批量处理任务中尤为有效。
  • Pydantic 验证:使用 Pydantic 模型定义数据结构,尝试解析模型输出。如果解析失败,捕获异常并触发重试或修复逻辑。

三、总结与展望

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

【前、中、后三阶段方法总结】
阶段方法准确率部署难度适用场景
推理前Prompt Engineering90%-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" } )

四、常见问题排查

在实际应用中,可能会遇到以下问题:

  1. Token 截断:如果生成的 JSON 过长,可能会被截断导致不完整。建议设置合理的 max_tokens,并在后处理中检查是否闭合。
  2. 特殊字符转义:模型输出的值中可能包含换行符或双引号,导致 JSON 解析失败。务必使用标准的 JSON 序列化库处理值部分。
  3. 性能瓶颈:动态限制解码会增加推理时间。如果吞吐量要求极高,建议仅在必要时开启约束解码,或使用 Prompt 优化+ 后处理方案。

五、结语

确保 LLM 输出严格的 JSON 格式是实现 Agent 自动化和系统集成的重要基石。通过理解 LLM 的生成机制,合理选择 Prompt 工程、约束解码或后处理方案,开发者可以构建更加稳定可靠的 AI 应用系统。随着大模型技术的演进,未来云端 API 可能会原生支持更强大的结构化输出能力,届时本地部署的需求可能会降低,但掌握底层原理依然是工程师的核心竞争力。

目录

  1. 导读
  2. 一、引言
  3. 1.1 JSON 结构化输出的意义
  4. 1.2 LLM 为何不能严格输出 JSON
  5. 1.3 现有方案对比
  6. 二、前中后三阶段的优化策略
  7. 2.1 推理“前”:Prompt Engineering
  8. 【实践案例】
  9. 【优势】
  10. 【不足】
  11. 2.2 推理“中”:基于动态限制解码实现 100% 输出 JSON
  12. 【原理】
  13. 【实践】
  14. Install FlashInfer CUDA kernels
  15. 定义“限制模型输出的正则式”
  16. 将正则式应用在输出范式中
  17. 设置 Qwen2 的本地通信端口,上图设置为 port30000
  18. 捕捉用户输入
  19. 打印必然的 JSON 输出结果
  20. 【优势】
  21. 【不足】
  22. 2.3 推理“后”:JSON 数据后处理
  23. 三、总结与展望
  24. 【前、中、后三阶段方法总结】
  25. 【彩蛋】
  26. 四、常见问题排查
  27. 五、结语
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Proteus 9.1 发布:引入 AI 助手与 MicroPython 支持
  • 小米 miclaw 手机智能体落地,重构智能家居底层逻辑
  • 谷歌开发者社区生态解析:助力开发者全球成长
  • SKResNet 架构详解:融合选择性卷积与残差结构
  • Being-H0.5:扩展以人为中心的机器人学习实现跨具身泛化
  • YOLOv8 与 ROS 的集成及目标检测应用
  • 机器人阻抗控制器与导纳控制器原理对比
  • Rust 与 WebAssembly 实战:在浏览器与 Node.js 中运行高性能代码
  • 文心一言与通义千问大模型能力对比评测
  • 计算机专业毕业生就业前景与岗位方向深度分析
  • Spring Cloud Feign 性能优化:连接池与超时配置详解
  • Spring AI 基于 Redis 实现对话持久存储详解
  • Git 原理与使用进阶:远程协作、标签管理及企业级开发模型
  • AIGC 在艺术创作中的变革与机遇
  • Home Assistant 界面美化指南:打造个性化智能家居体验
  • Phi-3-mini-128k-instruct Chainlit 插件开发:思维链可视化与 Token 统计
  • Git 版本管理基础与常用命令
  • C++ 多线程并发:资源保护、std::mutex 与 RAII 实践
  • VSCode Copilot 接入智谱 GLM-5.1 配置指南
  • OpenClaw 接入飞书机器人配置教程

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online