ここ2-3年、Amazon Connectを使ってコールセンターをクラウド化する案件に多数携わってきました。
Amazon Connectはエンドユーザーと直接繋がる窓口であり、コールセンターを構えている企業にとって今後の戦略を立てる上で非常に重要なデータが溜まっている宝の宝庫です。
少し前までは、Contact Lensでの日本語に対する文字起こし精度が低く、使いものにならなかったのですが精度が向上し感情分析など文字起こしデータから様々な示唆を得られるようになってきた実感があります。
また、Amazon Qとネイティブに接続されていたり、AIとの親和性を非常に高いサービスなので今のうちに集約されたデータに対する分析基盤を整備しておく必要があります。
Amazon Connectにおいてデータ活用の検討をする機会があったので少し書き出してみました。
背景
企業においてコンタクトセンターを大規模に構えている目的は大半がD2Cビジネスだと思います。
実際、携わった最近のコンタクトセンターをクラウドへ移行する案件は健康食品や化粧品の販売、テーマパークや金融業の顧客サポートなどエンドユーザー向けのものばかりです。
エンドユーザーからの問い合わせや注文、解約などさまざまなケースを目の当たりにするとコンタクトセンターが単なる窓口でないことを改めて感じます。
例えば、契約の解約の申し出をコールセンター経由で受け付けた場合、単なる事務手続きではなく企業とエンドユーザーの唯一の接点で企業の利益を守るための最前線になります。
最近では電話だけではなく、AIでの自動応答を含むチャットなど複数チャネルでの接点を用意する企業が増えているのでなおさら重要な接点あることを感じます。
単なる事務手続きの窓口ではなく、この唯一の接点から生まれるデータをビジネス・経営サイドに渡すことがコンタクトセンターの存在価値を高めています。
ただ、以前に比べデータが集めやすくなったとはいえ簡単ではありません。
CTR(通話記録)のJSON仕様変更で集約するLambdaに負荷がかかりタイムアウトで処理ができなくなったり、Glue Crawlerが突然止まってしまったり、データ分析をする前処理の保守で時間を潰してしまうことがあります。
2024年5月頃のアップデートで、今さらですが Amazon Connect Analytics Data Lakeについて検討する機会があったのでどう向き合うか、技術とビジネスの話を少し残しておきます。
Kinesis + LambdaからAmazon Connect Analytics Data Lakeへ
Kinesis Data StreamsとLambdaを組み合わせたデータ配信パイプラインは、AWSが得意とするビルディングブロックで組み合わせを考えることは、すべてのデータフローを制御できる万能感に溢れていて楽しい側面もありました。
ただ、運用が長くなったり、取り扱うデータ量が増えるとどれだけ精巧に設計していても必ずボロが出てきます。
Amazon Connectのアップデートで属性が取り扱えるデータが増えたり減ったりするたびにLambdaのコードを書き換える必要があったり、データ処理のために深夜でもシャードに課金が発生し続けコスト削減に対処しなくてはいけなくなったりします。
単純な「エージェントがいつログインしたか」というデータと通話履歴を紐づけるだけのことに複雑なクエリを書かなくてはいけません。
本来やりたいことはデータを活用してオペレーターの対応品質を向上させたり、AWSの利用料などシステムにかかる費用ではなく通話あたりの人的コストの削減などに工数を使いたいのにデータフローの保守に時間を取られてしまうことになります。
そこで Amazon Connect Analytics Data Lake です。
このサービスの詳しい説明は別途するとして、このサービスは一番の長所だと思う点はAmazon Connect内のデータを勝手にParquet形式でS3に同期してくれることです。
Parquetにしておけば、AthenaやQuick SuiteはもちろんSnowflakeやDatabricksとも相性がいいのでデータが莫大な量になっても分析がしやすくなります。
Amazon Connect Analytics Data Lakeがすべてではない
では、Kinesisがもう不要でゴミ箱行きなのかというとそうではありません。
このあたりがアーキテクトとしての面白いところです。
結論としてはハイブリッドな構成を保つことです。
例えば、「電話を切った瞬間にLINEでサンクスメッセージを送る」みたいな処理において、メッセージに必要なデータを含めるためにはKinesisとLambdaが必要です。
Data Lakeは同期に最低でも数分はかかるのでスピードが必要なケースではまだまだ使い物になりません。
一方で、「先月の解約理由の傾向を見たい」とか「オペレーターごとの工数管理がしたい」といったビジネス・経営的な分析処理にはAnalytics Data Lakeが適任です。
それぞれの特性を活かして使い分けをします。
図にするとこんなイメージです。
Amazon Connect Analytics Data Lakeの準備
Amazon Connect Analytics Dataを使い始めるのはとても簡単です。
コンソールで有効化してデータ保存するS3を紐付けるだけ。
AWS CDKだとこんな感じです。
import * as cdk from 'aws-cdk-lib';
import * as connect from 'aws-cdk-lib/aws-connect';
import * as s3 from 'aws-cdk-lib/aws-s3';
// データレイク用S3バケット。2年で消えるように設定しておきます。
const dataLakeBucket = new s3.Bucket(this, 'ConnectDataLakeBucket', {
encryption: s3.BucketEncryption.S3_MANAGED,
lifecycleRules: [{ expiration: cdk.Duration.days(730) }],
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
});
// ここでConnectとバケットを紐付けます。
const instanceId = 'YOUR_CONNECT_INSTANCE_ID';
const analyticsDataAssociation = new connect.CfnInstanceStorageConfig(this, 'AnalyticsDataLakeConfig', {
instanceId: instanceId,
resourceType: 'ANALYTICS_DATA_ASSOCIATION',
storageType: 'S3',
s3Config: {
bucketName: dataLakeBucket.bucketName,
bucketPrefix: 'connect-analytics-data', // プレフィックスは切っておいた方が後で泣きを見ません
},
});
注意点としては、デプロイしても過去のデータまで遡れません。
有効化した時点からのデータが対象となるので、移行期間中は新旧データが混在するので要注意です。
User Defined Attributesの取り出し
Amazon Connectのデータで要求が多いものは「会員ID」とか「解約理由」など、独自の属性情報(User Defined Attributes)です。
これらはCTRの中に存在しますが、Data Lakeのテーブルで見ると少し扱いづらい形式(MapやArray)で入っています。
これをSQLで綺麗に取り出すのが最初の難関でした。
一例を挙げると問い合わせフローの中で「解約理由(churn_reason)」を保存しているとして、それを集計したい場合はこんなクエリになります。
WITH unnested_ctr AS (
SELECT
contact_id,
initiation_timestamp,
-- 通話時間を計算
date_diff('second', from_iso8601_timestamp(connected_to_agent_timestamp), from_iso8601_timestamp(disconnect_timestamp)) as talk_time,
-- ここがキモです。Attributesを展開して特定のキーを狙い撃ちする
element_at(attributes, 'churn_reason') as churn_reason,
element_at(attributes, 'customer_grade') as customer_grade
FROM
"amazon_connect_db"."connect_ctr"
WHERE
-- パーティションプルーニングを忘れずに。これをサボるとAthenaの請求額で青ざめることになります
partition_date = to_char(current_date, 'yyyy-MM-dd')
AND attributes IS NOT NULL
)
SELECT
churn_reason,
AVG(talk_time) as avg_talk_time,
COUNT(contact_id) as call_count
FROM
unnested_ctr
WHERE
churn_reason IS NOT NULL
GROUP BY
churn_reason
ORDER BY
call_count DESC;
QuickSuiteとSPICEのコスト
Athenaで上記のようなクエリを通したらあとはQuick Suiteで可視化するだけです。
Quick SuiteではSPICEというインメモリエンジンを使いますが運用上でのコツがあります。
CTRデータのレコードは一度確定したら基本的に変動することがありません。
よって毎回全データを更新する必要がなく、増分更新を使うことでコストを抑えます。
過去3日分くらいのウィンドウで設定しておけば取り込み時間も短くなり、無駄なリソースを使うことがありません。
他にも、オペレーターの成績データなどはセンシティブなものなので、SVには自分のチームの数字だけ見えるようにするなど閲覧ができる人を絞るように行レベルセキュリティ(RLS)が必須です。
最後に
Amazon Connect Analytics Data Lakeを使うメリットは、データパイプラインの運用や保守に時間をかけなくてよくなることだと思います。
本来やりたい、やるべきデータを活用していかにシステムから見える戦略を立てていくか。に時間を使えるようになります。
パイプラインが壊れていないか監視する毎日から、ビジネス部門と「次はどんなデータで解約を防ごうか?」と議論する毎日へ。
浮いた工数で、解約予兆モデルを作ったり、新しいAI機能を試したりする。それこそが、本来やりたかったエンジニアリングではないかと実感しました。