AI Sales Call Analysis: Coaching Your Team with Conversation Intelligence
How to use AI to transcribe, analyze, and learn from every sales conversation
AI Sales Call Analysis: Coaching Your Team at Scale
Great sales managers listen to calls and coach reps. The problem: managers can't listen to every call, and the feedback loop is slow. AI conversation intelligence changes this — providing automated analysis and coaching insights for every single call.
The Conversation Intelligence Category
Gong raised $250M at a $7.25B valuation. Chorus was acquired by ZoomInfo for $575M. These valuations reflect the massive value of analyzing sales conversations systematically.
What these platforms do:
Building Your Own Conversation Intelligence
python
import anthropic
from openai import OpenAI
import json
from pathlib import Path
import tempfileclient_openai = OpenAI()
client_anthropic = anthropic.Anthropic()
class SalesCallAnalyzer:
"""
Analyzes sales call recordings using Whisper + Claude.
"""
def __init__(self):
self.whisper_model = "whisper-1"
def transcribe_call(self, audio_path: str) -> dict:
"""Transcribe call audio with speaker diarization."""
with open(audio_path, 'rb') as audio_file:
transcript = client_openai.audio.transcriptions.create(
model=self.whisper_model,
file=audio_file,
response_format="verbose_json",
timestamp_granularities=["segment"]
)
return {
'text': transcript.text,
'segments': transcript.segments,
'duration_seconds': transcript.duration if hasattr(transcript, 'duration') else None
}
def analyze_call(self, transcript: dict,
rep_name: str,
deal_stage: str,
call_type: str = 'discovery') -> dict:
"""
Comprehensive analysis of sales call transcript.
"""
message = client_anthropic.messages.create(
model="claude-opus-4-5",
max_tokens=4000,
messages=[{
"role": "user",
"content": f"""Analyze this sales call transcript and provide coaching insights.
Call Context:
Rep: {rep_name}
Call Type: {call_type}
Deal Stage: {deal_stage} Transcript:
{transcript.get('text', '')[:8000]}
Provide analysis in JSON format:
{{
"call_summary": "2-3 sentence summary",
"outcome": "positive/neutral/negative",
"next_steps_identified": ["..."],
"next_steps_committed": true/false,
"talk_ratio": {{
"rep_estimate_pct": 0-100,
"customer_estimate_pct": 0-100,
"assessment": "good/rep_dominated/customer_dominated"
}},
"topics_covered": {{
"pain_points_discovered": ["..."],
"product_discussed": ["..."],
"pricing_mentioned": true/false,
"competition_mentioned": ["competitor names"],
"timeline_discussed": true/false,
"budget_qualified": true/false,
"authority_confirmed": true/false
}},
"buying_signals": ["positive signals heard"],
"objections_raised": ["..."],
"objection_handling_quality": "strong/adequate/weak",
"bant_qualification": {{
"budget": "confirmed/uncovered/unknown",
"authority": "confirmed/uncovered/unknown",
"need": "confirmed/uncovered/unknown",
"timeline": "confirmed/uncovered/unknown"
}},
"coaching_feedback": {{
"strengths": ["what the rep did well"],
"improvements": ["specific things to improve"],
"missed_opportunities": ["what should have been asked/said"],
"overall_score": 1-10,
"priority_coaching_point": "single most impactful thing to work on"
}},
"deal_risk_assessment": "on_track/at_risk/needs_attention",
"risk_factors": ["any concerns about deal progression"]
}}"""
}]
)
try:
return json.loads(message.content[0].text)
except json.JSONDecodeError:
return {"raw_analysis": message.content[0].text}
def calculate_team_metrics(self, analyses: list[dict]) -> dict:
"""Aggregate call analyses into team performance metrics."""
if not analyses:
return {}
# Talk ratios
talk_ratios = [a.get('talk_ratio', {}).get('rep_estimate_pct', 50) for a in analyses]
avg_talk_ratio = sum(talk_ratios) / len(talk_ratios)
# BANT coverage rates
bant_coverage = {
dimension: sum(
1 for a in analyses
if a.get('bant_qualification', {}).get(dimension) == 'confirmed'
) / len(analyses)
for dimension in ['budget', 'authority', 'need', 'timeline']
}
# Next steps commitment rate
next_steps_rate = sum(
1 for a in analyses
if a.get('next_steps_committed', False)
) / len(analyses)
# Coaching scores
scores = [
a.get('coaching_feedback', {}).get('overall_score', 5)
for a in analyses
if a.get('coaching_feedback', {}).get('overall_score')
]
avg_score = sum(scores) / len(scores) if scores else 5
# Common improvement areas
all_improvements = []
for a in analyses:
all_improvements.extend(
a.get('coaching_feedback', {}).get('improvements', [])
)
# Count frequency of improvement themes
from collections import Counter
improvement_freq = Counter(all_improvements)
return {
'total_calls_analyzed': len(analyses),
'avg_talk_ratio_rep': round(avg_talk_ratio, 1),
'talk_ratio_optimal_pct': sum(
1 for r in talk_ratios if 35 <= r <= 50
) / len(talk_ratios),
'bant_coverage': {k: round(v, 2) for k, v in bant_coverage.items()},
'next_steps_commitment_rate': round(next_steps_rate, 2),
'avg_coaching_score': round(avg_score, 1),
'top_improvement_areas': improvement_freq.most_common(5)
}
Generate weekly coaching report for a manager
def generate_manager_coaching_report(rep_name: str,
call_analyses: list[dict]) -> str:
"""Generate weekly coaching report using Claude."""
metrics = SalesCallAnalyzer().calculate_team_metrics(call_analyses)
message = client_anthropic.messages.create(
model="claude-opus-4-5",
max_tokens=1500,
messages=[{
"role": "user",
"content": f"""Write a weekly sales coaching report for {rep_name}.Performance Metrics:
{json.dumps(metrics, indent=2)}
Individual Call Analyses (last 5 calls):
{json.dumps(call_analyses[-5:], indent=2)[:3000]}
Write a coaching report that:
Acknowledges specific strengths (with examples from calls)
Focuses on 1-2 specific improvement areas (not laundry list)
Gives concrete, actionable advice with examples
Sets specific goals for next week
Maintains motivating, constructive tone Format as a narrative coaching conversation, not bullet points."""
}]
)
return message.content[0].text
What Top Performers Do Differently
AI analysis of thousands of calls reveals consistent patterns:
Talk ratio: Top performers talk 43-47% of the time. Reps who dominate conversation (>65%) convert 30% less.
Questions per call: Top performers ask 11-14 questions per discovery call vs. 4-7 for average performers.
Competitor mentions: Top performers acknowledge competitors rather than avoiding the topic — addressing objections proactively.
Next steps: 100% of top performer calls end with a specific, committed next step with date. Bottom performers: 40%.
These insights can be surfaced automatically for every call — scaling coaching from "when manager has time" to "after every call."
Also available in 中文.