打开网易新闻 查看精彩图片

去年有个医疗SaaS团队找我复盘:他们的AI客服能流畅对话,但每100单里有37单需要人工二次录入。问题不在模型,在输出格式——大模型给的总结再漂亮,下游系统也读不懂。

这37%的返工率,本质是"人机接口"设计失误。

我翻遍他们的代码,发现工程师写了整整200行正则表达式,试图从自由文本里提取"是否需预授权""自付额多少"。正则越写越长,bug越修越多。他们不知道的是,OpenAI在2023年8月就发布了结构化输出(Structured Outputs)功能,只是藏得比较深。

这篇文章讲一个被严重低估的设计模式:把大模型输出当成API契约,而非聊天内容。

想象你让AI处理一份保险核保回复。自由文本输出可能是这样:

"患者保障似乎在Gold Plus计划下有效。根据支付方措辞,可能需要预授权,但不太确定。自付额大概在50到75美元之间,每月可能有30片的数量限制。"

这段文字人类读起来毫无障碍。但你要写代码处理它时,问题接踵而至:"似乎有效"等于确认覆盖吗?"可能需预授权"是要还是不要?自付额是50还是75?下次回复写成"一月供应量"或"qty limit: 30 units",你的提取逻辑直接失效。

我在生命科学领域做过多个受监管场景的AI agent——福利验证、临床试验中心筛选、医学咨询回复。每个场景都需要驱动下游自动化:更新记录状态、创建跟进任务、路由异常、触发工作流下一步。

早期实现全踩了同一个坑:让大模型返回自然语言总结,再试图解析。有时写正则,有时加第二次大模型调用"提取字段",有时干脆让人工重读总结手动填表。

每种方案都很脆弱,因为依赖大模型在措辞上保持一致——而一致性正是大模型不保证的东西。

结构化输出是带定义模式的JSON对象,大模型必须严格遵循。不是问"总结这份支付方回复",而是问"从这份支付方回复中提取以下字段,以JSON返回"。

福利验证总结的输出契约长这样:

{
"coverageConfirmed": true,
"priorAuthRequired": false,
"copayNotes": "$50 copay per fill",
"deductibleNotes": "$500 annual, not yet met",
"limitationsNotes": "Specialty pharmacy required",
"missingInfo": ["Effective date not stated"],
"confidence": 82
}

每个字段有类型,每个字段有用途。下游逻辑变得极其简单:

// 这就是全部路由逻辑。无需解析,无需解释。
if (summary.missingInfo.length === 0 && summary.confidence >= 75) {
status = "Verified";
} else {
status = "Needs Follow-up";
for (const item of summary.missingInfo) {
createTask(`Follow up: ${item}`, recordId);
}
}

对比从自由文本提取同样决策的代码:需要处理"可能""大概""似乎"等模糊词,需要应对同一概念的不同表述,需要容错拼写变体。50行代码缩成5行,bug率下降一个数量级。

打开网易新闻 查看精彩图片

一旦把结构化输出视为契约,其他设计决策会自然收敛。我总结了三个关键原则:

原则一:字段命名要对应下游动作,而非上游描述

坏例子:"payerResponseSummary"——下游不知道拿它怎么办。
好例子:"priorAuthRequired"——直接驱动if/else分支。

字段名是接口,不是文档。每个字段都应该回答"下游系统需要知道什么才能推进工作流"。

原则二:显式处理不确定性,而非追求流畅

自由文本喜欢用"可能""大概"来保持流畅,但这让自动化无从下手。结构化输出用独立字段承载不确定性:

"coverageStatus": "active",
"coverageConfidence": 82,
"coverageNotes": "Member ID verified, effective date not confirmed"

状态、置信度、备注分离,下游可以制定精确规则:置信度>90直接通过,70-90人工复核,<70触发补充查询。

原则三:预留扩展槽,但先验证核心闭环

我见过团队在第一个版本就设计20个字段,结果3个月后发现一半用不上,另一半不够用。更好的做法:先定义5个能走完完整工作流的字段,上线跑通,再按需扩展。

JSON模式支持可选字段和默认值,这是你的扩展槽。但别为了"未来可能用"而增加复杂度——每个字段都是契约条款,需要测试覆盖。

具体怎么落地?我分三个阶段:

阶段一:冻结输出格式(1-2周)

选一个已有工作流,把当前人工处理的决策点列出来。每个决策点对应一个字段。用OpenAI的JSON模式或Zod模式(如果你用TypeScript)强制输出结构。

关键动作:在提示词里放示例输出,但明确说明"这是格式示例,值来自实际输入"。大模型对格式模仿能力很强,但需要边界清晰。

阶段二:建立验证层(2-4周)

打开网易新闻 查看精彩图片

结构化输出不能保证值正确,只能保证格式合规。需要加一层验证:必填字段是否存在?枚举值是否在允许集合内?数值范围是否合理?

这层验证用代码写,不要用另一个大模型。契约的契约应该是确定性的。

阶段三:闭环优化(持续)

收集两类数据:验证层拦截的错误(格式合规但值明显错误)、下游系统反馈的误判(格式和值都对但决策错误)。前者优化模式定义,后者优化提示词和模型选择。

我在一个医学咨询项目中,通过三个月的闭环迭代,把"需人工复核"的比例从41%压到12%。主要改进不是换更强的模型,而是把模糊字段拆成更精确的组合字段。

最后提醒几个我踩过的坑:

反模式一:把JSON当字符串生成

有些实现让大模型生成JSON格式的文本,再用JSON.parse()解析。这完全没解决问题——大模型可能生成非法JSON,解析报错直接中断流程。要用原生支持结构化输出的API(OpenAI的response_format: {type: "json_object"}或function calling),让模型在token层面就遵循模式。

反模式二:模式设计受限于当前模型能力

早期GPT-4处理复杂嵌套模式容易出错,于是团队把模式拍扁成简单列表。但模型能力在进化,模式应该反映业务需求而非当前模型限制。我的做法:用最强模型设计理想模式,用验证层降级处理——复杂模式生成失败时,回退到简单模式并标记置信度降低。

反模式三:忽视人机协作界面

结构化输出是给机器读的,但人需要调试和例外处理。每个agent都应该有两个出口:结构化输出给下游系统,同时生成一段人类可读的摘要用于审核。这两份输出从同一份输入生成,但目的不同,不要试图用一份输出兼顾。

我在一个福利验证项目中,最初让模型同时返回JSON和摘要,结果摘要质量下降——模型注意力被分散。后来改成两次调用:第一次生成结构化输出,第二次用结构化输出作为输入生成摘要。成本增加一点,但两边质量都达标。

大模型demo和生产力工具之间,差的就是这层契约设计。自由文本适合探索性场景,结构化输出适合运营性场景。大多数B端AI应用属于后者,却在前者的架构上硬撑。

那个医疗SaaS团队后来重构了核心工作流,把37%的返工率压到4%。他们的CTO跟我说了个细节:以前工程师最怕接"优化核保流程"的工单,因为每次改提示词都可能破坏正则解析;现在他们敢每周迭代,因为契约边界清晰,改一边不会意外破坏另一边。

这大概就是软件工程里"解耦"的老道理,只是换了个新场景重新学一遍。

你现在的AI项目里,有多少"看起来能用"的自由文本输出,正在等着下游某个时刻崩溃?