
客服系统最危险的自动化不是模型答错一句话而是把“退款 9999 元”当成真指令一路执行。结构化输出Structured Outputs能要求模型按 JSON Schema 返回字段但它不是业务真相。你还需要第二道本地门金额、枚举值和缺失字段必须由程序复核。本篇用一个可复制的 Python 骨架完成这件事。官方 Responses API 参考说明json_schema可用于受约束的 JSON 输出且较旧的json_object不推荐优先使用。模型、权限与配额以你的账号为准。示例为了可离线验证先用模拟响应接入时只替换call_model密钥仅从环境变量读取。通过拒绝用户文本模型按 JSON Schema 提取JSON 对象本地字段/金额校验进入人工队列记录原因并回问环境准备需要 Python 3.10。演示没有第三方依赖真实请求可安装pip install openai并设置export OPENAI_API_KEY...。不要把密钥写进源码。下面代码的超时参数放在真实调用处避免网络问题无限等待。importjson,osfromdecimalimportDecimal ALLOWED{refund,shipping,other}MAX_REFUNDDecimal(500.00)SCHEMA{type:object,properties:{category:{type:string},amount:{type:string},summary:{type:string}},required:[category,summary]}defcall_model(text:str)-dict:# 真实接入确认 os.getenv(OPENAI_API_KEY) 非空# 使用客户端 timeout20并传 text.format{type: json_schema, ...}。ifnotos.getenv(OPENAI_API_KEY):return{category:refund,amount:128.50,summary:text}raiseRuntimeError(示例未在本次任务中实际调用线上 API)defvalidate(ticket:dict)-tuple[bool,str]:ifnotisinstance(ticket.get(summary),str)ornotticket[summary].strip():returnFalse,缺少摘要ifticket.get(category)notinALLOWED:returnFalse,未知分类ifticket.get(category)refund:try:amountDecimal(ticket.get(amount,-1))exceptException:returnFalse,金额不是十进制数ifnot(Decimal(0)amountMAX_REFUND):returnFalse,金额超出自动队列范围returnTrue,QUEUED_FOR_REVIEWif__name____main__:ticketcall_model(订单 A12 重复扣款请退 128.50 元)ok,reasonvalidate(ticket)print(json.dumps({ticket:ticket,ok:ok,reason:reason},ensure_asciiFalse))运行python ticket.py在未设置密钥时预期看到ok: true和QUEUED_FOR_REVIEW它只进入人工队列不会退款。关键点是 Schema 解决形状本地validate解决业务边界。常见失败有三类模型漏字段要求 Schema 的 required 字段并回问金额带“元”或逗号拒绝后让模型只输出数字字符串网络慢或 429真实调用设 20 秒超时并指数退避不要在超时后盲目重试有副作用的动作。适合把自由文本变成工单、表单和审核草稿不适合拿模型结果直接放款、删库或处理医疗结论。工程化时为每条记录保存原文、模型版本、Schema 版本和校验结果再用脱敏历史样本统计拒绝率。5 分钟实践新增priority枚举只让high工单走人工复核写一个断言验证未知优先级会被拒绝。你的工单系统里哪一个字段绝不能只相信模型输出关注「蜗牛聊AI」一起看懂技术变化背后的真正机会。本文首发于 java4u.cn转载请注明出处。