如何配置Boto3的retrieve_and_generate函数实现AWS Bedrock知识库的日期范围过滤(基于OpenSearch)
我之前在使用Bedrock的retrieve_and_generate搭配OpenSearch知识库做日期过滤时,也踩过几乎一模一样的坑!核心问题出在日期值的类型和格式传递上,尤其是你遇到的浮点数科学计数法解析错误,其实是boto3序列化大整数时的默认行为导致的。下面给你分享我实测有效的解决方案:
核心问题分析
你尝试用epoch毫秒的时候,OpenSearch报错无法解析1.6015104E12,这是因为当你把epoch毫秒转成整数后,boto3在把请求序列化成JSON时,会把超过一定大小的整数自动转换成浮点数(用科学计数法表示),而OpenSearch的epoch_millis格式只接受整数类型的毫秒数,自然就解析失败了。
而用字符串日期的时候如果报错,大概率是你传递的格式没有匹配OpenSearch默认支持的日期格式(默认是strict_date_optional_time||epoch_millis,完美兼容ISO 8601标准格式)。
最优解决方案:用ISO 8601标准字符串传递日期
直接使用UTC时区的ISO 8601格式字符串(比如2024-01-30T00:00:00Z)是最稳妥的方式,既不需要担心类型转换问题,OpenSearch也能完美解析。
步骤1:修改日期处理代码
把你Lambda函数里的日期转换逻辑改成直接生成标准ISO 8601字符串,替换原来的epoch毫秒转换:
import datetime from datetime import timezone def lambda_handler(event, context): # ... 其他原有代码 ... filters = [] pub_date_gte = body.get('publication_date_gte') pub_date_lte = body.get('publication_date_lte') # 处理起始日期 if pub_date_gte: try: # 兼容两种输入格式:yyyy-MM-dd 或者 带时区的ISO字符串(比如2024-01-30T12:00:00Z) if 'Z' in pub_date_gte or '+' in pub_date_gte: # 处理带时区的输入 pub_date_obj = datetime.datetime.fromisoformat(pub_date_gte.replace('Z', '+00:00')) else: # 处理yyyy-MM-dd格式,默认转成UTC的0点 pub_date_obj = datetime.datetime.strptime(pub_date_gte, '%Y-%m-%d').replace(tzinfo=timezone.utc) # 生成标准ISO 8601字符串(带Z后缀) pub_date_gte_str = pub_date_obj.isoformat().replace('+00:00', 'Z') filters.append({ "greaterThanOrEquals": { "key": "effective_date", # 对应你OpenSearch里的日期字段名 "value": pub_date_gte_str } }) except ValueError as e: print(f"无效的日期格式:{e}") # 可以根据需求添加错误处理逻辑 # 处理结束日期(同理) if pub_date_lte: try: if 'Z' in pub_date_lte or '+' in pub_date_lte: pub_date_obj = datetime.datetime.fromisoformat(pub_date_lte.replace('Z', '+00:00')) else: pub_date_obj = datetime.datetime.strptime(pub_date_lte, '%Y-%m-%d').replace(tzinfo=timezone.utc) pub_date_lte_str = pub_date_obj.isoformat().replace('+00:00', 'Z') filters.append({ "lessThanOrEquals": { "key": "effective_date", "value": pub_date_lte_str } }) except ValueError as e: print(f"无效的日期格式:{e}") # 组合过滤器(原有逻辑保留) if filters: chat_filter = {"andAll": filters} else: chat_filter = {} # ... 后续调用retrieve_and_generate的代码 ...
步骤2:确认OpenSearch的日期字段映射
确保你的OpenSearch索引中,effective_date字段的类型是date(默认的日期格式就包含strict_date_optional_time,所以不需要额外修改映射,除非你自定义了格式)。你可以通过OpenSearch的Dev Tools执行以下命令确认:
GET bedrock-knowledge-base-default-index/_mapping/field/effective_date
返回结果里应该显示type: "date",并且format包含strict_date_optional_time。
为什么不用epoch毫秒?
如果你坚持要用epoch毫秒,需要解决boto3的浮点数序列化问题:你可以尝试把epoch毫秒转成字符串?不行,因为OpenSearch的epoch_millis要求数值类型。另一种方法是确保boto3把整数序列化成整数而不是浮点数,但这需要修改boto3的序列化配置,操作起来比较麻烦,不如直接用ISO字符串省心。
验证过滤器结构
最后再确认你的过滤器结构是正确的,比如多个条件用andAll组合,单个条件用greaterThanOrEquals/lessThanOrEquals,布尔、字符串过滤的逻辑你已经能正常使用,所以只要日期值的格式对了,整个过滤器就能正常工作。
内容来源于stack exchange

