Análisis Inteligente de Emails con Mistral AI y Python

Introducción

En nuestro artículo anterior explicamos cómo acceder desde Python a nuestro email en Microsoft Outlook, que es el primer paso para poder procesar de forma automática la información que recibimos. Sin embargo, acceder a los emails es solo el comienzo. El verdadero reto está en poder identificar, entre todos los emails, aquellos que contienen oportunidades de inversión.

Para conseguir este objetivo necesitamos combinar la potencia de los modelos de lenguaje (los LLMs) con técnicas tradicionales de procesamiento de texto. En este artículo explicamos cómo utilizamos Mistral AI para analizar el contenido de nuestros emails y extraer la información relevante.

Veremos que una parte importante del trabajo está en definir los prompts que enviamos al modelo LLM. Esto no debería sorprendernos. Si los LLMs nos aportan una capacidad de comprensión de texto que de alguna manera reemplaza el trabajo que tendría que hacer una persona, los prompts son el equivalente a las indicaciones que podríamos darle a una persona que nos estuviera ayudando en esta tarea de revisar emails.

¿Por qué un enfoque híbrido?

Cuando comenzamos este proyecto, nuestra primera idea fue utilizar simplemente palabras clave para identificar oportunidades de inversión de forma automatizada en nuestro . Buscábamos palabras clave como “ronda de inversión”, “pitch deck” o “term sheet”. Por ejemplo, este es el tipo de términos que buscábamos inicialmente:

keywords = [
    r"ronda de (inversión|inversion)",
    r"investment round",
    r"funding round",
    r"serie [ABC]",
    r"pitch deck",
    r"term sheet",
    r"data room"
]

Sin embargo, rápidamente nos dimos cuenta de que este enfoque no siempre funcionaba.

Los emails sobre oportunidades de inversión no siempre son explícitos. A veces, alguien nos comenta una startup sin mencionar explícitamente si están buscando capital, o nos envían un deck sin usar ninguna de las palabras clave comentadas. Por otro lado, algunos emails pueden mencionar estas palabras clave sin ser realmente relevantes. La tabla siguiente resume estas casuísticas:

Palabras clave NOPalabras clave SÍ
Oportunidad de inversión NOEjemplo:
Emails internosEjemplo:
Newsletters, artículos
Oportunidad de inversión SÍEjemplo: alguien nos comenta una startup sin mencionar si buscan inversiónEjemplo: alguien nos comparte una oportunidad de inversión

La solución fue combinar lo mejor de dos mundos: la capacidad de comprensión contextual de los modelos de lenguaje y la eficiencia de las técnicas tradicionales de procesamiento de texto (como regex).

Un Módulo de Análisis de Emails con Mistral AI

Nuestro módulo mistral_analysis.py es el componente principal de este proyecto. Su trabajo principal es responder a una pregunta aparentemente simple: ¿Este email contiene una oportunidad de inversión relevante?

Para responder a esta pregunta, el módulo realiza un análisis en dos fases. Primero, utiliza Mistral AI para entender el contexto y el contenido del email. Después, busca señales adicionales que puedan confirmar o reforzar el análisis inicial.

El código base para conectarnos con Mistral AI es bastante sencillo:

def __init__(self, api_key: str):
    self.mistral_client = Mistral(api_key=api_key)

Para analizar cada email, le damos la siguiente indicación a Mistral, donde {subject} y {body} serán reemplazados por el título y cuerpo del email:

prompt = f"""
Analiza este email y determina si está relacionado con una oportunidad de inversión.
Considera tanto menciones directas como indirectas a:
- Rondas de financiación
- Pitch decks
- Oportunidades de inversión
- Captación de capital

Presta especial atención a indicadores sutiles como:
- Discusiones sobre valoración de empresa
- Referencias a reuniones con inversores
- Menciones de cap tables o equity
- Proyecciones financieras
- Métricas de negocio en contexto de presentación
- Referencias a notas SAFE u otros instrumentos
- Menciones de términos de inversión

Subject: {subject}
Body: {body}

Responde en formato JSON:
{{
    "is_investment_round": true/false,
    "confidence": 0-1,
    "reasoning": "explicación breve",
    "detected_signals": ["señal1", "señal2", ...]
}}
"""

Como se puede ver al final del prompt, le estamos pidiendo que nos responda si o no a la pregunta de si el email contiene una oportunidad de inversión y que nos de una puntuación entre 0 y 1 para indicar el nivel de confianza de la respuesta.

Mejorando la Precisión

Nos dimos cuenta que, aunque el análisis de Mistral era bastante preciso, podíamos mejorarlo significativamente añadiendo un sistema de señales adicionales. Por ejemplo, si un email viene con un archivo adjunto que es un PDF o una presentación, o si incluye links a plataformas como DocSend o Dropbox, es más probable que sea relevante.

Para implementar esto, cuando creamos un nuevo analizador de emails, preparamos dos listas de patrones que usaremos para buscar señales adicionales:

def __init__(self, api_key: str):
    self.mistral_client = Mistral(api_key=api_key)

    # Patrones para detectar contenido relacionado con inversiones
    self.keywords = [
        r"ronda de (inversión|inversion)",
        r"investment round",
        r"funding round",
        r"serie [ABC]",
        r"pitch deck",
        r"term sheet",
        r"data room"
    ]

    # Plataformas comunes donde se comparten decks
    self.sharing_platforms = [
        'dropbox.com',
        'drive.google.com',
        'docsend.com'
    ]

Con estas listas preparadas, implementamos un sistema de “boost de confianza” que ajusta la puntuación inicial del análisis LLM. El sistema es conservador: puede aumentar la confianza hasta un máximo de 30%, distribuido entre diferentes tipos de señales.

La función check_confidence_signals que se muestra abajo es parte de nuestra clase EmailAnalyzer y utiliza las dos listas que hemos definido arriba (self.keywords y self.sharing_platforms). Estas listas las preparamos al inicio porque:

  1. Son patrones que vamos a usar muchas veces, cada vez que analizamos un email
  2. Nos permite tenerlos todos en un mismo lugar y cambiarlos fácilmente
def check_confidence_signals(self, subject: str, body: str, attachments: List[Dict] = None) -> float:
    """Calcula confianza adicional basada en keywords y attachments"""
    confidence_boost = 0.0
    text = f"{subject} {body}".lower()

    # Boost por keywords (hasta +0.15)
    keyword_matches = sum(1 for pattern in self.keywords
                        if re.search(pattern, text, re.IGNORECASE))
    confidence_boost += min(keyword_matches * 0.05, 0.15)

    # Boost por attachments relevantes (hasta +0.10)
    if attachments:
        extensions = ['.pdf', '.ppt', '.pptx']
        attachment_matches = sum(1 for att in attachments
                              for ext in extensions
                              if att.get('name', '').lower().endswith(ext))
        confidence_boost += min(attachment_matches * 0.05, 0.10)

    return confidence_boost

La función recibe tres parámetros: subject y body que son el asunto y cuerpo del email como strings, y attachments que es una lista opcional de diccionarios con información sobre los archivos adjuntos. Cada archivo adjunto es un diccionario que contiene al menos el nombre del archivo en su clave name. La función busca coincidencias tanto en el texto del email como en los nombres de los archivos adjuntos, y asigna puntos adicionales según las coincidencias encontradas.

Lo interesante de este enfoque es que nos permite ser más flexibles con el análisis inicial de Mistral. Podemos establecer un umbral de confianza más bajo para el análisis LLM, sabiendo que las señales adicionales nos ayudarán a filtrar falsos positivos.

Generación de Resúmenes Estructurados

Una vez que identificamos un email relevante, el siguiente paso es extraer y estructurar la información clave. Aquí es donde Mistral realmente brilla. Al igual que con la detección inicial, creamos una función específica para esta tarea de extraer y estructurar la información clave:

def summarize_investment_email(self, subject: str, body: str) -> str:
    """Genera un resumen detallado de un email relacionado con inversión"""
    prompt = f"""
    Genera un resumen estructurado de este email relacionado con inversión.
    Enfócate en extraer:
    - Nombre y sector de la empresa
    - Tipo de ronda y monto buscado
    - Métricas clave y KPIs
    - Tesis de inversión

    Subject: {subject}
    Body: {body}
    """

    response = self.mistral_client.chat.complete(
        model="mistral-medium",
        messages=[
            {"role": "system", "content": "Eres un experto en analizar inversiones."},
            {"role": "user", "content": prompt}
        ]
    )
    return response.choices[0].message.content

Esta función recibe los mismos parámetros que usamos anteriormente (subject y body), pero ahora los utilizamos con un propósito diferente. En lugar de detectar si es una oportunidad de inversión, queremos extraer y organizar la información relevante.

La clave está en cómo estructuramos el prompt: le damos a Mistral una lista específica de los elementos que queremos que busque, pero no le imponemos un formato rígido para la respuesta.

De esta manera permitimos que Mistral nos devuelva la información de la manera más natural según el contenido del email, mientras nos aseguramos de que busque los elementos que sabemos son importantes para evaluar una oportunidad de inversión.

Ejemplos Prácticos

Para entender mejor cómo funciona todo el sistema, veamos dos ejemplos reales (con datos modificados por privacidad) que muestran diferentes escenarios.

Caso 1: Detección Clara

Primero, veamos un caso donde la detección es bastante directa:

Subject: Presentación Startup HealthTech - Ronda Seed
From: carlos@empresa.com

Hola equipo,

Me gustaría presentaros MediTech, una startup que está revolucionando el sector de la telemedicina en España. Han desarrollado una plataforma que permite a los hospitales reducir sus listas de espera en un 40% mediante IA.

Algunos datos relevantes:
- ARR actual: 800K€
- Crecimiento MoM: 25%
- Clientes: 12 hospitales privados
- Burn rate: 45K€/mes
- Unit economics positivos desde el mes 3

Están levantando una ronda seed de 1.5M€ para expandirse a nuevos mercados. Ya tienen comprometidos 800K€ de otros fondos.

Os adjunto el deck con más información. Si os interesa, podemos organizar una llamada la semana que viene.

Saludos,
Carlos

En este caso, el sistema lo detecta fácilmente:

  1. Análisis inicial con Mistral AI:
{
    "is_investment_round": true,
    "confidence": 0.85,
    "reasoning": "Email explícitamente menciona una ronda seed, incluye métricas de negocio y solicita inversión",
    "detected_signals": ["mención directa de ronda", "métricas financieras", "deck adjunto", "propuesta de siguiente paso"]
}

  1. Boost de confianza:
  • +0.05 por keywords (“ronda seed”)
  • +0.05 por el deck adjunto Total: 0.95 de confianza final

Caso 2: Detección Ambigua

Veamos ahora un caso menos evidente:

Subject: Actualización LogisticTech - Nuevos avances
From: ana@logistictech.com

Hola,

Quería compartir con vosotros algunos avances importantes de LogisticTech. En los últimos 6 meses hemos conseguido:

- Implementación exitosa en 15 nuevos clientes
- Reducción de costes operativos del 35% para nuestros clientes
- Expansión del equipo a 25 personas
- Apertura de oficina en Portugal

Os adjunto una presentación con más detalles sobre nuestro crecimiento y plan de expansión para los próximos 18 meses. Si os interesa profundizar, podemos organizar una call.

Un saludo,
Ana

[Presentación.pdf]
[Financial_Projections.xlsx]

En este caso, el análisis es menos directo:

  1. Análisis inicial con Mistral AI:
{
    "is_investment_round": false,
    "confidence": 0.45,
    "reasoning": "No hay mención directa de ronda, aunque incluye métricas de crecimiento y planes de expansión",
    "detected_signals": ["métricas de negocio", "planes de expansión"]
}

  1. Boost de confianza:
  • +0.05 por keywords en nombres de archivos (“Financial_Projections”)
  • +0.05 por múltiples archivos adjuntos relevantes (.pdf y .xlsx) Total: 0.55 de confianza final
  1. Resumen generado:
Empresa: LogisticTech
Sector: Logística / Enterprise Software
Métricas clave:
- 15 nuevos clientes en 6 meses
- 35% reducción de costes para clientes
- Equipo de 25 personas
- Expansión internacional iniciada
Señales indirectas de fundraising:
- Presentación de crecimiento y expansión
- Proyecciones financieras detalladas
- Formato típico de investor update
Estado: Posible preparación para ronda
Urgencia: Media, sugieren call de seguimiento

Este segundo caso ilustra perfectamente el valor del sistema híbrido:

El análisis LLM inicial es conservador debido a la falta de menciones explícitas, pero las señales adicionales (múltiples archivos relevantes, formato específico) aumentan la confianza.

El resumen final captura tanto la información explícita como los indicadores indirectos y el mail pasaría el filtro para revisión humana, evitando perder una posible oportunidad.

Conclusión

En este post hemos explicado cómo utilizar Mistral AI para analizar nuestros emails y detectar oportunidades de inversión. El módulo que hemos desarrollado hace varias cosas importantes:

  1. Se conecta a la API de Mistral AI y procesa el contenido de cada email mediante prompts específicos.
  2. Combina el análisis de LLM con técnicas tradicionales para mejorar la precisión, identificando señales adicionales como archivos adjuntos relevantes o links a plataformas de sharing.
  3. Genera resúmenes estructurados con la información clave de cada oportunidad.

La parte que inicialmente nos parecía más manual era diseñar los prompts adecuados, pero con ayuda de los propios LLMs, enriquecer y mejorar los prompts se ha vuelto una tarea mucho más fácil.

Este módulo es la segunda parte un proyecto más amplio, que es un script de Python que:

  1. Accede y lee nuestro email en Microsoft Outlook (explicado en el post anterior).
  2. Analiza los emails con Mistral AI para detectar y procesar oportunidades de inversión (este post).
  3. Almacena la información procesada en nuestro repositorio de Airtable u otra base de datos externa.

Aunque el módulo actual cumple con nuestros objetivos, vemos varios caminos prometedores para mejorarlo en el futuro. Por ejemplo, podríamos expandir el análisis para incluir el contenido de los documentos adjuntos, que actualmente solo consideramos como una señal positiva.

También sería interesante implementar un sistema de aprendizaje que nos permita ajustar automáticamente los pesos del sistema de confianza basándonos en resultados históricos.

Otra mejora sería considerar el contexto más amplio de cada email, analizando threads completos y manteniendo un registro de remitentes que típicamente envían oportunidades relevantes. Todo esto nos permitiría mejorar aún más la precisión de nuestro modelo.

Aún así iremos paso por paso, y en el próximo post explicaremos cómo almacenamos y organizamos toda esta información en Airtable utilizando su API.

Keep reading