La ingeniería rápida falla silenciosamente: la regresión rápida es la razón

Las indicaciones no son archivos de configuración estáticos. Cada instrucción que agregue cambia el comportamiento de cada tipo de consulta que el mensaje ya maneja. La mayoría de los equipos detectan fallas inmediatas a través de informes de usuarios, no de pruebas. Este artículo crea el conjunto de pruebas. La suite ejecuta 40 consultas de oro en cuatro versiones de mensajes, valida los resultados con cuatro comprobaciones deterministas y detecta el patrón de mejora falsa, donde la precisión general aumenta mientras una categoría crítica colapsa. v4, el "mejor" mensaje con una precisión general del 67,5 %, desencadenó una FALSA MEJORA DETECTADA debido a un colapso del 66,7 % en la clasificación de negación. Cero dependencias externas. Pitón puro. Se ejecuta en menos de dos segundos.

Mi capa de consulta RAG estaba funcionando bien. Luego agregué el enrutamiento de documentos para PDF y políticas, y el mensaje aumentó de seis instrucciones a catorce. Probé algunos casos, todo parecía correcto y lo envié.

Tres semanas después, estaba rastreando un problema de soporte en el que las consultas de negación (cosas como "¿Qué productos no están cubiertos por la garantía?") se clasificaban erróneamente como búsquedas de pólizas estándar en lugar de verificaciones de negación. Lo extraño fue que no había tocado la lógica de clasificación ni el código de ruta. Lo único que cambió fue el aviso del sistema.

Fue entonces cuando entendí el problema. Estaba tratando mi mensaje como un archivo de configuración estático. No lo es. Un mensaje es una API estocástica y cada vez que le agrega instrucciones, está cambiando el contrato de API para cada tipo de consulta que maneja, no solo aquellas en las que estaba pensando.

El mundo de la ingeniería de software tiene un nombre para lo que yo no tenía: un conjunto de pruebas de regresión. La idea es sencilla. Antes de enviar cualquier cambio, se ejecutan las pruebas. Si algo que estaba pasando ahora falla, no realizas el envío. No tenía nada de eso como indicaciones. La mayoría de los equipos no lo hacen.

Esto refleja la idea central detrás del desarrollo basado en pruebas (Beck[5]): define el comportamiento esperado antes de realizar cambios. La disciplina te obliga a definir el comportamiento correcto antes de tocar el código. Aplicado a las indicaciones, esto significa definir una lógica de clasificación válida para cada categoría antes de agregar una nueva instrucción. Sin estas definiciones, no hay forma de detectar cuándo un cambio rompe algo en lo que ni siquiera estaba pensando.

El problema de los costos ocultos también existe en los sistemas de aprendizaje automático. Sculley et al.[4]documentó cómo las dependencias no declaradas y las interfaces de datos inestables se acumulan como deuda técnica en los canales de producción de ML. Un mensaje que altera silenciosamente el comportamiento en todas las categorías sin ser detectado es exactamente esta clase de problema. La interfaz parece estable desde fuera, pero el comportamiento ha cambiado por debajo.

Todos los números a continuación provienen de ejecuciones reales de este sistema en Python 3.12, Windows 11, solo CPU.

El código está en: https://github.com/Emmimal/prompt-regression-suite

La configuración

El conjunto de regresión prueba cuatro versiones de solicitudes frente a 40 consultas de oro en seis categorías de intención, construidas sobre un sistema de clasificación de intenciones RAG.[1]. Las cuatro versiones reflejan una secuencia de iteración real del sistema de clasificación de intenciones RAG que construí para este artículo. Cada cambio se realizó por una razón legítima y cada uno introdujo un problema oculto.

v1 es la línea de base. Maneja una clasificación limpia de intenciones con instrucciones mínimas y cero pasos de razonamiento. Sólo hay una regla para mantener las cosas concisas y otra sobre el formato de salida JSON.

v2 agrega razonamiento en cadena de pensamiento. Incluí esto porque las consultas de múltiples saltos, como verificar el tiempo de respuesta para un plan empresarial con un ticket P1 fuera de horario, se clasificaban erróneamente. Se ha demostrado que la cadena de pensamiento mejora significativamente el rendimiento en tareas de razonamiento complejas.[2], y solucionó ese problema específico. El error fue aplicarlo globalmente. El mensaje v2 ahora le dice al modelo que "sea conciso" en una regla, mientras le exige "explica tu razonamiento paso a paso" en otra. Esas dos reglas se contradicen en cada consulta simple que toca el sistema.

v3 agrega enrutamiento de documentos. Las nuevas instrucciones le indican al modelo que verifique señales tabulares, de políticas y de PDF antes de clasificar la intención. Una línea en particular rompió por completo el manejo de negaciones: "Priorizar el enrutamiento de documentos antes que la clasificación de intenciones". Consultas de negación como "¿Qué regiones están excluidas de la política de envío exprés?" contienen palabras clave de política, por lo que en la versión 3, el modelo resuelve el tipo de documento antes de que toque la intención. El cheque de negación ni siquiera se activa.

v4 combina ambos cambios y esto es lo que se convirtió en el mensaje de producción. La superficie total de instrucción aproximadamente se triplicó y los conflictos latentes de v2 y v3 ahora se están agravando.

El conjunto dorado

Las 40 consultas se distribuyen en seis categorías.

Categoría NModo de falla objetivosimple_intent10overreasoning_noisecomparison8missing_comparative_anchoraggregation6numeric_scope_collapsenegation6instruction_conflictmulti_hop6benefits_from_cotedge_ambiguous4false_confidenceTOTAL40

Cada consulta se eligió para exponer un modo de falla específico, no para ser una representación general. Tomemos como ejemplo la categoría de comparación. Es una falla conocida en este sistema porque las consultas de comparación requieren un ancla comparativa que la arquitectura de solicitud actual simplemente no resuelve. No lo oculto en este punto de referencia, y verá la anotación [FALLO CONOCIDO] en cada informe de diferencias.

En lugar de compararla con una respuesta de referencia codificada, cada consulta lleva una firma de validación: un conjunto de restricciones deterministas.

{ "id": "NQ_01", "query": "¿Qué productos no están cubiertos por la política de garantía?", "category": "negation", "expected_intent": "negation_check", "expected_schema_keys": ["intent", "confidence", "query_type", "rewrite_query"], "expected_patterns": ["no cubierto", "garantía"], "must_not_contain": ["No puedo", "Como IA"], "failure_mode": "instruction_conflict" }

El campo Failure_mode no está ahí para documentación. Es una afirmación comprobable. Si el mensaje tiene un conflicto de instrucciones que intercepta la resolución de negación, esta consulta fallará y esa etiqueta de modo de falla le indicará exactamente dónde buscar.

El validador

La clase QueryValidator ejecuta cuatro comprobaciones deterministas en cada salida. Sin LLM como juez y absolutamente sin puntuación de calidad subjetiva.

clase QueryValidator: def validar (self, salida: dict, consulta: dict) -> ValidationResult: # 1. Verificación de esquema: claves requeridas presentes en el dict de salida. salida.valores()).lower() patrón_failures = [ p para p en patrones_esperados si no re.search(re.escape(p.lower()), salida_texto) ] patrón_pass = len(pattern_failures) == 0 # 3. Verificación de intención: la intención clasificada coincide con la etiqueta esperada intención_detectado = salida.get("intención", "") intención_paso = intención_detectada == intención_esperada # 4. Verificación de guardia: Las cadenas must_not_contain están ausentes guard_violations = [g para g en must_not_contain si g.lower() en output_text] guard_pass = len(guard_violations) == 0

Una consulta pasa las cuatro comprobaciones o falla. No hay crédito parcial ni ponderación compleja, y definitivamente no hay ningún modelo de juez que introduzca variación entre ejecuciones. La puntuación de la categoría acaba de pasar_count/total_count. Le proporcionas la misma entrada y obtienes exactamente el mismo resultado cada vez.

Me salté por completo la ruta del LLM como juez. Honestamente, me di cuenta de algo importante aquí: las pruebas de regresión no son realmente un problema de calidad, sino un problema de contrato. Verificar si la intención de salida coincide con la intención esperada es binaria, por lo que un modelo de evaluación solo agrega ruido. Además, ejecutar un juez de LLM en 40 consultas por cada ajuste menor se vuelve costoso rápidamente. Este script finaliza en menos de dos segundos y no cuesta absolutamente nada.

El anotador y la detección de falsas mejoras

La clase Scorer calcula la precisión por categoría y luego hace una cosa más que es el objetivo real de este sistema.

REGRESSION_THRESHOLD = 0.10 CRITICAL_CATEGORIES = {"simple_intent", "negation"} # Detección de mejora falsa global_improved = candidato.overall_score > baseline.overall_score si global_improved y regresiones_críticas: candidato.false_improvement_detected = Verdadero candidato.false_improvement_reason = ( f"Puntuación general mejorada en " f"{(candidate.overall_score – baseline.overall_score) * 100:.1f}% " f"pero las categorías críticas retrocedieron: [{cats}]" )

El patrón de mejora falsa es el siguiente: un cambio rápido mejora la puntuación de precisión agregada al tiempo que colapsa el rendimiento en una categoría crítica específica. La métrica general parece buena, por lo que la envía porque el número aumentó. El mensaje está roto.

CRITICAL_CATEGORIES es una decisión de diseño específica del sistema. Para mi clasificador de intenciones, simple_intent y negation son fundamentales porque representan la mayor parte del tráfico real. Las consultas de múltiples saltos son importantes, pero son poco comunes. Una mejora del 100% en consultas raras no justifica un colapso del 66,7% en las comunes. Es por eso que se escriben pruebas de integración antes que pruebas unitarias en un flujo de pago: proteja primero lo que perjudica a los usuarios.

El simulador determinista

La suite utiliza un simulador simulado determinista en lugar de llamadas de LLM en vivo. Esta es la decisión arquitectónica más importante en el código base y necesita una explicación directa.

El simulador no produce resultados aleatorios. Cada función de falla refleja un patrón de falla real específico causado por un conflicto de instrucción específico en la versión del mensaje correspondiente.

def simular_salida(prompt_version: str, consulta: dict) -> dict: # v2 + simple_intent → CoT se filtra en rewrite_query, la comprobación de guardia se activa si versión == "v2" y categoría == "simple_intent": return _overreasoning_noise(query) # v3 + negación → el enrutamiento de documentos se intercepta antes de que la intención se resuelva si versión == "v3" y categoría == "negación": if número_consulta en (1, 3, 5): devuelve _instruction_conflict_moderate(consulta) # v4 + negación → ambos conflictos compuestos, intención clasificada erróneamente como ambigua si versión == "v4" y categoría == "negación": si número_consulta en (1, 2, 4, 5): devuelve _instruction_conflict_severe(consulta)

La función _instruction_conflict_severe produce "intención": "ambigua" donde la respuesta correcta debería ser "negación_verificación". La confianza cae al 0,39. La consulta reescrita contiene ruido CoT: "Paso 1: Escanear en busca de señales de tipo de documento… Paso 2: Se detectó palabra clave de negación: pero el enrutamiento del documento tiene prioridad… Paso 3: Por lo tanto, se clasifica como ambiguo pendiente de resolución del contexto del documento".

Esa salida no pasa la verificación de intención (intención incorrecta), la verificación de patrón (patrones de negación ausentes) y la verificación de guardia (tokens de paso CoT presentes). Esto significa que tres de cada cuatro comprobaciones fallaron en el mismo resultado, que es lo que refleja el colapso de negación del 66,7% de referencia: 4 de 6 consultas de negación fallaron en la versión 4.

La elección entre simulación determinista y llamadas de LLM en vivo depende completamente de lo que esté tratando de medir. Las pruebas de regresión no son una evaluación de la calidad. La evaluación de la calidad pregunta si un resultado es bueno; Las pruebas de regresión preguntan si un cambio rompió algo que ya estaba funcionando. Son problemas distintos que requieren herramientas diferentes.

LLM como juez funciona bien para la evaluación de la calidad porque puede procesar resultados abiertos[3]donde las métricas deterministas se quedan cortas. Sin embargo, las pruebas de regresión exigen un determinismo absoluto. Si los resultados de su prueba fluctúan entre ejecuciones, perderá la capacidad de separar una regresión inmediata genuina del ruido de fondo. El hecho de que un simulador determinista produzca exactamente el mismo resultado en cada ejecución es una característica, no una limitación.

Los dos métodos se complementan. Ejecute este conjunto de regresión antes de cada confirmación para interceptar rupturas estructurales y ejecute periódicamente sus evaluaciones de LLM como juez para auditar los matices abiertos que las comprobaciones basadas en código no pueden detectar.

Al evitar llamadas API en vivo, ejecutar python run_regression.py produce números idénticos cada vez, independientemente de quién clone el repositorio. Elimina la variación de modelos, las actualizaciones del lado del proveedor y las facturas de API innecesarias. Para un marco de regresión, la reproducibilidad es la única métrica que importa.

Resultados de referencia

PUNTUACIONES DE CATEGORÍA POR VERSIÓN INDICADA

Categoríav1v2v3v4simple_intent100.0%40.0%80.0%90.0%negación100.0%66.7%50.0%33.3%agregación100.0%100.0%100.0%100.0%mul ti_hop0.0%100.0%100.0%100.0%comparación0.0%0.0%0.0%0.0%edge_ambiguous25.0%100.0%100.0%100.0% GENERAL57.5%60.0%67.5%67.5%

La fila general es la que recibe los mensajes enviados a producción. v4 empata con v3 en 67,5%, ambos por encima del valor de referencia de v1 de 57,5%. Según esa métrica, la v4 es su mejor indicación. Según la métrica del conjunto de regresión, la versión 4 es un mensaje roto.

VEREDICTO: v1 → v4 ⚠ FALSA MEJORA DETECTADA La puntuación general mejoró un 10,0 % pero las categorías críticas retrocedieron: [negación] Regresiones críticas: • negación 100,0 % → 33,3 % ▼ 66,7 % Modo de error: instrucción_conflicto ESTADO: ✗ NO PROMOVER A PRODUCCIÓN

El mismo veredicto se aplica a las versiones 2 y 3. Los tres candidatos activan FALSA MEJORA DETECTADA. Los tres muestran una mejora general con respecto al valor inicial. Los tres han superado categorías críticas.

Lo que realmente hizo cada versión

Este desglose de la imagen muestra la cascada de regresión entre los tres candidatos.

Desglose del rendimiento de las técnicas de ingeniería rápida (cadena de pensamiento y enrutamiento) frente a un modelo de referencia. Las puntuaciones de precisión agregadas son muy engañosas; la ganancia del 100% en el razonamiento de múltiples saltos enmascara por completo la grave degradación del rendimiento (colapso de negación) que ocurre en las tareas de negación estándar. Imagen por autor

La precisión de los múltiples saltos muestra exactamente lo que sucedió. La línea de base v1 obtiene una puntuación del 0,0% aquí. Sin una cadena de pensamiento, las consultas condicionales complejas (donde se deben resolver tres o más condiciones en secuencia) se clasifican erróneamente como fact_retrieval. El modelo no puede manejar esas condiciones en paralelo sin un andamiaje de razonamiento explícito. CoT solucionó eso por completo, elevando las versiones 2, 3 y 4 al 100,0 %.

La cadena de pensamiento era la solución adecuada para el problema específico que debía resolver. El error fue aplicarlo globalmente. La instrucción exacta que solucionó las cadenas de razonamiento condicional hizo que el modelo explicara en exceso consultas simples, corrompiendo el campo reescrito_query con ruido paso a paso. La implementación de CoT condicional (aplicando el razonamiento solo cuando query_type == "complejo") habría solucionado el salto múltiple sin romper la intención simple. Sin un conjunto de regresión, no hay forma de ver que eso suceda hasta que los usuarios comiencen a informarlo.

El patrón de mejora falsa, visualizado

Gráfico de barras que compara las puntuaciones generales del LLM con la precisión de la negación en las versiones de las indicaciones v1 a v4. El gráfico ilustra una tendencia peligrosa: a medida que las puntuaciones generales aumentan del 57,5% al ​​67,5%, la precisión de la negación específica colapsa desde un perfecto 100% hasta el 33,3%.
La trampa oculta de las métricas agregadas en la evaluación de LLM: las sucesivas iteraciones de ingeniería (v1 a v4) inflan con éxito la puntuación de seguimiento general, pero secretamente provocan una grave regresión en la precisión de la negación, degradando activamente la experiencia del usuario final. Imagen por autor

Este no es un peor caso construido. Es el resultado estándar de una mejora rápida iterativa sin seguimiento a nivel de categoría. Cada cambio resuelve un problema real. Cada cambio esconde un costo real dentro de la métrica agregada.

La Arquitectura

Un diagrama de flujo de trabajo que ilustra un proceso de evaluación de LLM automatizado. El proceso comienza con versiones de avisos YAML y un conjunto de datos JSON de consultas doradas, que fluyen a través de scripts secuenciales de Python: loader.py, runner.py, validator.py y Scorer.py, y finalmente producen una salida regression_report.txt a través de reporter.py.
La arquitectura de un canal de evaluación de avisos automatizado, diseñado para detectar regresiones de rendimiento mediante la simulación de resultados en múltiples versiones de avisos y la validación de los resultados frente a comprobaciones deterministas. Imagen por autor

Decisiones de diseño honestas

El analizador YAML en loader.py es un analizador mínimo escrito a mano que maneja campos de cadena y escalares de bloques multilínea. No agregué PyYAML porque agregar una dependencia a un marco diseñado para ser auditable y clonado fácilmente es una compensación incorrecta. Si necesita anclajes o alias YAML en sus archivos de solicitud, el intercambio en PyYAML es solo un cambio de una línea.

El simulador determinista produce una degradación controlada, no un ruido aleatorio. Las consultas específicas que fallan en cada versión del mensaje reflejan patrones de falla reales de mi sistema de producción. Un sistema diferente con diferentes conflictos de instrucción tendrá puntos de falla completamente diferentes. El marco es portátil, pero el modelo de degradación no lo es. Debe escribir su propio simulador basado en los conflictos reales en su propio historial de mensajes.

El umbral de regresión del 10% es arbitrario. Lo configuré porque es el cambio más pequeño que claramente no es una medición de ruido en un sistema determinista. Para un sistema de clasificación médica donde la clasificación de síntomas_urgentes es importante, la establecería en 5%. Para un sistema de recomendación de bajo riesgo, el 15% podría ser aceptable. El umbral es un parámetro, no un principio.

La categoría de comparación obtiene una puntuación del 0,0 % en las cuatro versiones de mensajes. Se trata de un fallo conocido en la arquitectura de avisos actual, no de una regresión introducida por ninguna de las cuatro versiones. El clasificador de intenciones no tiene un paso de resolución de anclaje comparativo, por lo que las consultas que requieren comparar dos entidades a través de un atributo compartido fallan constantemente. No lo he escondido ni lo he excluido del punto de referencia. Aparece en cada informe de diferencias con una anotación [FALLO CONOCIDO]. Un conjunto de regresiones de producción debe distinguir entre las fallas esperadas a las que se les da seguimiento y las regresiones que se introducen recientemente. Este punto de referencia hace explícita esa distinción.

CRITICAL_CATEGORIES actualmente cubre simple_intent y negación. Agregar una nueva categoría crítica requiere una línea de código y un conjunto correspondiente de consultas doradas. El marco no asume que estas dos categorías sean universalmente importantes: son importantes para mi sistema específico.

Cómo aplicar esto en su sistema

El validador y el anotador son independientes del sistema. Aquí está la versión mínima viable: lo suficiente para detectar el patrón de “mejora falsa” antes de que llegue a producción.

Comience con 20 consultas doradas divididas en dos categorías. Elija los dos tipos que manejan su mayor tráfico y escriba diez consultas para cada uno. Para cada consulta, defina la firma de validación antes de escribir la entrada. Verse obligado a articular cómo se ve el comportamiento correcto es exactamente lo que le ayuda a seleccionar los casos de prueba correctos. Si no puede escribir la firma, todavía no comprende qué se supone que debe hacer el mensaje para ese tipo de consulta.

Defina dos CRITICAL_CATEGORIES. Estos son los segmentos donde una regresión desencadena un bloqueo automático del barco. Para un robot de atención al cliente, podría ser refund_eligibility y escalation_trigger; para un sistema de clasificación médica, es clasificación de síntomas urgentes. La definición de "crítico" es completamente específica del sistema y este marco no hace suposiciones sobre sus requisitos.

Ejecute estas pruebas antes de cada cambio de solicitud, no después. Siguiendo la disciplina que Beck describió[5], la suite se ejecuta antes de que se envíe el código, nunca después de que el usuario informe de un error. Toda la suite tarda menos de dos segundos en ejecutarse; no hay ninguna justificación operativa para retrasarlo.

Amplíe su conjunto dorado cada vez que surja un error de producción. Cada vez que un usuario informe una clasificación errónea, agregue esa consulta al conjunto junto con su firma de validación correspondiente. Con el tiempo, el conjunto dorado se convierte en un archivo completo de toda la superficie histórica de fallas de su mensaje.

Ajuste el umbral para CRITICAL_CATEGORIES según el impacto del fallo. La caída predeterminada del 10% es solo un punto de partida. Para las categorías de alto riesgo, ajuste el umbral al 5%. Para áreas de bajo riesgo, el 15% puede ser aceptable. Recuerde que el umbral es un parámetro regido por el costo del fracaso, no una constante universal.

Para el simulador, audite su registro de cambios. Cada instrucción introducida después de la línea de base inicial representa un conflicto potencial. Para cada uno, escriba una función de falla que fuerce una salida que refleje ese conflicto específico. Si agregó una regla de prioridad de enrutamiento, cree una función que fuerce la clasificación errónea del tipo de consulta que intercepta la regla. El acto de construir este simulador lo obliga a mapear la superficie de falla del indicador de una manera que las pruebas manuales nunca lo harán.

Cierre

La ingeniería rápida no es una tarea de una sola vez. Es un mantenimiento continuo de una API estocástica. Cada vez que agrega una instrucción para manejar un nuevo caso límite, está cambiando el comportamiento de cada tipo de consulta que el mensaje ya maneja. Algunos de esos cambios son inofensivos. Algunos de ellos son colapsos silenciosos en categorías en las que no estabas pensando.

La suite de regresión no le impide cambiar las indicaciones. Te dice exactamente qué se rompió cuando lo hiciste.

Código completo: https://github.com/Emmimal/prompt-regression-suite

Divulgación

Todo el código de este artículo fue escrito por mí y es un trabajo original, desarrollado y probado en Python 3.12, Windows 11, solo con CPU. Los resultados de las pruebas comparativas provienen de ejecuciones reales de run_regression.py y son completamente reproducibles clonando el repositorio y ejecutando el punto de entrada. El simulador produce resultados deterministas: la misma ejecución produce los mismos números cada vez. No se llamó a ningún LLM durante la evaluación comparativa. El error en la consulta de comparación (0,0 % en las cuatro versiones de solicitud) es una limitación arquitectónica conocida del diseño de solicitud actual y se incluye en este punto de referencia sin cambios. No tengo ninguna relación financiera con ninguna herramienta, biblioteca o empresa mencionada en este artículo.

Referencias

[1]Lewis, P., Perez, E., Piktus, A., Petroni, F., Karpukhin, V., Goyal, N., Küttler, H., Lewis, M., Yih, W.-t., Rocktäschel, T., Riedel, S. y Kiela, D. (2020). Generación aumentada de recuperación para tareas de PNL intensivas en conocimiento. Avances en los sistemas de procesamiento de información neuronal, 33, 9459–9474. https://doi.org/10.48550/arXiv.2005.11401

[2]Wei, J., Wang, X., Schuurmans, D., Bosma, M., Ichter, B., Xia, F., Chi, E., Le, Q. y Zhou, D. (2022). La cadena de pensamiento provoca razonamiento en modelos de lenguaje grandes. Avances en sistemas de procesamiento de información neuronal, 35. https://doi.org/10.48550/arXiv.2201.11903

[3]Zheng, L., Chiang, W.-L., Sheng, Y., Zhuang, S., Wu, Z., Zhuang, Y., Lin, Z., Li, Z., Li, D., Xing, EP, Zhang, H., González, JE y Stoica, I. (2023). Juzgar LLM como juez con MT-Bench y Chatbot Arena. Avances en sistemas de procesamiento de información neuronal, 36, 46595–46623. https://doi.org/10.48550/arXiv.2306.05685

[4]Sculley, D., Holt, G., Golovin, D., Davydov, E., Phillips, T., Ebner, D., Chaudhary, V., Young, M., Crespo, J.-F. y Dennison, D. (2015). Deuda técnica oculta en los sistemas de aprendizaje automático. Avances en los sistemas de procesamiento de información neuronal, 28, 2503–2511. https://dl.acm.org/doi/10.5555/2969442.2969519

[5]Beck, K. (2002). Desarrollo basado en pruebas: con el ejemplo. Profesional de Addison-Wesley.

Si esto le resultó útil, no dude en conectarse conmigo en LinkedIn y explorar más de mi trabajo en mi sitio web.

Comparto periódicamente conocimientos sobre sistemas LLM, evaluación rápida y creación de IA confiable en producción.

LinkedIn: Emmimal P Alexander
Sitio web: EmiTechLogic