Construcción de un cliente de correo electrónico de AI

Read this article in:

En el proceso de construir un sistema de IA, primero construiré la parte "agentic" y "system", tocando muy poco en IA. Hay varias razones para esto. La auditoría es una de ellas. Quiero saber exactamente qué está pasando y por qué. Creo que la AI es fundamentalmente innecesaria para la toma de medidas (1) y (2) toma de decisiones para mí en este momento. See La automatización es más útil que la inteligencia artificial, por algún razonamiento de estilo libre sobre el tema.

Puede pensar en el sistema de software como animal. Los músculos, el esqueleto y el resto de la estructura van un largo camino, mucho antes de que la inteligencia en un animal se vuelva útil o deseable. Me tomaría un buey o una mula sobre un mono, por trabajo, la mayor parte del tiempo. Así que vamos a desarrollar la estructura primero - los músculos y los huesos - antes de desarrollar el cerebro.

Ya tengo un borrador de un sistema que se puede convertir a la clase de agente. En realidad, tengo dos. Uno es el cliente de correo electrónico. El otro es un bot comercial - ver Construyendo una plataforma de comercio.

Tengo un cliente de correo electrónico (una plataforma de correo electrónico completa en realidad) y se puede convertir a agenteic. Esto significa que el cliente de correo electrónico responderá automáticamente a los correos electrónicos. ¡Qué divertido sería eso! Me sorprende que no haya hecho esto antes. En realidad, he trabajado durante años en este proyecto, tomando descansos muy largos. Y otras personas y empresas también han estado trabajando en ello, estoy seguro de que ya existen sofisticados clientes de correo electrónico, de código abierto o propietarios. Haré mi propio ejercicio y porque lo necesito. Y no voy a dejar de trabajar con otra persona y simplemente pagar una cuota de API. No, yo mismo haré el trabajo, y seré dueño del producto acabado.

En el sistema de correo electrónico, las piezas son (0) recibiendo y analizando correos electrónicos, (0) manteniendo un seguimiento de conversaciones previas y todo el historial de conversaciones con este guía y guía, (0) generando un email de respuesta (quizás a través de una plantilla rica), (0) y siguiendo un ?intent para mover el plomo hacia abajo un embudo de ventas.

~ ♪♪

Muy bien, empecemos. Iremos de simple a complejo para ahorrarnos tiempo y dolor de cabeza. Vamos a revisar la arquitectura de la plataforma comercial ya que ya está bastante hecho. Además, vamos a estar haciendo esto en rubí en carriles principalmente, como cuestión de preferencia personal. Si usted está empezando desde cero probablemente tengo que recomendar pitón, ya que tanto código AI es pitón. Y definitivamente recomiendo contra el tiposcript, sugiero que use javascript puro porque es mucho más claro y más ligero.

Digamos que la configuración ya se ha hecho. Volveremos a rehacer la configuración una vez que establezcamos el paso del tiempo común. Por ahora, asumen que todo ya está funcionando.

En términos simples, el agente de correo electrónico hace lo siguiente:

 Upon receiving an email,
   Evaluate if any action needs to be taken.
     Examples are: add/remove tags, auto-respond, or (importantly) take an office action.
     Evaluation is semantically equivalent to taking the action.

Eso también suena bastante simple. Aquí, digo que decidir que una acción debe tomarse es la misma que tomar esta acción. Suena razonable para mí, y fluye en el espíritu de ruby-on-rails: el método es el mismo que el resultado de llamar el método. ¿Dónde está el agente entonces?

~ ♪♪

Veamos los sistemas de agentes existentes para ver cómo se construyen. Muchos de ellos son sistemas telefónicos: digamos que llama a su banco pero el teléfono trata de hablar con usted sin involucrar a un representante de servicio al cliente humano. ¿Cómo funcionan esos sistemas? Voy a saltar las cosas del lenguaje natural: el persing de voz, la generación de voz y LLM han sido hechas muy bien por los gigantes de la industria, y no puedo reinventar esas cosas ni realmente mejorar en ella. Usaré las rutinas de LLM y síntesis/análisis disponibles. Asumo que el texto inglés simple es la interfaz universal. Esto puede ser expandido en yaml o json - que es de nuevo un contenedor semántico mínimo con aspecto de lenguaje, pero mucho más estructurado que el inglés. La interfaz yaml/json convierte a código, especialmente para las integraciones de API - pero esa interfaz también puede ser limpia y comprensible. No necesito que AI escriba el código del conector de API, digamos que puede ser escrito por la gente.

Contexto

El sistema anticuado tiene contexto para el usuario: sabe quién es el usuario, qué hay en su cuenta, y lo que el usuario ha dicho o hecho anteriormente, de alguna manera. Para mí, esta información es datos estructurados del Leadset. Cada persona (dirección de correo electrónico) pertenece a su empresa (conjunto), y las muchas convergencias son retóricas referencias a esta persona (email). La información pertinente también es retráctil de todas las conversaciones de todos los compañeros de trabajo (compaña, guía). Esto se ha aplicado.

Intent

El sistema anti-temporal funciona con intención. El sistema lee la intención del cliente (por ejemplo: saldo de comprobación, tarjeta de informe robada, hacer un pago o cometer suicidio asistido por el gobierno). Por ahora vamos a tener todas las intenciones posibles. Entonces el sistema toma una de las acciones posibles. Parece que una acción disponible correlaciona muy de cerca con una intención. Tal vez cada intención corresponde a una o varias acciones. ¿Cómo escribiríamos eso en pseudocódigo?

 ## won't quite work:
 Upon receiving an email,
   Decide the intent (confirmable/overrideable), then
     Take action relevant to the intent.

Sin embargo, mi sistema de correo electrónico no es un chatbot de servicio al cliente. El cliente de correo electrónico no reacciona a la intención del remitente - tiene intención propia. El sistema tiene que tener sus propios objetivos. Llamo a la idea el embudo de ventas, por ahora. Dado que todo esto se está haciendo para generar ingresos, lo voy a hacer en ventas primero y más que nada.

Varias definiciones pragmáticas de botas de correo electrónico

Vamos a crear varias definiciones de bots de correo electrónico que tienen sentido y son pragratic. Vamos a diseñar uno o varios embudos de ventas, o acciones que un bot de agente puede tomar. Hagámoslo ya, en inglés. Recuerde que podemos convertir eso a yml/json, luego a las llamadas de interfaz de ruby, luego a la implementación de código real. Aquí vamos. Algunos agentes que ya tengo necesidad de:

  • Cumpleaños
  • SpamCocktailBot
  • EmailFluffBot
  • ColdcallBot

Y definiciones de pseudocódigo para cada uno por separado.

Cumpleaños

 BirthdayBot
   When it's someone's birthday as determined by tags and the clock,
     Generate an original birthday letter and send it.

ColdcallBot

 ColdcallBot
   For each tagged lead (in the campaign)
     periodically (every day)
       If I bothered them 0 times (n_impressions),
         send the main pitch.
         mark that I've bothered them 1 time.
       If I bothered them 1 time,
         send the 2nd reminder
         mark that I've bothered them 2 times.
       If I bothered them 2 times,
         send the 3rd sales pitch
         mark that I've bothered them 2 times.
       If I bothered them 3 times,
         remove tag, add tag `closed`
   When receiving an email in a relevant conversation,
     delete previously scheduled reminders
     remove tag, add tag `closing-manual`

SpamCocktailBot

 SpamCocktailBot
   When receiving an email from a spam lead (new or existing),
     Delete all previous follow-ups to this lead.
     Create a semi-meaningful reply and send it.
     Schedule to follow up in 2 days.

EmailFluffBot

 EmailFluffBot
   Periodically for each lead tagged to be conversed with,
     Taking previous conversations into account,
     Send them a generated email based on the general intent of the bot.

~ ♪♪

¿Cómo seguiría la pista de cuántas veces he llegado a una pista? Sería un nombre específico para la campaña por correo. El tiempo muestra todo en el nombre y mientras que por sí mismo no garantiza la unicidad del nombre, se acerca bastante a eso, y es muy semántico y utilizable. Un nombre de la campaña de ejemplo (slug) es `20260320-director` o '20260320 KY director coldcall' o algo similar, donde me dirijo a todos los directivos de Kentucky, hoy (diferente de hacer lo mismo mañana). El plomo de Seach tendría entonces el parámetro config:

 this_lead.memory ||= {}
 this_lead.memory['20260320 KY director coldcall'] ||= {}
 this_lead.memory['20260320 KY director coldcall']['n_impressions'] ||= 0
 this_lead.memory['20260320 KY director coldcall']['n_impressions'] += 1

La palabra 'memoria' arriba no significa absolutamente nada, pero también hay 'este lead.config' que es separado, y los elementos de memoria no deben estar en la raíz. La memoria es Contexto, pero ya uso la palabra Contexto en otro lugar.

Y enviar los principales, 2o y 3o lanzamientos son EmailTemplates. Este objeto ya ha sido construido, y tiene un contexto para el plomo, por lo que es un email transaccional con una sustitución rica templadora y variable como el nombre del líder.

La intención se puede implementar fácilmente con etiquetado (que ya existe). Tener etiquetas por ejemplo 'intent-they-salespitch-me' pertenece a la etiqueta 'intents', asignar esta etiqueta al plomo o la conversación, y allí vas, se ha hecho.

Posibles intenciones en el email:

  • me venden.
  • me molestan sin razón
  • spam
  • automatizado... periódico
  • un amigo cercano
  • un ser humano real
  • un cliente potencial
  • un reclutador

Así que, puedo asignar la intención al plomo y a la conversación etiquetandolos.

Una cosa más. Necesitamos conceptualizar un embudo de ventas. Véase el artículo sobre embudo de ventas: definición, modelos y etapas.

~ ♪♪

Es una buena idea escribir las manchas que planeas usar antes de tiempo, en la etapa de planificación, y no cambiarlas más tarde. Hay poca validación de las manchas, por lo que debe ser exacto en cómo acceder a los objetos. Me gusta comenzar cada slug con la fecha en formato yyyymmdd, o formato yyyyymm. Esto me funcionó bien, especialmente porque clasificar alfabéticamente también ordena por fecha.

Necesitas cada plantilla de correo electrónico. Las plantillas son:

  • 20260320-coldcall-intro
  • 20260320-coldcall-intro-1
  • 20260320-coldcall-intro-2

Necesitas la peluca de cada etiqueta. Son:

  • 20260320-coldcall-active
  • 20260320-coldcall-done

La lucha por esta campaña puede ser: `20260320-coldcall`. Observe que evito espacios en balas. Las manchas deben ser codificadas por url.

EmailTemplate

Así que mi bot de correo electrónico ai agente enviará una secuencia de correos electrónicos a pistas frías. Escribamos el contenido para los correos electrónicos. Este embudo es para los encargados de tomar decisiones técnicas, ejecutivos como CTO's en sus empresas. Primero, el bot se presentará y pedirá permiso para continuar. Entonces, la intención será capturada, que es una de las siguientes: (1) `no parar', (2) `sí-continue` y (3) `no respuesta`. Si responden positivamente, `sí-continue`, en realidad debería cambiar el proceso a manual, ya que sería un cliente interesado ya. En realidad conseguir que una sola persona responda `sies-continue` resultará en la terminación exitosa de esta tarea. Si contestan `no-stop`, el bot envía un buen mensaje final 'tmpl-fin-neg`. Si hay `no respuesta', se envía el mensaje `tmpl-intro-2`. Después de eso, si hay "no respuesta", se envía el mensaje "tmpl-fin-neg". Ese es el bot completo y el embudo completo. Vamos a revisar.

Hay dos maneras de crear las plantillas de correo electrónico. Puedes escribirlos tú mismo y salvarlos. O puede utilizar GPT para escribir y guardarlos. Este artículo es sobre el bot de correo electrónico, en lugar del agente de LLM conversacional, así que saltaré la segunda opción más complicada, y simplemente escribir la plantilla desde cero. En realidad, todavía usaré un GPT, pero copiaré el texto manualmente.

 20260320-coldcall-intro
   prompt: Write a cold-approach email directed at CTO's and other technical decision-makers of technology companies, asking them if they'd like to hear about the technology services (such as software development or feature implementation) that Wasya Co offers.

Asunto: Exploring Technology Solutions for [Nombre de la empresa]

Hola [primer nombre],

Espero que este mensaje te encuentre bien. Estoy llegando desde Wasya Co, donde ayudamos a las empresas tecnológicas a acelerar sus proyectos mediante el desarrollo de software experto y la implementación de funciones adaptadas.

Me encantaría entender sus prioridades tecnológicas actuales y explorar si nuestros servicios podrían apoyar a su equipo para lograrlos más eficientemente. ¿Estarías abierto a una breve llamada para discutir esto?

Esperando a sus pensamientos,

[Su nombre]
[Tu posición]
Wasya Co
[Información de contacto]

 20260320-coldcall-intro-1
   prompt: write a follow-up to the previous, if he doesn't reply in 2 days

Asunto: Seguimiento del soporte tecnológico para [Nombre de la empresa]

Hola [primer nombre],

Quería seguir mi correo electrónico anterior sobre cómo Wasya Co puede ayudar [Nombre de la empresa] con el desarrollo de software y la implementación de funciones.

Si estás abierto a una conversación rápida, estaría feliz de discutir cómo nuestras soluciones podrían ayudar a tu equipo a lograr sus objetivos más rápido y eficientemente. Por favor hágame saber un tiempo que funciona para usted, o me encantaría enviarle una breve información para que revise a su conveniencia.

Esperando escuchar de usted,

[Su nombre]
[Tu posición]
Wasya Co
[Información de contacto]

 20260320-coldcall-intro-2
   prompt: write a final, closing follow-up saying to reach out to me if anything changes

Tema: Último seguimiento – Wasya Apoyo tecnológico en Co

Hola [primer nombre],

Quería llegar a una última vez con respecto al desarrollo de software de Wasya Co y los servicios de implementación. Entiendo completamente si ahora no es el momento adecuado.

Si tus prioridades cambian o te gustaría explorar cómo podemos apoyar a tu equipo en el futuro, por favor no dudes en contactar con él, estaría feliz de conectarme cuando sea conveniente para ti.

Gracias por su tiempo y consideración,

[Su nombre]
[Tu posición]
Wasya Co
[Información de contacto]

Cree las plantillas de correo electrónico. Nos saltaremos el mensaje 'tmpl-fin-neg`, ya que el silencio servirá también por ahora.

Voy a combinar el código de rubí con el uso de la interfaz de usuario. La UI acomoda específicamente bloques de código eval'ing, en ciertos lugares. Aunque menos seguro que el punto y el clic, me ofrece dos ventajas. En primer lugar, no tengo que imaginar toda la UI que creo que necesitaré en el futuro. Sólo los callbacks de forma libre van muy lejos, y para un usuario técnico (experto) que será suficiente. En la línea, el sistema ofrecerá múltiples plazos de ejecución (por ejemplo, podrá escribir código de javascript o rubí, en su preferencia) así como UI para no escribir código en absoluto. Y segundo, me ofrece una tremenda flexibilidad. Mientras las variables correctas estén expuestas (y son), puedo ser muy sofisticado en lo que hago con ellas.

create email templates

Haga clic en el enlace `[+]` para comenzar a crear un nuevo EmailTemplate.

Tenga en cuenta que el sujeto, así como el cuerpo, permite las variables de plantilla erb. Las variables disponibles están listadas.

rich text editor

Haga clic en el enlace RTEditor en el pie de página para abrir el editor de texto rico en una ventana separada.

rich text editor

La razón por la que el editor de texto rico no se construye en el formulario, es que como usuario técnico, usted puede querer poner más que las etiquetas html en el cuerpo del correo electrónico. Específicamente, se puede utilizar la tentación erb (ruby) para insertar variables dinámicas en el texto. Las variables disponibles se enumeran en la información del campo de herramientas. Por ejemplo, puede escribir:

 Hello <%= @lead.name -%>,

Para personalizar el saludo. Para permitir esto, en la actualidad, debe escribir texto plano (que puede incluir código html u otro código). Pero todavía puede escribir texto rico en el editor proporcionado por separado, luego copiar-paste la fuente en la forma de la plantilla de correo electrónico.

Terminar pasando los valores y haga clic en Guardar.

finish and click save
Estados de maquinaria

Los estados de la máquina del estado actual son:

  • "Principio"
  • "no parar"
  • "no respuesta-1"
  • "no respuesta-2"
  • "si-continue"
  • "fin"

Las máquinas estatales y el estado, aunque no mencionado por este término en este artículo antes, se refieren al estado memorizado. El estado del líder se persistió por todos lados, y el líder tiene un diccionario estatal. Si salvaste algo en la memoria de este plomo hace un año, seguirá ahí. Por lo tanto, usted puede, o no, querer separar las variables para este campain en su propio hash:

## if you don't anticipate conflicts:
lead.memory['current_state'] = 'no-response-1'

## if you want to compartmentalize:
lead.memory['20260320-coldcall'] ||= {}
lead.memory['20260320-coldcall']['current_state'] = 'no-response-1'

que en realidad se correlaciona con la variable ' this lead.memory['20260320 KY director coldcall']['n impresions'] como tal:

n impresiones:current state:0(Principio)-(sin parar)1(sin respuesta-1)2(sin respuesta-2)-(si-continue)3(fin)

Usaré el estado actual, en lugar de las impresiones, ya que creo que es más preciso. O puedo usar ambas cosas. Ahora, implementemos este bot en la plataforma wco email. Una vez implementado, cargaremos unos 100 leads como datos de prueba, y lanzaremos la campaña!

\

OfficeActionTemplate's (OAT)

Ahora, vamos a configurar el bot, que consta de dos partes. Uno es un OfficeActionTemplate, que envía el EmailTemplate especificado anteriormente. El otro es un EmailFilter, que actúa sobre un responde desde el plomo.

Vamos a crear el OAT, que son las patatas y la carne de este bot/campaign. En Pseudocode puede parecer algo así:

 OfficeActionTemplate
   if leads.count == 0
     report to self: the campaign has ended
     this_oat.unschedule()
   For each lead in the tag `a20260320-active-leads`,
     case lead.memory['current_state']
     when
       (begin)
         send: a20260320-tmpl-intro
         lead.memory['current_state'] = no-response-1
       (no-stop)
       (no-response-1)
         send: a20260320-tmpl-intro-1
         lead.memory['current_state'] = no-response-2
       (no-response-2)
         send: a20260320-tmpl-intro-2
         lead.memory['current_state'] = no-stop
         lead.tags.delete a20260320-active-leads
         lead.tags.add    a20260320-done-leads
       (yes-continue)
       (fin)
   next_at( Time.now + 2.days )

Y el código:

tag = Wco::Tag.find_by({ slug: '20260320-coldcall-active' })
leads = tag.leads
if leads.count == 0
  @oat.update({ status: 'inactive' }) ## oat == office action template
  ApplicationMailer.notify_self({ subject: "Campaign 20260320-coldcall-active has finished." })
else
  leads.each do |lead|
    lead.memory['current_state'] ||= 'begin'
    lead.memory['n_impressions'] ||= 0

    case lead.memory['current_state']
    when 'begin':
      WcoEmail::EmailAction.create({ 
        lead: lead,
        template: EAT.find_by({ slug: '20260320-tmpl-begin' }), ## EAT == EmailActionTemplate
        perform_at: Time.now })
      lead.memory['current_state'] = 'no-response-1'

    when 'no-stop':
      lead.remove_tag tag

    when 'yes-continue':
      lead.remove_tag tag
      ApplicationMailer.notify_self({ 
        subject: "Campaign 20260320-coldcall-active lead #{lead.id} replied yes-continue!", 
        body: "Lead: #{lead.inspect} 

" }) when 'fin': lead.remove_tag tag when 'no-response-1': WcoEmail::EmailAction.create({ lead: lead, template: EAT.find_by({ slug: '20260320-tmpl-cont-1' }), ## EAT == EmailActionTemplate perform_at: Time.now }) lead.memory['current_state'] = 'no-response-2' when 'no-response-2': WcoEmail::EmailAction.create({ lead: lead, template: EAT.find_by({ slug: '20260320-tmpl-cont-2' }), perform_at: Time.now }) lead.memory['current_state'] = 'fin' else: ApplicationMailer.notify_self({ subject: "Campaign 20260320-coldcall-active something went wrong with lead #{lead.id}.", body: "Lead: #{lead.inspect}

Oat: #{@oat.inspect}" }) end end end

Vamos a pegarlo en la UI. Es un poco complicado y técnico, sin embargo, hacer una UI sin el código será aún más complicado, y sólo se hará en el futuro si se demuestra suficiente demanda de clientes.

OAT UI

Sigamos creando un filtro de correo electrónico.

EmailFilter

El EmailFilter es otra parte de este bot. Cuida las respuestas (si las hay) de las pistas.

 EmailFilter
   if lead.tags.include? a20260320-active-leads
     intent = induce_intent()
     lead.memory['current_state'] = intent
     case intent:
     when 'yes-continue':
       notify self: Email.find('this-lead-is-interested', lead:, )
     when 'no-stop':
       lead.tags.delete a20260320-active-leads
       lead.tags.add    a20260320-done-leads
     default:
       notify_self: Email.find('for-review', lead:, )

Y esto es casi todo. Lo único que queda por hacer es poner 100 pistas en esta etiqueta de prueba... ¡y lanzarla!

Aquí es cómo importar correos electrónicos en una etiqueta:

\

Y para lanzar la campaña, crear el OfficeAction fuera de la plantilla.

¡Genial! Ahora que se lanza, permite monitorear el proceso. Me he añadido como uno de estos líderes, así que voy a probar el flujo de trabajo participando en ambos lados de la campaña. Responderé tanto si-continue como sin parar, para probar el flujo de trabajo.

\

El flujo de trabajo anterior es un ejemplo de cómo configurar un agente de correo electrónico en el sistema wco email. Realmente no usamos IA para esto, sólo la parte de inducción de intención.

comments

Please login to post comments:
On Dom, 19/04/2026 - 20:14 admin said:

Many technologists rush to add AI into routine email workflows, but automation and well-structured rules often deliver far more reliability and transparency than agentic AI. Sometimes, a 'dumb' system is all a real business needs.