如何使用AWS Lex单个槽位处理日期、时长及日期范围?
AWS Lex单槽位统一处理日期/时长/日期范围输入的相对时间捕获方案
直接按以下步骤实现,不需要拆分多个槽位,单槽位即可覆盖三类时间输入,包括“上周”“上月”这类相对时间表述:
第一步:自定义槽位基础配置
- 新建自定义槽类型,不要使用Lex内置的
AMAZON.Date/AMAZON.Duration等内置时间槽,内置槽对中文相对时间、范围类时间的解析准确率极低,且无法混合识别三类时间。 - 槽值返回类型选择原始字符串(Original Value),关闭内置值解析。
- 槽类型的枚举训练样本覆盖三类时间的高频口语表述即可,比如“上周”“上月”“3天”“1号到5号”“下周一”这类,不需要穷举,依靠Lex的ML泛化能力即可识别变体表述。
第二步:Lambda端分层解析逻辑
拿到槽位返回的原始字符串后,按三层优先级解析,优先保证高概率表述的解析准确率:
固定规则匹配层(覆盖80%以上高频相对表述)
提前把“上周”“上月”这类固定语义的相对时间写成正则匹配规则,命中后直接计算对应时间值,同时标记输入类型(单日期/时长/日期范围),示例代码如下:import re from datetime import datetime, timedelta from dateutil.relativedelta import relativedelta import pytz # 规则格式:(匹配正则, 计算函数),返回值:(单日期值, 输入类型, 范围起始值, 范围结束值, 时长值) FIXED_RELATIVE_RULES = [ (re.compile(r"^(上周|上星期|上一周)$"), lambda m: ( None, "date_range", (datetime.now() - relativedelta(weeks=1, weekday=0)).date(), (datetime.now() - relativedelta(weeks=1, weekday=4)).date(), None )), (re.compile(r"^(上月|上个月|上一个月)$"), lambda m: ( None, "date_range", (datetime.now() - relativedelta(months=1)).replace(day=1).date(), (datetime.now().replace(day=1) - timedelta(days=1)).date(), None )), (re.compile(r"^昨天$"), lambda m: ( datetime.now().date() - timedelta(days=1), "date", None, None, None )), (re.compile(r"^近(\d+)天$"), lambda m: ( None, "date_range", (datetime.now() - timedelta(days=int(m.group(1)))).date(), datetime.now().date(), None )), (re.compile(r"^(\d+)(小时|分钟|天)$"), lambda m: ( None, "duration", None, None, timedelta(**{m.group(2): int(m.group(1))}) )) ] def match_fixed_rule(input_str): for pattern, calc_func in FIXED_RELATIVE_RULES: match_res = pattern.match(input_str.strip()) if match_res: return calc_func(match_res) return None这层可以直接精准覆盖“上周”“上月”这类固定相对时间表述,不会出现解析偏差。
模糊语义解析层(兜底长尾表述)
没有命中固定规则的输入,直接用中文时间解析库做模糊匹配,Python环境用dateparser即可,原生支持绝大多数中文相对时间表述,比如“大前天”“下下周一”“去年双十二”这类不需要单独写规则的表述,解析时注意传入当前时间作为基准,避免时区偏移:import dateparser def fuzzy_parse(input_str, timezone="Asia/Shanghai"): base_time = datetime.now(tz=pytz.timezone(timezone)) parsed = dateparser.parse( input_str.strip(), languages=["zh"], settings={"RELATIVE_BASE": base_time, "TIMEZONE": timezone} ) # 补全类型判断逻辑:根据解析结果特征区分单日期、日期范围、时长 return parsed歧义兜底逻辑
如果前两层都没有返回合法的时间结果,直接触发槽位澄清,让用户补充明确的时间信息即可,不需要强行解析低置信度输入。
关键踩坑点
- 所有时间计算必须绑定Lex会话传入的用户时区,不要直接用Lambda运行环境默认的UTC时间,否则会出现8小时的时间偏移。
- 自定义槽位不要开启值校验,否则非标准表述会被Lex直接拦截,根本传不到Lambda。
- 规则匹配优先于模糊解析,固定表述的解析准确率可以做到100%,比通用解析库的结果更可控。
内容的提问来源于stack exchange,提问作者Shahrukh Gouhar
相关产品推荐
相关产品推荐

