多模态提示(Multimodal Prompting)
通过组合图像、文本等多种信息形式来引导多模态模型完成视觉理解与推理任务的提示技术
通过 Schema 约束和约束解码技术,让 LLM 输出严格符合指定格式的结构化数据。
内容摘要
结构化输出(Structured Output)是一种让 LLM 的生成结果严格遵循预定义数据格式(JSON Schema、正则表达式、上下文无关文法等)的技术。它不是靠"在提示词里说清楚格式"来实现的,而是在模型生成 Token 的过程中,直接把不合规的 Token 屏蔽掉,从根源上杜绝格式错误。
结构化输出(Structured Output)是一种让 LLM 的生成结果严格遵循预定义数据格式(JSON Schema、正则表达式、上下文无关文法等)的技术。它不是靠"在提示词里说清楚格式"来实现的,而是在模型生成 Token 的过程中,直接把不合规的 Token 屏蔽掉,从根源上杜绝格式错误。
为什么需要它?LLM 本质上是一个"下一个 Token 预测器",它并不理解什么是合法的 JSON。你在提示词里写"请返回 JSON",模型大多数时候能给出正确格式,但总有概率漏掉引号、多加一段注释、或者把枚举值写成 Schema 里不存在的字符串。在实验环境里这些小问题可以人工修复,但在生产环境中——每天处理上百万条请求、下游系统直接解析 JSON——任何一次格式错误都会导致流水线中断。
结构化输出的出现,把格式正确性从"概率性保证"提升到了"确定性保证"。它在 Agent 系统中尤其关键:Agent 的工具调用(Tool Use)、状态流转、多 Agent 之间的消息传递,全都依赖格式严格一致的结构化数据。一旦某个 Agent 吐出一段格式不对的 JSON,整条决策链就会断掉。
结构化输出的实现由三层机制组成,从外到内分别是:
| 结构 | 作用 | 说明 |
|---|---|---|
| Schema 定义层 | 声明"输出长什么样" | 用 JSON Schema、Pydantic、Zod 等定义字段名、类型、枚举值、嵌套关系 |
| 约束解码层 | 强制"输出必须合规" | 在模型逐 Token 生成时,用有限状态机或 Earley 解析器实时屏蔽非法 Token |
| 提示工程层 | 引导"输出内容有意义" | 约束解码只管格式,内容的准确性和合理性仍然需要提示词来引导 |
Schema 是结构化输出的"合同"。它精确描述了输出的每一个字段——名称、类型、是否必填、值域范围、嵌套关系。常见的 Schema 定义方式包括:
Schema 的精确程度直接决定输出质量。一个只写了 {"type": "object"} 的 Schema 和一个详细定义了每个字段类型、枚举值、描述文本的 Schema,模型给出的结果天差地别。
约束解码(Constrained Decoding)是结构化输出的核心技术。它在模型生成每个 Token 之前,检查"哪些 Token 会导致最终输出违反 Schema",然后把这些 Token 的概率设为 0,只从合法 Token 中采样。
主流的约束解码引擎包括:
约束解码保证的是格式正确,但不保证内容正确。同一个 Schema 下,模型可以生成无数种格式都合法但内容质量千差万别的结果。提示工程的作用是引导模型在合法空间内选择最优解:解释每个字段的语义、给出边界条件的处理方式、提供 1-2 个示例。
结构化输出的核心机制是在 Token 采样阶段插入一个约束过滤器。整个过程分为三步:
第一步:Schema 预处理。 在首次请求时,约束解码引擎将 JSON Schema(或正则、CFG)编译成一个状态机。这个状态机记录了"在当前已生成的 Token 序列下,下一个 Token 可以是什么"。例如,当 Schema 规定 status 字段只能取 "success" / "pending" / "error" 三个值时,状态机会在生成到 "status": " 这个位置时,只允许 s、p、e 三个首字母对应的 Token 通过。
第二步:逐 Token 约束采样。 模型照常计算每个 Token 的概率分布(logits)。在采样之前,约束解码引擎根据当前状态机的状态,生成一个掩码向量(mask):合法 Token 对应的位置为 1,非法 Token 为 0。将 logits 与掩码相乘并重新归一化,得到一个只包含合法 Token 的新概率分布,从中采样。
第三步:状态转移。 采样完成后,状态机根据实际选中的 Token 进行状态转移,进入下一轮约束采样。如此循环,直到生成完整的输出。
这种机制的关键优势在于:它将全局的 Schema 约束分解为逐 Token 的局部决策,不需要模型"理解" Schema,而是从物理层面让违规输出不可能出现。
图中的核心环节是步骤 2(掩码过滤):它发生在模型计算完概率之后、实际采样之前,是一个纯计算过程,不涉及额外的模型推理,因此开销很小。整个循环每生成一个 Token 执行一次,直到输出完成。
# 基于 pydantic==2.7+ 和 openai==1.59+ 验证(截至 2026-03)
from pydantic import BaseModel, Field
from enum import Enum
from openai import OpenAI
# 1. 用 Pydantic 定义 Schema
class Sentiment(str, Enum):
POSITIVE = "positive"
NEUTRAL = "neutral"
NEGATIVE = "negative"
class TextAnalysis(BaseModel):
"""文本分析结果"""
sentiment: Sentiment = Field(description="情感分类")
confidence: float = Field(ge=0, le=1, description="置信度")
keywords: list[str] = Field(description="关键词列表")
# 2. 调用 API,通过 response_format 传入 Schema
client = OpenAI()
completion = client.beta.chat.completions.parse(
model="gpt-4o",
messages=[{"role": "user", "content": "分析:这家餐厅的牛排非常好吃,服务态度也很棒"}],
response_format=TextAnalysis, # SDK 自动转换为 JSON Schema + strict: true
)
# 3. 输出已保证符合 Schema,直接使用
result = completion.choices[0].message.parsed
print(result.sentiment) # Sentiment.POSITIVE
print(result.confidence) # 0.92
print(result.keywords) # ['牛排', '好吃', '服务态度', '棒']
上述代码展示了结构化输出的三步核心流程:定义 Schema、通过 API 参数传入约束、直接使用类型安全的解析结果。response_format=TextAnalysis 这一行让 SDK 自动将 Pydantic 模型转为 JSON Schema 并启用严格模式(strict: true),约束解码在服务端完成。
| 概念 | 与结构化输出的区别 | 更适合关注的重点 |
|---|---|---|
| JSON Mode | 只保证输出是合法 JSON,但不保证符合任何 Schema | 输出是否为合法 JSON |
| Function Calling | 本质上是结构化输出的一个特例,专用于工具调用场景 | 模型是否应该调用某个工具、传什么参数 |
| Prompt 格式约束 | 纯靠提示词引导格式,没有 Token 级别的强制约束 | 模型理解力足够时的轻量级方案 |
| Output Parser | 后处理阶段的格式解析和验证,不干预生成过程 | 对接不支持原生约束解码的模型时的兜底方案 |
核心区别:
age 字段是整数且在 0-150 之间,但不能保证模型填入的年龄是事实正确的。语义层面的正确性仍然依赖提示工程和 RAG 等技术。| 常见误区 | 正确理解 |
|---|---|
| "结构化输出就是让模型输出 JSON" | JSON Mode 只保证语法合法,结构化输出进一步保证内容符合指定 Schema(字段名、类型、枚举值、嵌套关系全部强制约束)。两者差了一个层级。 |
| "提示词写清楚格式就够了,不需要约束解码" | 提示词约束是"建议",模型可以不听;约束解码是"物理限制",模型不可能违反。在生产环境中,99% 的成功率和 100% 的成功率有本质区别。 |
| "约束解码会严重拖慢推理速度" | 2025 年后的引擎(XGrammar、llguidance)已将开销压到每 Token 50 微秒以内,对端到端延迟的影响可以忽略。某些情况下约束解码反而加快生成,因为模型不再需要"犹豫"格式问题。 |
| "结构化输出可以取代 Function Calling" | 两者定位不同。Function Calling 允许模型决定"是否调用工具",结构化输出强制模型返回固定格式。Agent 系统中通常两者配合使用:Function Calling 决定调用哪个工具,结构化输出约束工具参数的格式。 |
参考答案:
JSON Mode 只保证输出是语法合法的 JSON(大括号匹配、引号正确等),但不关心 JSON 的内容是否符合任何 Schema。模型可能遗漏必填字段、生成错误的字段类型、或使用 Schema 中不存在的枚举值。结构化输出通过约束解码,在 Token 生成阶段强制输出符合指定的 JSON Schema,字段名、类型、枚举值、嵌套关系全部受到约束。两者的关系是:结构化输出包含了 JSON Mode 的能力,但反过来不成立。
参考答案:
不用结构化输出时,需要:(1) 后处理 JSON 解析器,处理模型输出的非法 JSON(缺引号、多余注释等);(2) Schema 验证层,检查字段是否齐全、类型是否正确;(3) 重试机制,验证失败时重新调用模型;(4) 兜底逻辑,多次重试仍失败时的降级处理。使用结构化输出后,(1)(2)(3) 可以完全省掉,因为输出在物理上保证符合 Schema。(4) 仍然需要保留,用于处理模型拒绝回答(refusal)或请求超时等异常情况。此外,业务层面的语义验证(如价格不为负、评分在 1-5 之间)如果 Schema 已经用 minimum / maximum 定义了范围,也可以省掉。
参考答案:
递归结构($ref 自引用)超出了正则表达式和有限状态机(FSM)的表达能力,因此 Outlines 等基于 FSM 的引擎要么直接拒绝该 Schema,要么将递归展平到固定深度(比如最多 3 层),无法处理任意深度的嵌套。正确选择是使用基于上下文无关文法(CFG)的引擎,如 XGrammar(使用预计算位掩码 + 运行时栈检查)或 llguidance(使用 Earley 解析器)。如果选错了引擎但没有发现,系统可能在浅层嵌套时正常工作,但在实际数据中遇到深层嵌套时静默截断或生成不符合 Schema 的输出,导致 Agent B 解析失败、整条决策链中断。
优先展示同分类且标签更接近的内容,方便继续串联学习。
通过组合图像、文本等多种信息形式来引导多模态模型完成视觉理解与推理任务的提示技术
像管理代码一样管理提示词的版本、环境和发布,保证线上可追溯、可回滚
用科学的指标体系和对比实验方法量化提示词质量的完整评估方法论