← Volver al Blog
12 min de lectura

Cómo usé Jev con Salesforce para tomar decisiones de IA en tiempo real sobre casos de soporte

Un experimento práctico de Jev junto con Salesforce para convertir casos de soporte en decisiones clasificadas.

Cómo usé Jev con Salesforce para tomar decisiones de IA en tiempo real sobre casos de soporte

Un caso de soporte llega a Salesforce con esta descripción:

No es urgente, pero ninguno de nuestros 80 comerciales puede crear presupuestos desde ayer. Esta tarde tenemos una demo con un cliente.

Una regla de asignación puede gestionar esa frase exacta. El problema aparece cuando los clientes describen la misma situación de cientos de formas distintas.

He usado Jev, el primer modelo System One de TypeSafe AI, para probar una idea: dejar que el modelo interprete el texto libre y devolver el resultado una automatización de Salesforce.

Cuando se crea un Case, Salesforce envía a Jev el texto relevante y plantea cuatro preguntas:

  • ¿Qué tipo de incidencia es?
  • ¿Hasta dónde llega su impacto?
  • ¿Qué urgencia tiene?
  • ¿Hay información suficiente para empezar a investigar?

Jev devuelve respuestas tipadas y probabilísticas. Salesforce decide qué hacer con ellas.

Detalle de un registro Case en Salesforce

Jev devuelve decisiones

Jev es el primer System One model público de TypeSafe AI. La compañía describe estos modelos como sistemas construidos para tomar decisiones dentro de software, no para generar texto dirigido a personas.

Esa diferencia se ve directamente en la API. Envío un estado y un conjunto de preguntas tipadas. Cada pregunta utiliza una de estas tres primitivas:

  • choice: elige una opción de un conjunto predefinido;
  • score: sitúa algo dentro de una escala ordenada;
  • noul: devuelve una probabilidad calibrada para una pregunta de sí o no.

TypeSafe lo presenta como type safety. La respuesta incluye también probabilidades y confianza, de modo que la aplicación puede tratar de forma distinta un resultado sólido y uno incierto.

Uno de los aspectos más interesantes del modelo es su velocidad y coste frente a los modelos de lenguaje de frontera más recientes. Ahí tiene uno de sus puntos fuertes.

Un LLM ya puede clasificar un Case

Un LLM convencional puede recibir la misma descripción y devolver JSON estructurado:

{
  "category": "technical",
  "impact": "high",
  "urgency": "critical",
  "informationSufficiency": "sufficient"
}

Los structured outputs ya hacen que una respuesta así sea mucho más segura de consumir desde código. La clasificación, por sí misma, no es la novedad.

Lo que me interesaba era la forma de la operación. Este flujo no necesita prosa, un resumen ni contenido generado. Necesita cuatro decisiones pequeñas que otro programa va a consumir de inmediato. Jev está diseñado alrededor de salidas tipadas, probabilidades, varias preguntas evaluadas sobre un mismo estado y baja latencia.

Aun así, necesitaría datos antes de confiar en la automatización. Términos como «impacto alto», «urgente» o «información suficiente» dependen de las definiciones que yo proporcione. Un conjunto etiquetado de casos reales o representativos serviría para medir si esas definiciones funcionan y dónde deberían situarse los umbrales de confianza.

El triaje de casos que construí

Dejé fuera problemas que Salesforce ya resuelve bien con reglas deterministas. Si los Leads de España van a una cola y los de Francia a otra, una regla de asignación, un Flow o unas pocas líneas de Apex resultan más fáciles de entender y mantener.

Con los casos de soporte escritos en texto libre ocurre algo distinto. Compara estas dos descripciones:

«Un usuario recibe un error al crear un presupuesto».

y:

«Nadie del equipo comercial puede crear presupuestos. Tenemos 80 usuarios bloqueados y una presentación a un cliente dentro de dos horas».

El área de producto puede ser la misma. El significado operativo no lo es.

Dividí ese significado en cuatro decisiones.

Categoría

Pregunta: ¿Sobre qué contacta realmente el cliente?

Para el prototipo utilicé un conjunto cerrado parecido a este:

TECHNICAL
BILLING
ACCOUNT
PRODUCT
OTHER

Es una pregunta de tipo choice. Jev clasifica el lenguaje y Salesforce relaciona el resultado con objetos del CRM. Si Jev devuelve BILLING, una regla normal de Salesforce puede dirigir el caso a Billing_Support_Queue.

Impacto

Pregunta: ¿Qué parte de la operativa del cliente está afectada?

Modelé el impacto como una escala ordenada:

LOW
MEDIUM
HIGH
BUSINESS_WIDE

«Un usuario no puede restablecer su contraseña» y «todo el almacén ha dejado de imprimir etiquetas» no deberían generar la misma señal de impacto solo porque ambos puedan ser casos técnicos.

Extraer esto mediante palabras clave resulta bastante torpe. Los clientes rara vez rellenan un campo bien ordenado como Affected Users = 80; cuentan el impacto con sus propias palabras.

Urgencia

Pregunta: ¿Con qué rapidez requiere atención según la situación descrita?

Mantuve la urgencia separada del impacto. Un sistema puede afectar a muchos usuarios sin que exista presión de tiempo. También puede haber una sola persona bloqueada ante algo que debe ocurrir dentro de 20 minutos.

Jev no establece aquí Case.Priority. Produce una señal de urgencia. La prioridad continúa siendo una regla de negocio de Salesforce.

Suficiencia de la información

Pregunta: ¿Hay información suficiente para que un agente de soporte empiece a investigar sin pedir primero una aclaración al cliente?

La «información suficiente» depende de la categoría. Solo contaría los detalles presentes en el texto o en los campos del Case enviados a Jev. La tabla permite comprobar cada etiqueta: sufficient significa que están presentes todos los requisitos indicados; partial, que se pueden identificar la incidencia y su objeto, pero falta algún requisito; insufficient, que no es posible identificar la incidencia o el elemento afectado.

CategoríaINSUFFICIENTPARTIALSUFFICIENT
TécnicaSe desconoce el servicio o funcionalidad afectada, o bien el problema observable.El servicio y el problema están claros, pero falta el alcance o cuándo empezó o funcionó por última vez.Se indican el servicio o funcionalidad, el error, el alcance y cuándo empezó o funcionó por última vez.
FacturaciónSe desconoce el problema de facturación o la cuenta o transacción afectada.La cuenta o transacción y el cargo reclamado están claros, pero falta el importe o el periodo o fecha de facturación.Se indican la referencia de factura o transacción, el importe, el periodo o fecha y la diferencia entre el cargo realizado y el esperado.
CuentaSe desconoce la cuenta u organización, o la operación solicitada o fallida.La cuenta y la operación están claras, pero falta el usuario, ajuste o permiso afectado, o bien el resultado real o error.Se indican la cuenta u organización, el usuario, ajuste o permiso afectado, la operación y el resultado real o error.
ProductoSe desconoce el producto o funcionalidad, o bien el problema.El producto, la funcionalidad y el problema están claros, pero falta la versión o plan, el comportamiento esperado frente al real, o detalles para reproducirlo o del error.Se indican el producto y su versión o plan, la funcionalidad, el comportamiento esperado, el comportamiento real y los pasos de reproducción o el error exacto.
OtroSe desconoce el elemento afectado o no hay una petición o problema sobre el que actuar.El objeto y la petición o problema están claros, pero falta el síntoma observado o el resultado deseado.Se indican el elemento afectado, una petición o problema claro y el síntoma observado o resultado deseado.

Jev Playground

Dónde termina Jev y empieza Salesforce

Mantuve separadas la interpretación y la política de negocio.

Jev recibe lenguaje y devuelve señales:

Category                → TECHNICAL
Impact                  → BUSINESS_WIDE
Urgency                 → CRITICAL
Information Sufficiency → SUFFICIENT

Salesforce ya conoce datos que no necesitan un modelo de IA:

Account Tier   → Enterprise
Support Plan   → Premium
Entitlement    → 24x7
Region         → EMEA
Business Hours → EMEA Support

El CRM puede combinar ambos conjuntos de valores con reglas normales:

Category = TECHNICAL
→ Technical Support Queue

Impact = BUSINESS_WIDE
AND Urgency = CRITICAL
AND Support Plan = Premium
→ Case Priority = Critical

Information Sufficiency = INSUFFICIENT
→ Start "Request More Information" flow

Jev no necesita conocer el ID de una cola, el nombre de un Flow activo ni la política de SLA de la empresa. Esas reglas se quedan en Salesforce, donde los administradores pueden inspeccionarlas y cambiarlas sin tocar las instrucciones del modelo.

Diagrama de arquitectura

Sacar el callout de la transacción del Case

Mantuve pequeña la transacción síncrona del Case. La creación de un caso no debería depender de que un servicio HTTP externo esté disponible.

El trigger recopila los IDs de los casos nuevos y encola el trabajo asíncrono:

trigger CaseTrigger on Case (after insert) {
    Set<Id> caseIds = new Map<Id, Case>(Trigger.new).keySet();
    System.enqueueJob(new ClassifyCasesWithJevJob(caseIds));
}

En una base de código real, normalmente colocaría esto detrás de un trigger handler. La versión inline mantiene el ejemplo centrado en la integración con Jev.

El Queueable implementa Database.AllowsCallouts:

public with sharing class ClassifyCasesWithJevJob
    implements Queueable, Database.AllowsCallouts {

    private final Set<Id> caseIds;

    public ClassifyCasesWithJevJob(Set<Id> caseIds) {
        this.caseIds = caseIds;
    }

    public void execute(QueueableContext context) {
        List<Case> cases = [
            SELECT Id, Subject, Description, AccountId,
                   Account.Support_Plan__c
            FROM Case
            WHERE Id IN :caseIds
        ];

        for (Case currentCase : cases) {
            JevDecision decision = JevService.classify(currentCase);
            JevDecisionMapper.apply(currentCase, decision);
        }

        update cases;
    }
}

No asumiría que cada lote de un trigger puede hacer un callout por Case. Los límites de callouts de Salesforce siguen aplicándose. Si los casos pueden llegar en lotes grandes, dividiría el trabajo mediante una cadena de Queueables, un worker basado en Platform Events u otra estrategia de procesamiento por lotes.

La decisión externa ocurre después de que termine la transacción original del Case.

Llamar a Jev desde Apex

Configuré el endpoint de TypeSafe mediante una Named Credential de Salesforce.

La petición contiene un objeto de estado y las cuatro preguntas:

{
  "model": "jev-latest",
  "state": {
    "subject": "Unable to create quotes",
    "description": "None of our 80 sales reps can create quotes and we have a customer demo in two hours."
  },
  "questions": {
    "category": {
      "type": "choice",
      "instructions": "What is the primary type of support issue?",
      "criteria": {
        "technical": "A product error, malfunction or technical failure.",
        "billing": "Invoices, payments, refunds or charges.",
        "account": "Login, permissions, access or account administration.",
        "product": "Product usage, configuration, how-to or feature questions.",
        "other": "None of the other categories is a good fit."
      }
    },
    "impact": {
      "type": "score",
      "instructions": "How broad is the operational impact described by the customer?",
      "criteria": [
        "Low: isolated inconvenience with little operational impact.",
        "Medium: one or a small number of users or a non-critical workflow is affected.",
        "High: many users or an important business workflow is blocked or seriously degraded.",
        "Business-wide: a broad business operation or most/all relevant users are unable to work."
      ]
    },
    "urgency": {
      "type": "score",
      "instructions": "How quickly does this issue require attention based only on the situation described?",
      "criteria": [
        "Low: no meaningful time pressure.",
        "Medium: should be handled soon but normal support timing is acceptable.",
        "High: there is clear time pressure or a near-term business consequence.",
        "Critical: immediate attention is needed because a time-critical activity or major operation is blocked."
      ]
    },
    "information_sufficiency": {
      "type": "choice",
      "instructions": "Is there enough information for a support agent to begin investigating without first asking what is failing or what behavior is observed?",
      "criteria": {
        "insufficient": "The problem cannot be meaningfully investigated without first asking for basic clarification.",
        "partial": "The issue is understandable, but important diagnostic context is missing.",
        "sufficient": "The affected functionality and observed behavior are clear enough to begin investigating."
      }
    }
  }
}

La API de TypeSafe evalúa las preguntas sobre el mismo estado en una sola petición, así que no necesito cuatro llamadas de red para un Case.

El servicio Apex es un pequeño cliente HTTP alrededor de ese payload:

public with sharing class JevService {

    public static JevDecision classify(Case currentCase) {
        HttpRequest request = new HttpRequest();
        request.setEndpoint('callout:TypeSafe_Jev/v1/systemone');
        request.setMethod('POST');
        request.setHeader('Content-Type', 'application/json');
        request.setTimeout(10000);

        request.setBody(
            JSON.serialize(JevRequestFactory.forCase(currentCase))
        );

        HttpResponse response = new Http().send(request);

        if (response.getStatusCode() < 200 ||
            response.getStatusCode() >= 300) {
            throw new JevException(
                'Jev returned HTTP ' + response.getStatusCode()
            );
        }

        return JevResponseParser.parse(response.getBody());
    }

    public class JevException extends Exception {}
}

Guardar las decisiones en el Case

Para el experimento, mantendría la salida de Jev en campos específicos en lugar de sobrescribir de inmediato los campos estándar del Case:

  • AI_Category__c
  • AI_Category_Confidence__c
  • AI_Impact__c
  • AI_Urgency__c
  • AI_Information_Sufficiency__c
  • ...

Así puedo revisar lo que ha decidido Jev sin perder los valores originales de Salesforce.

Triaje con IA

Cuando el Queueable escribe esos campos, cualquier otra automatización puede utilizarlos como cualquier otro dato de Salesforce.

El enrutamiento podría ser así:

AI_Category__c = "TECHNICAL"
AND AI_Category_Confidence__c >= 0.85

→ OwnerId = Technical Support Queue

La prioridad puede incorporar datos de la cuenta que Jev nunca llega a ver:

AI_Impact__c = "BUSINESS_WIDE"
AND AI_Urgency__c = "CRITICAL"
AND Account.Support_Plan__c = "Premium"

→ Priority = "Critical"

Un Case descrito con poca precisión puede seguir otro camino:

AI_Information_Sufficiency__c = "INSUFFICIENT"
AND AI_Information_Sufficiency_Confidence__c >= 0.85

→ Start Request More Information flow

Dónde usaría Jev en Salesforce

Salesforce ya maneja bien las condiciones explícitas. Si una regla depende de un valor de campo, un permiso, un entitlement, una fecha, un importe u otro dato almacenado, seguiría usando Flow, Apex, reglas de asignación, reglas de validación o el mecanismo nativo que corresponda.

Los casos incómodos son aquellos en los que la regla depende del significado de un texto libre:

«Haz X cuando el cliente esté describiendo un impacto operativo grave».

La responsabilidad de Jev es interpretar la intención del usuario e intentar convertirla en valores medibles. Salesforce se encarga después de ejecutar el proceso de negocio que corresponda según esos valores.

Sobre el Autor

Soy Guillermo Miranda, consultor Salesforce especializado en definir y desarrollar soluciones escalables para empresas.

Trabajemos juntos

¿Necesitas ayuda con Salesforce?

Guillermo Miranda

Ayudo a empresas a diseñar y construir soluciones Salesforce escalables.