You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Amazon Lex槽位全填充后仍触发DialogCodeHook而非FulfillmentCodeHook问题

问题:Amazon Lex槽位填充完成后无法触发FulfillmentCodeHook

原本运行正常的预订试驾Lambda槽位验证代码出现异常:用户填写完所有必填槽位(FirstName、ContactDetails、Date)后,Lex并未触发预期的FulfillmentCodeHook(intent状态为ReadyForFulfillment),而是持续发送DialogCodeHook请求,intent状态始终为InProgress。

预期请求示例

{
    "sessionId": "526322052651484",
    ...
    "sessionState": {
      "sessionAttributes": {},
      "intent": {
        "name": "BookTestDrive",
        "slots": {
          "ContactDetails": {
            "shape": "Scalar",
            "value": {
              "originalValue": "mail@mail.com",
              "resolvedValues": [],
              "interpretedValue": "mail@mail.com"
            }
          },
          "FirstName": {
            "shape": "Scalar",
            "value": {
              "originalValue": "Buln",
              "resolvedValues": [
                "Bula"
              ],
              "interpretedValue": "Buln"
            }
          },
          "Date": {
            "shape": "Scalar",
            "value": {
              "originalValue": "14-03-2024",
              "resolvedValues": [
                "2024-03-14"
              ],
              "interpretedValue": "2024-03-14"
            }
          }
        },
        "state": "ReadyForFulfillment",
        "confirmationState": "None"
      },
      "originatingRequestId": "a13fd06a-bc03-4a80-94f9-8b65e7b2edb2"
    },
    "invocationSource": "FulfillmentCodeHook",
    ...
}

实际收到的请求示例

{
    "sessionId": "526322052651839",
    ...
    "sessionState": {
      "sessionAttributes": {},
      "activeContexts": [],
      "intent": {
        "confirmationState": "None",
        "name": "BookTestDrive",
        "slots": {
          "ContactDetails": {
            "shape": "Scalar",
            "value": {
              "originalValue": "email@mail.com",
              "resolvedValues": [],
              "interpretedValue": "email@mail.com"
            }
          },
          "FirstName": {
            "shape": "Scalar",
            "value": {
              "originalValue": "Bunleap",
              "resolvedValues": [],
              "interpretedValue": "Bunleap"
            }
          },
          "Date": {
            "shape": "Scalar",
            "value": {
              "originalValue": "today",
              "resolvedValues": [
                "2023-07-25"
              ],
              "interpretedValue": "2023-07-25"
            }
          }
        },
        "state": "InProgress"
      },
      "originatingRequestId": "47dd31f5-0119-42c1-9d22-89bf05d44d86"
    },
    ...
    "invocationSource": "DialogCodeHook",
}

当前Lambda Python代码

import boto3
import random

def validate_booking(slots):
    if not slots['FirstName']:
        return {
            'isValid': False,
            'invalidSlot': 'FirstName'
        }

    if not slots['ContactDetails']:
        return {
            'isValid': False,
            'invalidSlot': 'ContactDetails'
        }

    if not slots['Date']:
        return {
            'isValid': False,
            'invalidSlot': 'Date'
        }

    return {'isValid': True}


def lambda_handler(event, context):
    print(event)

    bot = event['bot']['name']
    slots = event['sessionState']['intent']['slots']
    intent = event['sessionState']['intent']['name']

    validate_result = validate_booking(slots)

    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table("CarBookTestDrive")
    
    if event['invocationSource'] == 'DialogCodeHook':
        if not validate_result['isValid']:
            if 'message' in validate_result:
                response = {
                    "sessionState": {
                        "dialogAction": {
                            "slotToElicit": validate_result['invalidSlot'],
                            "type": "ElicitSlot"
                        },
                        "intent": {
                            "name": intent,
                            "slots": slots
                        }
                    },
                    "messages": [
                        {
                            "contentType": "PlainText",
                            "content": validate_result['message']
                        }
                    ]
                }
            else:
                response = {
                    "sessionState": {
                        "dialogAction": {
                            "slotToElicit": validate_result['invalidSlot'],
                            "type": "ElicitSlot"
                        },
                        "intent": {
                            "name": intent,
                            "slots": slots
                        }
                    }
                }
        else:
            response = {
                "sessionState": {
                    "dialogAction": {
                        "type": "Delegate"
                    },
                    "intent": {
                        'name': intent,
                        'slots': slots
                    }
                }
            }

    if event['invocationSource'] == 'FulfillmentCodeHook':
        
        message = f"Thanks {event['sessionState']['intent']['slots']['FirstName']['value']['interpretedValue']}, We will contact you shortly to confirm the drive test."

        response = {
            "sessionState": {
                "dialogAction": {
                    "type": "Close"
                },
                "intent": {
                    "name": intent,
                    "slots": slots,
                    "state": "Fulfilled"
                }

            },
            "messages": [
                {
                    "contentType": "PlainText",
                    "content": message
                }
            ]
        }
        
        table.put_item(Item={
            'TestDriveID': str(random.randint(1000,9999)),
            'FirstName': event['sessionState']['intent']['slots']['FirstName']['value']['interpretedValue'],
            'ContactDetails': event['sessionState']['intent']['slots']['ContactDetails']['value']['interpretedValue'],
            'Date': event['sessionState']['intent']['slots']['Date']['value']['interpretedValue']
        })
    

    return response

解决方案

1. 检查Lex控制台Intent配置

  • 确认BookTestDrive Intent已启用Fulfillment,并绑定了正确的Lambda函数。
  • 检查Intent的Confirmation prompt是否开启:若开启,需用户确认Intent后才会触发Fulfillment,若流程不需要确认,需关闭该选项。
  • 检查各槽位的Slot confirmation prompt:若某个槽位开启了确认,需用户确认槽位内容后流程才会继续,若不需要则关闭。

2. 修改Lambda代码,手动触发Fulfillment

当所有槽位验证通过后,不再返回Delegate类型的DialogAction,而是直接将Intent状态设置为ReadyForFulfillment,告诉Lex可以触发Fulfillment流程:

修改Lambda代码中DialogCodeHook分支的else块:

else:
    response = {
        "sessionState": {
            "intent": {
                'name': intent,
                'slots': slots,
                'state': 'ReadyForFulfillment'
            }
        }
    }

3. 优化资源初始化(可选)

将DynamoDB的初始化代码移到FulfillmentCodeHook分支内,避免不必要的资源加载:

if event['invocationSource'] == 'FulfillmentCodeHook':
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table("CarBookTestDrive")
    # 后续Fulfillment逻辑...

内容的提问来源于stack exchange,提问作者Bunleap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 07:29:51