コンタクトセンターの自動応答をTwilioからAmazon Connectに移行した話

公開:2021/02/19
更新:2021/02/19
9 min読了の目安(約8400字TECH技術記事

概要

弊社のコンタクトセンターでは、電話が込み合っているときに自動でアナウンスを流すしくみを構築しています。今まではTwilioを利用していましたが、最近Amazon Connectに乗り換えました。

Twilioも簡単でしたが、Amazon Connectはそれに輪をかけて簡単でした。ただ、個別の設定は忘れやすいので、備忘録代わりに記事にしてみました。

今までの構成

今までの構成

こちらが今までの構成です。コンタクトセンターの電話はbrastelのBasixを利用しています。Basixは任意のグループを作ってその下に電話機を配置できるので、社内用にいくつかグループを作っています。図中の「Group4-1」がコンタクトセンターの外線着信用グループです。CTI(着信電話番号から顧客情報を表示するシステム)に連動させる都合上、コンタクトセンターのグループは「Group4-1」と「Group4-2」に分けています。

簡単に仕組みを説明します。

  1. 顧客がコンタクトセンター(03で始まる電話番号)に電話をかけます。図では省略していますが、実際にはフリーダイヤルから転送されて来る場合が多いです。
  2. コンタクトセンター(Group4-1)の電話が鳴り、CTIがDBに着信履歴を書き込みます。通常はここでスタッフが電話を取ります。
  3. 誰も対応できないまま10秒経過するとBasixがTwilioに電話を転送します。
  4. Twilioが自動応答で約1分間アナウンスを流します。
  5. アナウンスが終了するとTwilioがGroup4-2の050番号に電話を転送します。
  6. コンタクトセンター(Group4-2)に着信があります。CTIは2で記録済みのため、この時は動きません。ここでスタッフが対応可能なら電話に出て終了です。
  7. すべての電話が電話中か、15秒間対応できない状態が続いた場合は再度Twilioに電話が転送されます。以降は4に戻り、6でスタッフが電話に出るか、顧客が電話を切るまでループします。

全体像は複雑に感じるかもしれませんが、Basix側はn秒経過したら転送するだけ、Twilio側はアナウンスを流したら転送するだけなので、それぞれの設定はとてもシンプルです。

今までの構成の問題点

上記の構成には大きな問題があります。それは、営業時間外に顧客が携帯電話の操作ミスなどでコンタクトセンターに電話をかけ、電話をかけたことに気づかずに放置してしまうと、延々とループし続ける、という問題です。フリーダイヤル側には営業時間の設定がしてあり、03で始まるコンタクトセンターの電話番号に直接かけてくる顧客は非常に少ないので、めったに発生しないレアケースではあります。実際3年以上問題なく動いていたのですが、先日ついにこの事象が発生してしまったため、構成を見直すことにしました。

新しい構成

新しい構成(営業時間内)

新しい構成(営業時間外)

新しい構成がこちらです。営業時間内の場合はTwilioがAmazon Connectに置き換わっただけで全く一緒ですが、営業時間外の場合に時間外アナウンスを流して自動で切断できるようになりました。Twilioのままでも新しい構成に近いことは実現可能ですが、Amazon Connectの方が実装が容易なので移行することにしました。実際の手順を以下に示します。

構築手順

電話番号の申請

まずAWSのコンソールからAmazon Connectのインスタンスを作ります。このあたりは簡単なので説明は省略します。とりあえず電話番号を取得する必要がありますが、ここでいきなりつまづきました。

電話番号の取得でエラー

DID(直通ダイヤル)で国/地域で日本(+81)を選択すると「その国でお使いいただける番号はありません。必要な場合は、サポートにお問い合わせください。」と表示されます。以前は簡単に電話番号を発行できたのですが、日本の規制が厳しくなって、申請書類が必要になったそうです。ここは素直にサポートに問い合わせを行います。

AWSのサポートページに行くとAmazon Connectの電話番号申請用のカテゴリが用意されていました。「Limit Increase: Amazon Connect」というSubjectで、日本の電話番号が必要な旨を申請します。

サポートセンターからの返信で下記の書類をアップロードするように言われたので、免許証と会社の名刺、登記事項証明書を用意してアップロードしました。

A. 申請者の行政機関発行の有効な身分証明書 (運転免許証、パスポートなど)
B. 申請者と企業の関連性を示すドキュメント(社員証や、その他所属を確認できる書類)
C. 公共料金の請求書、法務省からの企業登録証明書 (登記事項証明書など)、行政機関からの領収書、国税または地方税に関する証明書 (納税証明書など)、社会保険料の領収書などの書類

書類のアップロードから2営業日後に電話番号が発行されました。祝日を挟んだため、申請から発行まで10日ほどかかりました。

問い合わせフローとオペレーション時間の設定

ルーティングの設定

電話番号が取得できれば後はスムーズです。Amazon Connectで設定するのは基本的に「問い合わせフロー」と「オペレーション時間」だけです。「オペレーション時間」とは営業時間のことです。設定方法は簡単なので省略します。

最初の問い合わせフロー

こちらが最初に作った問い合わせフローです。左側からブロックをドラッグ・アンド・ドロップして線でつないでいくだけなのでとても簡単です。アナウンスは「プロンプトの再生」で設定します。テキストを書いて喋らせることもできますし、音声ファイルを再生することもできます。

電話番号と問い合わせフローの紐づけ

問い合わせフローができたら電話番号の設定から紐づけを行います。実際に電話をかけてみると、問い合わせフローに設定したアナウンスが流れ、転送されることが確認できました。オペレーション時間を変更して、想定通り時間外アナウンスが流れ、自動的に電話が切れることも確認できました。

祝日判定の実装

オペレーション時間

Amazon Connectの「オペレーション時間」は曜日と時刻しか設定できないため、このままでは祝日に時間外アナウンスを流すことができません。そこでAWS Lambdaを用いて祝日判定の仕組みを組み込みました。こちらの記事を参考にさせていただきました。

まず、Googleカレンダーから祝日情報を取得してS3にテキストファイルとして保存する関数がこちらです。

import boto3
import urllib.request, urllib.error
import re
import os

s3 = boto3.resource('s3')
bucket = s3.Bucket('xxxxxxxxxxxxx)
sns = boto3.client('sns')
TOPIC_ARN = 'arn:aws:sns:ap-northeast-1:xxxxxxxxx:xxxxxxxxxxxxxxxxxx'


def lambda_handler(event, context):

    url = 'https://www.google.com/calendar/ical/ja.japanese%23holiday%40group.v.calendar.google.com/public/basic.ics'
    try:
        response = urllib.request.urlopen(url=url)
        list = response.readlines()
    except Exception as e:
        request = {
            'TopicArn': TOPIC_ARN,
            'Message': "祝日リストの取得に失敗しました。",
            'Subject': "get_holiday_txt is failed."
        }
        sns.publish(**request)
        return 1

    pattern = r'DTSTART;VALUE=DATE:'
    repattern = re.compile(pattern)

    with open("/tmp/holiday.txt", "w") as f:
        for num in range(len(list)):
            match = repattern.search(list[num-1].decode())
            if match is None:
                pass
            else:
                f.write(list[num-1][-10:-2].decode() + "\n")

    with open('/tmp/holiday.txt', 'rb') as data:
        result = bucket.put_object(Key='holiday.txt', Body=data)
    os.remove('/tmp/holiday.txt')

    request = {
        'TopicArn': TOPIC_ARN,
        'Message': "祝日リストを更新しました。",
        'Subject': "get_holiday_txt is succeeded."
    }
    sns.publish(**request)
    return 1

このLambda関数を実行すると、下記のようなファイルがS3上に生成されます。

20220923
20210923
20220718
20210722
20220429
{中略}
20201123
20200101
20200504
20200505

このファイルを用いて、本日が祝日かどうか判定するLambda関数がこちらです。

import os
import datetime
import boto3

s3 = boto3.resource('s3')
bucket = s3.Bucket('xxxxxxxxxxxxxxx')
TOPIC_ARN = 'arn:aws:sns:xxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxx'

def lambda_handler(event, context):
    result = is_holiday()
    resp = {
        'isHoliday': result
    }
    return resp


def is_holiday():
    now = datetime.datetime.now()
    now_jst = now + datetime.timedelta(hours=9)
    today = now_jst.strftime("%Y%m%d")

    try:
        obj = bucket.Object('holiday.txt')
        with open('/tmp/holiday.txt', 'wb') as data:
            obj.download_fileobj(data)
        with open('/tmp/holiday.txt') as f:
            holidays = f.readlines()
        os.remove('/tmp/holiday.txt')

        check = today + "\n" in holidays
        return check

    except Exception as e:
        sns = boto3.client('sns')
        request = {
            'TopicArn': TOPIC_ARN,
            'Message': "祝日判定処理でエラーが発生しました。",
            'Subject': "Exception occurred in is_holiday."
        }
        sns.publish(**request)
        return False

どちらの関数も通知用にAmazon SNSを利用しています。

Amazon SNS設定

図のように「サブスクリプションの作成」でプロトコルに「Eメール」を選ぶと、メールで通知できるようになります。生成されたサブスクリプションのARNをTOPIC_ARNに設定しておくと、祝日リストの更新時やエラー発生時にメールで通知されます。

祝日判定を問い合わせフローに組み込む

AWS Lambda関数を呼び出す

Lambda関数を作成し、問い合わせフローに「AWS Lambda関数を呼び出す」を配置しても、最初はLambda関数を選択することができません。

Lambda関数を問い合わせフローから呼び出せるようにするには次のようにします。

Amazon Connect メニュー

AWSコンソール側のAmazon Connectからインスタンスに入り、左上のメニューで「問い合わせフロー」をクリックします。Amazon Connect独自のURLではなく、AWSコンソールの方です。

Lambda関数の追加

下の方にAWS Lambdaという項目があるので、祝日判定の関数を選択して追加します。これでAmazon Connectの問い合わせフローから祝日判定を呼び出せるようになります。

問い合わせフロー最終形

問い合わせフローの最終形がこちらです。Lambda関数を呼び出した後、「問い合わせ属性を確認する」で祝日かどうかを判定しています。

問い合わせ属性を確認する

具体的な設定内容はこちらです。タイプは「外部」、属性は「isHoliday」にして、trueと等しいかどうかをチェックしています。

祝日リスト更新の自動化

Lambdaトリガーの設定

祝日リストの更新は自動化したいので、Lambda関数の設定でトリガーの追加を行い、「EventBridge(CloudWatch Events)」を選択します。

EventBridgeの設定

こちらがEventBridgeの設定です。設定した日が16日だったので、翌朝動作確認するためにcron(0 23 16 * ? *)というイベントスケジュールを設定しました。UTCで動作するので、この設定で日本時間の毎月17日朝8時に実行されます。普通のcronの書式では0 23 16 * * *ですが、こう書くとエラーになります。日付もしくは曜日を指定した場合は、もう一方を?にしなくてはいけないという独自ルールがあるそうで、ちょっとはまりました。

Amazon Connectからの着信番号を正しくする

Caller ID番号の設定

問い合わせフローで電話を転送させたときに、Amazon Connectで取得した050番号ではない03で始まる番号が着信番号として表示されていたので、転送設定を修正しました。図のように「Caller ID番号」にチェックを入れて、取得した050番号を選択すると、正常に050番号が着信番号として表示されるようになりました。

所感

祝日判定以外はノーコードでこれだけのことができてしまうのはすごいと思いました。今のところは必要ないので実装しませんでしたが、将来電話業務が複雑になってきたらIVR(顧客に番号をプッシュしてもらって処理を分岐する機能)を導入してみようかとも考えています。Amazon ConnectではIVRも問い合わせフローから簡単に作ることができます。

初期費用がかからないのも魅力です。BasixでIVRを導入する場合は数万円の初期費用がかかりますが、Amazon Connectの初期費用は0円です。ただし通話料はBasixより高いので、コストは長期的に判断する必要がありそうです。