提示与输出契约

本页目录

从一条模型请求开始建立工程契约:原文明确提供了什么,允许输出什么,哪些内容要继续确认?以订单表单预填为例,依次处理任务定义、缺失值、结构约束和业务验证。取得合法 JSON 之后,仍要证明字段有来源、状态允许使用。

提示描述目标、输入和边界

“你是专家,请准确提取”没有定义准确的含义。一个可验证任务至少说明输入是什么、需要哪些字段、允许推断到什么程度、缺失或冲突如何处理、最终结果供谁使用。提示工程也需要先有成功标准,才能比较改动是否有效。Prompt engineering overview

例如输入“想买 A1,数量稍后确认”,任务若只要求 sku 与 quantity,模型可能猜 1;明确规定未知数量为 null,并标记 needs_input,才让没有答案成为合法结果。

原始歧义应明确的约定
数量没写,是否默认一件不猜测,返回 null
提到多个商品但字段只支持一个标记歧义或改用数组,不随意选一个
“下周”是哪段时间指明参考日期与时区,或保留原文
来源中内容互相冲突保留冲突与来源,不自选权威
输出会直接触发订单提取只是候选,不自动授权执行

稳定规则可以放在相应的可信指令层,当前材料以来源清楚的数据提供。消息角色和内容块是接口结构,不应只把它们理解为随意拼接的文本。XML 标签、标题或分隔符有助于区分内容,但不是安全隔离;外部材料中的“忽略此前规则”仍应按数据处理。

一个教学提示可以这样组织:

任务:从用户原文提取一个商品 SKU 和数量,供人工确认前的表单预填使用。
规则:只使用原文明确给出的信息;缺失字段为 null。
状态:两个字段都明确且无冲突时为 complete,否则为 needs_input。
范围:不要创建订单、查询个人资料或推断支付信息。
输出:遵守提供的 schema;不在结果前后添加说明。
用户原文:想买 A1,数量稍后确认。

提示中的“范围”说明模型应做什么,实际工具权限仍由执行端落实。把操作权限写成一句话,不能替代 Agent 循环 中的执行前核验。

用示例消除真实歧义

few-shot 示例用具体输入和输出说明约定。它适合解释 null、枚举、单位和冲突等抽象规则容易误读的地方;并非示例越多越好,也并非正例总能替代边界说明。

输入期望核心结果说明的规则
买 A1,共 3 件A1、3、complete正常提取
想买 A1,数量稍后确认A1、null、needs_input缺失不能猜
A1 要 3 件,等等改成 2 件需按明确的更正规则处理时间顺序和改口语义
买 A1 或 B2,还未决定不能随意选 SKU歧义需要表达

如果 schema 没有表达歧义的空间,示例再好也难以避免强行填值;先调整数据模型,再调整措辞。不要把开发集中的所有测试答案写进示例后,把同一批题的提升当作泛化能力。

需要多样方案时可以明确要求各方案在约束或取舍上不同;需要简短输出时直接规定篇幅与字段。temperature、effort 和篇幅要求各管不同问题,不能写成 temperature=0 → effort=low 的迁移公式。具体机制见 Token 与采样 与 推理与 thinking。

结构约束的作用范围

仅在 prompt 中要求 JSON,是让模型遵循文字约定;受约束解码则在生成时限制合法的输出延续,使完整的成功输出符合支持的 schema。客户端校验是生成之后的检查,可以补充服务不支持的约束,但不会倒过来改变已经生成的 token。

响应完整检查结束原因解析与 schema结构、字段、类型业务与证据范围、来源、权限允许进入后续流程仍遵守动作授权从生成到业务动作:每个检查解决不同问题合法 JSON 是必要的格式条件,不证明字段值真实,也不等于已获执行许可。
机制约束对象仍需应用检查
JSON 格式要求或模式可解析的 JSON 语法,能力依接口而异字段、类型、语义
schema 约束响应最终输出的规定结构完整响应、证据与业务条件
严格工具参数工具选择及参数的允许结构权限、资源状态、动作语义
客户端类型/业务验证接收到的对象后续执行时的状态变化

Claude 的 output_config.format 用于 JSON 响应,工具上的 strict: true 用于严格工具调用;两者可以组合,但可用 schema 子集和功能兼容范围需要按目标模型与 SDK 核对。Structured outputs

JSON Schema 本身的几个边界

properties 描述字段,不表示这些字段必须出现;必填由 required 声明。additionalProperties: false 拒绝未定义字段,也不会自动把已定义字段变成必填。null 是一个值,与字段不存在不同。JSON Schema object

比如希望 quantity 字段总出现、但未知时为 null,就同时需要 required 和可空类型。把它只定义为 integer 并设为 required,会让“原文没有数量”无法得到符合预期的表达。

供应商的结构化输出可能只支持 JSON Schema 子集。某些 SDK 会将完整 schema 转成服务支持的简化形式,再在客户端按原始约束验证;这与直接发送不支持字段的原始 JSON 请求不同。不能把“SDK 能接受”解释成“服务端生成时强制了全部约束”。SDK schema 转换说明

合法 JSON 到可用结果,还差几关?

把 quantity 从 3 改成 5,JSON 与类型仍可通过,原文支持却失败;保持 3 而降低库存,失败又发生在业务层。图中显示每个独立判据,帮助确定应该修提示、数据模型、证据核对还是执行前条件。

正在呈现知识画面
合法 JSON 到可用结果,还差几关?

语法、schema、原文支持和业务条件是不同检查;前一层通过不会替后面作保证。

为非成功路径设计输出

结构化输出的保证要限定在接口支持且响应完整的路径。截断、拒绝、传输错误和取消需要独立处理,不能一律取第一个 text 块然后写进数据库。

情况应用处理
正常完成解析、schema 校验,再做业务核验
输出截断标记未完成,保留原因;不执行半截参数
信息缺失接受 schema 中的未知状态,按任务继续读取或询问
原文冲突返回可定位的冲突,不自动编造一致结论
模型拒绝按接口读取拒绝状态,不能伪造成正常业务数据
网络断流或超时区分生成未完成与外部操作结果未知

客户端可以有限重试或要求修正具体字段,但每次重试都要有上限并记入成本。如果失败源于缺失信息,重复同一输入不会凭空补出事实;若此前已经执行了工具副作用,不能因为解析失败就重放整个任务。

为结构化报告保留来源,可以在自己的 schema 中携带文档 ID、证据位置和版本,再由应用验证。供应商内建 citations 是否能与某种结构输出同时使用属于具体功能兼容问题,不等于“JSON 与可追溯性不能共存”。检索证据的完整性见 RAG。

一个完整的本地校验例子

以下 schema 用于应用侧完整校验,不承诺目标服务能原样支持其中所有关键字。例子依赖 Python 的 jsonschema 包,校验正常结果、缺失结果、额外字段、错误类型和跨字段矛盾;它不调用模型,也不创建订单。

from jsonschema import Draft202012Validator, ValidationError

schema = {
    "type": "object",
    "properties": {
        "sku": {"type": ["string", "null"], "minLength": 1},
        "quantity": {"type": ["integer", "null"], "minimum": 1},
        "status": {"type": "string", "enum": ["complete", "needs_input"]},
    },
    "required": ["sku", "quantity", "status"],
    "additionalProperties": False,
}
Draft202012Validator.check_schema(schema)
validator = Draft202012Validator(schema)

def check(data):
    validator.validate(data)
    fields_present = data["sku"] is not None and data["quantity"] is not None
    if (data["status"] == "complete") != fields_present:
        raise ValueError("状态与字段完整性不一致")
    return data

assert check({"sku": "A1", "quantity": 3, "status": "complete"})["quantity"] == 3
assert check({"sku": "A1", "quantity": None,
              "status": "needs_input"})["quantity"] is None
bad = [
    {"sku": "A1", "quantity": True, "status": "complete"},
    {"sku": "A1", "quantity": 0, "status": "complete"},
    {"sku": "A1", "quantity": None, "status": "complete"},
    {"sku": "A1", "status": "needs_input"},
    {"sku": "A1", "quantity": 3, "status": "complete", "extra": 1},
]
for item in bad:
    try:
        check(item)
    except (ValidationError, ValueError):
        pass
    else:
        raise AssertionError(f"错误结果被接受:{item}")
print("正常/缺失结果通过,5 类无效结果被拒绝")

这个简化数据模型只表达缺失,不表达多商品或冲突。如果真实任务需要这些状态,应增加相应字段和规则,而不能继续沿用 fields_present 作为完整性判据。例子也没有验证 SKU 是否存在、数量是否来自原文、库存是否足够;这些属于来源与业务校验。

执行动作时还要再次核验实时状态。例如提取时库存充足,提交时已经售罄,schema 不可能解决这个竞争。参数校验、业务约束与事务处理必须在对应系统里完成。

把提示与 schema 一起做版本管理

记录提示、schema、模型、SDK 和验证逻辑的版本。字段由可空改为必填、枚举增加新值、数组取代单对象,都可能改变下游行为;不仅要看模型输出,还要验证旧消费者如何处理新版结果。

评估集应覆盖正常输入、缺失、冲突、噪声、长输入、恶意材料和截断。分别统计结构有效率、字段准确率、未知处理是否正确,以及真正的任务成功率。若 JSON 全部合法但事实错了,继续加结构限制未必有效,应回到证据、提示与模型能力定位问题。

保留有意义的少量示例和清楚的约定,删掉相互冲突的重复要求;每次改动都用 评估与可观测 中的任务级比较验证。

继续阅读:上下文工程。