Amazon Connect フローでの放棄呼と離脱箇所を、Step Functionsを利用しローコードでDynamoDBに保存してみた

2024.05.07

はじめに

Amazon Connectのフローで離脱箇所や放棄呼をAmazon Kinesis Data Streams(以降、KDS)とStep Functionsを用いて取得し、Amazon DynamoDBに保存する方法をまとめました。

本記事の内容は以下のような用途に役立ちます。

  • IVRでの途中離脱箇所を知りたい
  • オペレーターにつながる前に切られる放棄呼の有無を知りたい

Connectは、各通話ごとに問い合わせレコード(Contact Trace Record, CTR)として通話記録を保存します。

Connectでは、KDSに問い合わせレコードを出力できます。通常は問い合わせレコードは、どのフローで切断されたか情報はありませんが、フロー内で工夫すると取得ができます。工夫内容は後述します。

以下の構成図に基づいて、処理の流れを説明します。

  1. Connectのフロー内で、図の青丸箇所のいずれかで切断したとします
  2. 切断直後、問い合わせレコードがKDSにストリーミングされます
  3. EventBridge PipesでソースをKDS、ターゲットをStep Functionsとし、Step Functionsで問い合わせレコードから切断情報などを抽出し、DynamoDBに保存します

以下のリソースを作成します。

  • DynamoDB
  • KDS
  • Step Functions ステートマシン
  • EventBridge Pipes
  • Connectフロー

DynamoDB

以下の設定で作成します

  • テーブル名:call-records
  • パーティションキー:contact_id

今回の切断箇所以外にも他の情報をDynamoDBに保存することを想定し、パーティションキーはContact IDとします。

Step Functionsによって、DynamoDBには以下の属性を保存する想定です。

  • コンタクトID
  • 放棄呼の有無
  • 発信日時
  • フロー離脱箇所
  • 発信元電話番号

KDS

KDSは、プロビジョンドモード、シャード1で作成します。

Step Functions ステートマシン

IAMロールでは以下のIAMポリシーを追加します

  • AmazonDynamoDBFullAccess

EventBridge Pipes内でKDSから渡される内容は、以下のとおりです。

[
    {
      "eventSource": "aws:kinesis",
      "eventVersion": "1.0",
      "eventID": "shardId-000000000000:xxxxxxx",
      "eventName": "aws:kinesis:record",
      "invokeIdentityArn": "arn:aws:iam::xxxxxxxxxxxx:role/service-role/Amazon_EventBridge_Pipe_cm-hirai-call-route_509278b3",
      "awsRegion": "ap-northeast-1",
      "eventSourceARN": "arn:aws:kinesis:ap-northeast-1:xxxxxxxxxxxx:stream/cm-hirai-call-route",
      "kinesisSchemaVersion": "1.0",
      "partitionKey": "f35752a8-261a-48bc-8d06-099b618e0e0c",
      "sequenceNumber": "49651139538302143095151058574031664653397744781153533954",
      "data": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      "approximateArrivalTimestamp": 1714308481.275
    }
  ]

上記のうち[0]['data']は、base64でエンコードされているため、デコードすることで以下のような値が取得できます。

{
    "AWSAccountId": "xxxxxxxxxxx",
    "AWSContactTraceRecordFormatVersion": "2017-03-10",
    "Agent": null,
    "AgentConnectionAttempts": 0,
    "AnsweringMachineDetectionStatus": null,
    "Attributes": {
        "call_completed": "false",
        "call_route": "start"
    },
    "Campaign": {
        "CampaignId": null
    },
    "Channel": "VOICE",
    "ConnectedToSystemTimestamp": "2024-04-17T23:47:52Z",
    "ContactDetails": {},
    "ContactId": "9c905123-6240-4484-b9d1-4e3e40660d8e",
    "CustomerEndpoint": {
        "Address": "+81xxxxxxxxx",
        "Type": "TELEPHONE_NUMBER"
    },
    "CustomerVoiceActivity": null,
    "DisconnectReason": "CUSTOMER_DISCONNECT",
    "DisconnectTimestamp": "2024-04-17T23:47:56Z",
    "InitialContactId": null,
    "InitiationMethod": "INBOUND",
    "InitiationTimestamp": "2024-04-17T23:47:52Z",
    "InstanceARN": "arn:aws:connect:ap-northeast-1:xxxxxxxxxxx:instance/3ff2093d-af96-43fd-b038-3c07cdd7609c",
    "LastUpdateTimestamp": "2024-04-17T23:49:03Z",
    "MediaStreams": [
        {
            "Type": "AUDIO"
        }
    ],
    "NextContactId": null,
    "PreviousContactId": null,
    "Queue": null,
    "Recording": null,
    "Recordings": null,
    "References": [],
    "ScheduledTimestamp": null,
    "SegmentAttributes": {
        "connect:Subtype": {
            "ValueString": "connect:Telephony"
        }
    },
    "SystemEndpoint": {
        "Address": "+81xxxxxxxxx",
        "Type": "TELEPHONE_NUMBER"
    },
    "Tags": {
        "aws:connect:instanceId": "3ff2093d-af96-43fd-b038-3c07cdd7609c",
        "aws:connect:systemEndpoint": "+81xxxxxxxxx"
    },
    "TaskTemplateInfo": null,
    "TransferCompletedTimestamp": null,
    "TransferredToEndpoint": null,
    "VoiceIdResult": null
}

デコード後、Step Functionsによって、DynamoDBに以下を保存します。

  • コンタクトID
  • 放棄呼の有無
  • 発信日時
  • フロー離脱箇所
  • 発信元電話番号

作成するステートマシンは以下の通りです。

[0]['data']のデコードには、Step Functionsの組み込み関数を利用できます。

{
  "decodedData.$": "States.Base64Decode($.[0].data)"
}

デコード後、Step Functionsの組み込み関数を利用して、文字列からJSONに変換します。

{
  "data.$": "States.StringToJson($.decodedData)"
}

最後に、JSON形式に変換したデータから必要な情報をDynamoDBに保存します。

ステートマシンの全体のコードは、以下の通りです。

{
  "Comment": "A description of my state machine",
  "StartAt": "Base64Decode",
  "States": {
    "Base64Decode": {
      "Type": "Pass",
      "Parameters": {
        "decodedData.$": "States.Base64Decode($.[0].data)"
      },
      "Next": "ParseJSON"
    },
    "ParseJSON": {
      "Type": "Pass",
      "Parameters": {
        "data.$": "States.StringToJson($.decodedData)"
      },
      "Next": "DynamoDB UpdateItem"
    },
    "DynamoDB UpdateItem": {
      "Type": "Task",
      "Resource": "arn:aws:states:::dynamodb:updateItem",
      "Parameters": {
        "TableName": "call-records-stepfunctions",
        "Key": {
          "contact_id": {
            "S.$": "$.data.ContactId"
          }
        },
        "UpdateExpression": "SET phone_number = :phone , call_route = :route, start_time = :start, call_completed = :completed",
        "ExpressionAttributeValues": {
          ":phone": {
            "S.$": "$.data.CustomerEndpoint.Address"
          },
          ":route": {
            "S.$": "$.data.Attributes.call_route"
          },
          ":completed": {
            "S.$": "$.data.Attributes.call_completed"
          },
          ":start": {
            "S.$": "$.data.InitiationTimestamp"
          }
        },
        "ReturnValues": "UPDATED_NEW"
      },
      "End": true
    }
  }
}

DynamoDBに保存する属性は以下です

  • コンタクトID:contact_id
  • 放棄呼の有無:call_completed
  • 発信日時:start_time
  • フロー離脱箇所:call_route
  • 発信元電話番号:phone_number

EventBridge Pipes

Pipesを作成します。

ソースは、KDSを設定します。

ターゲットは、Step Functionsを設定します。

今回はターゲット入力トランスフォーマーを利用しませんでしたが、ターゲット先ではdataのみを利用するため、トランスフォーマーを利用することも可能です。

Pipesを作成が完了です。

Amazon_EventBridge_Pipe_cm-hirai-call-route_509278b3というIAMロール名が自動で作成されました。

以下のポリシーが追加されてます。

Connect フロー

本記事で利用するAmazon Connect のフローは以下の通りです。

フローは以下の流れです。

  1. 発信する
  2. アナウンスが流れるので、ユーザーがプッシュ式で「1」または「2」を入力します。
  3. 再度、アナウンスが流れるので、ユーザーがプッシュ式で「1」または「2」を入力します。
  4. 入力された内容がアナウンスされる
  5. 切断される
フロー (クリックすると展開します)
{
  "Version": "2019-10-30",
  "StartAction": "83796d04-0550-4e7e-aa99-fce8b18c3f98",
  "Metadata": {
    "entryPointPosition": {
      "x": 241.6,
      "y": -47.2
    },
    "ActionMetadata": {
      "791eef75-931f-4116-8898-300cb47711db": {
        "position": {
          "x": 875.2,
          "y": 663.2
        }
      },
      "d6f52dbe-f77b-49ee-913e-11af21cf4f3b": {
        "position": {
          "x": 867.2,
          "y": 381.6
        },
        "dynamicParams": []
      },
      "0534b033-6e91-4b33-97f5-708c19b7aeec": {
        "position": {
          "x": 1324,
          "y": 138.4
        }
      },
      "d8f00f42-7a09-4ff9-b8d8-ef6d03ce172a": {
        "position": {
          "x": 2035.2,
          "y": 364
        }
      },
      "83796d04-0550-4e7e-aa99-fce8b18c3f98": {
        "position": {
          "x": 344,
          "y": -62.4
        }
      },
      "8ebcf8ff-9525-4b7e-b07e-b6699b340e2b": {
        "position": {
          "x": 859.2,
          "y": 200
        },
        "dynamicParams": []
      },
      "26cd035e-247c-4388-bff9-ba756df8235c": {
        "position": {
          "x": 1323.2,
          "y": 744.8
        }
      },
      "400c5522-9cb0-4054-93c1-1c813d715dee": {
        "position": {
          "x": 1084.8,
          "y": -184
        },
        "conditionMetadata": [
          {
            "id": "f52c7bdd-2d72-468e-926f-e37f0fc37aab",
            "value": "1"
          },
          {
            "id": "d6d3b356-0118-4876-97b7-4bd688c7f21b",
            "value": "2"
          }
        ]
      },
      "a1972ceb-07b7-483e-b03f-2bd3dd6063fd": {
        "position": {
          "x": 1090.4,
          "y": 289.6
        },
        "conditionMetadata": [
          {
            "id": "79e1cb23-1aa4-4841-8b71-b4723557d5f3",
            "value": "1"
          },
          {
            "id": "d618d60a-c533-46dd-a605-c55459e451e1",
            "value": "2"
          }
        ]
      },
      "0bb60df6-c203-413e-930c-0fe3eb2677ea": {
        "position": {
          "x": 349.6,
          "y": 110.4
        },
        "children": [
          "c276029c-6058-4b01-91e5-159cf7c622f4"
        ],
        "overrideConsoleVoice": true,
        "fragments": {
          "SetContactData": "c276029c-6058-4b01-91e5-159cf7c622f4"
        },
        "overrideLanguageAttribute": true
      },
      "c276029c-6058-4b01-91e5-159cf7c622f4": {
        "position": {
          "x": 349.6,
          "y": 110.4
        },
        "dynamicParams": []
      },
      "1046bd11-9a7f-4746-a1eb-2ab571ceda91": {
        "position": {
          "x": 591.2,
          "y": 301.6
        },
        "conditionMetadata": [
          {
            "id": "6b52ff60-18f7-4b45-81f3-02d69bb14d7f",
            "value": "1"
          },
          {
            "id": "d3298e8f-e0bd-4aea-bad9-2ea2bc28c4cd",
            "value": "2"
          }
        ]
      },
      "02b1970e-5964-40f3-8f02-a8a572528a8a": {
        "position": {
          "x": 349.6,
          "y": 289.6
        },
        "dynamicParams": []
      },
      "beb20743-c289-44c4-b15e-4296cd1524dc": {
        "position": {
          "x": 1323.2,
          "y": -48
        },
        "dynamicParams": []
      },
      "f8b767e9-6ce8-4d62-abe1-99ddb29a047b": {
        "position": {
          "x": 1823.2,
          "y": 292
        }
      },
      "2437cce9-a1c7-4b54-bd5e-48ee06780fcb": {
        "position": {
          "x": 1326.4,
          "y": -231.2
        },
        "dynamicParams": []
      },
      "9a65bea6-f010-4201-9b80-ba5fd949a730": {
        "position": {
          "x": 1322.4,
          "y": 343.2
        },
        "dynamicParams": []
      },
      "6ad4c36f-cde9-4895-9e2c-e3f0058300b0": {
        "position": {
          "x": 1324.8,
          "y": 553.6
        },
        "dynamicParams": []
      },
      "8cd3631c-4c50-486f-b1d0-0d19be958468": {
        "position": {
          "x": 1600.8,
          "y": 295.2
        },
        "dynamicParams": []
      }
    },
    "Annotations": [],
    "name": "cm-hirai-call-route",
    "description": "",
    "type": "contactFlow",
    "status": "published",
    "hash": {}
  },
  "Actions": [
    {
      "Parameters": {
        "Text": "有効な番号以外が入力されました。"
      },
      "Identifier": "791eef75-931f-4116-8898-300cb47711db",
      "Type": "MessageParticipant",
      "Transitions": {
        "NextAction": "1046bd11-9a7f-4746-a1eb-2ab571ceda91",
        "Errors": [
          {
            "NextAction": "1046bd11-9a7f-4746-a1eb-2ab571ceda91",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Attributes": {
          "call_route": "2"
        },
        "TargetContact": "Current"
      },
      "Identifier": "d6f52dbe-f77b-49ee-913e-11af21cf4f3b",
      "Type": "UpdateContactAttributes",
      "Transitions": {
        "NextAction": "a1972ceb-07b7-483e-b03f-2bd3dd6063fd",
        "Errors": [
          {
            "NextAction": "a1972ceb-07b7-483e-b03f-2bd3dd6063fd",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Text": "有効な番号以外が入力されました。"
      },
      "Identifier": "0534b033-6e91-4b33-97f5-708c19b7aeec",
      "Type": "MessageParticipant",
      "Transitions": {
        "NextAction": "400c5522-9cb0-4054-93c1-1c813d715dee",
        "Errors": [
          {
            "NextAction": "400c5522-9cb0-4054-93c1-1c813d715dee",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {},
      "Identifier": "d8f00f42-7a09-4ff9-b8d8-ef6d03ce172a",
      "Type": "DisconnectParticipant",
      "Transitions": {}
    },
    {
      "Parameters": {
        "FlowLoggingBehavior": "Enabled"
      },
      "Identifier": "83796d04-0550-4e7e-aa99-fce8b18c3f98",
      "Type": "UpdateFlowLoggingBehavior",
      "Transitions": {
        "NextAction": "0bb60df6-c203-413e-930c-0fe3eb2677ea"
      }
    },
    {
      "Parameters": {
        "Attributes": {
          "call_route": "1"
        },
        "TargetContact": "Current"
      },
      "Identifier": "8ebcf8ff-9525-4b7e-b07e-b6699b340e2b",
      "Type": "UpdateContactAttributes",
      "Transitions": {
        "NextAction": "400c5522-9cb0-4054-93c1-1c813d715dee",
        "Errors": [
          {
            "NextAction": "400c5522-9cb0-4054-93c1-1c813d715dee",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Text": "有効な番号以外が入力されました。"
      },
      "Identifier": "26cd035e-247c-4388-bff9-ba756df8235c",
      "Type": "MessageParticipant",
      "Transitions": {
        "NextAction": "a1972ceb-07b7-483e-b03f-2bd3dd6063fd",
        "Errors": [
          {
            "NextAction": "a1972ceb-07b7-483e-b03f-2bd3dd6063fd",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "StoreInput": "False",
        "InputTimeLimitSeconds": "10",
        "Text": "1、もしくは、2、を押して下さい"
      },
      "Identifier": "400c5522-9cb0-4054-93c1-1c813d715dee",
      "Type": "GetParticipantInput",
      "Transitions": {
        "NextAction": "0534b033-6e91-4b33-97f5-708c19b7aeec",
        "Conditions": [
          {
            "NextAction": "2437cce9-a1c7-4b54-bd5e-48ee06780fcb",
            "Condition": {
              "Operator": "Equals",
              "Operands": [
                "1"
              ]
            }
          },
          {
            "NextAction": "beb20743-c289-44c4-b15e-4296cd1524dc",
            "Condition": {
              "Operator": "Equals",
              "Operands": [
                "2"
              ]
            }
          }
        ],
        "Errors": [
          {
            "NextAction": "0534b033-6e91-4b33-97f5-708c19b7aeec",
            "ErrorType": "InputTimeLimitExceeded"
          },
          {
            "NextAction": "0534b033-6e91-4b33-97f5-708c19b7aeec",
            "ErrorType": "NoMatchingCondition"
          },
          {
            "NextAction": "0534b033-6e91-4b33-97f5-708c19b7aeec",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "StoreInput": "False",
        "InputTimeLimitSeconds": "10",
        "Text": "1、もしくは、2、を押して下さい"
      },
      "Identifier": "a1972ceb-07b7-483e-b03f-2bd3dd6063fd",
      "Type": "GetParticipantInput",
      "Transitions": {
        "NextAction": "26cd035e-247c-4388-bff9-ba756df8235c",
        "Conditions": [
          {
            "NextAction": "9a65bea6-f010-4201-9b80-ba5fd949a730",
            "Condition": {
              "Operator": "Equals",
              "Operands": [
                "1"
              ]
            }
          },
          {
            "NextAction": "6ad4c36f-cde9-4895-9e2c-e3f0058300b0",
            "Condition": {
              "Operator": "Equals",
              "Operands": [
                "2"
              ]
            }
          }
        ],
        "Errors": [
          {
            "NextAction": "26cd035e-247c-4388-bff9-ba756df8235c",
            "ErrorType": "InputTimeLimitExceeded"
          },
          {
            "NextAction": "26cd035e-247c-4388-bff9-ba756df8235c",
            "ErrorType": "NoMatchingCondition"
          },
          {
            "NextAction": "26cd035e-247c-4388-bff9-ba756df8235c",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "TextToSpeechEngine": "Neural",
        "TextToSpeechStyle": "None",
        "TextToSpeechVoice": "Kazuha"
      },
      "Identifier": "0bb60df6-c203-413e-930c-0fe3eb2677ea",
      "Type": "UpdateContactTextToSpeechVoice",
      "Transitions": {
        "NextAction": "c276029c-6058-4b01-91e5-159cf7c622f4"
      }
    },
    {
      "Parameters": {
        "LanguageCode": "ja-JP"
      },
      "Identifier": "c276029c-6058-4b01-91e5-159cf7c622f4",
      "Type": "UpdateContactData",
      "Transitions": {
        "NextAction": "02b1970e-5964-40f3-8f02-a8a572528a8a",
        "Errors": [
          {
            "NextAction": "02b1970e-5964-40f3-8f02-a8a572528a8a",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "StoreInput": "False",
        "InputTimeLimitSeconds": "10",
        "Text": "1、もしくは、2、を押して下さい"
      },
      "Identifier": "1046bd11-9a7f-4746-a1eb-2ab571ceda91",
      "Type": "GetParticipantInput",
      "Transitions": {
        "NextAction": "791eef75-931f-4116-8898-300cb47711db",
        "Conditions": [
          {
            "NextAction": "8ebcf8ff-9525-4b7e-b07e-b6699b340e2b",
            "Condition": {
              "Operator": "Equals",
              "Operands": [
                "1"
              ]
            }
          },
          {
            "NextAction": "d6f52dbe-f77b-49ee-913e-11af21cf4f3b",
            "Condition": {
              "Operator": "Equals",
              "Operands": [
                "2"
              ]
            }
          }
        ],
        "Errors": [
          {
            "NextAction": "791eef75-931f-4116-8898-300cb47711db",
            "ErrorType": "InputTimeLimitExceeded"
          },
          {
            "NextAction": "791eef75-931f-4116-8898-300cb47711db",
            "ErrorType": "NoMatchingCondition"
          },
          {
            "NextAction": "791eef75-931f-4116-8898-300cb47711db",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Attributes": {
          "call_route": "start",
          "call_completed": "false"
        },
        "TargetContact": "Current"
      },
      "Identifier": "02b1970e-5964-40f3-8f02-a8a572528a8a",
      "Type": "UpdateContactAttributes",
      "Transitions": {
        "NextAction": "1046bd11-9a7f-4746-a1eb-2ab571ceda91",
        "Errors": [
          {
            "NextAction": "1046bd11-9a7f-4746-a1eb-2ab571ceda91",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Attributes": {
          "call_route": "1-2"
        },
        "TargetContact": "Current"
      },
      "Identifier": "beb20743-c289-44c4-b15e-4296cd1524dc",
      "Type": "UpdateContactAttributes",
      "Transitions": {
        "NextAction": "8cd3631c-4c50-486f-b1d0-0d19be958468",
        "Errors": [
          {
            "NextAction": "8cd3631c-4c50-486f-b1d0-0d19be958468",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Text": "$.Attributes.call_route、が入力されました。終了します。"
      },
      "Identifier": "f8b767e9-6ce8-4d62-abe1-99ddb29a047b",
      "Type": "MessageParticipant",
      "Transitions": {
        "NextAction": "d8f00f42-7a09-4ff9-b8d8-ef6d03ce172a",
        "Errors": [
          {
            "NextAction": "d8f00f42-7a09-4ff9-b8d8-ef6d03ce172a",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Attributes": {
          "call_route": "1-1"
        },
        "TargetContact": "Current"
      },
      "Identifier": "2437cce9-a1c7-4b54-bd5e-48ee06780fcb",
      "Type": "UpdateContactAttributes",
      "Transitions": {
        "NextAction": "8cd3631c-4c50-486f-b1d0-0d19be958468",
        "Errors": [
          {
            "NextAction": "8cd3631c-4c50-486f-b1d0-0d19be958468",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Attributes": {
          "call_route": "2-1"
        },
        "TargetContact": "Current"
      },
      "Identifier": "9a65bea6-f010-4201-9b80-ba5fd949a730",
      "Type": "UpdateContactAttributes",
      "Transitions": {
        "NextAction": "8cd3631c-4c50-486f-b1d0-0d19be958468",
        "Errors": [
          {
            "NextAction": "8cd3631c-4c50-486f-b1d0-0d19be958468",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Attributes": {
          "call_route": "2-2"
        },
        "TargetContact": "Current"
      },
      "Identifier": "6ad4c36f-cde9-4895-9e2c-e3f0058300b0",
      "Type": "UpdateContactAttributes",
      "Transitions": {
        "NextAction": "8cd3631c-4c50-486f-b1d0-0d19be958468",
        "Errors": [
          {
            "NextAction": "8cd3631c-4c50-486f-b1d0-0d19be958468",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Attributes": {
          "call_completed": "true"
        },
        "TargetContact": "Current"
      },
      "Identifier": "8cd3631c-4c50-486f-b1d0-0d19be958468",
      "Type": "UpdateContactAttributes",
      "Transitions": {
        "NextAction": "f8b767e9-6ce8-4d62-abe1-99ddb29a047b",
        "Errors": [
          {
            "NextAction": "f8b767e9-6ce8-4d62-abe1-99ddb29a047b",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    }
  ]
}

フローの離脱箇所

コンタクト属性は問い合わせレコードに保存されるため、分岐先情報をコンタクト属性として設定することで、フロー離脱箇所をDynamoDBに保存できます。

[コンタクト属性の設定]ブロックでフローの分岐情報として、キー:call_route、値(分岐先)を付与します。

今回は以下のように、キー:call_routeの値は、数字にしていますが、問い合わせの種別(例えば、カードの紛失や口座開設希望など)を設定するとよいでしょう。

例えば、1を入力後、切断すると、切断箇所は1になります。1を押して次のフローで2を押して切断すると、1-2が切断箇所になります。

放棄呼

放棄呼の有無は、発信直後とフローの最後に[コンタクト属性の設定]ブロックとして、キー:call_completed、値(true or false)を付与することで確認できます。

オペレーターにつながるまでに電話を切られることを、放棄呼と指しますが、今回は最後まで進めたかどうかでtrue or falseと判定します。フローの最後にオペレーターに繋がるようにしてもよいです。

例えば、発信し、最初の音声が流れた瞬間に切断すると、放棄呼がありとなりコンタクト属性はfalseとなります。最後まで進めると、放棄呼なしであり、コンタクト属性はtrueになります。

試してみる

それでは実際に電話をかけて動作を確認してみましょう。

電話を終了してからDynamoDBに反映されるまでに、1分ほどかかります。

以下の結果となりました。

フローの離脱箇所はcall_routeで確認できます。例えば、call_route1の場合は、最初の選択肢で1を選び、次の選択で切断されたということです。call_route2-1の場合は、最初の選択で2を選び、次の選択で1を選んだ後に切断された場合です。

最後まで進めた場合(call_route1-21-1)、call_completedtrueとなり、放棄呼ではないということです。一方、発信直後に切断された場合は、call_completedfalseで放棄呼があったことがわかります。

本記事の実装における改善点としては以下が挙げられます。

  • 発信日時start_timeは、UTCになっている。JSTに変換したい
  • 電話番号phone_numberには、「+81」がついてる。「+81」を「0」に置き換えたい
  • 発信日時から切断までの通話時間も知りたい

上記は、Step Functionsのみでは実現できず、AWS Lambdaを利用する必要があります。

最後

本記事では、Amazon Connectのフローで離脱箇所や放棄呼をKDSとStep Functionsを用いて取得し、DynamoDBに保存する方法について解説しました。

Amazon Connect フローのコンタクト属性に分岐先情報を設定することで、離脱箇所や放棄呼の情報を比較的容易に取得できます。本記事が参考になれば幸いです。

参考