Diseño de un buscador de empleos multiagente: pipeline, HyDE y observabilidad.
Un pipeline LangGraph de nueve pasos que relaciona los currículos con los empleos, con ocho opciones de diseño en cuanto a la recuperación con HyDE, la enrutación de modelos, los límites de tasa y la observabilidad.
Fuentes: Agentic AI in Practice: A Case Study in Multi-Agent System Design
Agentes, IA agente, sistemas multiagente: este vocabulario está por todas partes, y cada semana aparece otro modelo, framework o patrón de orquestación. Prompting, RAG, llamadas a herramientas, MCP, capas de memoria. El ecosistema evoluciona más rápido de lo que la mayoría de los profesionales pueden seguir. Debajo del ruido, las preguntas difíciles no han cambiado:
- ¿Dónde se debe dividir un problema en partes para su resolución?
- ¿Qué llamadas corresponden a un LLM, y cuáles nunca deberían dejarse en manos de uno solo?
- ¿Cómo podría alguien confirmar que el sistema hace lo que se cree que hace?
El lanzamiento de una nueva versión del framework no hace que estas tareas sean más fáciles. Para mantenerlo concreto, este estudio de caso utiliza un problema que afecta a millones de personas: encontrar los empleos adecuados entre una cantidad abrumadora de ofertas. Se diseña un sistema de IA de extremo a extremo para ello y se utiliza dicho diseño para responder a tres preguntas prácticas. ¿Qué significa “agente” en términos arquitectónicos? ¿Cuándo varios agentes aportan valor y cuándo representan una carga adicional? ¿Y qué hace que un sistema de IA sea observable, fiable y apto para su uso en producción?
Buscar trabajo no es realmente una búsqueda
La mayoría de las personas consideran la búsqueda de empleo como una tarea de búsqueda. En realidad se asemeja más a una tarea de correspondencia. Nadie busca realmente ofertas que contengan ciertas palabras clave. La pregunta subyacente es más difícil: dado esta experiencia, estas habilidades y esta dirección profesional, ¿cuáles son las oportunidades que realmente encajan?
Las plataformas de empleo lo tratan como una búsqueda. Escribes algunos términos, añades una ubicación y esperas que aparezca algo relevante. Sin embargo, un currículum refleja años de experiencia, conocimiento del sector, profundidad técnica, habilidades transferibles, progresión y contexto, y un cuadro de búsqueda reduce todo eso a unas pocas palabras, asumiendo que palabras coincidentes significan intenciones coincidentes.
Todos saben cómo es esto:
- Navegar por cientos de anuncios en varias plataformas
- Juzgar la relevancia uno por uno
- Encontrar duplicados, anuncios vencidos y enlaces rotos
- Preguntarse si los puestos objetivo eran realmente los adecuados desde el principio
El aburrimiento no es el problema principal. La verdadera brecha radica entre lo que indica el historial de un candidato y lo que realmente busca la oferta, y cerrarla requiere interpretación, contexto y juicio. En resumen, se necesita razonamiento, área en la que los modelos de lenguaje grandes son fuertes. Supongamos que un sistema pudiera leer un currículum, inferir trayectorias profesionales razonables, encontrar oportunidades laborales y clasificarlas según su adecuación real en lugar de la coincidencia de palabras clave. Ese es el problema para el cual se creó este sistema.
El proceso, paso a paso
Comienza con una acción: subir un currículum. Después de eso, nadie toca el cuadro de búsqueda, desplaza las listas ni decide qué puestos merecen ser solicitados. El sistema asume el control y ejecuta nueve pasos, cada uno con una tarea definida.
- Agente analizador de currículums. Al actuar como un reclutador experimentado, convierte el currículum en un perfil estructurado en lugar de una lista de palabras clave. El perfil incluye los empleos ocupados, habilidades, áreas de especialización, el desarrollo profesional y una breve descripción al estilo ATS que todos los demás agentes consideran como la descripción canónica del candidato. Modelo: Claude Sonnet.
- Agente recomendador de perfiles. Propone dos o tres títulos de empleo adecuados al nivel, área y habilidades del candidato, junto con variantes de consultas de búsqueda para cada uno. Modelo: Claude Haiku.
- Puerta de confirmación humana. Este es el único punto en el que una persona toma decisiones. El usuario revisa los perfiles sugeridos, elige el que le parece adecuado, opcionalmente agrega preferencias de ubicación y antigüedad, y confirma. El proceso espera hasta ese momento. No participa ningún modelo, solo el juicio humano.
Eso suma nueve pasos, cuatro llamadas al LLM, una decisión humana y un tiempo total de ejecución inferior a tres minutos.
El mapa tecnológico
El diagrama anterior muestra cada componente principal de una pila de IA actual dentro de este flujo de trabajo. Cada sistema es un conjunto de decisiones, por lo que las secciones siguientes tratan sobre qué se consideró, qué se rechazó y cuál fue el costo.
Ocho decisiones de diseño
1. LangGraph en lugar de CrewAI, AutoGen o un bucle ReAct
Los candidatos habituales fueron LangGraph, CrewAI y AutoGen; dentro de LangGraph existe además una división entre un grafo dirigido y un bucle ReAct.
CrewAI pone énfasis en la colaboración autónoma, con agentes que actúan como personajes y negocian y delegan tareas entre sí. AutoGen se centra en el diálogo conversacional entre múltiples agentes. Ambos son adecuados para flujos de trabajo abiertos. Sin embargo, ambos también generan sobrecargas de coordinación y no determinismo que un flujo de trabajo fijo no puede permitirse depurar.
Los bucles ReAct son útiles cuando el número de pasos no se conoce de antemano, como en el caso de un LLM que navega por la web y no puede predecir cuántas búsquedas necesitará. Encontrar trabajo no es así: la estructura del problema define claramente las etapas: analizar antes de recomendar, buscar antes de filtrar, eliminar duplicados antes de incrustar. No se descubre nada en tiempo de ejecución.
Un grafo dirigido se adapta perfectamente a todo esto. Cada transición es explícita, la intervención humana es una herramienta fundamental, y el estado se representa mediante un modelo Pydantic compartido que cada nodo lee y escribe. Cuando algo falla, el nodo problemático resulta evidente.
2. Agentes especializados en lugar de un único mega-prompt
Escribir una sola instrucción amplia que analice el currículum, proponga títulos y calificaciones resulta tentador, además de ser más rápido de desarrollar. Sin embargo, falla de maneras complejas y acumulativas: un error en cualquier parte se convierte en un error en todas. Es imposible determinar qué instrucción causó un resultado deficiente, ajustar una parte conlleva riesgo de regresiones en otra, y el contexto se llena de instrucciones irrelevantes para la tarea en curso.
Los agentes separados evitan esto. Un bajo puntaje del clasificador se puede depurar examinando únicamente su instrucción correspondiente. Cada agente cuenta con su propio script de prueba, por lo que el analizador puede someterse a pruebas de regresión sin afectar todo el proceso. Además, diferentes agentes pueden dirigirse a modelos distintos, como se muestra en la opción de diseño 6.
3. Una puerta de control con intervención humana
La mayoría de los tutoriales sobre agentes consideran la revisión humana como un acabado opcional, algo para hacer que los usuarios se sientan involucrados. Aquí, en cambio, dicha puerta de control constituye una decisión arquitectónica fundamental.
El sistema de recomendación ofrece dos o tres títulos, y el perfil que el usuario confirme guiará todas las etapas posteriores: las búsquedas, los filtros y la puntuación. Dejar que el sistema elija automáticamente puede arruinar todo si hace una suposición errónea, generando una lista ordenada para un perfil que el candidato nunca quiso. Ninguna otra decisión en el proceso conlleva tanto riesgo, y ninguna se maneja mejor por parte de una persona, ya que los candidatos conocen aspectos sobre su propia orientación que un analizador no puede extraer.
4. Un prefiltro antes del clasificador
Los datos del mundo real nunca son limpios, y las listas provenientes de cinco APIs presentan problemas predecibles:
- Enlaces rotos y errores 404, debido a publicaciones que expiraron y nunca se eliminaron
- Duplicados, ya que el mismo puesto aparece simultáneamente en varias APIs
- Redirecciones de los agregadores, donde una URL lleva a la página principal de un portal de empleos en lugar de a la lista correspondiente
Estos no son casos extremos. Representan el estado normal de los datos de las API externas. Los pasos de validación y deduplicación existen para limpiar el conjunto de datos antes de que ocurra algo costoso, de modo que lo que llega al prefiltro semántico sea válido, único y real.
Luego sí importa el costo. En las ejecuciones en producción, el clasificador representa entre el 70 y el 80 por ciento del gasto total en LLM. El analizador cuesta una cantidad fija de ₹2,7 a ₹3,0 sin importar cuántas tareas pasen por él, y el recomendador alrededor de ₹0,30, también de forma fija. El clasificador varía entre ₹3 y ₹11 según cuántas tareas lleguen a él, lo que hace que el costo total por ejecución esté entre ₹6 y ₹14. El prefiltro mantiene solo las listas más alineadas con el candidato, de modo que el clasificador trabaje con un subconjunto de alta calidad en lugar de la salida bruta y ruidosa de cinco APIs de tareas.
5. HyDE en lugar de comparación directa
El enfoque obvio es incrustar el resumen del candidato en el espacio de embeddings y compararlo con cada descripción de puesto mediante similitud de coseno. Es sencillo, rápido y no requiere llamadas adicionales a modelos de lenguaje grande. En las pruebas, los resultados fueron decepcionantes.
La causa es una discrepancia en el espacio de embeddings. El resumen de un candidato se presenta como una historia en primera persona, algo como “desarrollé pipelines de ML, me encargué del despliegue de modelos y colaboré con varios equipos”. Una descripción de puesto, en cambio, se presenta como una lista de requisitos en tercera persona, como “se requieren más de 3 años de experiencia en ML, habilidades con PyTorch y buena comunicación”. Incluso cuando ambos describen las mismas habilidades, los dos estilos se ubican en regiones diferentes, por lo que la comparación directa subestima las coincidencias reales.
HyDE evita esto planteando una pregunta diferente: ¿cómo sería la descripción de puesto ideal para este candidato? Un modelo de lenguaje grande redacta dos descripciones hipotéticas a partir del currículum.
- JD1 está anclado al sector específico, redactado como si una empresa del mismo campo que el candidato estuviera contratando a alguien con esa experiencia.
- JD2 se centra en habilidades transferibles, escrito como si la experiencia sectorial fuera secundaria y las capacidades generales lo más importante.
Estas descripciones sintéticas se encuentran en la misma categoría que las reales, ya que son descripciones de empleo, aunque solo sean hipotéticas. Al compararlas con los anuncios reales se logra una correspondencia semántica similar. Cada anuncio real entonces es asignado a la descripción sintética con la que tenga más similitud: si se parece más a JD1, lo coloca en la sección 1, con puestos dentro del sector del candidato; si se parece más a JD2, lo coloca en la sección 2, con oportunidades más amplias.
Hubo una restricción constante: solo embeddings de uso general, sin modelos específicos para un dominio determinado. La especificidad del dominio proviene del contenido HyDE, que el LLM integra en las descripciones sintéticas, y no de la elección del modelo de embedding. Esto permite que el sistema sea portable entre diferentes profesiones.
6. Modelos diferentes para agentes distintos
No toda tarea requiere la misma capacidad de razonamiento. El analizador y el generador HyDE cuestan aproximadamente ₹2.7 a 3.0 y ₹0.50 por ejecución, valores fijos independientemente del volumen de trabajo. Su calidad determina todo lo que sigue, ya que un análisis deficiente corrompe el perfil y una descripción hipotética deficiente afecta la correspondencia del embedding; por eso Sonnet es la elección adecuada.
La puntuación se calcula por tarea en el clasificador, por lo que es la etapa cuyo costo aumenta con el volumen, y ya consume del 70 al 80 por ciento del presupuesto. Sin puntuaciones mejor estructuradas, Sonnet triplicaría aproximadamente esa cifra. Haiku cumple con la función. Aquí está el enrutamiento:
7. Un archivo de configuración para cada parámetro ajustable
Los sistemas agentes eventualmente enfrentan problemas de ajuste. Cambiar un modelo, ajustar un umbral o modificar un límite de concurrencia no debería significar buscar entre cinco archivos de agentes la constante adecuada.
Este sistema mantiene un único archivo YAML que controla todos los parámetros del proceso, de modo que ninguna constante está codificada directamente en el código del agente ni hay números ocultos en los prompts. Regula lo siguiente:
- Modelo por agente. Sustituir Claude Haiku por un modelo más reciente se hace con una sola edición.
semaphore_size: 4, batch_size: 4 y batch_delay_secs: 2, cuya explicación se proporciona a continuación.8. Clasificación concurrente, influenciada por los límites de velocidad
El primer sistema de clasificación era secuencial: una llamada al LLM, espera, y luego el siguiente trabajo. Con 40 tareas y unos 2.5 segundos por llamada, se necesitan 100 segundos en tiempo real. Los datos del pipeline lo confirman, ya que solo el sistema de clasificación consume alrededor de 95 segundos de los 166 segundos totales del proceso.
Enviar las 40 llamadas al mismo tiempo parece ser la solución, pero choca con los límites de velocidad establecidos por Anthropic. El acceso de nivel 1 limita las solicitudes por minuto, por lo que 40 a 60 llamadas simultáneas exceden inmediatamente ese límite y generan errores 429. La primera versión en producción, sin ningún tipo de control de flujo, devolvió solo una parte de los resultados: las tareas del 1 al 70 fueron procesadas antes de que la API dejara de responder.
La solución consiste en un diseño de concurrencia de tres partes, controlado íntegramente desde el archivo de configuración:
- Un semáforo (
semaphore_size: 4) limita el número de llamadas en ejecución en cualquier momento. Cuatro llamadas a la vez se mantienen dentro de los límites del nivel 1. - El procesamiento por lotes (
batch_size: 4) procesa las tareas en grupos de cuatro, y cada grupo se completa antes de que comience el siguiente. - Un retraso entre lotes (
batch_delay_secs: 2) añade una pausa de dos segundos entre grupos para tener margen frente a los límites de carga.
El resultado: 60 tareas en 15 lotes se procesan en aproximadamente 90 a 95 segundos, unas cuatro veces más rápido que el método secuencial con la misma cantidad de tareas, sin alcanzar los límites.
Observabilidad
Un sistema que nadie puede observar es solo una esperanza, no un sistema real. Un incidente verdadero lo demuestra. En la primera ejecución completa en producción, faltaba VOYAGE_API_KEY en la instancia EC2. El prefiltrado de HyDE omitió silenciosamente el proceso de incrustación y envió las 89 tareas al clasificador, lo que provocó el límite de velocidad en la tarea 70 y generó una lista parcial. Sin observabilidad, esto parecería un comportamiento aleatorio e inexplicable; con ella, rastrear la causa tomó menos de un minuto.
La observabilidad aquí funciona en dos niveles:
- LangSmith registra cada llamada al LLM: el prompt exacto, la respuesta, la latencia por llamada y el recuento de tokens. Ofrece una visibilidad a nivel micro del razonamiento y se utiliza durante el desarrollo para detectar regresiones en los prompts antes de que afecten a todo el proceso.
- MLflow registra cada ejecución con la latencia por agente, el costo total y el recuento de tokens. Su archivo
job_audit.jsones el diagnóstico más útil, ya que contiene un registro completo de cada tarea que ingresó al proceso: en qué sección de HyDE terminó, su puntuación de similitud, qué filtro la descartó y por qué, los componentes de su puntuación de ajuste y su posición final.
Así es la madurez
La madurez de un sistema de IA no se mide por su grado de autonomía, sino por cuán bien las personas comprenden qué hace, por qué lo hace y dónde comete errores. Hablar de IA agente optimizada bajo la métrica incorrecta es un error. La autonomía permite demostraciones impresionantes, pero a menudo representa una mala característica desde el punto de vista ingenieril, ya que observar y depurar su comportamiento autónomo es costoso.
Para quienes desarrollan sistemas de IA hoy en día, las preguntas útiles no son cuán agente es o cuántos agentes tiene, sino estas:
- ¿Puede observarse qué está haciendo en cada paso?
- ¿Se puede explicar un resultado específico sin acceder al código fuente?
- ¿Se puede recalibrarlo cuando su comportamiento se desvía?
- ¿Se puede distinguir un buen rendimiento de un fallo silencioso?
Un sistema que supera estas cuatro pruebas es un sistema de ML funcional. Todo lo demás no es más que un prototipo con un buen marketing.
Lecturas relacionadas
- Orquestación de múltiples agentes en Bedrock y LangGraph: cuatro patrones — Patrones de supervisor-trabajador, pipeline, difusión y debate con LangGraph en AWS Bedrock, además de mecanismos de transferencia de tareas, controles de presupuesto, seguimiento y modos de fallo en producción.
- Agentes paralelos de LangGraph que revisan solicitudes de pull request mediante webhooks de FastAPI — Cómo un webhook, una cola de Redis y cuatro agentes de LangGraph convierten una solicitud de pull request en una revisión estructurada y puntuada por IA en aproximadamente 30 segundos, con ngrok para pruebas locales.