
很多后端服务接入大模型后,代码结构看起来没变:Controller 调 Service,Service 调一个模型客户端,再把结果返回给前端。真正的变化藏在依赖性质里——数据库超时就是超时,规则引擎给出结果就是确定结果,而模型可能延迟、拒答、输出半段 JSON,甚至格式完全正确地给错内容。
所以 AI 原生后端不是多装一个 SDK,而是给一个非确定性依赖补上过去由确定性组件天然提供的契约。
不要让模型返回一段解释,再用正则从里面抠字段。把输出定义成明确 Schema,并在反序列化后执行领域校验:
record TicketResult(String category, String priority, double confidence) {}
TicketResult classify(String text) {
String raw = chatClient.prompt()
.system("只输出符合 Schema 的 JSON,不要 Markdown")
.user(text)
.call().content();
TicketResult r = objectMapper.readValue(raw, TicketResult.class);
if (!Set.of("billing", "bug", "feature", "other").contains(r.category())) {
throw new ModelOutputInvalidException("unknown category");
}
if (r.confidence() < 0 || r.confidence() > 1) {
throw new ModelOutputInvalidException("bad confidence");
}
return r;
}解析失败、字段缺失、枚举越界,都应像调用任何外部 API 一样进入明确的异常路径,而不是带着脏数据继续向下游传播。
模型给出的 confidence 可以当参考,但不能天然等同于真实概率。更可靠的做法是把多种信号组合成复核规则:Schema 校验是否通过、关键字段是否缺失、检索证据是否覆盖结论、业务规则是否冲突、模型自评置信度是否过低。
低置信结果可以走三条路:缩小为保守答案、请求用户补充信息、转人工处理。关键是提前决定由谁在什么条件下接管。一个 85% 正确但拥有可靠退出机制的功能,通常比 95% 正确、剩下 5% 静默出错的功能更容易上线。
生产 Prompt 不是随手写在代码里的长字符串,它实际上规定了输入、约束、异常行为和输出协议。修改一句“请详细分析”可能让 JSON 后面多出解释;删一个 few-shot 示例,可能让某类历史工单重新误分类。
建议把以下内容放进同一个可版本化配置包:系统提示词、输入模板、输出 Schema、示例、适用模型、超时和降级策略。每次变更都跑固定的真实故障样本集,记录通过率和结构错误率。发布时像数据库迁移一样保留版本号,出现问题能明确回滚到上一套契约,而不是在聊天记录里找“之前那句 Prompt”。
不是所有请求都值得调用最贵模型。简单分类走小模型,复杂推理走大模型,检索失败时停止生成,供应商超时后切换到备用路径——这些决策应由应用层路由完成,而不是再写进 Prompt 让模型自己决定。
分类/抽取 -> 小模型 -> Schema 校验 -> 业务处理
复杂分析 -> 大模型 -> 证据校验 -> 必要时人工复核
模型超时 -> 有界重试 -> 备用模型或规则路径 -> 明确降级结果重试必须有上限,并区分“网络失败”和“内容校验失败”。前者重试可能恢复,后者原样重试往往只会得到另一种错误表达。
超时、熔断、幂等、背压、容量规划,在模型服务里依然有效,只是成本单位从连接数和 CPU 变成了 Token、KV Cache 与 GPU 时间。自建模型也不是天然省钱:流量波动大时,低利用率 GPU 可能比托管 API 更贵。
真正值得建立的能力不是记住某个框架的 API,而是把模型当成一个可能慢、可能错、可能不可用的外部依赖。输出有 Schema、不确定有出口、变更有版本、故障有降级,这四件事补齐后,AI 功能才从 Demo 变成可以值守的后端系统。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。