Skip to content

Schema as Prompt

业务代码需要的是字段,不是一段“看起来像 JSON”的文本。Agently 的 .output(...) 让同一份结构同时给模型看,也给 parser 和 validator 用。

Schema as Prompt 是 prompt-native 的结构化输出写法,不是另一套外部 JSON Schema 系统。

最小写法

python
agent.input("整理这条工单。").output({
    "summary": (str, "一句话摘要", True),
    "severity": (str, "P0/P1/P2/P3", True),
    "next_actions": [(str, "下一步动作", True)],
})

叶子元组:

python
(TypeExpr, "description", True)
位置含义
TypeExprPython 类型、typing 表达式、Enum、BaseModel,或字符串 token
description给模型和读者看的字段说明
Trueensure 必填标记

第三槽是 ensure,不是默认值。旧的“第三槽 = default value”约定不再适用。

Object 和 array

dict 表示 object,list 表示数组 prototype:

python
{
    "title": (str, "文章标题", True),
    "tags": [(str, "标签", True)],
    "sections": [
        {
            "heading": (str, "小节标题", True),
            "body": (str, "正文", True),
        }
    ],
}

list 里通常只写一个元素,表示数组中每个元素的形态。字段顺序会被保留,也会影响模型生成顺序。

ensure 会变成路径检查

python
{
    "title": (str, "标题", True),
    "items": [
        {
            "name": (str, "名称", True),
            "value": (str, "值"),
        }
    ],
}

会编译出类似:

python
ensure_keys = ["title", "items[*].name"]

如果 title 缺失,或 items 里任一元素缺少 name,就进入 Output Control 的 retry 流程。value 没有 True,允许缺失。

整套 schema 都要回来时,可以设置 ensure_all_keys: True,或在 YAML/JSON prompt 顶层写 $ensure_all_keys: true

YAML 写法

yaml
output:
  title:
    $type: str
    $desc: 标题
    $ensure: true
  items:
    $type:
      - name:
          $type: str
          $desc: 名称
          $ensure: true
        value:
          $type: str
          $desc: 

推荐字段:

  • $type:类型表达。
  • $desc:字段说明。
  • $ensure: true:必填标记。

.type / .desc 等别名仍可被 loader 接受,但新文档和新 prompt 推荐 $ 前缀。$default 不再支持。

字符串类型 token

配置文件里常用字符串表达类型:

Token含义
strintboolfloat标量类型
list[str]字符串数组
dict[str, int]dict typing 形态
Literal[open, closed]字面量枚举
Optional[str]可选字符串

简单字段可以先用标量和数组。复杂数据结构再引入 Pydantic。

Pydantic 和 Enum

python
from enum import Enum
from pydantic import BaseModel


class Severity(str, Enum):
    P0 = "P0"
    P1 = "P1"
    P2 = "P2"


class Ticket(BaseModel):
    severity: Severity
    rationale: str


result = agent.input("判断工单等级。").output(Ticket).get_result()
ticket = result.get_data_object()

output() 接收 BaseModel 时,可以用 get_data_object() 读取 Pydantic 实例。

字段顺序怎么设计

把支撑信息放在结论前面:

python
.output({
    "facts": [(str, "输入中的事实", True)],
    "risk_reason": (str, "风险原因", True),
    "risk_level": (str, "high / medium / low", True),
    "customer_reply": (str, "客户回复", True),
})

这样模型先整理事实,再给判断和回复。不要要求模型输出隐藏推理过程;只暴露业务系统确实要保存和消费的字段。

什么时候不用它

只需要一段自由文本时,不要写 .output(...)

python
result = agent.input("写一封 200 字以内的客户邮件。").get_result()
text = await result.async_get_text()

只要下游需要保存字段、做分支、校验或展示,就回到 .output(...)

边界

Schema as Prompt 是单次模型请求的 authoring 层,不是:

  • 外部 API 契约里的 JSON Schema 替代品。
  • TriggerFlow contract。
  • UI 表单定义。

早期把 .output()、TriggerFlow contract 和外部 schema 统一为一个 DSL 的方向已经归档。每个消费者保留自己的入口。

常见误用

  • 手写“请返回 JSON”,却不写 .output(...)
  • 把第三槽当默认值。
  • list 里写多个不同示例,导致数组 prototype 不清楚。
  • 把 UI 表单 schema 直接等同于模型输出 schema。
  • 要求模型输出一堆不会被业务使用的“推理字段”。

下一步