本节摘要:模板生成是最基础的 NLG——预写句子、填入数据。本节讲清模板的写法、变量填充、条件模板、以及"模板 = 可控性"的核心理解(什么时候用模板)。
阅读完本节,你应当能够:
"明天有 2 个航班,最早 8:00 起飞"——这句话怎么生成的?最直接的方式是模板:预写好句子骨架,把数据填进去。模板生成"可控但死板",却是生产系统最常用的方案——因为格式可控、不会出错。
模板生成的流程:
模板:"明天有 {count} 个航班,最早 {time} 起飞" 填充:count=2, time=8:00 结果:"明天有 2 个航班,最早 8:00 起飞"
| 维度 | 模板 | 自由生成 |
|---|---|---|
| 可控性 | 高 | 低 |
| 自然度 | 中 | 高 |
| 出错率 | 低 | 高 |
| 开发量 | 手写多 | 训练模型 |
💡 关键直觉:模板 = 用"开发量"换"可控性"——格式要求严、不能出错的场景(订单、余额、政策),模板是安全选择。
if 有航班 → "有 {count} 个航班" if 无航班 → "抱歉,当天没有航班" if 查询失败 → "暂时查不到,请稍后再试"
⚠️ 常见坑:模板覆盖不全。只写了"有航班"的模板,没写"无航班"——真实场景一出现空结果就崩。模板要覆盖所有分支,包括异常分支。
按场景分模板组 变量校验(别填错格式) 多语言/多语气版本
表达单一:所有回复一个句式 扩展费劲:新场景新模板 改进:模板 + 随机变体 + 局部生成
模板打底了,下一节进阶——深度学习生成。
模板看似简单,规模化之后同样需要"工程管理"。这一节把模板从"写一个"升级到"维护一组"的实践讲清楚。
模板的组织:按业务场景分组成模板库,每条模板有唯一编号、适用条件、变量列表和异常分支。结构示意:
flight_result / found : "明天有 {count} 个航班,最早 {time} 起飞" flight_result / empty : "抱歉,当天没有航班" flight_result / fail : "暂时查不到,请稍后再试" flight_result / confirm : "确认出发日期是 {date},目的地 {dest} 吗?"
同一场景至少覆盖三条路径:正常、空结果、失败——缺任何一条,线上就会在对应场景"哑火"。
变量校验:模板里的变量填入前必须做格式校验,防止"把 0 填成 0.0""把日期填成时间戳"这类问题:
# 概念示意:变量校验 def render_flight(tmpl, count, time): assert count > 0, "count 必须为正数" assert isinstance(time, str) and ":" in time, "time 需为 HH:MM" return tmpl.format(count=count, time=time)
模板的演进:纯模板表达单一、扩展费劲,演进路径通常是:纯模板 → 模板 + 同义变体(同一条信息多套句式随机选)→ 模板 + 局部生成(固定骨架,片段用模型填充)。每演进一步,自然度提升一点,但可控性要守住——核心信息(金额、时间、订单号)永远走模板保证准确,只有修饰性片段交给模型。
模板适用场景判断:格式要求严、信息必须准确、出错成本高的场景(订单结果、余额查询、政策告知),模板是第一选择;需要自然表达、信息允许变通的场景(闲聊、开放问答),再考虑生成式。评估模板质量的简单方法:把每种分支用真实数据跑一遍,检查"每一条信息是否都对、每一句是否都通顺"。
动手为一个场景写齐整套模板分支:场景是"航班查询结果",结构化数据包含出发日期、目的地、航班数、最早时刻。请写出五条模板:有航班且多条、只有一班、当天无航班、查询失败、以及一条"用户未指定日期时"的追问模板。写完后对照检查三点:一是变量是否全部校验(航班数不能为负、时刻格式统一);二是异常分支是否齐全(空结果、失败各有一套话术,而不是复用正常话术);三是语气是否一致(都在同一角色设定下)。这套练习做完,你会发现模板生成的难点从来不在"写一句话",而在"把所有分支都想全"。把分支清单写进模板规范文档,是模板工程化的第一步。