Amazon Lex ElicitIntent场景下ResponseCard必填异常求助
问题分析与解决方案
从你的错误信息能明显看出,Lambda返回给Lex的响应里自动带上了一个空的ResponseCard字段:
"ResponseCard":{"version":0,"genericAttachments":null}
而Lex对于ElicitIntent类型的DialogAction,要求的是完全不包含该字段才符合"可选"的定义——官方文档里的"可选"不是指允许传空值对象,而是可以彻底省略这个字段。
问题根源在于Go的JSON序列化机制和你使用的Lex SDK模型结构体:Go的json.Marshal默认会序列化所有零值字段,如果SDK的DialogAction结构体中ResponseCard是值类型(而非指针),且没有添加json:",omitempty"标签,哪怕你没主动设置它,也会被序列化成默认的零值对象,最终触发Lex的校验错误。
具体解决方案
方案1:自定义结构体并添加omitempty标签
自己定义符合Lex格式的响应结构体,确保ResponseCard字段是指针类型并带有omitempty标签,这样未设置时就不会被序列化输出:
// 自定义符合Lex规范的响应结构体 type MyDialogAction struct { Type string `json:"type"` Message *model.Message `json:"message,omitempty"` ResponseCard *model.ResponseCard `json:"responseCard,omitempty"` // 指针+omitempty确保未设置时不输出 Slots map[string]interface{} `json:"slots,omitempty"` } type MyLexResponse struct { SessionAttributes map[string]interface{} `json:"sessionAttributes,omitempty"` DialogAction MyDialogAction `json:"dialogAction"` } func HandleRequest(m model.LexCodeHookRequest) (model.LexCodeHookResponse, error) { fmt.Println("Already reached the function") input, _ := json.Marshal(&m) fmt.Println(string(input)) var myRes MyLexResponse var res model.LexCodeHookResponse if m.CurrentIntent.Name == "determineIntent" { myRes = MyLexResponse{ DialogAction: MyDialogAction{ Type: "ElicitIntent", Message: &model.Message{ ContentType: "PlainText", Content: "Hi, thanks for contacting us, what can I help you with?", }, // 不设置ResponseCard字段,序列化时会自动忽略 }, } } else { myRes = MyLexResponse{ DialogAction: MyDialogAction{ Type: "Delegate", Slots: map[string]interface{}{ "intent": nil, }, }, } } // 序列化为JSON resBytes, err := json.Marshal(myRes) if err != nil { return res, err } fmt.Printf("Return: %s", string(resBytes)) // 反序列化为SDK要求的返回类型 err = json.Unmarshal(resBytes, &res) return res, err }
方案2:手动构建JSON映射
如果不想自定义结构体,直接用map[string]interface{}来构建响应,精确控制输出的字段,彻底排除ResponseCard:
func HandleRequest(m model.LexCodeHookRequest) (model.LexCodeHookResponse, error) { fmt.Println("Already reached the function") input, _ := json.Marshal(&m) fmt.Println(string(input)) var resBytes []byte var res model.LexCodeHookResponse var err error if m.CurrentIntent.Name == "determineIntent" { responseMap := map[string]interface{}{ "dialogAction": map[string]interface{}{ "type": "ElicitIntent", "message": map[string]string{ "contentType": "PlainText", "content": "Hi, thanks for contacting us, what can I help you with?", }, // 完全不包含ResponseCard字段 }, } resBytes, err = json.Marshal(responseMap) } else { res = model.LexCodeHookResponse{ DialogAction: model.DialogAction{ Type: "Delegate", Slots: map[string]interface{}{ "intent": nil, }, }, } resBytes, err = json.Marshal(res) } if err != nil { return res, err } fmt.Printf("Return: %s", string(resBytes)) err = json.Unmarshal(resBytes, &res) return res, err }
方案3:修改SDK结构体(若可行)
如果你有权限修改使用的Lex SDK模型结构体,给DialogAction里的ResponseCard字段添加json:",omitempty"并改为指针类型:
type DialogAction struct { Type string `json:"type"` Message *Message `json:"message,omitempty"` ResponseCard *ResponseCard `json:"responseCard,omitempty"` // 修改这里 Slots map[string]interface{} `json:"slots,omitempty"` }
这样当你不设置ResponseCard时,它会被序列化为nil,omitempty标签会让JSON序列化时忽略这个字段,完美符合Lex的要求。
内容的提问来源于stack exchange,提问作者nhthai
相关产品推荐
相关产品推荐

