让大模型做业务决策:结构化输出与规则兜底
让大模型做业务决策:结构化输出与规则兜底
把「要不要给这个用户发优惠券」「这条工单转给谁」这类业务决策交给大模型,听起来很美好——直到它在生产环境跑了三天:同一输入昨天返回 JSON、今天返回一段散文;置信度 0.98 的决策依据是一段它编出来的用户画像。这篇讲一套在实践里站得住的三层决策架构。
一、三个必踩的坑
| 坑 | 表现 | 根因 |
|---|---|---|
| 输出漂移 | 同一输入,格式/结论随机变化 | 自然语言生成天然非确定 |
| 幻觉决策 | 给出高置信度但依据不存在 | 模型补全倾向压过事实约束 |
| 无法审计 | 业务问「为什么批了这笔」,答不出 | 决策过程是黑盒 token 流 |
三个坑的共性:把大模型当「决策系统」用,而它只是「决策信号源」。定位摆正,方案就顺了。
二、三层架构:模型给信号,规则做决策,日志保审计
请求 → [规则层] 命中硬规则?→ 是 → 直接出决策(可解释、可审计)
↓ 否
[模型层] LLM 结构化输出 → 校验通过 → 决策 + 置信度
↓ 校验失败/低置信
[兜底层] 保守默认值 / 转人工
关键设计:规则层在前不在后。能被确定性规则覆盖的决策(黑名单、阈值、白名单)绝不进模型——既省调用成本,又保证这部分决策 100% 可审计。模型层只处理规则覆盖不了的灰度地带。
三、模型层:结构化输出的最小实现
结构化输出不是「提示词里说请返回 JSON」——那不叫约束。用 schema 强约束 + 严格校验:
from pydantic import BaseModel, ValidationError
class Decision(BaseModel):
approve: bool
confidence: float # 0~1
reason_code: str # 枚举:reason_*,禁止自由文本
evidence: list[str] # 必须引用输入里的事实
def decide(payload) -> Decision:
resp = llm.create(
model="...",
response_format={"type": "json_object"}, # 硬约束 JSON
messages=[system_prompt(payload), user_payload(payload)],
)
try:
d = Decision.model_validate_json(resp)
except ValidationError:
return FALLBACK # 校验失败即兜底,不重试硬凑
return d if d.confidence >= 0.7 else FALLBACK
两个工程细节比模型选型更重要:
- reason_code 用枚举:理由必须落在预定义码表里(
reason_blacklist_hit/reason_low_activity…)。自由文本的理由等于没有理由——审计时没法聚合统计 - evidence 必须回指输入:要求模型引用输入 payload 里真实存在的字段值,幻觉率显著下降——编造比引用费劲
四、兜底层:宁可保守,不可玄学
校验失败、低置信、超时,一律走兜底:保守默认值或转人工。不要让模型「再试一次」——重试只是在采样另一个随机数,失败成本(错误决策)远高于兜底成本(少自动决策一笔)。
五、选型时看什么
决策类场景选模型服务,除了兼容性和延迟,重点看结构化输出是否硬约束(JSON mode / schema 约束)和用量明细能否按请求回溯——前者决定校验层的工作量,后者是审计的原料。按量计费的平台在这类场景有天然优势(如算邻坊 suanlinfang.cn 的智能决策接口,决策链路每一步调用可回溯,配 reason_code 聚合正好凑齐审计闭环)。
六、小结
大模型进决策链路的正确姿势:规则层挡住确定性、模型层只接灰度、schema+枚举锁死输出、兜底层兜住一切异常。四件事都做了,「为什么批了这笔」就永远有答案——业务信任不是靠模型更聪明,是靠每一层都可解释。
浙公网安备 33010602011771号