AI Call Analytics: Natural-Language Answers to 'Why Do Customers Call?'
Sole architect of a production AI pipeline ingesting ~1,400 calls/day for a multi-billion-dollar rental company — then used its own data to cut total call volume ~30%.
- Role
- Solutions Architect
- Where
- Multi-billion-dollar equipment-rental company (consulting engagement)
- TypeScript
- Python
- AWS Bedrock
- AWS Transcribe
- AWS Lex
- Amazon S3
- EventBridge
- Lambda
- QuickSight
- Terraform
Context
A multi-billion-dollar rental company had thousands of customer calls coming in daily and no systematic answer to the most basic question: why are customers calling?
The state of the art before this project: employees shared credentials to log into the Nice API and manually download sample call recordings — and usually, nobody did even that. There were no transcriptions, no insight into what issues customers were facing, and no visibility into customer-service performance. Executives wanted natural-language answers, not spreadsheets. I was the sole architect for what became the client's first production AI system.
The Problem
- Call volume (~1,400 calls/day) made manual sampling meaningless — even diligent listening couldn't characterize it.
- The only access path was credential-sharing into the recording system, so in practice there was zero systematic insight.
- Executives wanted to ask questions about call drivers, not read static reports.
Architecture
An end-to-end AWS pipeline, from raw call audio to an executive-facing chatbot:
flowchart LR
N["Nice API<br/>call recordings"] --> T["AWS Transcribe"]
T -->|"redacted<br/>transcripts"| S3[("S3")]
S3 -->|"hourly batches<br/>(chunked above 3,000)"| B["Bedrock<br/>Batch Inference"]
B -->|"JSONL results mapped to<br/>each call's metadata.json"| DL[("Data Lake")]
DL --> QS["QuickSight<br/>dashboards"]
DL --> LEX["Lex + Bedrock<br/>executive chatbot"]
Transcripts are redacted before they land in S3. Every hour, accumulated transcripts run
through Bedrock Batch Inference — with a chunking strategy above 3,000 transcripts per batch.
The output is one large JSONL file, and each classification result is mapped back to its call
recording's metadata.json, keeping every insight traceable to its source call. From the
data lake, QuickSight serves the dashboards and a Lex + Bedrock chatbot lets executives ask
questions in plain language.
From Hours to Minutes
The first version classified transcripts one at a time — a full day's call records took hours to process, and it was the pipeline's clear bottleneck. Rather than optimize around it, I went to our AWS architect and asked what was on the horizon. The timing was almost comical: Bedrock Batch Inference shipped days after I described exactly that need. I re-architected the classification stage around it — invoking classification per-transcript became dumping redacted transcripts to S3 and running hourly batches — and classification went from hours to minutes.
Classification was also version-controlled — every change to the question set was tracked, so metrics stayed comparable over time.
Key Decisions & Trade-offs
- Why Bedrock: the ability to swap models in and out without heavy rewrites, value-driven token pricing, and native tie-ins with the AWS services already carrying the rest of the pipeline.
- Designing the questions ourselves: executives didn't have much input on what they wanted analyzed, so I designed the question set and reusable output formats: Was the issue resolved? On a scale of 1–4, how frustrated was the customer? Did the customer attempt self-service? What steps did they take to resolve it on their own?
- XML-structured prompts: after researching prompt-engineering practice, I structured the classification prompts with XML — reliable output parsing beats clever phrasing.
- Validate correctness, not latency: it's a batch job, so speed mattered less than truth. We pulled call samples through a React dashboard I built, put the classification next to the recording, and verified them against each other by hand.
- Next on the roadmap: an LLM-judge test harness — an outside model scoring classification quality 1–5 — so model choices can be evaluated continuously and cheaper models adopted when they hold up.
Closing the Product Loop
Once the classified data was flowing into the data lake and QuickSight, the pattern jumped out: ~30% of inbound calls were customers canceling reservations — or calling because the poor cancellation UX left them unsure whether their cancellation had actually gone through.
The platform wasn't just reporting anymore; it had found its first product fix. I owned the product discovery, built the frontend self-service cancellation flow, and specced the backend changes. From insight to ship: one week of discovery, a month for UX to finalize the design, a month to move up the groomed backlog — then built in a single sprint and released successfully.
Result: total call volume cut by ~30%.
Outcome
- ~1,400 calls/day transcribed, redacted, and classified automatically with a version-controlled question set
- Classification throughput went from hours to minutes by adopting Batch Inference the week it shipped
- Executives self-serve answers via QuickSight and a Lex + Bedrock chatbot — replacing credential-sharing and guesswork
- The platform's own insights drove a ~30% reduction in call volume