先抓住一次假成功
你对日程助手说:“把周五的周会改到下午4点。”
AI回答:“好的,已经帮你修改完成。”
现在打开数据库。日程没有变化。
这句话语法正确、态度友好,甚至还有点体贴。但它没有告诉程序要修改哪条记录,也不能证明任何操作已经发生。它只是说得像完成了。
如果AI只陪你聊天,这可能只是一次错误回答。如果它负责日程、文件、邮件或付款,这就是产品事故。
结构化输出的作用,是把AI的候选答案放进程序能够逐项检查的格子里。
十秒演示:让程序读下面两句话
第一份输出:
好的,我会在明天下午提醒你参加项目会。
第二份输出:
{
"action": "create_event",
"title": "项目会",
"start_at": "<ISO 8601 datetime with timezone>",
"reminder_minutes": 15
}
现在问程序四个问题:操作类型是什么?标题是什么?时间在哪里?提前多久提醒?
第一份需要程序重新猜句子。第二份可以直接找到对应字段。这就是最基本的区别。
不过别急着宣布胜利。第二份虽然整齐,时间仍可能理解错,提醒也可能不合理。结构化输出让检查成为可能,但没有替你完成检查。
自然语言和程序各自擅长什么
用户可以用许多方式表达同一件事:
- 明天下午3点提醒我开会。
- 帮我记一下,明天15点有个会。
- 明天三点安排项目会议,提前15分钟叫我。
AI擅长从这些变化中提取意图。数据库却不能把“差不多这个意思”写进时间列。它需要明确的动作、时间、时区、标题和提醒分钟数。
所以工作应该分开:
人负责自然表达
AI负责提出候选理解
程序负责验证和执行
让AI直接承担最后一步,就是把概率判断当成确定事实。
JSON不是魔法,Schema才说明格子怎么画
JSON只是一种写数据的方法。下面也是合法JSON:
{"banana":"Tuesday","duration":-9000}
程序能解析它,但它对日程没有意义。
Schema规定字段和规则,例如:
action只能是允许的动作。title必须是字符串。duration_minutes必须是合理范围内的正数。- 创建操作必须有开始时间。
- 删除操作必须能够定位目标。
JSON Schema官方资料把验证描述得很直接:验证器接收一份Schema和一份JSON实例,然后返回它是否符合规则。
这仍然只解决“数据有没有按格子填”。它没有证明格子里的事实正确。
四道关,少一道都不行
看这份输出:
{
"action": "delete_event",
"event_id": 42
}
它要经过四道关。
第一关:能不能读
JSON语法是否合法?如果少了引号或括号,程序连数据都拿不到。
第二关:形状对不对
字段、类型和允许值是否符合Schema?event_id是不是系统要求的类型?
第三关:事情讲不讲得通
编号42的日程是否存在?它是否已经删除?修改后的结束时间会不会早于开始时间?
第四关:允不允许做
这条日程属于当前用户吗?用户是否真的要求删除?批量操作是否需要再次确认?
前两关是结构检查,后两关是业务与权限检查。模型通过前两关,仍然可能在后两关犯大错。
合法JSON不是正确答案。表格填得漂亮,也可能整张表都是假的。
信息不够时,正确答案是停下来
用户说:“把周会改到4点。”数据库里却有周五上午和周五下午两场周会。
如果系统的Schema只允许create、update和delete,模型会被迫猜一个动作。更可靠的设计应该允许:
{
"action": "clarify",
"question": "你指的是上午还是下午的周会?",
"candidates": [
{"event_id": "<candidate A>", "start_at": "<datetime A>"},
{"event_id": "<candidate B>", "start_at": "<datetime B>"}
]
}
停止不是失败。信息不足时还敢执行,才是失败。
可靠的结构至少要容纳三种结果:继续、追问、拒绝。模型自报的置信度只能作为参考,不能单独决定是否删除数据。一个人很自信地答错,答案不会因此变对;模型也一样。
时间最适合揭穿假理解
“明天下午”“下周五”“月底前”看起来简单,实际上依赖:
- 当前日期和时间。
- 用户时区。
- 本地日历约定。
- 默认时长和提醒规则。
- 月份边界和夏令时。
做个实验:在周日晚上接近零点时,让系统解释“下周一”。换一个时区,再做一次。结果是否一致?用户看到的日期是否正确?
如果系统没有把可信的当前时间和时区提供给模型,模型只能猜。它完全可能输出格式标准、内容错误的时间戳。
时间必须由后端再次解析和标准化,再以用户熟悉的本地时间展示确认。
Tool Calling没有取消验证
Prompt告诉模型任务背景和规则。Schema规定参数形状。Tool Calling让模型从预先定义的工具中提出调用意图。支持受约束输出的模型接口还能减少格式错误。
这些能力很有用。但“模型调用了工具”仍然不是安全证明。
如果工具参数里写着删除别人的日程,后端必须拒绝;如果时间不合理,必须追问;如果外部服务超时,不能宣布完成。
给按钮贴上Tool Calling标签,不会让按钮后面的程序自动可靠。名字不是机制。
做个失败实验
拿同一个日程功能测试这些输入:
- “明天下午提醒我。”缺少具体事项和时间。
- “删除周会。”存在两条同名日程。
- “把会议改到2月30日。”日期不存在。
- “删除所有人的会议。”当前用户没有权限。
- 同一个创建请求连续发送两次。
- 数据库写入前突然断网。
观察系统是否会:追问、拒绝、避免重复、如实说明未知状态。
这比展示十次正常输入更能证明结构化输出设计是否可靠。只演示成功案例,是货物崇拜测试。
失败时别让模型无限“修一下”
输出无法解析时,可以在有限次数内请求模型按校验错误修正。无限重试只会增加延迟和成本,还可能把一次明确失败磨成一份表面合法的错误数据。
更诚实的处理是:有限重试,仍失败就停止;告诉用户没有执行;保留脱敏错误类型;让用户改写或手动填写。
系统能够明确失败,是可靠性的一部分。
怎样验证理解
下面这些外观不能证明系统已经可靠:
- 模型返回了JSON。
- JSON通过了Schema验证。
- 页面展示了“Tool Calling”。
- 十个正常样例全部成功。
去掉这些标签,测试含糊时间、同名日程、越权操作、重复请求和执行超时。系统能不能停止、追问、拒绝,并对没有完成的事情保持诚实?这才是结构化输出的核心目的。
你真的搞清楚了吗
试着回答:
- 为什么“请返回JSON”还不够?
- Schema验证通过后,为什么仍不能直接删除日程?
- 信息不足时,结构应该怎样表达“先别做”?
- Tool Calling和真正执行工具是什么关系?
- 怎样用一个反例证明系统不是只会处理正常输入?
- 如果不能使用“JSON”“Schema”“结构化”三个词,你怎样向六年级学生解释这件事?
最后一题可以这样开始:先把AI的答案填进固定表格,程序逐格检查,检查不过就不动真实数据。
我现在知道什么,还不知道什么
我现在能确定:结构化输出是AI与程序之间的检查面。它让模型负责理解语言,让程序继续负责规则、权限、执行和结果。
截至2026年8月28日的应用验收记录,拾时已有Tool Calls、受控操作计划、意图校验及失败路径测试。本文的JSON是教学示例;真实登录、用户级外部日历及退出后的通知仍未完成验收。
资料与验证范围
- 项目依据:
docs/WEBSITE_VISION.md中自然语言日程与“检查草稿、确认创建”的产品规划。 - 相关内容:《API到底连接了什么》。
- 底层资料:JSON Schema官方入门、JSON Schema规范入口。
- 发布前待核对:拾时应用代码、实际模型服务官方文档、Schema、时间解析、权限、重试和幂等测试。