Improve lead tracking and agent advice quality

- Use GACampaignID field + FIND(gad_campaignid) fallback in Leads Lake filter
- Add ConvLeadsLakeMes to campaign data for tracking discrepancy comparison
- Update ConvLeadsLakeMesFinal daily as snapshot of Airtable lead count
- Agent: ignore capping when capping=0 in advice

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jose Manuel 2026-04-22 12:25:00 +02:00
parent e80ed58000
commit c728cfc149
4 changed files with 36 additions and 4 deletions

View File

@ -19,6 +19,9 @@ ESTADO DE LA CAMPAÑA:
- Nunca recomiendes reactivar una campaña si status_google = ENABLED (ya está activa).
- Si status_google = PAUSED y la acción es AUMENTAR_PRESUPUESTO, menciona en el consejo que primero hay que reactivarla.
CAPPING:
- Si capping = 0, significa que no hay límite de leads configurado para este mes. No menciones el capping en el consejo ni en la justificación. Toma la decisión basándote únicamente en rentabilidad y ritmo.
REGLAS DE DECISIÓN:
1. urgencia=PAUSAR accion=PAUSAR siempre. El capping está lleno, seguir gastando destruye margen.
2. urgencia=SPRINT accion=AUMENTAR_PRESUPUESTO con parametro entre 1.3 y 1.5. Quedan pocos días y leads por entregar.

View File

@ -306,6 +306,7 @@ class AirtableClient:
"capping_mensual": int(f.get("CapTotalMes") or 0),
"cpa_maximo": float(f.get("CPAMax") or 0),
"margen_objetivo": float(f.get("MargenObjetivo") or 0),
"conv_leads_lake_mes": int(f.get("ConvLeadsLakeMes") or 0),
})
return result
@ -341,7 +342,10 @@ class AirtableClient:
mes_inicio = f"{now.year}-{now.month:02d}-01"
formula = (
f"AND("
f"FIND('gad_campaignid={campaign_id}',{{attr_referer}}),"
f"OR("
f"{{GACampaignID}}='{campaign_id}',"
f"FIND('gad_campaignid={campaign_id}',{{attr_referer}})"
f"),"
f"{{attr_utm_medium}}='paid_search',"
f"{{creado}}>='{mes_inicio}'"
f")"
@ -354,6 +358,19 @@ class AirtableClient:
"""Actualiza el campo 'Leads Lake' de un registro GACampaignMes."""
self.gacampaignmes.update(gcm_record_id, {"Leads Lake": lead_ids})
def batch_update_gacampaignmes_final_leads(self, gcm_records: list[dict]) -> None:
"""
Copia ConvLeadsLakeMes ConvLeadsLakeMesFinal en GACampaignMes.
Se llama una vez por ejecución diaria.
gcm_records: lista de dicts con 'airtable_id' y 'conv_leads_lake_mes'
"""
batch = [
{"id": r["airtable_id"], "fields": {"ConvLeadsLakeMesFinal": r["conv_leads_lake_mes"]}}
for r in gcm_records
]
for i in range(0, len(batch), 10):
self.gacampaignmes.batch_update(batch[i:i+10])
def batch_update_gacampaignmes_advice(self, updates: list[tuple[str, str, str]]) -> None:
"""
Actualiza en lote los campos 'Consejo' y 'Criticidad' de GACampaignMes.

View File

@ -35,8 +35,9 @@ def analyze(campaign_config: dict, leads_entregados: int, ads_metrics: dict) ->
else:
urgencia = "EN_RITMO"
# Discrepancia entre leads Airtable y conversiones Google
discrepancia = abs(conversiones_google - leads_entregados)
# Discrepancia entre leads Airtable (ConvLeadsLakeMes) y conversiones Google
conv_leads_lake_mes = campaign_config.get("conv_leads_lake_mes", leads_entregados)
discrepancia = abs(conversiones_google - conv_leads_lake_mes)
return {
"curso": campaign_config["curso"],

13
run.py
View File

@ -211,7 +211,7 @@ def run():
if analysis["alerta_tracking"]:
print(f" 🚨 ALERTA TRACKING: {analysis['discrepancia_tracking']} leads de diferencia "
f"entre Airtable ({leads}) y Google Ads ({int(analysis['conversiones_google'])})")
f"entre Airtable ({campaign['conv_leads_lake_mes']}) y Google Ads ({int(analysis['conversiones_google'])})")
print(f" Decisión: {accion_icono} {decision['accion']} "
f"(confianza: {decision['confianza']*100:.0f}%)")
@ -251,6 +251,17 @@ def run():
at.batch_update_gacampaignmes_advice(advice_updates)
print(" ✓ Consejos y criticidad guardados.")
# Copiar ConvLeadsLakeMes → ConvLeadsLakeMesFinal (snapshot diario)
final_leads_data = [
{"airtable_id": item["campaign"]["airtable_id"],
"conv_leads_lake_mes": item["campaign"]["conv_leads_lake_mes"]}
for item in collected
]
if final_leads_data:
print(f"→ Actualizando ConvLeadsLakeMesFinal ({len(final_leads_data)} registros)...")
at.batch_update_gacampaignmes_final_leads(final_leads_data)
print(" ✓ ConvLeadsLakeMesFinal actualizado.")
# Resumen final ordenado por prioridad (ya está ordenado)
print(f"{'='*55}")
print("RESUMEN FINAL")