DEV Community

Silviu Technology
Silviu Technology

Posted on

LLMs: aprobaciones por email con contexto minimo

Cuando un agente con LLM necesita aprobacion humana por email, el fallo mas comun no suele estar en el modelo. Suele estar en el contrato entre decision, mensaje y ejecucion. El correo llega, alguien responde, el job continua... y unas horas despues nadie puede explicar con precision que version del plan fue aprobada, que entrada uso el agente o por que el resultado final no coincide del todo con lo que se vio en la inbox.

He visto que este problema aparece mucho en automatizaciones pequenas que crecen rapido. Al principio basta con "manda un resumen y espera OK". Luego llegan reintentos, varios operadores, cron jobs solapados y pruebas manuales con una inbox temporal o un generador de correos desechables. Incluso una prueba sencilla con tepm mail com puede verse bien para QA y aun asi dejar el sistema medio ciego. Para mi, el punto clave es este: la aprobacion por email debe cerrar una decision, no abrir una conversacion ambigua.

Por que los agentes con aprobacion por email pierden contexto

Yo dibujo este flujo en palabras:

  1. El agente prepara un plan.
  2. El sistema envia un resumen por email.
  3. Una persona aprueba o rechaza.
  4. Otro proceso retoma la ejecucion.

Suena ordenado, pero hay dos cortes peligrosos. El primero es entre el plan original y el resumen enviado. El segundo es entre la respuesta humana y el proceso que la interpreta. Si esos cortes no tienen identificadores claros, se cuela ambiguedad muy facil.

Los sintomas clasicos son bastante repetidos:

  1. El operador aprueba una version resumida, no el plan congelado.
  2. El worker retoma con contexto nuevo porque el prompt base ya cambio.
  3. Un reintento consume una respuesta vieja y paresca valida.
  4. Soporte ve "el email correcto" pero no puede unirlo con la corrida correcta.

Por eso me gusto mucho este enfoque de rastrear correos duplicados con run ids. Aunque habla de otro caso, deja clara una idea util: si el run no se puede seguir extremo a extremo, la lectura humana del inbox enga;a mas de lo que ayuda.

El contrato minimo que yo congelaria antes del envio

Si tuviera que simplificarlo al maximo, congelaria solo cinco cosas antes de mandar el correo:

  1. run_id
  2. plan_hash
  3. decision_scope
  4. reply_token
  5. expires_at

run_id une toda la corrida. plan_hash evita que el agente ejecute una version distinta de la aprobada. decision_scope deja claro que se esta aprobando: publicar, borrar, reenviar, desplegar. reply_token impide consumir respuestas cruzadas. Y expires_at evita que una aprobacion vieja reviva un job que ya no deberia correr.

Un contrato minimo se veria asi:

{
  "run_id": "20260804T232227Z-lucasg88",
  "plan_hash": "2d4f6c19",
  "decision_scope": "publish_devto_post",
  "reply_token": "approve_7b31",
  "expires_at": "2026-08-05T01:00:00Z"
}
Enter fullscreen mode Exit fullscreen mode

No hace falta mandar todo el contexto del agente dentro del correo. De hecho, ahi empieza el ruido. El email deberia contener una vista estable y corta: objetivo, riesgos, accion esperada y el identificador de la decision. Si quieres mas detalle, mejor enlazar al log interno o al artefacto congelado, no reescribir todo con cada intento.

Como separar decision humana y ejecucion automatica

La mejor separacion que encontre es pensar en tres capas:

  1. Capa de planeacion: el agente produce plan y artefactos.
  2. Capa de aprobacion: el humano responde sobre una version congelada.
  3. Capa de ejecucion: un worker retoma usando ids, no interpretaciones libres.

Ese corte baja bastante el acoplamiento. Tambien ayuda a que producto, operaciones y quien mantiene los prompts hablen de la misma cosa. Cuando no haces esta separacion, la inbox termina funcionando como base de datos improvisada, y eso casi siempre sale regular.

Si ademas el equipo ya trabaja con secuencias de onboarding o alertas operativas, vale la pena observar como otros sistemas escriben mensajes con una sola accion clara. Este ejemplo de recordatorios de onboarding que si ayudan me parece una buena referencia de claridad operacional, aunque no trate de agentes.

Un pseudocodigo simple:

type ApprovalEnvelope = {
  runId: string;
  planHash: string;
  replyToken: string;
  decisionScope: "publish_devto_post";
};

async function resumeAfterApproval(envelope: ApprovalEnvelope, reply: string) {
  const decision = parseHumanReply(reply, envelope.replyToken);
  if (decision !== "approve") return;

  const frozenPlan = await loadFrozenPlan(envelope.runId, envelope.planHash);
  await executeApprovedAction(frozenPlan);
}
Enter fullscreen mode Exit fullscreen mode

La idea es medio aburrida, pero funciona: el worker no "entiende emails", solo valida un sobre pequeno y luego carga artefactos congelados. Eso reduce bastante el riesgo de que un cambio en el prompt o en la bandeja altere la accion final.

Que revisar cuando el inbox parece correcto pero el sistema no

Cuando una aprobacion "se vio bien" pero el resultado salio raro, yo revisaria estas cuatro cosas antes de culpar al modelo:

  1. Si el plan_hash del correo coincide con el artefacto ejecutado.
  2. Si hubo mas de una respuesta humana para el mismo reply_token.
  3. Si el worker retomo con una configuracion distinta de la corrida original.
  4. Si la prueba manual y la prueba automatizada compartieron mailbox o alias.

Este ultimo punto importa mas de lo que paresce. Muchos equipos mezclan pruebas de operadores, smoke tests y sandbox usando la misma ruta de correo. Entonces el inbox "demuestra" que todo esta bien, pero la trazabilidad real quedo contaminada. Para flujos con temp mail so o cualquier inbox efimera, yo dejaria clarisimo que esas cuentas sirven para validar entrega y formato, no para convertirse en la fuente canonica de decision.

Checklist de implementacion

Si quisiera dejar esto mejor en una semana, haria lo siguiente:

  1. Congelar plan.json o equivalente antes de enviar el correo.
  2. Generar un plan_hash corto y visible en el email.
  3. Consumir respuestas humanas solo mediante reply_token.
  4. Separar completamente aprobacion de ejecucion en workers distintos.
  5. Guardar un verdict file o recibo final con run_id, decision y artefacto ejecutado.

No es una arquitectura glamourosa, pero si es bastante defendible. En sistemas con LLMs, casi siempre conviene gastar complejidad en limites claros y no en prompts cada vez mas largos. El contexto extra ayuda hasta cierto punto; despues solo hace mas dificil auditar lo que paso de verda.

Preguntas frecuentes

Debo incluir todo el prompt en el correo?

Yo no lo haria. Pondria solo un resumen estable y los ids de control. El prompt completo cambia mas seguido, ocupa espacio y complica mucho la revision humana.

Que pasa si alguien responde tarde?

Marca expiracion y rechaza respuestas fuera de ventana. Es un poco estricto, si, pero evita reactivar ejecuciones que ya quedaron obsoletas.

Y si necesito rehacer el plan despues de una correccion?

Genera un nuevo plan_hash y pide una nueva aprobacion. Reusar una aprobacion vieja para un plan nuevo es justo la clase de atajo que despues rompe auditoria, soporte y confianza del equipo.

Si una automatizacion con LLM ya depende de aprobaciones por email, yo empezaria por aqui. Menos contexto flotando, mas contratos pequenos y una linea de ejecucion que se pueda explicar sin adivinar nada.

Top comments (0)