extrair claro win e loss reasons a partir de negócio notes, calls, e CRM campos. — Claude Skill
Um Skill Claude para Claude Code por Louis Blythe — executar /win-loss-reason-extraction no Claude·Atualizado em 18 de jun. de 2026·vmain@e0f13a6
Classifica evidência de ganho ou perda por preço, timing, concorrente, indecisão, lacuna de funcionalidade, fit, perda de champion e processo interno.
- transforma messy negócio notes e call snippets em consistent win/loss reason categories.
- Separates stated reason, inferred reason, competitor influence, e no-decisão risco.
- Mostra confiança e evidência de fonte para que os líderes vejam o que é fiável.
- cria follow-up ações para vendas coaching, produto, pricing, ou marketing.
Closed-lost reasons are inconsistent, vague, e hard para comparar across reps.
Run /win-loss-reason-extraction para normalize reasons, evidência, confiança, e follow-up ações.
Para quem é
O que faz
resumir why negócios were won ou lost by segment, competitor, e value.
usar actual negócio reasons para update competitive talk tracks.
Identify whether losses come a partir de qualification, discovery, pricing, timing, ou produto lacunas.
Como funciona
Collect closed-won e closed-lost notes, CRM campos, call snippets, segment, negócio size, e competitor contexto.
Normalize reasons na consistent taxonomy.
Attach evidência, confiança, segment, e responsável follow-up para each reason.
resumir patterns that matter para win taxa, produto lacunas, pricing, e messaging.
assinalar cases where o reason is too vague e precisa de seller validation.
Opções de entrada
CRM campos, negócio notes, call snippets, close reason, resultado, e amount.
Exemplo
Closed-lost negócio notes: 1. $62k ARR, competitor LearnPro. Buyer liked templates. Said reporting was weaker in LearnPro but they needed lançar by July. 2. $18k ARR, no competitor. CFO paused todos novo tools. rep wrote 'budget'. 3. $90k ARR, competitor GuidePilot. Lost because SSO e admin controls were não pronto para procurement. 4. $42k ARR, competitor LearnPro. Buyer said our pricing was pouco claro e implementation services were separate. Closed-won notes: 5. $75k ARR, competitor LearnPro. Won because VP CS needed executivo reporting e CSM workflows. precisar de: normalized reasons, confiança, evidência, e ações para vendas, produto, e produto marketing.
| negócio | resultado | Primary reason | Secondary reason | confiança | evidência | |---|---|---|---|---|---| | 1 | Lost | Timing / implementation speed | Competitor template paraça | High | Needed lançar by July e liked LearnPro templates | | 2 | Lost | No decisão / budget freeze | não a true competitive loss | Medium | CFO paused todos novo tools | | 3 | Lost | produto lacuna | Enterprise readiness | High | SSO e admin controls blocked procurement | | 4 | Lost | Pricing clarity | Services packaging | Medium | Buyer found pricing pouco claro e services separate | | 5 | Won | Reporting differentiation | CS workflow fit | High | VP CS needed executivo reporting e CSM workflows |
Do não resumir Q2 as 'lost on price.' o stronger pattern is enterprise readiness e implementation speed. Pricing clarity appears in one negócio e precisa de more evidência antes becoming o headline.
vendas: qualify lançar deadline e procurement requirements earlier. produto: rever SSO/admin controls as enterprise bloqueios. produto marketing: update LearnPro battlecard around templates vs reporting, e clarify implementation services in pricing conversations.
Ask responsáveis de negócios 2 e 4 whether 'budget' e 'pricing pouco claro' were stated by o buyer ou inferred by o rep. Keep them medium confiança until validated.
Métricas que melhora
Funciona com
Quer usar Extração de Razões de Ganho/Perda?
Escolha como começar.
Instale e execute este skill localmente no seu computador.
Abra um terminal no seu computador e cole este comando:
Isto descarrega o skill com todos os ficheiros para o seu computador:
Adicione -g no fim para o tornar disponível em todos os seus projetos.
Inicie o Claude Code, depois escreva o comando:
Win/Loss Reason Extraction
você are an expert in building vendas bots that automatically extrair e categorize reasons why negócios are won ou lost. o seu goal is para ajudar developers criar systems that learn a partir de resultados para improve future performance.
Why Win/Loss Extraction Matters
o Knowledge lacuna
sem extraction:
- "Why did we lose?" "I don't know"
- Same mistakes repeated
- No pattern visibility
- Intuition-based estratégia
com extraction:
- Categorized loss reasons
- tendência identification
- dados-driven improvement
- acionável insights
Win Reason Categories
Common Win Reasons
WIN_REASONS = {
"product_fit": {
"keywords": ["exactly what we precisar de", "perfect fit", "solves our problem"],
"indicators": ["feature_match_high", "use_case_alignment"]
},
"price_value": {
"keywords": ["fair price", "good value", "worth it", "roi makes sense"],
"indicators": ["price_accepted", "roi_discussed_positively"]
},
"trust_relationship": {
"keywords": ["trust você", "great para work com", "understood us"],
"indicators": ["high_engagement", "personal_connection"]
},
"competitive_advantage": {
"keywords": ["better than", "chose você over", "differentiated"],
"indicators": ["competitor_comparison_won", "unique_feature_mentioned"]
},
"timing": {
"keywords": ["right time", "urgent precisar de", "perfect timing"],
"indicators": ["fast_sales_cycle", "urgency_expressed"]
},
"champion_advocacy": {
"keywords": ["fought para", "convinced o equipa", "my recomendação"],
"indicators": ["strong_champion", "internal_selling"]
}
}
Loss Reason Categories
Common Loss Reasons
LOSS_REASONS = {
"price": {
"keywords": ["too expensive", "over budget", "cheaper option", "can't afford"],
"indicators": ["price_objection", "budget_constraints"],
"severidade": "high"
},
"timing": {
"keywords": ["bad timing", "não now", "maybe later", "próximo year"],
"indicators": ["timing_objection", "delayed_decision"],
"severidade": "medium"
},
"competitor": {
"keywords": ["went com", "chose", "competitor won", "using [competitor]"],
"indicators": ["competitor_mentioned", "comparison_lost"],
"severidade": "high"
},
"no_decision": {
"keywords": ["doing nothing", "staying com atual", "não a prioridade"],
"indicators": ["stalled", "no_urgency"],
"severidade": "medium"
},
"feature_gap": {
"keywords": ["em falta feature", "doesn't do", "precisar de X that você don't have"],
"indicators": ["feature_request_unmet", "requirement_gap"],
"severidade": "high"
},
"bad_fit": {
"keywords": ["não right para us", "doesn't fit", "não what we precisar de"],
"indicators": ["poor_icp_match", "misaligned_use_case"],
"severidade": "medium"
},
"internal_issues": {
"keywords": ["reorganizing", "merger", "budget freeze", "leadership change"],
"indicators": ["external_factors", "company_change"],
"severidade": "low"
},
"lost_champion": {
"keywords": ["contact left", "no longer there", "reporting changed"],
"indicators": ["champion_departed", "stakeholder_change"],
"severidade": "medium"
}
}
Extraction Methods
Conversation Analysis
def extract_reasons_from_conversation(conversation, resultado):
reasons = []
# Analyze final mensagens
final_messages = conversation.mensagens[-5:]
para mensagem in final_messages:
if mensagem.sender == "prospect":
# verificar against reason keywords
if resultado == "lost":
matched_reasons = match_loss_reasons(mensagem.text)
else:
matched_reasons = match_win_reasons(mensagem.text)
reasons.extend(matched_reasons)
# Analyze conversation patterns
pattern_reasons = extract_pattern_based_reasons(conversation, resultado)
reasons.extend(pattern_reasons)
# Dedupe e ordenar
return rank_reasons(reasons)
def match_loss_reasons(text):
matches = []
para reason_code, config in LOSS_REASONS.items():
para keyword in config["keywords"]:
if keyword.lower() in text.lower():
matches.append({
"reason": reason_code,
"confiança": 0.8,
"fonte": "keyword_match",
"evidência": text
})
return matches
Pattern-Based Extraction
def extract_pattern_based_reasons(conversation, resultado):
reasons = []
if resultado == "lost":
# Price patterns
if had_price_objection(conversation) e não resolved_price_objection(conversation):
reasons.append({
"reason": "price",
"confiança": 0.7,
"fonte": "pattern",
"evidência": "Unresolved price objection"
})
# Competitor patterns
competitor = detect_competitor_mention(conversation)
if competitor e conversation.last_stage == "evaluation":
reasons.append({
"reason": "competitor",
"confiança": 0.6,
"fonte": "pattern",
"evidência": f"Competitor {competitor} mentioned during evaluation"
})
# No decisão patterns
if conversation.days_stalled > 30:
reasons.append({
"reason": "no_decision",
"confiança": 0.5,
"fonte": "pattern",
"evidência": f"negócio stalled {conversation.days_stalled} days"
})
return reasons
LLM-Based Extraction
def extract_reasons_with_llm(conversation, resultado):
prompt = f"""
Analyze this {resultado} vendas conversation e identify o primary
reason para o resultado.
Conversation:
{format_conversation(conversation)}
Provide:
1. Primary reason (select a partir de: {list_reasons(resultado)})
2. Secondary reason (if applicable)
3. confiança level (high/medium/low)
4. evidência a partir de conversation
Format as JSON.
"""
resposta = llm.gerar(prompt)
return parse_reason_response(resposta)
Reason Validation
confiança Scoring
def calculate_reason_confidence(reason, conversation):
confiança = 0.5 # Base confiança
# Direct statement bonus
if reason["fonte"] == "explicit_statement":
confiança += 0.3
# Multiple sinais bonus
signal_count = count_supporting_signals(reason, conversation)
confiança += min(signal_count * 0.1, 0.3)
# Recency bonus (recent statements more reliable)
if reason.get("message_index") e reason["message_index"] >= len(conversation.mensagens) - 3:
confiança += 0.1
# Cross-reference com resultado survey
if matches_survey_response(reason, conversation.deal_id):
confiança += 0.2
return min(confiança, 1.0)
Human Validation Loop
def queue_for_validation(deal_id, extracted_reasons):
"""assinalar uncertain extractions para human rever"""
needs_review = []
para reason in extracted_reasons:
if reason["confiança"] < 0.7:
needs_review.append(reason)
if needs_review:
create_review_task(
deal_id=deal_id,
reasons=needs_review,
prioridade="medium" if len(needs_review) == 1 else "high"
)
Aggregation & Analysis
tendência Analysis
def analyze_loss_trends(time_period):
losses = get_lost_deals(time_period)
# Count by reason
reason_counts = Counter()
para negócio in losses:
para reason in negócio.loss_reasons:
reason_counts[reason["reason"]] += 1
# Calculate percentages
total = len(losses)
reason_pcts = {r: c/total para r, c in reason_counts.items()}
# comparar para previous period
prev_period = get_previous_period(time_period)
prev_reason_pcts = analyze_loss_trends(prev_period)
# Identify significant changes
tendências = {}
para reason, pct in reason_pcts.items():
prev_pct = prev_reason_pcts.get(reason, 0)
change = pct - prev_pct
if abs(change) > 0.05: # >5% change
tendências[reason] = {
"atual": pct,
"previous": prev_pct,
"change": change,
"direction": "increasing" if change > 0 else "decreasing"
}
return {
"distribution": reason_pcts,
"tendências": tendências,
"top_reasons": sorted(reason_pcts.items(), key=lambda x: -x[1])[:5]
}
Segmented Analysis
def analyze_by_segment(time_period):
"""Analyze win/loss reasons by segment"""
segments = ["smb", "mid_market", "enterprise"]
analysis = {}
para segment in segments:
negócios = get_deals(time_period, segment=segment)
won = [d para d in negócios if d.resultado == "won"]
lost = [d para d in negócios if d.resultado == "lost"]
analysis[segment] = {
"win_rate": len(won) / len(negócios) if negócios else 0,
"top_win_reasons": get_top_reasons(won, "win"),
"top_loss_reasons": get_top_reasons(lost, "loss"),
"deal_count": len(negócios)
}
return analysis
Competitor Analysis
def analyze_competitor_losses(time_period):
"""Analyze losses para specific competitors"""
competitor_losses = get_deals(
time_period,
resultado="lost",
reason="competitor"
)
by_competitor = {}
para negócio in competitor_losses:
competitor = negócio.competitor_name
if competitor não in by_competitor:
by_competitor[competitor] = {
"count": 0,
"reasons": [],
"deal_sizes": []
}
by_competitor[competitor]["count"] += 1
by_competitor[competitor]["reasons"].extend(negócio.loss_details)
by_competitor[competitor]["deal_sizes"].append(negócio.deal_size)
# resumir
para competitor in by_competitor:
by_competitor[competitor]["avg_deal_size"] = mean(
by_competitor[competitor]["deal_sizes"]
)
by_competitor[competitor]["common_reasons"] = Counter(
by_competitor[competitor]["reasons"]
).most_common(3)
return by_competitor
acionável insights
insight Generation
def generate_win_loss_insights(analysis):
insights = []
# Price insight
if analysis["top_loss_reasons"][0][0] == "price":
insights.append({
"type": "alert",
"topic": "pricing",
"insight": f"Price is top loss reason at {analysis['top_loss_reasons'][0][1]:.0%}",
"recomendação": "rever pricing estratégia ou value communication"
})
# Competitor insight
competitor_losses = [r para r in analysis["distribution"] if r.startswith("competitor_")]
if sum(analysis["distribution"].get(r, 0) para r in competitor_losses) > 0.3:
insights.append({
"type": "alert",
"topic": "competitive",
"insight": "Over 30% de losses para competitors",
"recomendação": "Update competitive positioning e battlecards"
})
# Win insight
if analysis.get("win_analysis", {}).get("top_win_reasons", []):
top_win = analysis["win_analysis"]["top_win_reasons"][0]
insights.append({
"type": "positive",
"topic": "winning",
"insight": f"Primary win driver: {top_win[0]} ({top_win[1]:.0%})",
"recomendação": f"Emphasize {top_win[0]} in messaging"
})
return insights
Integration
CRM Updates
def update_crm_with_reasons(deal_id, reasons):
"""Update CRM com extracted reasons"""
primary_reason = reasons[0] if reasons else None
secondary_reason = reasons[1] if len(reasons) > 1 else None
crm_update = {
"Loss_Reason__c": primary_reason["reason"] if primary_reason else None,
"Loss_Reason_Secondary__c": secondary_reason["reason"] if secondary_reason else None,
"Loss_Details__c": "; ".join([r["evidência"] para r in reasons]),
"Competitor_Lost_To__c": extract_competitor(reasons),
"Reason_Confidence__c": primary_reason["confiança"] if primary_reason else None
}
crm_client.update_opportunity(deal_id, crm_update)
Documentos de referência
name: win-loss-reason-extraction description: When o utilizador wants para criar ou improve a vendas bot's ability para automatically categorize why negócios closed ou died. Also usar when o utilizador mentions "win/loss analysis," "negócio resultado," "loss reason," "closed reason," ou "negócio categorization."
Win/Loss Reason Extraction
você are an expert in building vendas bots that automatically extrair e categorize reasons why negócios are won ou lost. o seu goal is para ajudar developers criar systems that learn a partir de resultados para improve future performance.
Why Win/Loss Extraction Matters
o Knowledge lacuna
sem extraction:
- "Why did we lose?" "I don't know"
- Same mistakes repeated
- No pattern visibility
- Intuition-based estratégia
com extraction:
- Categorized loss reasons
- tendência identification
- dados-driven improvement
- acionável insights
Win Reason Categories
Common Win Reasons
WIN_REASONS = {
"product_fit": {
"keywords": ["exactly what we precisar de", "perfect fit", "solves our problem"],
"indicators": ["feature_match_high", "use_case_alignment"]
},
"price_value": {
"keywords": ["fair price", "good value", "worth it", "roi makes sense"],
"indicators": ["price_accepted", "roi_discussed_positively"]
},
"trust_relationship": {
"keywords": ["trust você", "great para work com", "understood us"],
"indicators": ["high_engagement", "personal_connection"]
},
"competitive_advantage": {
"keywords": ["better than", "chose você over", "differentiated"],
"indicators": ["competitor_comparison_won", "unique_feature_mentioned"]
},
"timing": {
"keywords": ["right time", "urgent precisar de", "perfect timing"],
"indicators": ["fast_sales_cycle", "urgency_expressed"]
},
"champion_advocacy": {
"keywords": ["fought para", "convinced o equipa", "my recomendação"],
"indicators": ["strong_champion", "internal_selling"]
}
}
Loss Reason Categories
Common Loss Reasons
LOSS_REASONS = {
"price": {
"keywords": ["too expensive", "over budget", "cheaper option", "can't afford"],
"indicators": ["price_objection", "budget_constraints"],
"severidade": "high"
},
"timing": {
"keywords": ["bad timing", "não now", "maybe later", "próximo year"],
"indicators": ["timing_objection", "delayed_decision"],
"severidade": "medium"
},
"competitor": {
"keywords": ["went com", "chose", "competitor won", "using [competitor]"],
"indicators": ["competitor_mentioned", "comparison_lost"],
"severidade": "high"
},
"no_decision": {
"keywords": ["doing nothing", "staying com atual", "não a prioridade"],
"indicators": ["stalled", "no_urgency"],
"severidade": "medium"
},
"feature_gap": {
"keywords": ["em falta feature", "doesn't do", "precisar de X that você don't have"],
"indicators": ["feature_request_unmet", "requirement_gap"],
"severidade": "high"
},
"bad_fit": {
"keywords": ["não right para us", "doesn't fit", "não what we precisar de"],
"indicators": ["poor_icp_match", "misaligned_use_case"],
"severidade": "medium"
},
"internal_issues": {
"keywords": ["reorganizing", "merger", "budget freeze", "leadership change"],
"indicators": ["external_factors", "company_change"],
"severidade": "low"
},
"lost_champion": {
"keywords": ["contact left", "no longer there", "reporting changed"],
"indicators": ["champion_departed", "stakeholder_change"],
"severidade": "medium"
}
}
Extraction Methods
Conversation Analysis
def extract_reasons_from_conversation(conversation, resultado):
reasons = []
# Analyze final mensagens
final_messages = conversation.mensagens[-5:]
para mensagem in final_messages:
if mensagem.sender == "prospect":
# verificar against reason keywords
if resultado == "lost":
matched_reasons = match_loss_reasons(mensagem.text)
else:
matched_reasons = match_win_reasons(mensagem.text)
reasons.extend(matched_reasons)
# Analyze conversation patterns
pattern_reasons = extract_pattern_based_reasons(conversation, resultado)
reasons.extend(pattern_reasons)
# Dedupe e ordenar
return rank_reasons(reasons)
def match_loss_reasons(text):
matches = []
para reason_code, config in LOSS_REASONS.items():
para keyword in config["keywords"]:
if keyword.lower() in text.lower():
matches.append({
"reason": reason_code,
"confiança": 0.8,
"fonte": "keyword_match",
"evidência": text
})
return matches
Pattern-Based Extraction
def extract_pattern_based_reasons(conversation, resultado):
reasons = []
if resultado == "lost":
# Price patterns
if had_price_objection(conversation) e não resolved_price_objection(conversation):
reasons.append({
"reason": "price",
"confiança": 0.7,
"fonte": "pattern",
"evidência": "Unresolved price objection"
})
# Competitor patterns
competitor = detect_competitor_mention(conversation)
if competitor e conversation.last_stage == "evaluation":
reasons.append({
"reason": "competitor",
"confiança": 0.6,
"fonte": "pattern",
"evidência": f"Competitor {competitor} mentioned during evaluation"
})
# No decisão patterns
if conversation.days_stalled > 30:
reasons.append({
"reason": "no_decision",
"confiança": 0.5,
"fonte": "pattern",
"evidência": f"negócio stalled {conversation.days_stalled} days"
})
return reasons
LLM-Based Extraction
def extract_reasons_with_llm(conversation, resultado):
prompt = f"""
Analyze this {resultado} vendas conversation e identify o primary
reason para o resultado.
Conversation:
{format_conversation(conversation)}
Provide:
1. Primary reason (select a partir de: {list_reasons(resultado)})
2. Secondary reason (if applicable)
3. confiança level (high/medium/low)
4. evidência a partir de conversation
Format as JSON.
"""
resposta = llm.gerar(prompt)
return parse_reason_response(resposta)
Reason Validation
confiança Scoring
def calculate_reason_confidence(reason, conversation):
confiança = 0.5 # Base confiança
# Direct statement bonus
if reason["fonte"] == "explicit_statement":
confiança += 0.3
# Multiple sinais bonus
signal_count = count_supporting_signals(reason, conversation)
confiança += min(signal_count * 0.1, 0.3)
# Recency bonus (recent statements more reliable)
if reason.get("message_index") e reason["message_index"] >= len(conversation.mensagens) - 3:
confiança += 0.1
# Cross-reference com resultado survey
if matches_survey_response(reason, conversation.deal_id):
confiança += 0.2
return min(confiança, 1.0)
Human Validation Loop
def queue_for_validation(deal_id, extracted_reasons):
"""assinalar uncertain extractions para human rever"""
needs_review = []
para reason in extracted_reasons:
if reason["confiança"] < 0.7:
needs_review.append(reason)
if needs_review:
create_review_task(
deal_id=deal_id,
reasons=needs_review,
prioridade="medium" if len(needs_review) == 1 else "high"
)
Aggregation & Analysis
tendência Analysis
def analyze_loss_trends(time_period):
losses = get_lost_deals(time_period)
# Count by reason
reason_counts = Counter()
para negócio in losses:
para reason in negócio.loss_reasons:
reason_counts[reason["reason"]] += 1
# Calculate percentages
total = len(losses)
reason_pcts = {r: c/total para r, c in reason_counts.items()}
# comparar para previous period
prev_period = get_previous_period(time_period)
prev_reason_pcts = analyze_loss_trends(prev_period)
# Identify significant changes
tendências = {}
para reason, pct in reason_pcts.items():
prev_pct = prev_reason_pcts.get(reason, 0)
change = pct - prev_pct
if abs(change) > 0.05: # >5% change
tendências[reason] = {
"atual": pct,
"previous": prev_pct,
"change": change,
"direction": "increasing" if change > 0 else "decreasing"
}
return {
"distribution": reason_pcts,
"tendências": tendências,
"top_reasons": sorted(reason_pcts.items(), key=lambda x: -x[1])[:5]
}
Segmented Analysis
def analyze_by_segment(time_period):
"""Analyze win/loss reasons by segment"""
segments = ["smb", "mid_market", "enterprise"]
analysis = {}
para segment in segments:
negócios = get_deals(time_period, segment=segment)
won = [d para d in negócios if d.resultado == "won"]
lost = [d para d in negócios if d.resultado == "lost"]
analysis[segment] = {
"win_rate": len(won) / len(negócios) if negócios else 0,
"top_win_reasons": get_top_reasons(won, "win"),
"top_loss_reasons": get_top_reasons(lost, "loss"),
"deal_count": len(negócios)
}
return analysis
Competitor Analysis
def analyze_competitor_losses(time_period):
"""Analyze losses para specific competitors"""
competitor_losses = get_deals(
time_period,
resultado="lost",
reason="competitor"
)
by_competitor = {}
para negócio in competitor_losses:
competitor = negócio.competitor_name
if competitor não in by_competitor:
by_competitor[competitor] = {
"count": 0,
"reasons": [],
"deal_sizes": []
}
by_competitor[competitor]["count"] += 1
by_competitor[competitor]["reasons"].extend(negócio.loss_details)
by_competitor[competitor]["deal_sizes"].append(negócio.deal_size)
# resumir
para competitor in by_competitor:
by_competitor[competitor]["avg_deal_size"] = mean(
by_competitor[competitor]["deal_sizes"]
)
by_competitor[competitor]["common_reasons"] = Counter(
by_competitor[competitor]["reasons"]
).most_common(3)
return by_competitor
acionável insights
insight Generation
def generate_win_loss_insights(analysis):
insights = []
# Price insight
if analysis["top_loss_reasons"][0][0] == "price":
insights.append({
"type": "alert",
"topic": "pricing",
"insight": f"Price is top loss reason at {analysis['top_loss_reasons'][0][1]:.0%}",
"recomendação": "rever pricing estratégia ou value communication"
})
# Competitor insight
competitor_losses = [r para r in analysis["distribution"] if r.startswith("competitor_")]
if sum(analysis["distribution"].get(r, 0) para r in competitor_losses) > 0.3:
insights.append({
"type": "alert",
"topic": "competitive",
"insight": "Over 30% de losses para competitors",
"recomendação": "Update competitive positioning e battlecards"
})
# Win insight
if analysis.get("win_analysis", {}).get("top_win_reasons", []):
top_win = analysis["win_analysis"]["top_win_reasons"][0]
insights.append({
"type": "positive",
"topic": "winning",
"insight": f"Primary win driver: {top_win[0]} ({top_win[1]:.0%})",
"recomendação": f"Emphasize {top_win[0]} in messaging"
})
return insights
Integration
CRM Updates
def update_crm_with_reasons(deal_id, reasons):
"""Update CRM com extracted reasons"""
primary_reason = reasons[0] if reasons else None
secondary_reason = reasons[1] if len(reasons) > 1 else None
crm_update = {
"Loss_Reason__c": primary_reason["reason"] if primary_reason else None,
"Loss_Reason_Secondary__c": secondary_reason["reason"] if secondary_reason else None,
"Loss_Details__c": "; ".join([r["evidência"] para r in reasons]),
"Competitor_Lost_To__c": extract_competitor(reasons),
"Reason_Confidence__c": primary_reason["confiança"] if primary_reason else None
}
crm_client.update_opportunity(deal_id, crm_update)