>_ DevTrendszh

语言

首页

语言

板块

前端 后端 移动端 DevOps AI / ML 游戏开发 区块链 嵌入式 安全
Python

如何让神经网络输出有效 JSON,无需变通方案和重试请求

每个尝试将语言模型连接到真实后端的人都遇到过这个问题。你编写了详细的提示词,要求模型返回严格符合结构的 JSON,在十个示例上测试——一切都很顺利。但在第一百次请求时,神经网络突然忘记关闭引号,在响应开头添加了"Here is your answer!"这样的短语,或者凭空编造一个不存在的字段。结果,Pydantic 抛出验证错误,服务崩溃。

通常,开发者通过重试 API 请求、使用复杂正则表达式,或在生成后尝试"修复"损坏的响应来解决这个问题。.txt 团队的开发者采取了不同的方法,创建了 Outlines——一个在单个 token 级别引导文本生成过程的库。

受控生成的工作原理

大多数框架将 LLM 视为黑盒:发送文本,等待返回完整字符串。Outlines 在采样过程中拦截控制权。在每个生成步骤中,库会检查模型词表中的哪些 token 符合指定模式,哪些违反了规则。

如果你请求一个数字,库会简单地将所有包含字母或标点的 token 的采样概率设为零。模型在物理上无法选择无效符号。结果不是对有效 JSON 的期望,而是从第一次尝试就能保证正确的结构。

这种方法节省 token 和时间。你不再需要在提示词中要求模型"不要添加额外文本",也不需要在解析失败时运行重新生成。

该库的功能

Outlines 的接口尝试模仿熟悉的 Python 类型语法。你只需将所需的数据类型与提示词一起传递。

固定响应选项

如果你需要从有限的值集合中进行选择,可以通过 LiteralEnum 来定义。模型不会写长篇推理——它会立即输出指定的值之一。

import outlines
from typing import Literal
from transformers import AutoTokenizer, AutoModelForCausalLM

model_name = "microsoft/Phi-3-mini-4k-instruct"
model = outlines.from_transformers(
    AutoModelForCausalLM.from_pretrained(model_name, device_map="auto"),
    AutoTokenizer.from_pretrained(model_name)
)

# Модель вернет строго одно из трех слов
sentiment = model(
    "Оцени тональность ответа: 'Сервис работает отлично, спасибо!'",
    Literal["Positive", "Negative", "Neutral"]
)
print(sentiment)  # Positive

基于 Pydantic Schema 生成

对于复杂对象,可以使用标准的 Pydantic 模型。Outlines 根据 schema 构建语法,并确保响应结构完全符合它。

from pydantic import BaseModel
from enum import Enum

class TicketPriority(str, Enum):
    low = "low"
    medium = "medium"
    high = "high"
    urgent = "urgent"

class ServiceTicket(BaseModel):
    priority: TicketPriority
    category: str
    requires_manager: bool
    summary: str

prompt = """
Проанализируй обращение:
Срочно! Не могу войти в личный кабинет после оплаты. Через час презентация клиенту!
"""

# Модель сгенерирует JSON, который точно совпадает со структурой ServiceTicket
ticket_json = model(prompt, ServiceTicket, max_new_tokens=200)
ticket = ServiceTicket.model_validate_json(ticket_json)

print(ticket.priority)          # TicketPriority.urgent
print(ticket.requires_manager)  # True

正则表达式和语法

如果 Pydantic 模型对你的任务来说过于繁琐,可以定义严格的正则表达式。这对于提取电话号码、日期、邮政编码或创建内部 DSL 非常方便。

支持的模型

Outlines 适配你的技术栈。该库支持多种模式:

  • 通过 transformersllama.cpp 进行本地推理
  • 基于 vLLM 和 Ollama 的服务器解决方案
  • OpenAI 和 Gemini 等外部 API

当使用自己的本地模型或本地推理服务器时,该库的优势最为明显。在这些场景中,直接的 token 掩码控制提供了 100% 的结构保证并加快了操作速度。

生产环境用例

在实践中,该库同时解决了几个常见的开发任务:

  1. 自动工单分类。从传入的客户邮件中提取类别、紧急程度和标签,而不会遇到损坏对象的风险。
  2. 实体提取与不完整数据处理。通过 Union 类型,你可以允许模型返回填充的对象或带有缺失信息消息的显式字符串。
  3. 函数调用。你可以向模型传递一个常规 Python 函数,Outlines 自动从其参数中提取类型以形成正确的调用参数。
  4. 产品目录分类。将产品描述快速解析为类别、品牌和关键特征。

局限性和注意事项

尽管有这些优势,理解这项技术的具体细节很重要。为 token 计算掩码需要额外的资源。如果你的 Pydantic schema 由数十个嵌套对象和复杂正则表达式组成,生成前的语法准备可能需要一些时间。

此外,如果你仅通过 OpenAI API 工作,该库将使用提供商内部的机制(Structured Outputs / JSON Mode)。在这种情况下,Outlines 充当一个方便的统一接口,但采样过程本身由 OpenAI 服务器控制。

Outlines 解决了任何团队在将 LLM 投入生产时面临的真实工程问题。该项目消除了生成过程中的不稳定性,使得能够像使用常规类型化函数一样与神经网络交互。如果你正在基于开源模型构建后端服务或自主代理,这个工具绝对值得加入你的工具箱。

相关项目