Ir al contenido

Esta entrada aborda los límites del cliente y de la plataforma que subyacen a la experiencia de usuario y a las interacciones con Ask DoorDash: cómo pasamos de los carruseles de hackatones a ese modelo, cómo un mismo artefacto da servicio a tres lectores y cómo el contexto y el estado se mantienen coherentes a medida que los usuarios navegan por DoorDash. A continuación, «Creación del asistente de DoorDash: una visión general desde el punto de vista de la ingeniería» y nuestros análisis en profundidad «Creación de Ask DoorDash (Parte 2): Inteligencia», «Creación de Ask DoorDash (Parte 3): Evaluación», y Creación de Ask DoorDash (Parte 4): una plataforma para crear y desarrollar agentes.


Ask DoorDash convierte peticiones como «prepárame una cena de 60 dólares para 10 personas», «ayúdame a hacer tacos de pollo» y «aperitivos para toda la semana» en listas de la compra editables. Genera una lista con productos que se pueden comprar, precios, fotos, controles de cantidad y botones sencillos para cambiar cualquier artículo y finalizar la compra. En el caso de las peticiones relacionadas con restaurantes, se muestran establecimientos y platos que se integran en el flujo de compra nativo. Ambas funcionalidades se ejecutan en el mismo cliente y en la misma infraestructura de la plataforma. Este artículo se centra en el caso de uso de la compra de alimentación, ya que es el que plantea mayores dificultades a la hora de crear una interfaz intuitiva para las compras gestionadas por un agente. Las listas de la compra suelen contener entre diez y veinte artículos, pasan por varias rondas de revisión y deben adaptarse fácilmente a las limitaciones de los consumidores, como el presupuesto y las restricciones dietéticas.

Las sesiones de usuarios de julio de 2026 mostraron que, en las sesiones relacionadas con la compra de alimentación en las que se mostraba una lista de la compra, los consumidores realizaban una media de casi dos interacciones con la interfaz de usuario cada uno. Aproximadamente un tercio de esas sesiones continuaron con la aplicación de la lista al carrito. El asistente recoge la intención general de los consumidores y la sintetiza. El resultado son componentes nativos, que permiten a los consumidores realizar ajustes detallados. Las modificaciones sencillas actualizan inmediatamente un elemento de referencia, mientras que los cambios que requieren razonamiento dan inicio a un nuevo turno del agente.

Para crear una experiencia de compra colaborativa eficaz entre el consumidor y el agente, los agentes de compra deben integrarse en una interfaz interactiva basada en datos de comercio en tiempo real y en el contexto actual de la aplicación del consumidor. Cuando un consumidor está comprando en una aplicación, espera ver de un vistazo artículos reales que pueda adquirir. El texto puede describir ese entorno, pero los componentes interactivos basados en imágenes permiten a los consumidores recorrerlo realmente. El contexto también es importante. Los consumidores que abren DoorDash llegan con expectativas diferentes a las que tienen al utilizar una aplicación de chat de uso general. Compran navegando, pasando de una tienda a otra y de una página a otra, en lugar de describir lo que quieren. Salirles al encuentro allí donde se encuentran es una pieza esencial del rompecabezas.

Las grandes cosas tienen un pequeño comienzo

El asistente de compra de DoorDash comenzó como un proyecto de hackatón. Sabíamos desde el principio que la integración de los componentes existentes de DoorDash sería una pieza clave de cualquier cosa que construyéramos. Las primeras versiones se basaban en gran medida en carruseles: primero, una lista de tiendas cercanas; después, un carrusel con los resultados de búsqueda para cada artículo que buscaba el agente. Se mostraban en línea, cada uno con su término de búsqueda adjunto. El resultado era, básicamente, una transcripción de chat con resultados comerciales pegados en ella.

Desde el punto de vista funcional, se parecía mucho a lo que ofrecemos hoy en día. En cuanto a la experiencia de usuario, era más rudimentaria, y merece la pena repasar los detalles.

Una vez encontradas varias tiendas, el asistente preguntaba cuál quería explorar y esperaba a que se escribiera la respuesta. Cada carrusel representaba un único artículo que el consumidor necesitaba, y al elegir una opción de él, ese artículo se añadía al carrito. Cada uno aparecía con sus opciones desplegadas a todo lo ancho y la elección aún abierta. Así pues, preparar la compra para una semana significaba ir bajando por la lista, selección a selección, sin posibilidad de seleccionar varios artículos a la vez.

Detrás de todo ello se escondía un fallo que afectaba en ambos sentidos: la interfaz se había diseñado principalmente para presentar el trabajo del asistente. Cada carrusel iba precedido de la consulta que lo había generado y los resultados aparecían en el orden en que se habían recuperado. Los términos de búsqueda y los conjuntos de resultados sin procesar son el material de trabajo de un agente. Presentar los resultados directamente es el equivalente, en una interfaz, a imprimir un seguimiento de la pila. El asistente se sometía con la misma facilidad a la interfaz, trabajando con un elemento cada vez, porque lo único que la pantalla podía mostrar era una pila de carruseles por elemento. Cada uno se había diseñado en función de las limitaciones del otro, en lugar de hacerlo en función del usuario.

La lección no era que reutilizar componentes existentes estuviera mal; la familiaridad que aportan es precisamente la razón por la que el asistente se parece a DoorDash. Simplemente habíamos creado el contenedor equivocado para ellos. El contenedor es lo que determina el orden en el que aparecen, junto a qué se sitúan y qué puede hacer el usuario con ellos. Por encima de todo, el usuario necesita una interfaz de compra, más que una interfaz conversacional. Habíamos creado una interfaz conversacional que, casualmente, contenía componentes de compra. La reutilización de componentes nos proporcionó el vocabulario. Lo más difícil fue organizarlo todo en una interfaz de compra.

Lo que sí sobrevivió al hackatón fue la base: la experiencia se ejecuta hoy en día sobre la misma infraestructura de streaming que se estableció entonces. Por su parte, la capa de decodificación que convertía los resultados de las herramientas en una interfaz de usuario no perduró. El asistente ya no muestra en absoluto los resultados de las herramientas. En su lugar, dedicamos tiempo a desarrollar una arquitectura de artefactos que separa los requisitos de los usuarios finales de los requisitos de almacenamiento y de los agentes. En otras palabras: dejamos de decodificar el material de trabajo del agente para su visualización y empezamos a diseñar en función de las necesidades de los diferentes componentes y usuarios del sistema.

Figura 1: La misma solicitud de la compra, con un año de diferencia. La versión creada en el hackatón mostraba un carrusel por artículo, cada uno encabezado por la consulta que lo había generado; la selección se dejaba en manos del consumidor. Hoy en día, el asistente muestra cada lista como una tarjeta en la conversación, con los artículos más solicitados ya seleccionados.

Un objeto, tres lentes

Una lista de la compra tiene tres lectores: el servicio que la almacena, el agente que la revisa y la persona que hace la compra. Cada uno necesita ver algo diferente. Mantenerlos separados es lo que permite que los cambios del consumidor aparezcan de inmediato y sigan siendo válidos sin que ello suponga una nueva iteración del modelo.

El formato almacenado es el sistema de registro: un blob JSON que se guarda como un artefacto en Managed Agent Services, tal y como se describe en la publicación sobre la plataforma. Debe estar completo y es la única copia oficial.

El agente no lee ese bloque de datos directamente. Una lista de la compra interactiva contiene muchos más detalles de los que un modelo necesita para la mayoría de las respuestas. Repetir el nombre de cada producto, el precio, la cantidad, las sustituciones y cada dato de metadatos de visualización en cada turno entraría en conflicto con lo que el consumidor realmente ha solicitado. Por eso, cuando un agente emite un «widget», lo que permanece en el contexto de la conversación es un resumen conciso: la tienda y el contenido de la lista. Cuando un turno requiere el estado exacto, el agente lee el artefacto y obtiene una vista reducida en la que se han eliminado los metadatos de visualización. Esa vista es inequívoca y lo suficientemente pequeña como para procesarla de forma eficiente. Una lista media ocupa entre 40 y 60 KB de JSON. Lo que permanece en el contexto de la conversación es una sola línea de unos 240 caracteres, aproximadamente 250 veces más pequeña.

Lo que ve el consumidor es otra cosa, y adopta más de una forma. En la conversación, la lista se muestra como un widget compacto: la tienda, el nombre de la lista, la hora estimada de llegada, algunas fotos de los artículos y un botón «Añadir al carrito» que indica el total estimado. Eso basta para evaluar la lista de un vistazo sin salir del chat. El botón «Ver lista» abre la vista a página completa, que muestra la lista completa y todo lo necesario para revisarla en detalle. Ambas vistas están diseñadas para que se comprendan al instante y se pueda actuar directamente sobre ellas.

Hay un detalle que pone de manifiesto hasta qué punto divergen estas perspectivas. Cuando el agente elige un producto para un artículo de la lista, conserva los demás productos que coincidían con la misma búsqueda, y el consumidor puede alternar entre ellos con un simple toque. Se mantienen diez opciones por artículo, y el 99,7 % de los artículos tienen suficientes coincidencias para completar esa lista, por lo que casi cada línea en la vista del consumidor tiene una selección y nueve alternativas detrás. La vista del consumidor muestra todas y cada una de esas alternativas. La vista del agente no muestra ninguna de ellas, ya que elegir entre ellas es tarea del consumidor (a menos que se le pida explícitamente al asistente que lo haga).

Figura 2: Una lista, tres perspectivas. El consumidor ve los precios, las fotos y una opción alternativa detrás de cada línea. El agente solo ve la tienda y el contenido de la lista. El artefacto lo recoge todo, incluidas nueve alternativas solo para las láminas de lasaña.

Mantener los pies en la tierra

Si, con un carrito que contiene yogur de frambuesa, pulsas «Recomendaciones para el carrito», aparecen dos sugerencias: muesli, «porque combina bien con tu yogur», y arándanos, «para añadir fruta a tu yogur» (véase la figura 3). El caso de contraste ya existe en nuestro propio producto, en la misma pantalla: la página del carrito incluye un carrusel de artículos complementarios que ofrece productos que el consumidor podría querer añadir, sin indicar ningún motivo. Nuestro agente del carrito podría haber devuelto exactamente eso: una lista de artículos plausibles. Es muy posible que los artículos fueran los mismos en ambos casos. El razonamiento es lo que indica al consumidor que la sugerencia está fundamentada y no es meramente plausible, y dado que cada elemento de la interfaz es también un lugar para actuar, esa distinción tiene una función real.

Eso es lo que aporta el enfoque práctico: la diferencia entre una experiencia de compra atractiva y una simple novedad. Si el resultado del asistente no es tangible, los consumidores tienen pocos motivos para dejar de lado la completa experiencia que ya ofrece la aplicación de DoorDash. El texto sigue cumpliendo su función, pero en un papel secundario. Hemos colocado deliberadamente la lógica del asistente dentro de los widgets y a su alrededor, en lugar de mostrar las celdas de los artículos exactamente como aparecen en el resto de la aplicación.

La integración también debe mantenerse a nivel de los datos, y ahí el trabajo se divide. Un agente elige un tipo de contenido compatible y proporciona los datos comerciales correspondientes; el cliente de iOS se encarga de la presentación y la interacción, adaptando ese contenido a los componentes nativos del sistema de diseño de DoorDash. Una solicitud de compra de comestibles genera una lista de la compra editable con cantidades, sustituciones y un subtotal. Una solicitud de restaurante puede generar fichas de tienda, fichas de productos o sugerencias para el carrito.

Esa división es lo que da validez a los propios datos. Los valores comerciales de un widget no proceden del modelo. Los precios, el inventario, el horario de la tienda y el contenido del carrito se obtienen de los mismos sistemas de registro que utiliza el resto de la aplicación, por lo que un precio que aparece en Ask coincide con el precio de la página de la tienda en ese momento. El contenido tipado también proporciona al backend y al cliente un contrato estable. La implementación de un nuevo widget requiere algo más que un simple cambio. El agente tiene que saber cuándo utilizarlo y qué incluir en él, y el cliente necesita un esquema con nombre, además del código para descodificarlo y representarlo. Más allá de eso, un nuevo widget llega al consumidor a través del mismo mecanismo de conversación y transmisión que cualquier otro.

Figura 3: Dos tipos de sugerencias sobre el mismo carrito. Solo una de ellas explica el motivo.

Los widgets como canales de E/S

Cada nuevo widget que hemos integrado ha hecho que el asistente resulte más funcional. La razón tiene tanto que ver con la entrada como con la salida. Hay un límite que rige todos ellos: una edición determinista permanece en el cliente y se aplica directamente al artefacto, mientras que un cambio que requiera un juicio inicia un turno del agente. Los ejemplos que figuran a continuación se organizan en función de dónde se sitúa esa línea divisoria.

La versión del hackatón preguntaba al usuario qué tienda quería y luego esperaba a que la escribiera. No tenía forma de elegir por sí misma; hoy en día, esa elección es automática. Todavía hay muchas otras preguntas que requieren la intervención del usuario, y el texto directo puede ser una forma poco adecuada de recabar las respuestas. La introducción de texto es una limitación de un solo hilo: el usuario puede saber todas las respuestas, pero solo puede proporcionarlas a la velocidad a la que escribe o habla.

Aquí es donde los widgets cobran sentido. Un consumidor puede tener que realizar diez operaciones en una lista de la compra, todas ellas sencillas. Por separado, son trivialidades; pero, cuando se describen con palabras, se convierten en una tarea compleja. Es la diferencia entre mirar por encima del hombro de alguien y decirle qué botones debe pulsar, y pulsar los botones uno mismo.

Las preguntas aclaratorias estructuradas son el ejemplo más claro, y el patrón se ha tomado prestado de los agentes de programación: la herramienta AskUserQuestion de Claude Code realiza la misma función para los desarrolladores. Ofrecemos un widget que interrumpe al consumidor con un pequeño conjunto de preguntas (de opción múltiple y selección múltiple), lo que le permite dirigir la conversación en momentos verdaderamente abiertos. Se ha convertido en un pilar fundamental del modelo de interacción del agente de supermercados y ahora se está incorporando al agente de restaurantes para simplificar este mismo tipo de interacción. Lo integramos con nuestra plataforma de memoria del consumidor, lo que reduce considerablemente las opciones, pero siguen existiendo lagunas de conocimiento que requieren la aportación del consumidor. Hacer preguntas es inevitable. Pero podemos preguntar de una forma que resulte fácil y eficiente para el consumidor a la hora de responder.

La vista de lista a página completa es donde la colaboración entre entrada y salida se hace tangible. Un consumidor puede modificar la cantidad de un artículo, eliminar un artículo, cambiarlo por una de las alternativas que el asistente ha encontrado junto a él y añadir la lista finalizada a su carrito. Cada una de esas acciones manipula el objeto directamente. Ninguna requiere que el asistente actúe en nombre del consumidor, y ninguna supone una ida y vuelta al modelo de lenguaje grande (LLM). El caso del cambio aprovecha mejor los conjuntos de candidatos de la versión del hackatón. Las alternativas entre las que elige el consumidor son los demás candidatos que el asistente recuperó al seleccionar el artículo. La lista de todas las opciones disponibles para el consumidor ocupaba anteriormente un carrusel. Ahora se encuentran a un solo toque de distancia de la decisión, en lugar de estar dispersas ante el consumidor como una pregunta abierta.

Cambiar de tienda es la excepción, y la excepción es lo interesante. No se trata de una modificación de la lista existente. Se convierte en una solicitud al asistente que reconstruye la lista en la tienda alternativa. Esta interacción también es poco frecuente: fue la primera acción en el 0,1 % de las sesiones activas, lo que se ajusta más o menos a lo que cabría esperar si el límite se establece más o menos en el lugar adecuado. Si se sitúa esa línea en el lugar equivocado, el consumidor o bien espera a que el asistente haga algo que podría haber hecho con un solo toque, o bien tiene que ir tocando para realizar una acción en la que habría sido útil el criterio del asistente.

El artefacto garantiza la seguridad de la división, y las dos partes escriben en él de forma diferente. Un cambio de cantidad, una eliminación o un intercambio siguen la ruta corta: el cliente actualiza la lista in situ y la modificación aparece de inmediato. En cambio, un cambio de almacenamiento inicia un turno del agente, ya que es necesario volver a hacer coincidir toda la lista con un catálogo diferente. Una revisión del agente no sobrescribe lo que había; genera una nueva lista derivada de la anterior.

El resultado es que una modificación directa tiene carácter vinculante. Antes de que un turno modifique la lista, el agente consulta la lista actual en lugar de basarse en la transcripción; por lo tanto, si el consumidor elimina la leche de avena, el siguiente turno comienza con una lista en la que ya no figura la leche de avena.

El comportamiento observado durante ese mismo periodo muestra dónde se sitúa esa línea divisoria. Inmediatamente después de la primera solicitud, casi tres cuartas partes de las primeras acciones siguientes se realizaron a través de un componente. A partir del segundo mensaje, la tendencia se invierte, y las acciones de seguimiento escritas constituyen la mayoría en todos los niveles de profundidad que hemos medido. Los controles se encargan de los ajustes inmediatos y estructurados; el lenguaje toma el relevo cuando el cambio es mayor o más difícil de expresar con un simple toque.

Figura 4: La lista al cruzar el límite de un turno. El consumidor retira las manzanas directamente en la vista de lista, sin necesidad de un intercambio de datos con el modelo. Cuando el cambio de tienda marca el inicio de un nuevo turno, el agente lee el artefacto en lugar de la transcripción, por lo que la lista que reconstruye en la nueva tienda sigue sin incluirlas.

Todas las revisiones de los asistentes permanecen activas

Cuando el asistente revisa una lista de la compra, la versión que sustituye permanece en pantalla y sigue estando disponible.

Esa no fue nuestra primera implementación. La primera versión ocultaba las listas sustituidas: una vez que llegaba una revisión, la lista anterior ya no se podía ver ni editar. Una sola lista actual, sin desorden. Parecía un comportamiento más ordenado. Sin embargo, lo que conseguía era que solicitar una revisión resultara costoso. Si pedir un cambio puede borrar una lista con la que estás satisfecho, lo más seguro es dejar de pedirlo, y eso socava el sentido mismo de un flujo colaborativo.

Así, cada revisión realizada por un asistente genera ahora un nuevo elemento derivado del anterior, y cada uno permanece en el lugar de la conversación donde se creó. Si te desplazas hacia atrás, las versiones anteriores siguen ahí, siguen activas: un usuario puede abrir una lista anterior, editarla o añadirla a su carrito en lugar de la más reciente. Solicitar un cambio no cuesta nada, porque lo que tenía hace un momento está a solo un desplazamiento de distancia.

No todas las listas que elabora el asistente se convierten en una versión que ve el consumidor. Cuando el asistente elabora una lista de opciones y llega a la conclusión de que la tienda no dispone de lo solicitado, esa lista nunca se muestra. Se informa al consumidor mediante un texto de que la tienda no tenía los artículos y de que se le está preparando una nueva lista. Es uno de los pocos casos en los que el texto cumple su función de forma directa, y es la razón que subyace a todo lo demás en esta entrada: la interacción se utiliza para simplificar, y el texto se utiliza para justificar.

Cuando una lista se convierte en un carrito

Un asistente que edite directamente el carrito puede eliminar un artículo que el cliente quería o añadir uno que nunca haya confirmado, sin que se le pregunte. Un solo error de este tipo basta para perder la confianza del cliente, ya que el fallo pasa desapercibido y afecta precisamente a lo que está a punto de pagar.

Por eso, en su lugar, presentamos una lista de la compra como propuesta. Puede contener docenas de artículos y pasar por varias rondas de revisión, ya sea para eliminar un producto de despensa que el consumidor ya tiene, cambiar una cantidad, sustituir un producto o modificar parte de una receta, y nada de ello afecta al carrito. Para confirmar la selección es necesario hacer clic explícitamente en «Añadir al carrito», que es la estructura más sencilla que hemos encontrado y que ofrece al consumidor un control real sin obligarle a supervisar cada paso.

Aún hay que conciliar ambos elementos, y lo interesante es decidir quién lo hace. El asistente lee el contenido del carrito mientras elabora la lista, pero no la ajusta automáticamente para que coincida: si una receta requiere dos plátanos, la lista solicita dos, independientemente de si ya hay cuatro en el carrito. Elaborar la lista con exactamente lo que se ha solicitado y conciliarla con el contenido del carrito en un paso aparte permite que cada decisión se tome en su contexto.

Ese paso se pone de manifiesto en el momento de confirmar la compra. Cuando la lista y el carrito coinciden, se muestran al consumidor los productos duplicados y este decide si desea sustituir esas cantidades o añadir otras. Es un pequeño momento, pero son precisamente los pequeños momentos como este los que determinan si se gana o se pierde la confianza.

Mantener el contexto en DoorDash

No basta con que el asistente se encuentre en un único lugar; debe poder accederse a él desde cualquier parte de la aplicación. Abrir el asistente ya es una señal clara de intención, pero ambigua. En ese momento, un consumidor puede estar haciendo un pedido en su restaurante favorito, comprando la compra para la semana, buscando unos auriculares nuevos o solicitando ayuda con un pedido anterior. Un consumidor que ha accedido a la página web de una tienda de alimentación concreta está enviando una señal mucho más clara: es probable que tenga la intención de crear una cesta de la compra en esa tienda. Facilitar ese contexto al asistente es lo que le permite centrarse en la intención probable en lugar de tener que preguntar.

El sistema de ámbito que hemos diseñado para esto abarca tanto el cliente como la pasarela. El cliente adjunta a cada solicitud datos clave sobre el contexto de la entrada: el tema bajo el que se ha registrado el usuario (supermercado, restaurante), la tienda que está consultando y algunos identificadores relacionados. La pasarela utiliza el tema para decidir a qué agente se deriva la solicitud, y el resto de datos para proporcionar a las herramientas los identificadores que necesitan.

Scope es, deliberadamente, un conjunto plano de pares clave-valor en lugar de un esquema tipado, y es el cliente quien decide qué se incluye en él. Las claves no reconocidas se transmiten tal cual, en lugar de rechazarse, por lo que una nueva superficie puede empezar a enviar contexto sin tener que esperar a que se produzca un cambio en la pasarela. La excepción es el propio tema: añadir uno nuevo implica indicar a la pasarela a qué agente debe dirigirlo. Así pues, aunque crear una nueva superficie es sencillo, crear un nuevo dominio no lo es.

El tema es también la parte que se aplica únicamente al primer mensaje de un contexto. Eso proporciona al asistente una base sólida sobre la que trabajar sin ser excesivamente prescriptivo, y es lo que permite a los usuarios salir de un ámbito cuando así lo eligen explícitamente. Un usuario que utilice el asistente dentro de un restaurante puede salir por completo del ámbito del restaurante pidiéndole: «Búscame una receta para este plato y prepárame una lista de la compra para que pueda prepararlo en casa». Esa solicitud no es gratuita, pero el coste supone un pequeño desvío en el proceso en lugar de un callejón sin salida: el agente del restaurante tiene que reconocer que la solicitud queda fuera de su ámbito y devolverla antes de que otro agente se haga cargo de ella.

En ciertos casos, los ámbitos también nos permiten prescindir por completo del modelo. Tomemos como ejemplo el punto de entrada «Volver a pedir mi último carrito». Podríamos limitarnos a enviar esa frase al asistente como un mensaje y, aunque eso funcionaría, añadir un ámbito nos permite ser más precisos. El caso de «volver a pedir» es, en la práctica, determinista, por lo que podemos saltarnos el modelo de lenguaje grande (LLM) y devolver una lista de la compra casi de inmediato. Lo que se devuelve es un widget de lista de la compra normal y corriente: el consumidor puede cambiar las cantidades, intercambiar productos o pedirle al asistente que la revise en el chat, exactamente igual que lo haría con cualquier otra. Ten en cuenta que esta omisión solo es válida si la tienda sigue teniendo todos los artículos del carrito anterior; si un artículo no está disponible, la solicitud se envía al agente de alimentación, que vuelve a generar la lista del mismo modo que lo haría a partir de una solicitud escrita.

El ámbito es también lo que hace posible mantener una única conversación continua a lo largo de una sesión de la aplicación, pero solo funciona porque el ámbito, la asignación de agentes y el estado de la sesión se mantienen separados. Tratamos el ámbito como un contexto por turno. La asignación, descrita anteriormente en la serie de entradas del blog, mantiene los turnos de seguimiento con el agente que resolvió el turno anterior. Tanto la asignación como la transcripción (la conversación propiamente dicha) se asocian al chat en lugar de al ámbito, por lo que un consumidor que se desplaza de una tienda a otra reasigna la asignación a un agente de un nuevo ámbito sin descartar lo que se había dicho. Varios agentes se especializan en segundo plano, y el conjunto sigue comportándose como un único asistente.

Figura 5: Un chat, al que se accede desde dos lugares. El ámbito de aplicación varía en función de cada solicitud, por lo que si se realiza una solicitud dentro de Safeway, la lista se crea en Safeway.

Conclusión

La integración de los agentes en los productos de consumo aún se encuentra en una fase temprana. Sin embargo, las bases se están perfilando con claridad. Los widgets son el lugar donde los consumidores realizan el trabajo, y la conversación entre el consumidor y el agente es lo que los guía. Actualmente hay tres lectores de nuestro artefacto de lista de la compra, y cada uno necesita una visión diferente del mismo. Utilizamos la parte orientada al usuario para que el consumidor se sitúe en el contexto de los productos reales y para que las modificaciones habituales se puedan realizar con un solo toque. A medida que los agentes asuman una mayor parte del trabajo, esperamos que lo que el consumidor necesita ver y lo que el agente necesita analizar sigan cambiando, y que la línea divisoria entre la interfaz de una aplicación y la de un chat sea cada vez más difícil de trazar.

La plataforma de experimentación de DoorDash gestiona más de 60 000 indicadores de funciones repartidos en unos 623 repositorios. Hemos identificado más de mil indicadores de características obsoletos; en otras palabras, la característica a la que en su día daban acceso ya se ha implementado por completo, pero el indicador y su lógica de ramificación siguen ocupando espacio en el código como lastre. Limpiar uno solo de ellos manualmente le lleva a un ingeniero entre una y dos horas. Con unos 2.300 nuevos indicadores creados cada mes, la lista de tareas pendientes no hace más que crecer.

Así pues, hemos creado un sistema LLM multiagente que elimina las marcas de «caducado» de principio a fin, desde un ticket de Jira hasta una solicitud de incorporación de cambios (PR) lista para la fusión, sin intervención humana alguna, salvo la de un ingeniero que confirma el valor objetivo y la incorporación de la PR. De las 50 marcas de obsoleto más recientes que procesó, el sistema generó PR utilizables para 45 de ellas, con un coste medio de 4,79 dólares y 13,8 minutos por marca, lo que supuso un ahorro de innumerables horas de trabajo de los ingenieros. El sistema que creamos no solo tenía que ser eficaz, sino que su límite de fiabilidad debía ser la exhaustividad, no la corrección; si el agente fallaba, debía hacerlo de forma segura, sin realizar cambios en el código que pudieran provocar errores.

En esta entrada se explica por qué las herramientas estándar no podían llevar a cabo esta tarea en nuestro código fuente, cómo diseñamos el sistema y qué aprendimos durante su implementación. Nota: Este trabajo fue revisado por pares y aceptado para la sección dedicada a la industria de ICSME 2026.

Por qué merece la pena automatizar la eliminación de los «feature flags» obsoletos

Los «feature flags» son una pieza fundamental de la entrega moderna de software. Nos permiten implementar funciones de forma gradual, realizar experimentos A/B y activar mecanismos de desactivación inmediata cuando algo sale mal. Sin embargo, cada «feature flag» tiene un ciclo de vida y, una vez que una función se ha implementado por completo, su «feature flag» queda obsoleto. Los «feature flags» obsoletos suelen convertirse en deuda técnica, ya que el tiempo de un ingeniero tiene más valor si se dedica a crear nuevas funciones en lugar de a eliminarlas. 

Su lógica condicional ya no tiene ninguna utilidad, pero no se queda ahí sin causar ningún daño:

  • Los «feature flags» obsoletos pueden permanecer en el código durante años. Estudios previos han revelado que, aproximadamente, el 25 % de los «feature flags» persisten durante más de ocho años en los proyectos de código abierto; los profesionales del sector señalan constantemente que su eliminación resulta laboriosa y que se pospone una y otra vez.
  • Una señal obsoleta es deuda técnica. Cada señal obsoleta añade una rama, un caso extremo y un poco más de texto que leer y analizar, lo que puede resultar especialmente complicado durante un incidente.
  • Los indicadores obsoletos pueden suponer un riesgo operativo. Un indicador obsoleto mantiene activa una ruta de código inactiva que puede reactivarse por accidente. En un caso bien documentado, una empresa de negociación reutilizó un indicador obsoleto durante una implementación, lo que provocó operaciones no deseadas por valor de 460 millones de dólares en tan solo 45 minutos.

Si multiplicamos decenas de miles de banderas por una tasa de creación mensual de cuatro cifras, queda claro que la limpieza manual simplemente no puede seguir el ritmo. Eliminar manualmente nuestro atraso acumulado supondría miles de horas de ingeniería que sería mejor dedicar al desarrollo.

Valores dinámicos

En DoorDash, los «feature flags» se denominan «valores dinámicos» (DV). Funcionan gracias a nuestra plataforma de experimentación. A lo largo de esta entrada, el término «DV» es sinónimo de «feature flag».

El ciclo de vida de un DV sigue el patrón: creación → experimentación → implantación → obsoleto → eliminación. Clasificamos un DV como obsoleto cuando cumple todos los criterios siguientes:

  1. No se ha modificado en 90 días.
  2. Todavía aparece mencionado en el código.
  3. Aún no se encuentra en estado de fin de vida útil (archivado o retirado).
  4. No figura en ninguna lista de exclusión.

Una tarea programada diaria crea un ticket de Jira con la etiqueta «STALEDV» para cada DV obsoleto identificado y lo asigna a la persona que lo creó. Esto marca el inicio de la cola a partir de la cual funciona nuestro sistema de limpieza.

Flujo de trabajo basado en agentes frente a herramientas de limpieza basadas en AST

El enfoque automatizado más conocido para la limpieza de indicadores es Piranha y su sucesor poliglota, que simplifican las condiciones controladas por indicadores mediante la coincidencia de patrones en el árbol de sintaxis abstracta (AST). Funciona bien cuando un indicador se lee a través de una llamada directa a la API con la que una regla de reescritura puede establecer una coincidencia de patrones.

Pero en DoorDash no es así como se accede a los DV. Nuestros servicios utilizan un patrón de envoltura de tres capas con inyección de dependencias:

// Layer 1: RuntimeKeys.kt – the DV name as a string constant
object RuntimeKeys {
  const val ENABLE_X = “enable_feature_x”
}

// Layer 2: FeatureFlags.kt – a DI wrapper that calls the DV client
@Singleton
class FeatureFlags @Inject constructor(
    private val dvClient: DynamicValuesClient
) {
  fun shouldEnableX(userId: String): Boolean =
    dvClient.getBoolean(ENABLE_X, withContext(“user_id” to userId), false)
}

// Layer 3: business logic – uses the flag via dependency injection
class MyService @Inject constructor(
    private val featureFlags: FeatureFlags
) {
  fun process(userId: String) {
    if (featureFlags.shouldEnableX(userId)) handleNewPath()
    else handleOldPath()
  }
}

Se trata de una clara separación de responsabilidades, pero implica que el nombre del DV, la llamada a la API y la lógica condicional se encuentran cada uno en un archivo diferente, conectados únicamente a través de llamadas a métodos y la inyección de dependencias. Se trata de relaciones semánticas, no sintácticas; los comparadores de patrones del AST no pueden seguirlas. 

Determinación del valor objetivo

Existe un problema adicional que una herramienta basada únicamente en el código fuente no puede resolver: la determinación del valor de destino y la consulta del estado de implementación en tiempo real. Una herramienta que solo lee el código fuente podría codificar de forma definitiva un valor erróneo y modificar el comportamiento sin avisar. Para garantizar que la herramienta realice la limpieza correcta del código, es necesario conocer el estado de implementación en tiempo real del indicador, que se encuentra en la plataforma de experimentación, no en el repositorio. Por ejemplo, la plataforma de experimentación de DoorDash admite el uso de indicadores de función de tipo entero, cadena y JSON. Una lectura en tiempo real del valor objetivo garantiza que la herramienta modifique el código con el valor correcto del indicador de función, que representa el estado actual del sistema. Del mismo modo, la información sobre la implementación también es una parte importante de la ecuación. Es posible que un experimento se haya implementado en un 60 % y luego se haya abandonado. La herramienta debería tener la capacidad de determinar que se trata de una implementación parcial y solicitar la confirmación del usuario antes de realizar cualquier limpieza. Esto puede llevar al usuario a completar la implementación o la reversión antes de utilizar la herramienta para realizar la limpieza, o bien indicarle que omita la limpieza por el momento.

Alcance y complejidad

Por último, incluso una simple variable de datos booleana puede afectar a entre cinco y veinte archivos tras tener en cuenta la constante, el contenedor, cada punto de llamada y la actualización o eliminación de las pruebas pertinentes. Se trata de una tarea que requiere comprender el código, no solo hacer coincidir la sintaxis. Precisamente por eso optamos por utilizar agentes LLM. Pero la tarea no era tan sencilla como escribir una instrucción y pedirle al agente que realizara la limpieza; eso no permitiría lograr una limpieza eficiente en términos de coste y tiempo, con medidas de seguridad a gran escala.

Un proceso en dos fases con intervención humana

El sistema se basa en el Kit de Desarrollo de Agentes (ADK) de Google y se ejecuta en dos fases, con un único punto de control humano entre ellas, tal y como se muestra en la figura 1.

Figura 1: Arquitectura del sistema. Un agente de orquestación ejecuta el análisis de la Fase 1, extrae los DV obsoletos de Jira, consulta el estado de implementación a la plataforma de experimentación a través del protocolo de contexto de modelo (MCP) y realiza búsquedas en el código fuente; un ingeniero verifica el informe. A continuación, la Fase 2 genera agentes de limpieza en paralelo en árboles de trabajo de Git aislados que editan, prueban, comprueban la cobertura y realizan análisis de lint antes de abrir una solicitud de incorporación de cambios (PR).

Fase 1: Análisis e informe

Un agente de coordinación, en este caso Claude Sonnet, procesa las solicitudes de DV caducadas. Para cada DV, realiza lo siguiente:

  1. Recupera los tickets de DV en Jira caducados mediante la herramienta de línea de comandos de Atlassian.
  2. Consulta la plataforma de experimentación de DoorDash a través del protocolo de contexto de modelos (MCP) para obtener los metadatos de la variable dependiente (DV): su UUID, el porcentaje de implementación y el valor objetivo.
  3. Detecta el repositorio local y busca todas las referencias de código al DV.
  4. Genera un informe estructurado en el que se propone un valor objetivo y se enumeran los archivos afectados para cada DV.

Esa integración con MCP es el héroe silencioso del diseño. Al leer el estado de implementación en producción en tiempo real, el agente determina el valor objetivo correcto en lugar de tener que adivinarlo a partir del código. Por ejemplo, un DV que se introdujo para una función que acabó abandonándose muestra un 0 % de implementación en la plataforma, por lo que el agente sabe que debe eliminarlo utilizando el valor de referencia, en lugar de dar por hecho que la función está activada.

Punto de control humano

Antes de realizar cualquier cambio en el código, un ingeniero revisa el informe y confirma el valor objetivo de cada DV. Se trata de una medida de seguridad deliberada para casos ambiguos, como implementaciones parciales o experimentos abandonados, en los que la respuesta correcta requiere el criterio humano. Por ejemplo, puede darse el caso de que un experimento se haya implementado en un 60 % y luego se haya abandonado. El control humano permite al usuario intervenir para decidir, por ejemplo, si se completa la implementación o se revierte el experimento antes de que continúe la limpieza.

Fase 2: Limpieza en paralelo

Por cada DV confirmado, el coordinador genera un agente de eliminación específico —Claude Opus— que se ejecuta en su propio árbol de trabajo de Git aislado. Se pueden ejecutar hasta cuatro agentes simultáneamente por repositorio, aunque este número es configurable. Cada uno de ellos lleva a cabo una limpieza completa y abre una solicitud de incorporación de cambios asignada al propietario del DV.

El interior de una empresa de mudanzas

Cada agente de eliminación ejecuta un flujo de trabajo iterativo tal y como se indica a continuación:

  1. Busca todas las referencias al DV, incluyendo la constante, la función envolvente y cada punto de llamada.
  2. Decide una estrategia de limpieza en función del tipo de variable DV —booleana, entera o de cadena— y de su uso.
  3. Aplica los cambios; sustituye las llamadas a la función «wrapper» por el valor de destino y simplifica las condiciones que ahora son constantes.
  4. Elimina la función envolvente, la definición y la constante.
  5. Actualiza o elimina las pruebas afectadas, por ejemplo, eliminando las ramas de pruebas «marcadas como desactivadas».
  6. Comprueba que la compilación se haya realizado correctamente.
  7. Comprueba que las pruebas se superen.
  8. Comprueba que la cobertura de los parches sea, como mínimo, del 95 % en las líneas modificadas.
  9. Ejecuta el linter de Detekt.
  10. Si falla alguna validación, diagnostica el problema, corrígelo y vuelve a intentarlo.

La autonomía sobre un código fuente solo funciona si las medidas de seguridad son reales. Hay cuatro mecanismos que garantizan la seguridad de los agentes:

  • Aislamiento del árbol de trabajo de Git: cada agente trabaja en un árbol de trabajo específico, por lo que los agentes que se ejecutan simultáneamente nunca interfieren entre sí, y si falla una limpieza, esta se descarta simplemente eliminando el árbol de trabajo.
  • Un tiempo de espera fijo de una hora por agente: esto garantiza que una sesión bloqueada no se prolongue indefinidamente.
  • Validación de la cobertura de parches de JaCoCo: esto garantiza una cobertura de pruebas de al menos el 95 % en las líneas que ha modificado el agente.
  • Análisis estático de Detekt: garantiza el cumplimiento de las normas de estilo y detecta problemas habituales.

Además, ejecutamos Gradle con la opción –no-daemon para evitar la contaminación del estado entre árboles de trabajo durante las ejecuciones paralelas. Es fundamental destacar que no se permite a ningún agente abrir una solicitud de pull hasta que las pruebas y el análisis estático se hayan superado localmente.

Resultados

Crear un sistema es una cosa, pero cuando funciona a la escala de DoorDash solo importa una pregunta: ¿qué tal funciona? En este caso, la verdad es que muy bien.  De las 50 señales de código obsoleto más recientes que procesó el sistema, generó una solicitud de incorporación de cambios (PR) lista para fusionarse en 45 de ellas, con un coste medio de 4,79 dólares y 13,8 minutos por limpieza, en lugar de las una o dos horas que habría llevado una limpieza manual. El sistema no introdujo ningún error ni regresión durante el proceso.

Cómo lo hemos evaluado

Evaluamos el sistema con los 50 DV obsoletos más recientes que procesó en varios repositorios de Kotlin. Clasificamos cada uno de ellos según su complejidad: 

  • Sencillo: una sola comprobación booleana en uno o dos archivos; n = 6
  • Medio: múltiples usos en entre tres y cinco archivos con algunos cambios de prueba; n = 18
  • Complejo: condiciones anidadas, dependencias entre archivos, tipos no booleanos o actualizaciones importantes de las pruebas; n = 26 

Por tipo, 41 eran booleanos, seis eran cadenas y tres eran enteros/long. Cada PR se evaluó según tres criterios: superación de las pruebas de CI —incluido el requisito de cobertura del 95 % de los parches—, corrección del código y revisión por parte de los desarrolladores. 

Resultados según el grado de complejidad

Figura 2: Resultados de la limpieza según la complejidad. Las variables dependientes simples se aceptan al 100 % a la primera; las de complejidad media alcanzan una tasa de limpieza del 94 %; las complejas presentan más revisiones y fallos, pero aún así alcanzan el 85 %.

Como se muestra en la figura 2, 31 de las 50 limpiezas se completaron a la primera, 14 necesitaron una pequeña revisión y cinco requirieron la intervención de un ingeniero. El desglose por complejidad refleja el límite de fiabilidad del sistema:

  • DV simples: depuradas al 100 % en una sola pasada.
  • Valores de datos medios: 94 % (17/18). 14 se completaron en una sola pasada, tres tras una revisión y uno requirió la intervención de un ingeniero.
  • Variables de datos complejas: 85 % (22/26), incluso con la eliminación en cascada de parámetros a lo largo de más de cinco capas de métodos, condiciones anidadas y una profunda refactorización de las pruebas.

Las 14 revisiones fueron de carácter menor y se corrigieron por sí solas; seis presentaban una cobertura insuficiente del parche, lo que requirió una iteración más para añadir pruebas, y ocho consistían en una eliminación incompleta de código muerto, con alguna variable o referencia residual en lo más profundo de una cadena de llamadas. No obstante, todas se corrigieron con una sola nueva solicitud al modelo de lenguaje grande (LLM).

El hallazgo más importante tuvo que ver con el tipo de problema que se produjo. En las 50 solicitudes de incorporación de cambios generadas, no observamos ningún error ni regresión provocados por el código modificado. Cada uno de los cinco casos de intervención se redujo a la profundidad de la cadena de llamadas con encadenamiento de parámetros entre interfaces; el agente eliminó correctamente la mayor parte del código muerto, pero se le escaparon uno o dos eslabones en una larga cadena que abarcaba varios archivos. En otras palabras, el límite de fiabilidad del sistema es la exhaustividad, no la corrección, lo que disipa la preocupación de que el sistema pudiera generar problemas mayores cuando no lograba su objetivo.

Coste y tiempo

El coste y el plazo varían en función de la complejidad, pero se mantienen claramente dentro del ámbito de la «ejecución a gran escala», tal y como se muestra en la Tabla 1 y en la Figura 3. 

La tabla 1 desglosa los indicadores de rendimiento medios y medianos —concretamente, el tiempo y el coste— de los 50 «feature flags» analizados, clasificados según su complejidad. Estos datos ponen de manifiesto que, si bien los «feature flags» más complejos requieren, como es lógico, más tiempo y presupuesto, el sistema sigue siendo muy eficiente incluso en las tareas de limpieza más difíciles.

ComplejidadnTiempo medioTiempo medianoCoste medioCoste medio
Sencillo67,5 min8,2 min$2.69$2.50
Medio1810,4 min9,9 min$3.46$3.42
Complejo2617,7 min14,4 min$6.20$4.50

Tabla 1: Indicadores de rendimiento por nivel de complejidad en las 50 opciones de configuración evaluadas.

Figura 3: Coste de la API frente al tiempo real para cada DV, clasificados por colores según su complejidad. Los DV simples y de complejidad media se agrupan en la zona de bajo coste y tiempo reducido. Los DV complejos se distribuyen de forma dispersa, con algunos valores atípicos que se acercan a los 40 minutos y los 19 dólares. Los DV fallidos (×) tienden a presentar tiempos de ejecución más largos.

Como se muestra en la figura 3, los DV simples y medios se agrupan estrechamente en el rincón de «barato y rápido». Los DV complejos se dispersan, con unos pocos valores atípicos que alcanzan aproximadamente los 40 minutos y unos 19 dólares. Incluso en el extremo superior de ese rango, el agente supone una reducción drástica del esfuerzo de ingeniería y de los costes, incluso en comparación con una estimación conservadora de una hora de lo que se necesitaría para eliminar manualmente un solo DV.

Lo que aprendimos

  • Especializar los modelos según su función da sus frutos. Utilizamos Claude Sonnet para la orquestación, lo que incluye el contexto general, la recopilación de metadatos ligeros y la planificación, y Claude Opus para los agentes de eliminación, lo que incluye el razonamiento profundo sobre la semántica del código, las cadenas de llamadas y las dependencias de las pruebas. Reservar el modelo más costoso para la fase de edición, que exige un mayor esfuerzo cognitivo, nos ha permitido reducir el coste global de la API sin perjudicar la calidad de la limpieza.
  • El aislamiento del árbol de trabajo es imprescindible para los agentes paralelos. Nuestros primeros experimentos sin aislamiento del árbol de trabajo dieron lugar a condiciones de carrera en las que agentes concurrentes editaban los mismos archivos y generaban diferencias corruptas. Un árbol de trabajo específico para cada agente, junto con Gradle en modo –no-daemon, hizo que la limpieza paralela fuera segura y que los fallos se pudieran descartar.
  • La integración de la experimentación en tiempo real fue la decisión más decisiva. Sin el estado actual de implementación, cualquier enfoque automatizado —ya sea basado en reglas o en modelos de lenguaje grande (LLM)— corre el riesgo de codificar de forma rígida un valor erróneo y de mantener de forma encubierta un comportamiento incorrecto. Su aplicación a través de MCP añadió una latencia insignificante y eliminó toda una clase de errores de valores objetivo.

Cualquier equipo que esté considerando una automatización similar debe tener en cuenta que nuestros resultados apuntan a tres requisitos previos prácticos: 

  • Una fuente fiable de información sobre el Estado de la bandera en que navega el buque
  • Aislamiento del árbol de trabajo para ediciones en paralelo, y 
  • Las comprobaciones de validación determinísticas se realizan antes incluso de que se abra una solicitud de incorporación de cambios (PR).

Próximos pasos

Vamos a ampliar el sistema en dos direcciones:

  1. Una puntuación de confianza de fase 1 para aprobar automáticamente las correcciones de bajo riesgo. Por ejemplo, una variable dependiente booleana con un 100 % de implementación cuyo código por defecto ya coincide con el de producción, lo que reserva la revisión humana para los casos realmente ambiguos.
  2. Una revisión de la calidad del código tras la limpieza. Esto permitiría detectar problemas semánticos, como nombres de variables que ya no reflejan su finalidad una vez que se ha eliminado un indicador.

La limpieza de los «feature flags» es el tipo de trabajo que, individualmente, resulta insignificante, pero que, en conjunto, supone una tarea ingente —especialmente a la escala de DoorDash— y que se pospone constantemente. Al combinar un orquestador, agentes de eliminación en paralelo en árboles de trabajo aislados, consultas en la plataforma de experimentación en tiempo real y controles de validación estrictos, nuestro sistema de limpieza de indicadores de funcionalidades transforma un trabajo atrasado de miles de horas en un proceso en segundo plano económico y fiable que genera solicitudes de incorporación de cambios (PR) listas para fusionarse para el 90 % de los indicadores que procesa, con un coste de unos 4,79 dólares y 14 minutos por cada uno, sin regresiones. El único obstáculo que queda es la exhaustividad en las cadenas de llamadas más profundas, y ahí es precisamente donde centraremos nuestros esfuerzos a continuación.

¿Te interesa desarrollar sistemas como este? El departamento de ingeniería de DoorDash está contratando: únete a nosotros para ayudarnos a desarrollar a gran escala.

Flux es la plataforma de agentes basada en la nube de DoorDash para ingenieros. En un solo mes de 2026, utilizamos Flux para automatizar 130 000 tareas de ingeniería. Tras su lanzamiento en el primer trimestre de 2026, Flux ha experimentado una rápida expansión y ya gestiona flujos de trabajo en segundo plano de gran volumen en toda DoorDash, incluyendo más de 25 000 revisiones de código automatizadas cada semana, así como más de 300 guías de procedimientos únicas y más de 10 000 ejecuciones semanales. Estos flujos de trabajo pueden ejecutarse de forma autónoma, en paralelo y las 24 horas del día.

En esta entrada del blog, analizaremos las limitaciones que nos llevaron a ir más allá de las cargas de trabajo de los agentes locales ejecutados en portátiles, por qué decidimos desarrollar Flux internamente en lugar de depender exclusivamente de agentes de programación alojados, y los elementos básicos de la plataforma —como los entornos aislados de los agentes, la pasarela MCP, los guiones y las superficies de invocación— que permiten que la delegación de agentes sea repetible y segura.

Casos de uso del flujo de trabajo de fondo de Flux

Tabla 1: Resumen del uso de Flux en DoorDash durante un mes, que abarca revisiones automáticas de código, ejecuciones de guiones y finalización de tareas en segundo plano

De dónde partimos

A lo largo del último año, los usuarios que ejecutan cargas de trabajo de tipo «agente» en sus portátiles se han topado rápidamente con una serie de limitaciones:

  • Recursos y disponibilidad. Un portátil tiene un número fijo de núcleos de CPU, memoria limitada y una batería, todos ellos compartidos con todas las aplicaciones instaladas. Los flujos de trabajo de Agentic a menudo necesitan ejecutar en paralelo tareas que requieren un gran esfuerzo computacional, como compilaciones, pruebas y búsquedas de gran envergadura, lo que hace que los portátiles se queden sin capacidad rápidamente. Además, los flujos de trabajo dependen de que el dispositivo esté encendido, conectado y disponible; el trabajo se detiene cuando un ingeniero cierra el portátil, pierde la conexión o se aleja.
  • Controles de seguridad. Los ordenadores portátiles suelen tener un amplio acceso a credenciales y sistemas sensibles, como claves SSH, sesiones VPN y herramientas autenticadas. Otorgar a un agente autónomo ese mismo nivel de acceso genera un riesgo innecesario y un alcance potencialmente amplio. Los entornos locales también dificultan definir con precisión a qué puede acceder un agente y durante cuánto tiempo.
  • Visibilidad y auditabilidad. Cuando las cargas de trabajo se ejecutan en ordenadores portátiles individuales, la ejecución resulta fragmentada y difícil de supervisar. Resulta más complicado saber qué se está ejecutando, dónde se está ejecutando, en nombre de quién y a qué sistemas o archivos ha afectado.

Nuestra propuesta para abordar estas cuestiones es sencilla: 

Delegar tareas en agentes de programación seguros y autónomos para que los ingenieros puedan dedicar más energía a la innovación, al pensamiento crítico y a la resolución de problemas complejos.

Por qué desarrollamos Flux internamente

Los agentes de programación alojados son útiles, pero obligan a elegir entre dos opciones: o bien enviar código sensible y el contexto de ejecución a un tercero, o bien abrir una vía desde ese tercero de vuelta a los sistemas internos. Para DoorDash, el mayor reto no era simplemente conseguir que un agente escribiera código; eso ya está prácticamente resuelto. Se trataba de proporcionar a ese agente el entorno, las herramientas, los permisos, las integraciones y las restricciones adecuados.

Nuestra estrategia consiste en controlar los elementos básicos que rodean al agente, entre los que se incluyen la orquestación, los entornos aislados, los flujos de trabajo, los permisos, las integraciones y los agentes de contexto específicos de DoorDash necesarios para trabajar con eficacia. Además, hemos diseñado esos elementos básicos para que sean modulares, lo que nos da la flexibilidad de utilizar la mejor herramienta de terceros para cada tarea o de desarrollarla internamente cuando sea importante contar con un mayor nivel de seguridad, integración, rendimiento o control sobre la experiencia de usuario. 

Estas primitivas democratizan la creación de flujos de trabajo y hacen que los sistemas sean más adaptables a futuros casos de uso. Dado que se pueden combinar de diferentes maneras, los equipos pueden crear nuevos flujos de trabajo para los agentes sin tener que modificar la infraestructura subyacente ni imponer a cada ingeniero cómo debe estructurar su flujo de trabajo. Por ejemplo, ejecutamos las evaluaciones de nuestra revisión de código en la infraestructura de Flux.

Elementos primitivos, no flujos de trabajo

Como se muestra en la figura 1, Flux se basa en cuatro elementos fundamentales de la plataforma: entornos aislados, la pasarela del protocolo de contexto de modelos (MCP), los guiones de trabajo y las superficies de invocación. En conjunto, hacen que la delegación de tareas a los agentes sea repetible. Un guión de trabajo define la tarea. Un entorno aislado en la nube proporciona al agente un espacio real para llevarla a cabo. Una pasarela de agente controla a qué sistemas puede acceder el agente. Y las superficies de invocación permiten a los ingenieros iniciar y recibir tareas desde los entornos que ya utilizan.

Figura 1: Las cuatro primitivas de la plataforma que conforman Flux —entornos aislados, la pasarela MCP, los guiones y las superficies de invocación— y cómo se conectan entre sí para convertir una tarea en un trabajo que un agente pueda llevar a cabo de forma segura

Los entornos aislados proporcionan el entorno de ejecución

Los agentes locales funcionan bien para el desarrollo interactivo, pero no son adecuados para flujos de trabajo sin supervisión. Dependen de los ordenadores portátiles de cada ingeniero, compiten por los recursos locales, son difíciles de auditar y no se adaptan de forma eficiente a tareas paralelas.

Flux traslada la ejecución a entornos aislados en la nube, respaldados por microvirtuales (microVM) de Firecracker, que garantizan el aislamiento a nivel de hardware. Cada entorno cuenta con los repositorios, las herramientas de desarrollo, los secretos y las dependencias de tiempo de ejecución que requiere la tarea, lo que proporciona a los agentes un espacio de trabajo de ingeniería completo, al tiempo que ofrece a DoorDash un modelo coherente de ejecución, seguridad y observabilidad.

El control de esta capa nos permite dar soporte a flujos de trabajo de ingeniería reales, incluyendo cambios en varios repositorios y múltiples solicitudes de incorporación de cambios desde una única sesión. Flux tiene un objetivo de nivel de servicio en el percentil 95 de menos de cinco segundos para la configuración completa de principio a fin: desde el inicio de la microVM hasta la clonación de los repositorios necesarios, la instalación de las herramientas de compilación y la configuración de los entornos de prueba compatibles con el agente de codificación.

La pasarela MCP proporciona un acceso controlado

Los agentes necesitan tener acceso a los sistemas que utilizan los ingenieros a diario, entre los que se incluyen la integración continua (CI), las plataformas de observabilidad, los sistemas de seguimiento de incidencias, las herramientas de implementación, la búsqueda de código, la documentación y los metadatos de los servicios. Sin embargo, conceder un acceso amplio y sin restricciones no debería ser la opción por defecto.

Flux conecta a los agentes con los sistemas internos a través de una pasarela MCP propia denominada «Agent Gateway». Cada guion de acciones especifica las herramientas que necesita, y Flux solo concede los permisos específicos necesarios para esa tarea. Se registra cada acción, lo que genera un registro de auditoría claro.

Esta arquitectura de puerta de enlace nos proporciona un punto de control centralizado para la autenticación, la autorización, la observabilidad, el seguimiento del uso y la aplicación de políticas, lo que hace que el acceso de los agentes sea más seguro y más fácil de gestionar a gran escala.

Los manuales de estrategias definen el trabajo

Un «playbook» es una unidad reutilizable de trabajo autónomo, el equivalente a un contenedor Docker para habilidades y tareas gestionadas por agentes en la plataforma Flux. Definido en un único archivo YAML de marcado, agrupa la tarea, los datos de entrada, el contexto, las habilidades, las herramientas, los permisos, la validación, los resultados esperados y los límites de seguridad necesarios para ejecutar el trabajo de forma coherente.

Los «playbooks» pueden combinar pasos basados en agentes —que aportan flexibilidad y capacidad de juicio— con pasos deterministas —que ofrecen previsibilidad, un menor coste y una validación más sencilla—. Esto permite a los equipos trasladar la lógica entre la ejecución basada en agentes y el código convencional a medida que evolucionan los requisitos, sin necesidad de rediseñar el flujo de trabajo.

Las interfaces de invocación se adaptan a las necesidades de los desarrolladores

El mismo guion de acciones se puede activar desde Slack, GitHub, cron, la interfaz de línea de comandos (CLI) o una habilidad conversacional. Esto significa que los equipos pueden definir un flujo de trabajo una sola vez e invocarlo desde la interfaz que mejor se adapte a cada momento:

  • Slack para la delegación colaborativa
  • GitHub para la automatización de las solicitudes de incorporación de cambios (PR) y la integración continua (CI)
  • Cron para tareas de mantenimiento periódicas
  • Interfaz de línea de comandos (CLI) para que el desarrollador tenga control directo, o que se pueda invocar a través de una skill

Esto es lo que hace que Flux sea fácil de adoptar.

Lecciones aprendidas

La creación de Flux nos enseñó tanto sobre la adopción de productos como sobre la infraestructura, entre otras cosas:

  • Empieza por algo concreto para ganarte la confianza. Comenzamos con la revisión automatizada del código, en lugar de intentar automatizar todo el ciclo de vida del desarrollo de software. La revisión del código era frecuente, cuantificable y fácil de evaluar para los ingenieros. Esto nos proporcionó un flujo de trabajo en producción que nos permitía ajustar la calidad, la latencia, el coste y el comportamiento antes de ampliarlo al triaje de CI, las tareas de guardia, los manuales de mantenimiento y el desarrollo basado en tickets.
  • Haz que el trabajo sea visible. Nuestra primera integración con Slack creaba canales privados para cada tarea asignada a un agente. Eso hacía que Flux resultara útil a nivel individual, pero no fomentaba los hábitos de trabajo en equipo. Trasladar el trabajo a hilos públicos cambió el patrón de adopción. Los ingenieros podían ver lo que otros delegaban, seguir el progreso en Flux, revisar los resultados y generar confianza entre todos.
  • Los manuales operativos necesitan apoyo. Los flujos de trabajo reutilizables no surgen por el mero hecho de que exista la plataforma. Los talleres y los hackatones ayudaron a los equipos a plasmar en manuales operativos las tareas operativas recurrentes. Los elementos básicos hicieron posible la automatización; el apoyo ayudó a los equipos a identificar qué flujos de trabajo merecía la pena codificar.

Próximos pasos

En próximas entradas, profundizaremos en los componentes básicos de la plataforma que hacen posible el funcionamiento de Flux, así como en la experiencia de los desarrolladores a la hora de crear nuevos flujos de trabajo. También hablaremos de las aplicaciones que hemos desarrollado a partir de ella, entre ellas Flux Responder, nuestro agente interno de Slack.

Agradecimientos

Agradecemos a Adam Rogal, Adam Yarger, Andy Fang, Ashwin Kachhara, Fan Xia, Ivan Rudovol, Jason Prasad, Jialu Deng, Justin Block, Justin Deocampo, Justin Fan, Keith Lyall, Praneet Singh, Sean Chen, Tyler Berrett y Volanda Zhu sus aportaciones a la plataforma y a esta publicación.

Manténgase informado con Actualizaciones

Suscríbase a nuestro blog de ingeniería para estar al día de todos los los proyectos más interesantes en los que trabaja nuestro equipo

Los agentes de IA resultan útiles cuando pueden actuar en sistemas reales. En DoorDash, eso significa acceder a API internas, sistemas de ingeniería, plataformas de observabilidad, sistemas de gestión de incidencias, bases de conocimiento y productos SaaS de terceros. El protocolo de contexto del modelo (MCP) facilitó la exposición de esas herramientas al proporcionar a los agentes y servidores una forma común de describir, descubrir e invocar capacidades.

A medida que los agentes pasaban de los experimentos a los flujos de trabajo reales, nos topamos con un problema diferente. Aunque MCP estandarizaba el formato de una llamada a una herramienta, no respondía a preguntas clave relacionadas con la producción en torno a dicha llamada:

  • ¿Qué agente tiene permiso para utilizar esta herramienta?
  • ¿En nombre de qué usuario, equipo o servicio actúa?
  • ¿Qué credencial se debe utilizar?
  • ¿Qué subconjunto de herramientas debería ver el agente?
  • ¿Cómo se revoca el acceso?
  • ¿Cómo sabemos qué pasó después de la llamada?

Estas necesidades crecen rápidamente. Un agente de programación podría necesitar GitHub, Jira, búsqueda de código, integración continua (CI), observabilidad y documentación. Un servidor MCP de terceros podría ofrecer cientos de herramientas cuando un flujo de trabajo solo necesita cinco. Un agente de atención al usuario podría necesitar una autorización OAuth del usuario, mientras que la automatización del equipo debería utilizar una entidad de servicio no personal. Si cada equipo resuelve estos problemas de forma independiente, cada combinación de agente y herramienta acaba teniendo su propio código de autenticación, flujo OAuth, gestión de secretos, catálogo de herramientas, límites de frecuencia y registros.

Por eso hemos creado una «Agent Gateway» para que el acceso a las herramientas de los agentes sea una funcionalidad de la plataforma. Se trata de un único punto de entrada regulado desde el que los agentes pueden detectar e invocar herramientas. La pasarela autentica al usuario que realiza la llamada, comprueba la autorización, muestra únicamente las herramientas aprobadas, introduce las credenciales adecuadas, redirige la llamada al servidor MCP correspondiente y registra un evento de uso estructurado para cada llamada.

La pasarela no es solo un proxy. Es el plano de control del ecosistema de agentes. Se encarga de determinar quién puede acceder a las herramientas, selecciona las herramientas a las que pueden acceder los agentes, agrupa las herramientas en interfaces orientadas a tareas y proporciona a DoorDash un único punto desde el que supervisar, limitar el número de solicitudes, revocar y mejorar el acceso de los agentes a las herramientas.

Problema: El acceso a las herramientas consta de tres partes

Aunque MCP ayuda a los agentes a utilizar herramientas, el problema más complejo en el entorno de producción tiene tres dimensiones:

  1. El primero es el acceso. La plataforma debe saber quién está llamando, si tiene permiso para hacerlo y qué modelo de credenciales se aplica: identidad interna, token gestionado por la pasarela, OAuth por usuario o acceso mediante entidad de servicio.
  2. El segundo aspecto es la selección de herramientas y superficies. Los agentes no deben recibir un volcado sin procesar de todas las herramientas expuestas por los servidores MCP posteriores. Los catálogos más reducidos y relevantes para la tarea mejoran la seguridad, reducen la confusión de los modelos y facilitan el manejo de los agentes.
  3. El tercero es el ámbito operativo. Las llamadas a las herramientas deben contar con límites de frecuencia, seguimientos, métricas, eventos de uso, atribución de costes, metadatos de propiedad y visibilidad en producción.

Nuestra Agent Gateway existe porque el acceso, la gestión de contenidos y las operaciones deben integrarse en una única plataforma compartida, en lugar de duplicarse en cada agente y en cada servidor MCP.

Arquitectura de pasarela

La pasarela consta de dos componentes principales: un proxy y un registro, tal y como se muestra en la figura 1 a continuación. El proxy es el plano de datos; recibe cada solicitud de MCP, autentica al solicitante, autoriza la acción, aplica límites de tasa, inyecta credenciales, reenvía la solicitud y emite datos de observabilidad. El registro es la fuente de información de referencia del plano de control; almacena agentes, servidores MCP, propietarios, configuraciones de transporte, modos de autenticación, políticas, catálogos de herramientas detectadas y configuraciones de la superficie de herramientas.

Figura 1: Arquitectura de alto nivel de la pasarela de agentes

Esta división dota a la pasarela de algunas características que resultan difíciles de conseguir con las integraciones punto a punto:

  • Los agentes utilizan un patrón de punto final MCP único y coherente, en lugar de tener que aprender el modelo de autenticación y enrutamiento de cada servidor posterior.
  • Los propietarios de las herramientas registran las capacidades una sola vez, asocian la titularidad y la política, y consultan el uso en producción.
  • Los equipos de seguridad disponen de un único punto desde el que pueden gestionar los accesos, revocar autorizaciones y auditar las llamadas.
  • Los equipos de la plataforma pueden mejorar la ruta compartida una sola vez y hacer que todos los agentes se beneficien de esa mejora.

Además, mantenemos separados los límites de confianza internos y externos. Los flujos de trabajo internos de DoorDash y los casos de uso de agentes orientados al exterior se ejecutan a través de planos de proxy independientes con bibliotecas compartidas y conceptos de registro. Esto limita el alcance de los posibles incidentes frente a Internet y permite que cada modelo de autenticación evolucione de forma independiente.

Identidad, autorización y claves de acceso centralizadas

Cada solicitud de la pasarela se asocia a un solicitante: un usuario, un servicio o un agente que actúa con un contexto de usuario delegado. Esa identidad se mantiene a lo largo de los procesos de autorización, inyección de credenciales, enrutamiento y observabilidad, de modo que se pueda atribuir cada acción posterior.

La pasarela comprueba la autorización de forma centralizada. Las cuestiones relacionadas con la política no se limitan a determinar si este solicitante puede acceder a este servidor. También pueden ser:

  • ¿Puede este agente acceder a este servidor?
  • ¿Puede este usuario acceder a esta herramienta a través de este agente?
  • ¿Se puede exponer esta herramienta en este entorno?
  • ¿Puede este usuario utilizar una variante con capacidad de escritura o solo una de solo lectura?
  • ¿Este flujo de trabajo puede utilizar una entidad de servicio de equipo o requiere OAuth por usuario?

Dado que la política se gestiona en la puerta de enlace, DoorDash dispone de un único lugar desde el que modificar y revocar el acceso. Los responsables de las herramientas evitan tener que volver a configurar la autorización para cada servidor, y los desarrolladores de agentes evitan tener que codificar las decisiones de seguridad en las solicitudes o en el código de la aplicación.

La gestión de credenciales sigue el mismo patrón, tal y como se muestra en la Tabla 1:

Modo de autenticación¿Quién es el titular de la credencial?Qué hace la pasarela
Identidad de servicio internaInfraestructura de DoorDashReenvía el contexto de la llamada verificada a los servicios internos
Token gestionado por GatewayAlmacenamiento seguro de claves de puerta de enlaceInyecta un token de proveedor o de servicio sin exponerlo al agente
OAuth por usuarioAlmacén de autorizaciones cifrado por usuarioInserta y actualiza el token del usuario para las acciones con ámbito de usuario
Servicio principalDirector del equipo gestionado por GatewayLos emisores o intermediarios emiten credenciales no personales de corta duración

Los agentes no deben disponer de credenciales sin procesar, como claves API de proveedores, tokens de actualización de OAuth o autorizaciones de usuarios prestadas para las automatizaciones del equipo. La pasarela garantiza que esos límites sean explícitos y auditables.

OAuth por usuario sin interrumpir el turno del agente

Las herramientas de terceros con ámbito de usuario requieren la autorización del usuario. Para consultar la documentación de un usuario, crear un ticket en su nombre o actualizar datos de SaaS en su nombre, no es seguro utilizar una clave compartida. Antes de implementar la pasarela, cada equipo solía crear su propio flujo de OAuth, su propio almacenamiento de tokens y su propia experiencia de «conectarse primero».

La pasarela centraliza la concesión de OAuth. La unidad de acceso se limita al agente, al usuario y al servidor. En la primera llamada que requiere autorización, la pasarela inicia el flujo OAuth del proveedor, almacena los tokens cifrados de acceso y de actualización resultantes, e inserta el token del usuario en las llamadas posteriores. Los agentes nunca ven el token sin procesar.

En el caso de los clientes que admiten la solicitud de autorización MCP, la pasarela puede pausar la llamada a la herramienta, solicitar al cliente que muestre un mensaje de conexión y reanudar la llamada original una vez que el usuario la haya autorizado. Para los clientes que no admiten la solicitud de autorización, devuelve una respuesta estructurada que indica que se requiere autorización, junto con una URL de conexión, tal y como se muestra en la figura 2. De este modo, la conexión pasa de ser un paso fallido a convertirse en una parte recuperable de la llamada a la herramienta.

Figura 2: Protocolo de intercambio de información

Superficies de herramientas seleccionadas: paquetes y filtrado

Los agentes no piensan de forma natural en servidores MCP, sino en tareas. Un agente de programación no quiere que GitHub, Jira, la observabilidad y la documentación sean pasos de configuración independientes; lo que quiere es disponer de las herramientas necesarias para investigar un problema, modificar el código, abrir una solicitud de incorporación de cambios, inspeccionar la integración continua y comprender el comportamiento en producción.

Al mismo tiempo, la mayoría de los servidores MCP de nivel inferior exponen muchas más herramientas de las que debería utilizar un solo agente. Los servidores de terceros pueden publicar cientos de operaciones, entre las que se incluyen acciones administrativas, acciones destructivas, API de facturación y funciones específicas de proveedores especializados. La mayoría de los flujos de trabajo de DoorDash solo necesitan un pequeño subconjunto autorizado de ellas.

La pasarela resuelve ambos problemas mediante interfaces de herramientas seleccionadas, tal y como se muestra en la figura 3. Los paquetes combinan herramientas de varios servidores MCP en un único punto final lógico de MCP. Los filtros determinan qué herramientas de cada servidor se muestran para un paquete, agente, grupo de usuarios, entorno o público determinado.

Por ejemplo, un paquete de herramientas para desarrolladores puede incluir:

  • herramientas seleccionadas de GitHub para los flujos de trabajo de repositorios y solicitudes de incorporación de cambios;
  • herramientas seleccionadas de Jira para la búsqueda y actualización de incidencias;
  • herramientas de observabilidad seleccionadas para registros, métricas y trazas;
  • determinadas herramientas de búsqueda de código y documentación; y
  • herramientas seleccionadas de implementación o de control de funciones.

Figura 3: Experiencia del usuario con el paquete MCP incluido

El agente se conecta a una URL de la pasarela, como un punto final de herramientas para desarrolladores. Detrás de esa URL, la pasarela distribuye «tools/list» entre los servidores del paquete, aplica filtros de autorización y de herramientas, asigna espacios de nombres o alias a los nombres de las herramientas cuando es necesario, y devuelve un catálogo coherente. Cuando el agente invoca «tools/call», la pasarela vuelve a aplicar la política, enruta la llamada al servidor de destino correcto y aplica el modelo de credenciales de dicho servidor.

Esto proporciona a los agentes una interfaz de calidad, en lugar de un simple conjunto de capacidades de nivel inferior, e incluye elementos como herramientas aprobadas, nombres estables, descripciones más claras, metadatos de propiedad y paquetes específicos para cada público. Los departamentos de ingeniería, análisis de datos y operaciones de soporte, así como los paquetes externos, pueden utilizar las mismas primitivas de la pasarela al tiempo que exponen diferentes interfaces de herramientas.

Las ventajas son prácticas:

  • La configuración del agente es más sencilla: un único punto de acceso de puerta de enlace en lugar de múltiples puntos de acceso de servidor.
  • La detección de herramientas es más segura: los agentes solo ven las herramientas que se encuentran dentro del límite autorizado.
  • Mejora el comportamiento de los modelos: los catálogos más reducidos disminuyen las opciones irrelevantes y la confusión a la hora de elegir herramientas.
  • La autorización sigue estando centralizada: tanto el descubrimiento como la invocación aplican la misma política.

Aquí es donde la pasarela deja de ser un simple proxy de acceso. Determina qué pueden encontrar los agentes, a qué pueden acceder y cuánto contexto irrelevante transportan. Una selección de herramientas bien organizada puede marcar la diferencia entre un agente que elige la herramienta adecuada y otro que se pierde en un catálogo de API desmesuradamente amplio.

Observabilidad, atribución de costes y protección en las fases posteriores

Dado que todas las llamadas pasan por la pasarela, cada solicitud puede generar un evento estructurado que incluya:

  • el servidor, la herramienta, el paquete y el equipo responsable;
  • el usuario, el agente, el servicio y la plataforma implicados en la llamada;
  • resultado de la autorización, código de estado, origen del error y desglose de la latencia;
  • el tamaño de la solicitud y de la respuesta; y
  • metadatos sobre los costes comunicados por los eslabones posteriores de la cadena de suministro, cuando estén disponibles.

La pasarela también genera métricas sobre el volumen de solicitudes, la latencia por herramienta, las decisiones de autorización, los resultados de la actualización de OAuth, las decisiones de limitación de tasa, las conexiones de streaming y los fallos en el lado de origen. La propagación de trazas permite a los equipos seguir el recorrido de una llamada desde el agente, pasando por la pasarela, hasta el servidor de destino.

Esto tiene un valor operativo directo: el equipo de seguridad puede auditar los accesos, los equipos de la plataforma pueden detectar agentes que generan ruido, los responsables de las herramientas pueden ver los niveles de adopción y los errores, y los equipos de infraestructura pueden atribuir los costes.

Este mismo mecanismo protege los sistemas posteriores. Los límites de tasa pueden aplicarse por servidor, herramienta, entidad solicitante, usuario, paquete o tipo de entidad solicitante. Los nuevos límites pueden ejecutarse en modo simulado antes de su aplicación efectiva, mostrando lo que se habría rechazado sin interrumpir el tráfico de producción.

La pasarela transforma la gestión en datos, en lugar de depender de que cada equipo registre los campos adecuados y aplique los límites correctos.

Incorporación de autoservicio

Una pasarela solo funciona si los equipos prefieren utilizarla en lugar de eludirla. El registro, la detección, el filtrado y la gestión de paquetes deben poder realizarse de forma autónoma.

A través de la interfaz de usuario y la API del plano de control, los equipos pueden registrar servidores y agentes MCP, configurar la autenticación, detectar herramientas, asignarles un propietario, definir filtros, añadir herramientas a paquetes e inspeccionar el uso en producción.

El proceso de incorporación de la pasarela sigue estos pasos:

  1. Registra el servidor MCP.
  2. Descubre su catálogo de herramientas sin procesar en tools/list.
  3. Selecciona y aprueba las herramientas que DoorDash quiere poner a disposición.
  4. Especifica el modo de autenticación, la titularidad y la política.
  5. Añade las herramientas aprobadas a uno o varios paquetes.
  6. Supervisa el tráfico, la latencia, los errores, las decisiones de autorización y los costes.

Una gestión que requiera tickets no es escalable. El camino allanado tiene que ser más sencillo que copiar una clave secreta en un agente y conectarse directamente a un servidor.

¿Qué ha cambiado?

La pasarela ofrece a cada grupo una ventaja diferente:

  • Los desarrolladores de agentes disponen de una única integración, un catálogo seleccionado y no tienen que ocuparse de la autenticación posterior, OAuth, la gestión de claves secretas ni el enrutamiento por herramienta.
  • Los propietarios de las herramientas disponen de una vía de distribución gestionada con control de acceso, exposición autorizada de las herramientas y datos sobre su uso en producción.
  • Los equipos de seguridad disponen de políticas centralizadas, datos confidenciales, autorizaciones OAuth, revocaciones y registros de auditoría.
  • Los equipos de la plataforma obtienen ventajas; la identidad, la limitación de tasas, la observabilidad, la calidad de las herramientas, la atribución de costes y la experiencia de los desarrolladores mejoran, todo ello desde un único lugar.
  • Los agentes disponen de catálogos más reducidos, nombres de herramientas más claros, paquetes orientados a tareas, menos opciones irrelevantes y flujos de conexión recuperables.

Adopción

La adopción es la verdadera prueba de fuego de una plataforma: los equipos solo la utilizan si resulta más fácil que acceder directamente. Según este criterio, Agent Gateway se ha convertido en la vía predeterminada para el acceso de los agentes a las herramientas en todo el departamento de ingeniería de DoorDash:

  • Hay más de 200 servidores MCP registrados detrás de la pasarela, que en conjunto ponen a disposición miles de herramientas organizadas en subconjuntos aprobados y orientados a tareas concretas, en lugar de catálogos sin filtrar.
  • Más de 30 agentes y servicios, utilizados por miles de empleados, acceden a esas herramientas a través de la pasarela y ninguno de ellos gestiona credenciales sin procesar. 
  • Cada semana se canalizan millones de llamadas a herramientas a través de Agent Gateway, y cada una de ellas se autentica, se autoriza y se registra como un evento de uso estructurado.
  • La incorporación es rápida y se realiza de forma autónoma. Registrar un nuevo servidor MCP y sus herramientas es cuestión de minutos, y asignar un agente a una herramienta ya registrada es aún más rápido.

Lecciones aprendidas

La creación y la ampliación de la pasarela han cambiado nuestra forma de concebir el acceso de los agentes a las herramientas. Hay algunas lecciones que destacan, y no solo en DoorDash:

  • MCP resuelve la invocación, no la gobernanza. La identidad, las políticas, los secretos, la gestión, la observabilidad y la revocación se convierten en las partes más complejas.
  • El catálogo de herramientas descubierto es una interfaz, lo que significa que los nombres, las descripciones, los filtros, las agrupaciones y el público objetivo son importantes.
  • Los paquetes son la unidad adecuada para los flujos de trabajo. Los agentes necesitan conjuntos de herramientas orientados a tareas, no listas de servidores.
  • El filtrado de herramientas mejora tanto la seguridad como la calidad de los agentes, al ofrecer un conjunto de acciones más reducido y claro.
  • Las credenciales deben almacenarse en la pasarela, donde se pueden renovar, auditar y revocar de forma centralizada.
  • La ausencia de autorizaciones OAuth es un estado normal, no una excepción, en la gestión de la conexión dentro del protocolo.
  • La vía regulada debe ser de autoservicio; de lo contrario, los equipos recurrirán directamente a otras vías.

Próximos pasos

La próxima inversión importante se centrará en reforzar la identidad de los agentes y la delegación de usuarios. El modelo objetivo otorga a cada agente una identidad criptográfica y permite que la pasarela genere credenciales delegadas de corta duración, limitadas al usuario, al agente, a la tarea y a la herramienta de destino. De este modo, el registro de auditoría cuenta con dos sujetos reales: el usuario y el agente.

También estamos invirtiendo en herramientas de compilación, lo que incluye fichas de evaluación de calidad y seguridad, comprobaciones de descripciones de herramientas que puedan suponer un riesgo, detección de secretos o información de carácter personal en los errores, creación escalonada de servidores, registro automático, detección dinámica de herramientas y flujos de eventos de llamadas a herramientas censurados para fines de análisis y cumplimiento normativo.

El descubrimiento dinámico sigue la misma línea. En lugar de proporcionar a un agente todas las herramientas de un paquete, la pasarela puede utilizar el contexto de la tarea, la política y las señales de uso para mostrar únicamente aquellas herramientas que puedan resultar útiles para el trabajo en curso.

Conclusión

Agent Gateway transforma el acceso a las herramientas de los agentes, que antes suponía un trabajo de integración repetitivo, en una funcionalidad compartida de la plataforma. MCP facilitó la descripción y la ejecución de herramientas; la pasarela hace que ese acceso esté regulado, supervisado, sea observable y escalable.

Agradecimientos

Introducción

Hemos desarrollado Ask DoorDash sobre una plataforma común que permite a los equipos de cada área desarrollar y mejorar sus agentes sin tener que reconstruir los sistemas subyacentes. Hemos evaluado la plataforma en función de dos resultados prácticos: la rapidez con la que los equipos podían añadir funciones y áreas, y la rapidez con la que podían evaluar e implementar mejoras en materia de costes, calidad y latencia.

Lanzamos «Ask DoorDash» con soporte para restaurantes y tiendas de alimentación en unos dos meses, y desde entonces ha gestionado más de dos millones de conversaciones. La incorporación de «Reservations», nuestro tercer agente temático, nos llevó una semana, lo que supone aproximadamente 10 veces más rápido que la creación de los agentes temáticos iniciales.

Nuestro sistema compartido de evaluación y nuestros controles de implementación proporcionan a los equipos indicadores claros de calidad a medida que incorporan los cambios al entorno de producción. En el plazo de una semana desde el lanzamiento de un nuevo modelo de lenguaje grande (LLM), lo evaluamos y lo implementamos, reduciendo la latencia p50 en un 35 % sin que se produjera ninguna disminución en las puntuaciones de calidad. Una actualización posterior del modelo redujo la latencia p50 en otro 40 %.

En esta entrada se explica cómo elegimos qué elementos debían formar parte de la plataforma, cómo encajan sus componentes entre sí y las concesiones que hay detrás de esas decisiones. Es la continuación de nuestra descripción general de ingeniería, nuestro análisis en profundidad sobre la inteligencia y nuestro análisis en profundidad sobre la evaluación. Próximamente publicaremos un análisis en profundidad sobre la experiencia de usuario.

Cómo elegimos qué normalizar

Solo centralizábamos una funcionalidad cuando varios ámbitos la necesitaban y unas implementaciones independientes podrían generar problemas de fiabilidad u operativos. La orquestación, la memoria, el acceso a los modelos, el seguimiento, la infraestructura de evaluación y los controles de implementación cumplían ese requisito. Los equipos de cada ámbito conservaban la responsabilidad sobre las instrucciones, las competencias, las herramientas, los criterios de evaluación y la elección de modelos que definen a sus agentes.

Cuando existía un estándar del sector adecuado, lo adoptábamos. Agent2Agent (A2A) definía cómo se comunicaban los agentes, mientras que el Kit de Desarrollo de Agentes de Google (ADK) proporcionaba el marco para crearlos y ejecutarlos. Estos estándares limitaban en ocasiones nuestras opciones de diseño, pero proporcionaban a los equipos contratos comunes y nos ahorraban tener que desarrollar equivalentes propios.

En el caso de los problemas recurrentes para los que no existía una norma adecuada, desarrollamos nosotros mismos la capacidad necesaria. Una regresión en el código compartido podía afectar a varios agentes, por lo que era imprescindible contar con controles de evaluación y de implementación. Cada cambio compartido debía superar controles de calidad comunes y medidas de seguridad para el lanzamiento.

Consulta a los arquitectos de DoorDash

La decisión arquitectónica fundamental consistió en determinar qué elementos debían compartir todos los agentes y cuáles debían ser propios de cada dominio. Creamos una ruta de ejecución compartida en torno a agentes especializados, propios de cada dominio. Un único agente de uso general resultaría cada vez más difícil de analizar a medida que asumiera más responsabilidades, mientras que unas pilas de agentes totalmente independientes duplicarían la infraestructura y darían lugar a experiencias incoherentes.

Como muestra la figura 1, cada solicitud entra a través de la pasarela. La pasarela autentica al usuario, recopila el contexto del punto de entrada y realiza la traducción entre las interfaces HTTP y de streaming del cliente y el protocolo A2A de la plataforma. A continuación, envía la solicitud al orquestador, que elige el agente de dominio para cada turno, preservando la continuidad a medida que la conversación se desplaza entre dominios. El agente seleccionado carga las habilidades adecuadas y utiliza herramientas del Protocolo de Contexto de Modelo (MCP) para interactuar con los servicios existentes de DoorDash.

Por debajo de esa ruta de solicitud, la plataforma proporciona estado de sesión, memoria, artefactos, acceso a modelos, seguimiento, infraestructura de evaluación y controles de implementación. Los agentes de dominio utilizan estos servicios comunes sin dejar de mantener el control sobre sus instrucciones, competencias, herramientas y criterios de evaluación.

Figura 1: Ask DoorDash separa el comportamiento específico de los agentes de cada dominio de las capacidades compartidas de ejecución y producción que se utilizan en todo el sistema.

Una plataforma para experiencias adaptativas y multimodales

Las pasarelas de clientes de DoorDash se diseñaron para API que devuelven una respuesta completa rápidamente. Los agentes funcionan de forma diferente. El primer mensaje de texto puede estar listo mientras el agente aún está accediendo a las herramientas, y la respuesta final puede combinar texto con fichas interactivas de tiendas o productos. Necesitábamos gestionar ese flujo de trabajo sin tener que explicar a cada cliente cómo se comunican los agentes.

Gateway se encarga de esta traducción. Autentifica al usuario, añade contexto sobre dónde se inició la conversación y convierte las solicitudes HTTP de los clientes en solicitudes A2A. En la ruta de retorno, utiliza el SDK de IA de Vercel para enviar actualizaciones de texto y datos de los widgets a los clientes a través de Server-Sent Events (SSE). Los clientes muestran las actualizaciones a medida que llegan, de modo que los usuarios pueden ver el progreso mientras el agente completa su turno.

La creación y el funcionamiento del Gateway supusieron un esfuerzo, pero permitieron concentrar el trabajo que, de otro modo, se habría duplicado en cada cliente de DoorDash. Los agentes pueden realizar cambios en el marco de un único contrato de cliente estable, sin necesidad de coordinar las versiones de los clientes. Un nuevo agente de dominio reutiliza la ruta de autenticación y transmisión existente, en lugar de integrarse por separado con cada aplicación.

Un asistente, agentes especializados en el sector

Una conversación puede pasar de un ámbito a otro sin previo aviso. Un usuario podría empezar diciendo: «Quiero que me traigan un pastel de pollo en menos de 30 minutos», y luego decidir: «En realidad, prefiero prepararlo en casa». La primera solicitud pertenece al ámbito de los restaurantes y la segunda, al de la alimentación, pero la experiencia debe dar la sensación de ser una sola conversación.

Probamos una arquitectura con un único agente, pero los ámbitos «Restaurante», «Supermercado» y «Reservas» se basan en herramientas, políticas y criterios de evaluación diferentes. Combinarlos dificultaría las pruebas del agente y obligaría a todos los ámbitos a seguir el mismo ciclo de lanzamiento. Por lo tanto, cada ámbito cuenta con su propio agente especializado. El «Orchestrator» lee la conversación y redirige cada turno al agente adecuado a través de A2A.

Ese enrutamiento añade latencia y tokens de entrada, incluso cuando la conversación permanece en el mismo dominio. Para reducir este coste, el Orchestrator asigna los turnos siguientes al agente de dominio seleccionado. Esta asignación permite que dicho agente gestione las solicitudes posteriores directamente, sin necesidad de otro paso de enrutamiento. Si la conversación cambia de dirección, el agente de dominio reconoce el mensaje fuera de su ámbito y devuelve el control al Orchestrator. El Orchestrator redirige la solicitud dentro del mismo turno, de forma invisible para el usuario.

Figura 2: El «pinning» evita que se realice una llamada al Orchestrator en los turnos siguientes, al tiempo que permite que la conversación se desplace entre dominios.

Las habilidades mantienen el contexto y los costes dentro de unos límites

Los agentes especializados evitaban que «Restaurante», «Tienda de alimentación» y «Reservas» compartieran una única ventana de contexto enorme. Sin embargo, a medida que cada agente adquiría nuevas capacidades, el mismo problema de contexto aparecía dentro de cada dominio. Las nuevas funciones añadían instrucciones y herramientas a cada turno, incluso cuando ese turno nunca las utilizaba. Esto aumentaba el coste de los tokens de entrada, y las instrucciones superpuestas o contradictorias confundían al agente.

Hemos añadido compatibilidad con habilidades a nuestro sistema para modular las instrucciones y las herramientas. En cada turno, el agente carga solo lo que es relevante. Un usuario podría empezar diciendo: «Búscame un restaurante tailandés bien valorado que haga entregas en menos de 30 minutos», y luego decir: «Muéstrame el menú del primero y añade pad see ew a mi carrito». Ambas solicitudes se gestionan a través del agente «Restaurante», pero la primera activa la habilidad de búsqueda y descubrimiento, mientras que la segunda activa la habilidad de pedido y carrito, que se encarga de la navegación por el menú y las acciones relacionadas con el carrito.

La carga dinámica plantea un problema de selección. El selector debe reconocer cuándo se necesita una capacidad sin cargar contexto ajeno con demasiada frecuencia, por lo que evaluamos la selección de habilidades como parte del comportamiento del agente. La complejidad añadida mereció la pena, ya que los equipos pudieron añadir capacidades sin ampliar el contexto de cada turno.

Para medir el efecto, contamos los tokens de las instrucciones de la base del agente y de las habilidades cargadas. Excluimos el historial de conversaciones, los mensajes de los usuarios, los esquemas de herramientas y los resultados de las herramientas. La mediana de los turnos correspondientes a las habilidades utilizó menos de la mitad de tokens de instrucciones que la solicitud del sistema monolítico.

AgenteInstrucciones básicas y de habilidades con todas las habilidades cargadasMediana de instrucciones con especificación de habilidades por turnoReducción
Restaurante~42 000 fichas

~20 000 fichas50 %+
Tienda de comestibles~25 000 fichas~10 000 fichas60%

Acceso seguro y reutilizable a los servicios a través de MCP

Ask DoorDash necesita acceso a los servicios de DoorDash para buscar establecimientos y artículos, consultar menús, gestionar carritos y actuar en nombre del usuario. Las API que sustentan estas operaciones parten de la base de que el código de la aplicación es determinista. Un modelo de lenguaje grande (LLM) que elija las operaciones en tiempo de ejecución necesita una interfaz más específica. Exponer las API directamente obligaría al modelo a interpretar interfaces de bajo nivel. Codificar los permisos y las reglas de negocio únicamente en la indicación añadiría contexto sin garantizar su cumplimiento.

Hemos creado una capa compartida del Protocolo de Contexto del Modelo (MCP) entre los agentes y las API de DoorDash. Cada herramienta MCP expone una operación específica con las entradas y salidas que necesita el modelo. El modelo decide qué herramienta llamar. Un código determinista valida cada solicitud y garantiza el cumplimiento de los permisos y las reglas de negocio antes de que la llamada llegue al servicio subyacente.

Las indicaciones ayudan al modelo a elegir la operación adecuada, pero esa orientación es meramente consultiva. La validación y la aplicación se ejecutan en el código de la herramienta en cada llamada, lo que crea un límite de seguridad estable a medida que cambian las indicaciones y los modelos.

El diseño de herramientas requiere equilibrio. Una herramienta demasiado amplia puede ofrecer al modelo demasiadas opciones, mientras que una demasiado limitada puede convertir una tarea en una larga cadena de llamadas. Nuestro servidor MCP compartido ofrece ahora más de 60 herramientas para los flujos de trabajo de los agentes, tanto públicos como internos. Un agente nuevo selecciona las herramientas que necesita de esa biblioteca, y las mejoras en la validación, la telemetría o la integración de servicios benefician a todos los agentes que las utilizan.

Figura 3: Las indicaciones influyen en lo que solicita el modelo; el código de la herramienta MCP determina lo que se puede ejecutar.

Listo para producción de forma predeterminada

ADK nos proporcionó los elementos básicos para crear un agente, incluyendo instrucciones, herramientas, callbacks, sesiones y la integración de modelos. Los agentes de DoorDash también necesitaban rastreo distribuido, acceso a modelos, estado duradero y controles de implementación. Sin una capa compartida, cada equipo de dominio tendría que tomar esas decisiones y gestionar la infraestructura resultante de forma independiente.

Hemos creado módulos reutilizables basados en ADK para que las funcionalidades funcionen de la misma manera en todos los agentes. Los equipos de cada área siguen eligiendo sus instrucciones, herramientas y configuración de modelos. La plataforma conecta esas elecciones con los sistemas necesarios para ejecutar los agentes de forma fiable en producción.

El rastreo es un ejemplo. Un equipo lo habilita mediante la configuración, y el SDK compartido propaga un identificador de rastreo a través de las llamadas A2A, las herramientas MCP y los servicios posteriores de DoorDash. Los ingenieros pueden seguir una solicitud a lo largo del Orchestrator, los agentes de dominio y las llamadas a herramientas, en lugar de tener que recopilar registros de sistemas independientes. Esos mismos datos de rastreo sirven para la depuración y la evaluación. Ofrecer rastreo a través de la plataforma ahorra aproximadamente un mes de trabajo de observabilidad por cada lanzamiento de un nuevo agente.

El acceso a los modelos sigue el mismo principio. Los equipos de dominio eligen qué modelos utilizan sus agentes, mientras que la plataforma estandariza la forma en que se invocan, se rastrean y se protegen dichos modelos mediante un comportamiento de respaldo. Los equipos pueden evaluar y adoptar nuevos modelos sin necesidad de reescribir las integraciones específicas de cada proveedor. Esa vía común permitió las rápidas actualizaciones de los modelos y las mejoras en la latencia descritas anteriormente.

Estado compartido para conversaciones fiables

Los primeros intentos de crear productos con agentes de DoorDash en 2025 demostraron lo rápido que se deteriora la experiencia cuando el estado no es fiable. Un agente podía responder bien a una solicitud y, a continuación, olvidar o utilizar incorrectamente la información de un turno anterior. Resolver ese problema requirió algo más que añadir el historial de la conversación a la indicación.

Ask DoorDash utiliza tres tipos de estado. El estado de sesión realiza un seguimiento de la conversación activa y del trabajo ya realizado en ella. La memoria conserva información que puede resultar útil en conversaciones posteriores, como las preferencias del usuario. Los artefactos contienen resultados estructurados que los agentes crean y actualizan, como listas de la compra y tarjetas interactivas. Cada uno de ellos tiene una vida útil y un patrón de acceso diferentes.

En proyectos anteriores de agentes de DoorDash, estas capacidades se implementaban de forma independiente. Esto suponía una duplicación del trabajo de persistencia y hacía que la fiabilidad dependiera de las decisiones de cada equipo. Las hemos centralizado en Managed Agent Services, que proporciona API compatibles con ADK para sesiones, memoria y artefactos. Los agentes de dominio utilizan las mismas interfaces sin necesidad de gestionar sus propios sistemas con estado.

Aunque la centralización sigue requiriendo normas de almacenamiento y ciclo de vida independientes para los datos de sesión, la memoria a largo plazo y los artefactos, Managed Agent Services agrupa esos límites en un único lugar. Cada dominio sigue decidiendo qué información debe guardar y recuperar su experiencia.

Los servicios de agentes gestionados y la arquitectura de memoria se tratan con más detalle en la segunda parte.

Manténgase informado con Actualizaciones

Suscríbase a nuestro blog de ingeniería para estar al día de todos los los proyectos más interesantes en los que trabaja nuestro equipo

Qué cambió con la plataforma

«Reservas» supuso una prueba concreta de la plataforma. El equipo reutilizó la ruta de producción que ya daba servicio a «Restaurante» y «Tienda de comestibles» y puso en marcha la compatibilidad con «Reservas» en una semana, lo que supuso una velocidad aproximadamente 10 veces mayor que la necesaria para crear los agentes de dominio iniciales.

Los equipos de cada ámbito son los responsables del comportamiento de los agentes y de los criterios de calidad. La plataforma proporciona el marco de evaluación, las herramientas MCP, el seguimiento, el acceso a los modelos y los controles de implementación, de modo que las mejoras introducidas en dichos componentes se aplican a todos los agentes que los utilizan.

La infraestructura compartida amplía el alcance de los errores. Un defecto puede afectar a varios agentes, y una abstracción prematura puede obligar a productos diferentes a adoptar el mismo formato. Solo estandarizamos una funcionalidad cuando varios ámbitos la necesitan y las implementaciones independientes podrían generar problemas de fiabilidad u operativos.

Únete a nosotros

Si te interesa desarrollar plataformas de agentes y IA orientada al usuario a gran escala, consulta nuestras ofertas de empleo en ingeniería en careersatdoordash.com.

Cómo creamos una capa de medición que nos indica dónde, por qué y en qué medida podemos confiar en un revisor de código proactivo, y por qué una única métrica nunca podría hacerlo.

En pocas palabras

DoorDash describió recientemente cómo creamos un agente de revisión de código en producción al que los ingenieros realmente prestan atención. Esa publicación abordaba las decisiones sobre el producto y la arquitectura que hay detrás del agente: un «lead scout», revisores en profundidad, contexto específico, un enfoque que prioriza la precisión sobre la recuperación y un diseño independiente del modelo. DashBench es nuestra capa de medición que lo sustenta. DashBench reproduce las solicitudes de incorporación de cambios (PR) históricas y evalúa si los sistemas ofrecen conclusiones reales y aplicables por parte de los humanos, en lugar de limitarse a generar comentarios plausibles. Esa distinción es importante porque indicadores convenientes como la tasa de aceptación, los «me gusta» o una única puntuación agregada pueden hacer que un revisor parezca útil, al tiempo que ocultan sus fallos: pasar por alto problemas importantes, centrarse excesivamente en comentarios fáciles o sacrificar la precisión en favor de la recuperación de resultados, de formas que las métricas del producto no revelan.

El resultado más destacado: en el informe de 105 casos, el revisor de código de producción de DoorDash (Claude Sonnet 4.6 «high scout» + Claude Opus 4.8 «high reviewer») detectó 504 hallazgos reales con una recuperación ponderada del 53,6 %, frente a los 164 hallazgos reales y una recuperación ponderada del 30,7 % de una línea de base sin «scout» con GPT 5.5 «high». La visión más amplia de la combinación de modelos resulta más interesante que un único ganador: la combinación de Kimi K2.6 como «scout» y Claude Fable 5 como «reviewer» lideró la recuperación ponderada y el F1, mientras que la combinación de Composer 2.5 como «scout» y GPT 5.5 «medium» como «reviewer» lideró la precisión ponderada, y las líneas de base de una sola pasada resultaron mucho más económicas.

Figura 1: Compromiso entre precisión y recuperación ponderadas
Figura 2: Compromiso entre el F1 ponderado y el coste.

Nota: Las métricas ponderadas otorgan mayor peso a los problemas de mayor gravedad (crítico = 4, alto = 2, medio = 1, bajo = 0,5).

Por qué las señales evidentes engañan

La forma más tentadora de evaluar a un revisor de código —y la principal métrica que utilizan hoy en día la mayoría de las herramientas de revisión de código— es observar lo que ocurre en producción: ¿aceptan los autores sus comentarios? ¿Actúan en consecuencia? Esa señal es real. Pero se basa en una serie de suposiciones poco sólidas e información incompleta. En el lenguaje de las matrices de confusión, la aceptación solo ocupa dos de las cuatro celdas: un comentario que el autor acepta se registra como un verdadero positivo (TP), y uno que rechaza, como un falso positivo (FP). Ambas clasificaciones dan por sentado que la decisión humana es la verdad fundamental: que los ingenieros son infalibles o, al menos, que se equivocan tan raramente y de forma tan aleatoria que los errores no tienen importancia en conjunto. Como veremos, esa es una apuesta arriesgada. 

Las otras dos celdas permanecen vacías, y ese es el verdadero coste. La aceptación no puede registrar falsos negativos (errores que se le han pasado por alto al revisor) ni verdaderos negativos (código limpio en el que el silencio era la respuesta correcta). Te indica que ha ocurrido algo; no te dice si la revisión fue correcta, si el silencio estaba justificado o qué se ha pasado por alto. DashBench lo gestiona de otra manera: tras la evaluación, los grupos de problemas reales que se han pasado por alto cuentan como falsos negativos a la hora de calcular la puntuación de referencia, aunque la telemetría de aceptación en producción no pueda observarlos.

El otro problema al que se alude más arriba es que la aceptación humana es una señal útil, pero no la verdad absoluta. Los autores aceptan y rechazan comentarios por motivos relacionados con el producto y el flujo de trabajo: el momento, la urgencia de las relaciones públicas, el contexto de responsabilidad, lo invasiva que sea la corrección o si el problema ya se había resuelto de otra manera. Eso convierte la aceptación en una valiosa telemetría del producto, pero en una etiqueta de referencia débil por sí misma. En las auditorías de desacuerdo, tanto la revisión humana como la verificación automática sacaron a la luz errores; el objetivo no era declarar que una de las partes tenía razón, sino diferenciar entre «fue aceptado» y «era real». La métrica más accesible puede seguir apuntando al objetivo equivocado.

Esa es la razón por la que creamos DashBench. Si nos basáramos en una métrica cómoda para desarrollar y mejorar un sistema del que ahora dependen nuestros ingenieros, estaríamos optimizando con total confianza hacia un objetivo que adolece de un fallo fundamental. La solución no es una única métrica mejor. Es un punto de referencia que cruza datos de varias señales imperfectas y nunca se basa en ninguna de ellas como verdad absoluta. 

De una arquitectura de producción a un entorno limpio en el que realizar mediciones

Nuestro revisor de producción utiliza una arquitectura por etapas que separa la detección de la verificación. Un revisor inicial examina el cambio y señala las áreas sospechosas. A continuación, los revisores en profundidad investigan las pistas más sólidas, confirman si cada duda se sostiene y descartan las afirmaciones que no superan el escrutinio. Esto refleja la forma de trabajar de los buenos revisores humanos: se basan en corazonadas, centran su atención en las partes de riesgo de la comparación y, a continuación, validan los resultados antes de pedirle nada al autor.

Ese diseño nos proporciona una superficie de evaluación clara. Dado que el flujo de trabajo es independiente del modelo, cada componente es una variable que podemos mantener fija o modificar por separado: el modelo de exploración, el modelo de revisión, la política de contexto, la política de herramientas y el presupuesto de tiempo de ejecución. Podemos reproducir las mismas solicitudes de incorporación de cambios (PR) congeladas a través del agente de producción, mediante variantes en etapas con diferentes asignaciones de modelos y mediante revisores sencillos de una sola pasada, y lo que se mide permanece constante.

Así pues, la pregunta relevante deja de ser «¿qué modelo es el mejor?». Pasa a ser: para una arquitectura, una política de contexto, una política de herramientas, un presupuesto de tiempo de ejecución y una combinación de modelos determinados, ¿qué equilibrio entre cobertura, precisión, coste y latencia obtenemos realmente, y en qué aspectos falla? El término «mejor» carece de sentido hasta que se especifique «mejor en qué», «en qué casos» y «a qué coste».

Cómo elaboramos el índice de referencia

Figura 3: Proceso de pruebas de rendimiento de DashBench

Lo importante es el bucle, no ninguna casilla en concreto. Los nuevos casos y los cambios de modelo siguen entrando en el mismo ciclo de repetición y puntuación, mientras que la revisión de desacuerdos garantiza la fiabilidad del punto de referencia cuando la retroalimentación humana, el comportamiento en producción y el criterio de los agentes no coinciden. En esa fase, inspeccionamos manualmente las pruebas, decidimos si el hallazgo es real y volvemos a introducir los casos resueltos en la calibración del juez. El juez en sí está basado en un modelo de lenguaje grande (LLM), pero DashBench lo trata como una señal calibrada, no como la verdad fundamental.

Los casos.

DashBench partió de unos 1.000 candidatos de PR sin procesar y se seleccionó para incluir casos que pusieran a prueba diferentes comportamientos de revisión, como diferencias complicadas, historiales de revisión confusos y resultados de gravedad variados. La publicación utiliza el informe válido de 105 casos para analizar los sistemas por etapas frente a los de una sola pasada, las opciones de modelos de explorador/revisor y la calidad ponderada por gravedad en una sección de evaluación coherente.

  • Informes de prensa históricos con conclusiones reales de las revisiones y suficiente contexto para reproducir fielmente el proceso de revisión.
  • Las solicitudes de incorporación de cambios (PR) benignas con resultados reales prácticamente nulos, de modo que el criterio de referencia pueda evaluar la moderación y detectar falsos positivos; un revisor que insista demasiado en el código limpio es, en sí mismo, un factor de fallo.
  • Las solicitudes de incorporación de cambios (PR) que posteriormente se revirtieron o se corrigieron mediante un hotfix, de modo que la prueba de rendimiento pueda comprobar si el sistema detecta regresiones reales a nivel de código antes de la fusión.

Las etiquetas. 

Aquí es donde la mayoría de las pruebas comparativas se saltan un paso que nosotros nos negamos a omitir. La preparación de las etiquetas supuso mucho más que simplemente importar los comentarios de los revisores. Hicimos que los ingenieros que redactaron las solicitudes de incorporación de cambios (PR) anotaran los hallazgos candidatos y, a continuación, comparamos tres fuentes entre sí: las anotaciones humanas, los hallazgos candidatos originales y un juez autónomo. Los comentarios humanos eran valiosos, pero a menudo erróneos: los revisores pasaban por alto problemas válidos, aceptaban afirmaciones poco sólidas o interpretaban el contexto de una solicitud de incorporación de cambios anterior de forma diferente a como lo haría el siguiente revisor. Cuando las tres fuentes discrepaban, volvíamos a revisar las pruebas manualmente y resolvíamos el caso, y esos casos resueltos se convertían en datos de calibración para el juez.

El resultado es un punto de referencia cuya verdad de referencia no se basa en una única fuente falible. El juicio humano, la retroalimentación de la producción y la evaluación por parte de los agentes contribuyen por igual; ninguno de ellos se considera infalible. 

El entorno de ejecución. 

En el marco de una comparación, cada configuración se ejecuta con el mismo conjunto de casos congelados, la misma pista de contexto, la misma selección de indicaciones y paquetes de habilidades, el mismo contrato de salida normalizado y el mismo proceso de evaluación. El entorno de pruebas forma parte de lo que estamos midiendo: los perfiles difieren en el tipo de ejecutor, los modelos de explorador/revisor, la interfaz de la herramienta, la mecánica del contexto y los límites del proveedor. Algunos se ejecutan desde un repositorio preparado con herramientas de tipo «read/grep», otros reciben un contexto de repositorio delimitado en la indicación, y otros desactivan los pasos de búsqueda o evaluación en la ejecución de revisión. El coste, la latencia, los tiempos de espera, los reintentos y los fallos se registran en los artefactos de la ejecución y en los resúmenes de la suite, en lugar de tratarse como constantes controladas. La clave es la repetibilidad: cuando una cifra varía, queremos saber si ha variado porque el modelo o el entorno de pruebas han cambiado, y no porque la evaluación se haya desviado.

El informe: lo que realmente muestra DashBench

Utilizamos DashBench para responder a cuatro preguntas que la telemetría de producción por sí sola no puede resolver. En primer lugar, ¿la organización por etapas realmente mejora la cobertura? En segundo lugar, ¿qué opciones de modelos de exploradores/revisores modifican la frontera entre coste, precisión y recuperación? En tercer lugar, ¿se mantienen las clasificaciones generales cuando desglosamos los resultados por gravedad? En cuarto lugar, ¿en qué casos las configuraciones por etapas de exploradores/revisores superan a los revisores de una sola pasada más potentes, y qué sacrifican para lograrlo?

Ventajas de la puesta en escena

La simulación garantiza la cobertura, y el precio es visible. En el informe de 105 casos, el revisor de código de producción de DoorDash (Claude Sonnet 4.6 «high scout» + Claude Opus 4.8 «high reviewer») detectó 504 hallazgos reales con una recuperación ponderada del 53,6 %, en comparación con los 164 hallazgos reales y una recuperación ponderada del 30,7 % de la línea de base GPT 5.5 «high» sin «scout». La precisión ponderada se mantuvo en niveles similares, un 87,0 % frente a un 84,1 %, pero el revisor de producción supuso un mayor coste por PR y tardó más tiempo. Ese es exactamente el tipo de resultado que queremos que DashBench ponga de manifiesto: no un trofeo, sino una compensación cuantificada.

SistemaConclusiones realesPrecisión ponderadaRecuperación ponderadaCoste / Relaciones públicas
Revisor de código de producción en DoorDash50487.0%53.6%$3.91
Sin scout + GPT 5,5 (revisor de alto nivel)16484.1%30.7%$0.75
Sin explorador + Claude Opus 4,8 (crítico destacado)11589.8%20.2%$0.65

Elección del modelo de explorador/revisor

La comparación de combinaciones de modelos es donde el punto de referencia resulta más útil: intercambiamos qué modelo actúa como explorador y cuál como revisor, manteniendo fijo el punto de referencia. Ninguna configuración destaca en todos los ejes. La combinación de Kimi K2.6 como explorador y Claude Fable 5 como revisor obtuvo la mayor precisión ponderada y el mayor F1 en el subconjunto válido de 105 casos, con un 65,2 % de precisión ponderada y un 75,3 % de F1 ponderado. La combinación de Composer 2.5 como explorador y GPT 5.5 medium como revisor obtuvo la precisión ponderada más alta, con un 92,2 %, pero con un recall considerablemente inferior. Las líneas de base sin explorador resultaron más económicas, mientras que la combinación de Kimi K2.6 como explorador y Claude Opus 4.8 high como revisor constituyó una alternativa por etapas de menor coste, aunque con un recall considerablemente inferior.

ConfiguraciónConclusiones realesPrecisión ponderadaRecuperación ponderadaF1 ponderadoCoste / Relaciones públicas
Kimi K2.6, explorador + Claude Fable 5, crítico53789.2%65.2%75.3%$3.81
Claude Sonnet 4.6: explorador destacado + Claude Opus 4.8: crítico destacado50487.0%53.6%66.3%$3.91
Kimi K2.6, explorador + Claude Opus 4.8, crítico destacado39682.3%45.8%58.9%$2.35
Claude Sonnet 5: explorador de alto nivel + Claude Sonnet 5: revisor de alto nivel32177.3%40.1%52.8%$6.55
Claude Sonnet 5: explorador de alto nivel + Claude Opus 4.8: crítico de alto nivel22680.8%32.9%46.8%$5.06
GPT 5.5 «scout» de nivel medio + GPT 5.5 «revisor» de nivel alto27691.5%19.9%32.6%$5.95
Composer 2.5 scout + GPT 5.5 revisor de nivel alto26791.1%19.6%32.2%$4.68
Composer 2.5 (scout) + GPT 5.5 (revisor medio)24692.2%18.0%30.1%$3.53
Sin scout + GPT 5,5 (revisor de alto nivel)16484.1%30.7%45.0%$0.75
Sin explorador + Claude Opus 4,8 (crítico destacado)11589.8%20.2%33.0%$0.65

Repercusión de la gravedad de los hallazgos en la evaluación

La gravedad vuelve a cambiar el panorama. En el subconjunto válido de 105 casos, el conjunto de hallazgos reales evaluados contiene 40 clústeres críticos, 136 de gravedad alta, 271 de gravedad media y 385 de gravedad baja. La combinación de Kimi K2.6 como explorador y Claude Fable 5 como revisor fue la más eficaz en la cobertura de los casos críticos, de gravedad alta y media, mientras que la combinación de Claude Sonnet 4.6 como explorador y Claude Opus 4.8 como revisor cubrió ligeramente más la cola de gravedad baja. La fila «GPT 5.5 high» sin «scout» resultaba económica y seguía siendo útil en problemas de alta gravedad, pero era más débil en cuanto a la cobertura general. Por eso existe la puntuación ponderada: otorga más peso a los errores críticos y de alta gravedad que a los de baja gravedad, al tiempo que nos permite examinar la distribución completa de la gravedad.

Figura 4: Recuperación según la gravedad.

La vista de gravedad muestra por qué una sola puntuación no es suficiente: las configuraciones que, en general, parecen muy similares, pueden presentar problemas de naturaleza muy diferente.

Influencia de la calidad y el tamaño del modelo en los resultados de las pruebas comparativas

Los datos de la combinación de modelos lo confirman con cifras: la combinación de Kimi K2.6 (scout) + Claude Fable 5 (revisor) lidera la recuperación ponderada y el F1; la combinación de Composer 2.5 (scout) + GPT 5.5 (revisor medio) lidera la precisión ponderada; y las líneas de base de una sola pasada sin scout siguen siendo más económicas, aunque a costa de perder cobertura. Una configuración específica no convierte mágicamente a un modelo más débil en el mejor en todo; lo que hace es modificar la naturaleza de la disyuntiva. Los «scouts» mejoran la amplitud cuando el «reviewer» puede verificar de forma exhaustiva. Las configuraciones más estrictas del «reviewer» mejoran la precisión cuando el objetivo empresarial es reducir el ruido. Las líneas de base de una sola pasada sin «scout» constituyen un punto de partida útil y de menor coste, pero dejan de lado parte de la cobertura. El resultado no es que un modelo salga ganador. El resultado es que ninguna configuración concreta domina, y poder afirmar precisamente eso es lo importante.

Lecciones extraídas del análisis comparativo de la evaluación de las relaciones públicas

La confianza hay que ganársela. Ninguna señal por sí sola es una fuente fiable de verdad para las evaluaciones comparativas en el mundo real. Las etiquetas humanas, la aceptación en producción y el juicio autónomo contribuyeron cada uno a su manera, y cada uno se equivocó con la suficiente frecuencia como para que considerar cualquiera de ellos como «verdad absoluta» hubiera viciado silenciosamente las puntuaciones. La calidad de la evaluación comparativa radica precisamente en su negativa a confiar únicamente en cualquier dato falible.

Los seres humanos no son escalables. La capacidad de atención humana para el etiquetado se deteriora rápidamente en tareas complejas, y aún más rápido al realizar muchas de ellas, incluso cuando quien realiza el etiquetado es el mismo ingeniero que redactó o revisó la solicitud de incorporación de cambios original. El análisis mediante IA es lo que hace que el etiquetado a esta escala sea factible, pero solo bajo las restricciones que se explicarán en las dos próximas lecciones.

La varianza es una característica, no un error. Los LLM son no deterministas, por lo que varias ejecuciones del mismo agente revelan resultados válidos adicionales, lo que significa que una sola ejecución subestima la cobertura real del agente, y hay que ejecutarlo repetidamente y agregar los resultados para evaluarlo con precisión. La misma estocasticidad se aplica al evaluador: la correspondencia determinista es estable, pero pasa por alto la equivalencia semántica, mientras que los evaluadores basados en LLM razonan de forma más rica, pero necesitan calibración, conjuntos de auditoría y rúbricas estables para seguir siendo fiables. Todo el proceso de medición es estocástico; la tarea consiste en diseñarlo teniendo esto en cuenta, en lugar de fingir que no existe.

Cuando un único indicador no funciona, hay que recurrir a varios. Una puntuación única es, por definición, engañosa. La precisión ponderada, la recuperación ponderada, el F1 ponderado, los resultados no reales, la recuperación alta o crítica, la latencia y el coste varían de forma independiente; un sistema puede destacar en un aspecto y fallar en otro en la misma ejecución, por lo que decir que es «mejor» no tiene sentido hasta que se especifique en qué sentido.

Manténgase informado con Actualizaciones

Suscríbase a nuestro blog de ingeniería para estar al día de todos los los proyectos más interesantes en los que trabaja nuestro equipo

Próximos pasos

DashBench existe para que podamos seguir mejorando el revisor basándonos en datos, en lugar de en anécdotas. El objetivo nunca ha sido crear una clasificación estática, sino un ciclo de retroalimentación en el que cada cambio significativo en el modelo, la indicación, el contexto, el uso de herramientas, el flujo de trabajo o el presupuesto de tiempo de ejecución se pruebe con los mismos casos reales de revisión de PR antes de que llegue a manos de un ingeniero.

La siguiente etapa consiste en una evaluación comparativa continua:

  • Los nuevos modelos y conjuntos de pruebas se incorporan rápidamente al índice de referencia a medida que se lanzan al mercado, incluidos los conjuntos de pruebas de agentes adicionales que hemos previsto para esta fase.
  • Los casos de relaciones públicas obsoletos se eliminan del conjunto de datos, mientras que se añaden nuevos casos de forma continua, por lo que el punto de referencia sigue la evolución del código en lugar de alejarse de él.
  • Estamos pasando de un único juez a un jurado autónomo, con el fin de mitigar los sesgos entre los distintos modelos de juez.
  • Estamos comparando nuestras soluciones con otras soluciones externas de revisión de código, no solo con variantes internas.

Y estamos empezando a evaluar el rendimiento de los agentes de programación —no solo de los revisores— en un código fuente empresarial real, con tareas y funcionalidades reales. Más adelante hablaremos de ello.

El resumen sincero es el siguiente: conseguir que un sistema de IA sea útil es solo la mitad del trabajo. Lo más difícil es saber dónde falla, por qué falla y si el siguiente cambio lo ha mejorado o simplemente lo ha modificado. La mayor parte del sector sigue midiendo la unidad equivocada con la cifra equivocada. DashBench es nuestro intento de medir el trabajo que realmente importa: resultados reales, en PR reales, dejando a la vista las compensaciones. Si ese es el tipo de problema en el que te gustaría trabajar, nos gustaría hablar contigo.


Apéndice

Espacio para incluir detalles que respalden la publicación sin ralentizar el texto. La sección «Informe» mantiene al lector al tanto de las ventajas e inconvenientes; esta sección conserva el registro de auditoría.

A. Entorno de ejecución (especificaciones completas). En una comparación, cada configuración se ejecuta sobre el mismo fragmento del conjunto de datos y genera el mismo contrato de resultados estructurado: gravedad, evidencia y referencias de archivo. El propio entorno de pruebas forma parte de lo que mide DashBench, por lo que los perfiles pueden diferir en cuanto al tipo de ejecutor, la distribución entre explorador y revisor, la elección del modelo, la interfaz de la herramienta, la mecánica del contexto y los límites del proveedor. A continuación, la puntuación utiliza la misma ruta de correspondencia para esa comparación, con una correspondencia determinista siempre que sea posible y una evaluación discrecional cuando se requiera una correspondencia semántica. El objetivo no es eliminar las diferencias entre los sistemas, sino hacer que dichas diferencias sean lo suficientemente explícitas como para que el coste, la latencia y la calidad varíen por razones interpretables.

B. Tamaños del conjunto de datos y del conjunto de evaluación. DashBench partió de unos 1.000 candidatos a PR sin procesar, para luego reducir la selección a los casos que podían reproducirse y evaluarse. La publicación utiliza el informe válido de 105 casos para el análisis principal de la combinación de modelos y el análisis de «pasos por etapas» frente al de «paso único». El denominador de gravedad en esa selección de 105 casos es la unión de los grupos de hallazgos reales: 40 críticos, 136 altos, 271 medios y 385 bajos. Se trata de grupos de hallazgos, no de recuentos de PR; un PR puede contribuir a más de un grupo.

C. Métricas completas de configuración. En el cuerpo se muestra la versión reducida, ya que es la más legible. Las métricas completas se incluyen a continuación con fines de auditoría, divididas para que quepan en la página.

MétricaRevisor de código de producción en DoorDashSin scout + GPT 5,5 (revisor de alto nivel)
ConfiguraciónClaude Sonnet 4.6: explorador destacado + Claude Opus 4.8: crítico destacadoUn único revisor
Resultados sin procesar611200
Conclusiones reales504164
Precisión ponderada87.0%84.1%
Recuperación ponderada53.6%30.7%
F1 ponderado66.3%45.0%
Nivel de recuperación alto/crítico52.8%51.7%
Coste / Relaciones públicas$3.91$0.75
Coste / resultado real$0.82$0.48
Revisar la latencia / PR725.0s170.3s
AdvertenciaMayor coste y latencia, pero mayor coberturaMenor coste y latencia, pero una tasa de recuperación global mucho menor

ConfiguraciónResultadosCalidadCoste / latencia
Kimi K2.6, explorador + Claude Fable 5, crítico669 sin procesar
537 reales
132 no reales
89,2 % de precisión
65,2 % de recuperación
75,3 % de F1
3,81 $ / PR
0,75 $ / real
589,3 s / PR
Mejor recuperación ponderada/F1
Claude Sonnet 4.6: explorador destacado + Claude Opus 4.8: crítico destacado611 sin procesar
504 real
107 no real
87,0 % de precisión
53,6 % de recuperación
66,3 % de F1
3,91 $ / PR
0,82 $ / real
725,0 s / PR
Kimi K2.6, explorador + Claude Opus 4.8, crítico destacado574 sin procesar
396 reales
178 no reales
82,3 % de precisión
45,8 % de recuperación
58,9 % de F1
2,35 $ / PR
0,62 $ / real
263,9 s / PR
La configuración por etapas más rápida registrada
Claude Sonnet 5: explorador de alto nivel + Claude Sonnet 5: revisor de alto nivel509 sin procesar
321 reales
187 no reales
1 indeterminado
77,3 % de precisión
40,1 % de recuperación
52,8 % de F1
6,55 $ / PR
2,14 $ / real
657,9 s / PR
Claude Sonnet 5: explorador de alto nivel + Claude Opus 4.8: crítico de alto nivel327 sin procesar
226 reales
100 no reales
1 indeterminado
80,8 % de precisión
32,9 % de recuperación
46,8 % de F1
5,06 $ / PR
2,35 $ / real
565,3 s / PR
GPT 5.5 «scout» de nivel medio + GPT 5.5 «revisor» de nivel alto332 sin procesar
276 reales
56 no reales
91,5 % de precisión
19,9 % de recuperación
32,6 % de F1
5,95 $ / PR
2,26 $ / real
619,5 s / PR
Composer 2.5 scout + GPT 5.5 revisor de nivel alto324 sin procesar
267 reales
57 no reales
91,1 % de precisión
19,6 % de recuperación
32,2 % de F1
4,68 $ / PR
1,84 $ / real
539,2 s / PR
Composer 2.5 (scout) + GPT 5.5 (revisor medio)285 sin procesar
246 reales
39 no reales
92,2 % de precisión
18,0 % de recuperación
30,1 % de F1
3,53 $ / PR
1,50 $ / real
429,4 s / PR
La mejor precisión ponderada
Sin scout + GPT 5,5 (revisor de alto nivel)200 sin procesar
164 reales
36 no reales
84,1 % de precisión
30,7 % de recuperación
45,0 % de F1
0,75 $ / PR
0,48 $ / real
170,3 s / PR
Sin explorador + Claude Opus 4,8 (crítico destacado)134 sin procesar
115 reales
19 no reales
89,8 % de precisión
20,2 % de recuperación
33,0 % de F1
0,65 $ / PR
0,60 $ / real
112,8 s / PR

D. Desglose por gravedad (completo). La vista de gravedad es la razón más clara por la que existe la métrica principal ponderada. Los fallos críticos y de gravedad alta no son intercambiables con los de gravedad baja, y las configuraciones varían según el nivel.

Retirada del mercado según el grado de gravedad

GravedadConjuntos reales de unionesKimi K2.6 + Fable 5Sonnet 4.6 alto + Opus 4.8 altoKimi K2.6 + Opus 4.8 altoGPT 5.5 alto
Crítico4080.0%62.5%72.5%37.5%
Alto13677.9%50.0%46.3%55.9%
Medio27156.8%53.5%43.2%20.3%
Bajo38546.8%51.4%26.8%4.2%

Precisión según el grado de gravedad

GravedadKimi K2.6 + Fable 5Sonnet 4.6 alto + Opus 4.8 altoKimi K2.6+ Opus 4.8 altoGPT 5.5 alto
Crítico100.0%100.0%100.0%n/a
Alto96.0%95.6%94.9%86.9%
Medio94.2%87.8%86.8%80.9%
Bajo65.3%76.8%49.7%70.4%

Las intenciones de las tareas son de varias etiquetas, por lo que la suma de los recuentos supera los 105.

Propósitos de las tareas

Objetivo de la tareaRecuentoPorcentaje de casos
pruebas9085.7%
config_build8581.0%
característica4139.0%
api_schema3331.4%
docs_kb2019.0%
herramientas_de_dependencias1918.1%
corrección de errores1817.1%
modelo_de_datos1514.3%
refactor_cleanup1514.3%
ui109.5%
rollout_guard98.6%
seguridad_privacidad87.6%
observabilidad76.7%
rendimiento65.7%
cambio_de_comportamiento11.0%

Cambiar el tamaño de la nota de prensa

Clase de tamaño PRRecuentoPorcentaje de casos
grande3634.3%
medio3634.3%
pequeño3331.4%

Verificabilidad

VerificabilidadRecuentoPorcentaje de casos
medio5451.4%
negrita3836.2%
débil1312.4%

Ámbitos de productos

Se muestran los 20 dominios principales.

Ámbito del productoRecuentoPorcentaje de casos
consumer_feed1817.1%
suministros_de_campaña65.7%
logística_mano de obra54.8%
carrito_de_pedidos54.8%
support_support_funnel43.8%
riesgo_de_fraude_básico32.9%
logística_gestión de pedidos32.9%
money_payin32.9%
contenido_de_descubrimiento_para_consumidores21.9%
Helios21.9%
merchant_mdh21.9%
pedidos_de_comerciantes21.9%
asistencia_a_comerciantes21.9%
servicio_de_gestión_de_usuarios_comerciales21.9%
platform_pretzel21.9%
público21.9%
repo_config21.9%
soporte_automatización_agente_IA21.9%
voz_de_apoyo21.9%
herramientas21.9%

Impacto

Las etiquetas de impacto son etiquetas múltiples, por lo que el total supera las 105.

ImpactoRecuentoPorcentaje de casos
de atención al cliente3432.4%
operaciones_comerciales3331.4%
fiabilidad_de_las_infraestructuras3028.6%
logística2221.0%
integridad de los datos1817.1%
conocimientos_de_desarrollo1615.2%
desconocido1615.2%
calidad_de_la_prueba98.6%
seguridad_privacidad87.6%
dinero76.7%

DoorDash presta servicio a un amplio y variado conjunto de comercios, en el que cada restaurante, menú y plato se presenta de una forma única. Un catálogo gastronómico de alta calidad constituye la columna vertebral de las búsquedas de los clientes y de la experiencia de personalización, lo que representa un factor clave para el éxito de los restaurantes. A diferencia de los catálogos estandarizados, la gastronomía es profundamente contextual, rica en cultura y muy poco estandarizada; un mismo plato puede describirse de innumerables formas, mientras que platos totalmente diferentes pueden compartir nombres, descripciones o imágenes similares.  A esto hay que añadir que, dada la envergadura de DoorDash, existen millones de artículos únicos y actualizaciones constantes de los menús. Esta variabilidad y este volumen hacen que resulte extremadamente complicado generar metadatos fiables mediante los enfoques tradicionales. 

Para abordar este problema, hemos creado una plataforma de metadatos para restaurantes basada en la inteligencia artificial. Nuestra plataforma deduce atributos a nivel de plato y de local —por ejemplo, si un plato es picante o si la cocina de un restaurante es china— utilizando señales multimodales procedentes de textos, imágenes y búsquedas generales en la web. Para generar metadatos fiables y precisos a gran escala, hemos incorporado varias innovaciones clave en el complejo sistema de DoorDash, entre las que se incluyen: 

  • Un sistema de evaluación basado en un modelo de lenguaje a gran escala (LLM) que permite realizar evaluaciones de alta calidad y que ha aumentado la precisión de la anotación en aproximadamente un 20 % en comparación con los revisores humanos habituales.
  • Agentes de optimización contextual para mejorar de forma iterativa las indicaciones en cuestión de minutos, lo que aumenta la precisión del modelo en más de un 20 % y evita la ineficiencia de las indicaciones creadas manualmente y subóptimas. Este ciclo multiplicó por diez la velocidad de desarrollo de las indicaciones.
  • La computación distribuida permite realizar inferencias en modelos de lenguaje a gran escala (LLM) con un gran volumen de datos, reduciendo el tiempo de rellenado de más de un mes a solo unos días, lo que hace que sea viable desde el punto de vista operativo generar millones de elementos.
  • Anotación basada en IA para generar datos de entrenamiento, lo que permitió el ajuste fino para alcanzar la calidad de los modelos de lenguaje a gran escala (LLM) de vanguardia con un 10 % del coste de inferencia y sin ningún esfuerzo de anotación por parte de los humanos.

Esta plataforma de metadatos nos permite implementar con éxito la IA generativa de forma fiable y rentable a gran escala, mejorando nuestro flujo de trabajo de ingeniería y la experiencia del usuario de DoorDash. 

Descripción general del proceso a alto nivel

Como se muestra en la figura 1, nuestro proceso comienza con la importación de las actualizaciones de los menús y la deduplicación para minimizar los costes de inferencia. Introducimos estos elementos en generadores de IA para producir metadatos, que se someten a una validación estructural inmediata para la detección de errores y la realización de nuevos intentos. Supervisamos continuamente la calidad de las predicciones generadas mediante un «jurado» de modelos de lenguaje grande (LLM); el resultado de la evaluación también se utiliza para la ingeniería de contexto con el fin de mejorar la calidad de la generación. Además, ofrecemos un mecanismo de anulación por parte del comerciante que permite a los propietarios de los negocios validar o corregir los atributos.

Figura 1: Esta visión general del flujo de generación de metadatos de comida de DoorDash incluye las actualizaciones de los menús y la deduplicación mediante la generación con IA, la evaluación y las modificaciones realizadas por los comerciantes.

Innovaciones técnicas

Los procesos tradicionales de recopilación de datos, etiquetado, entrenamiento y evaluación son excesivamente lentos y costosos, lo que dificulta la generación y extracción de metadatos de alta calidad a la escala que requiere DoorDash. Para solucionar este problema, hemos desarrollado un sistema que utiliza tanto modelos de lenguaje multimodales como modelos de lenguaje pequeños (SLM) entrenados, con el fin de lograr una generación de alta calidad y baja latencia a un coste razonable. Nuestro sistema «LLM Jury», cuidadosamente diseñado, permite realizar evaluaciones fiables a gran escala, optimizar continuamente el contexto a partir de señales de fallo reales y generar de forma automatizada datos etiquetados de alta calidad para acelerar la mejora de los modelos y el entrenamiento interno.

Evaluaciones eficientes y de alta calidad con jurados de LLM

Validar las etiquetas generadas mediante el etiquetado humano resulta poco práctico en la producción a gran escala. Solo un reducido grupo de expertos en la materia puede aplicar etiquetas de forma que se ajusten a cómo los clientes toman realmente sus decisiones de pedido, y son aún menos los expertos que comprenden de forma fiable los matices entre las distintas cocinas y el lenguaje de los menús —por ejemplo, distinguir entre platos nepalíes y del norte de la India, o interpretar si «al estilo de Sichuan» implica un perfil de picante—. Como resultado, ampliar la validación humana para abarcar millones de elementos resulta prohibitivamente caro y poco viable desde el punto de vista operativo; la evaluación tradicional simplemente no funciona para la generación continua de metadatos a gran escala.

Nuestro sistema automatizado de evaluación de consensos basado en modelos de lenguaje grande (LLM) —los «jurados LLM»— sustituye a la validación humana, que resulta lenta, costosa e inconsistente. Tal y como se muestra en la figura 2, incluye los siguientes pasos:

  • Evaluación consensuada de modelos de lenguaje grandes (LLM): varios evaluadores expertos en LLM valoran de forma independiente cada etiqueta propuesta, en lugar de basarse en un único modelo o en un evaluador humano.
  • Votación y agregación: cada evaluador emite un veredicto y expone los motivos; los votos se agregan para llegar a una única decisión consensuada.
  • Verificación a nivel de etiqueta: los evaluadores validan cada etiqueta por separado —por ejemplo, «proteína», «preparación» o «salud»—, en lugar de evaluar el elemento en su conjunto. Las etiquetas verificadas se guardan y se utilizan en la base de datos.

Figura 2: El sistema de evaluación del jurado de LLM utiliza varios evaluadores de LLM de gran capacidad para valorar de forma independiente las etiquetas propuestas. Agregamos los votos y verificamos las etiquetas una por una.

Descubrimos que las etiquetas consensuadas de los modelos de lenguaje grande (LLM) eran aproximadamente un 20 % más precisas que las etiquetas típicas anotadas por personas. El éxito de nuestro marco de evaluación automatizado fue fundamental para automatizar todo el sistema de generación de metadatos.

Optimización automática del contexto inspirada en el aprendizaje por refuerzo 

Nuestro sistema utiliza modelos de lenguaje de visión para mejorar la calidad y la eficiencia en la generación de metadatos de alimentos. Aunque puede resultar sencillo proporcionar contexto a una indicación para generar algunas etiquetas, generar etiquetas de gran precisión a gran escala es mucho más difícil y no se puede lograr con una sola indicación. Incluso con ingenieros altamente cualificados, la ingeniería de contexto manual es lenta, frágil e impredecible. Pequeños cambios en la redacción que a los humanos nos parecen equivalentes pueden dar lugar a un comportamiento muy diferente del modelo, y gestionar los casos extremos requiere un proceso repetitivo de ensayo y error. A medida que surgen nuevos patrones de elementos y casos extremos, mantener la calidad de las indicaciones se convierte en un esfuerzo manual continuo e imposible de escalar.

Figura 3: El bucle de optimización contextual utiliza señales de fallo procedentes de conjuntos de datos de evaluación de alta calidad para proponer y probar cambios en las indicaciones, mejorando de forma iterativa la calidad del modelo.

Inspirándonos en el aprendizaje por refuerzo, desarrollamos un bucle autónomo, que se muestra en la figura 3, que permitió multiplicar por diez la velocidad de desarrollo del contexto de las indicaciones. Definimos la recompensa de la tarea utilizando el rendimiento del modelo en un conjunto de datos de evaluación de alta calidad. Un agente de ajuste identifica en qué aspectos el prompt actual no rinde lo suficiente y utiliza estas señales de fallo para proponer un contexto mejor para el modelo. En cada paso, se generan métricas utilizando un conjunto de datos de evaluación de alta calidad. Estas actúan como nuestras barreras de seguridad, garantizando que el sistema mejore siempre la precisión y la recuperación globales. Optimizamos el propio prompt, en lugar de actualizar los pesos del modelo, lo que hace que el bucle sea mucho más rápido y económico de ejecutar.

Hemos optado por este enfoque basado en señales de fallo en lugar de los métodos evolutivos basados en poblaciones, como el algoritmo GEPA, que mantienen una población de prompts candidatos y se basan en operadores de mutación y cruce para explorar el espacio de prompts. En lugar de puntuar a ciegas numerosas variantes de prompts por generación, nuestro agente lee directamente los casos de fallo y propone cambios específicos en las reglas. Esto hace que cada iteración tenga un propósito concreto, en lugar de ser probabilística, y requiere menos rondas de evaluación, sin necesidad de hiperparámetros de población que requieran ajuste.

Algunas lecciones importantes que nos gustaría compartir:

  • La calidad de los datos es fundamental para esta tarea: el conjunto de datos de evaluación utilizado para puntuar las propuestas de prompts determina directamente la dirección de la optimización. Los ejemplos de baja calidad o mal etiquetados hacen que el agente se fije en el ruido en lugar de en la señal real, lo que da lugar a prompts de menor calidad o inestables.
  • Los casos de fallo aportan más información que los de éxito: a lo largo del desarrollo, probamos diferentes combinaciones de casos de fallo y de éxito. Descubrimos que dar mayor peso a los casos de fallo era lo que mejor funcionaba para nuestro caso de uso.
  • Optimización de los «prompts» frente a optimización de los pesos del modelo: la optimización de los «prompts» sigue la misma dinámica de convergencia que el entrenamiento del modelo; una IA puede completar en unas horas lo que a un ser humano le llevaría días o semanas. 

Este enfoque convierte la ingeniería de contexto de una tarea puntual y dependiente del factor humano en un proceso de optimización escalable y cuantificable que se adapta a la evolución de los datos y los casos de uso. Observamos que la precisión en nuestros casos aumentó más de un 20 % en un conjunto de datos de evaluación independiente.

Anotación de datos basada en la inteligencia artificial para acelerar la recopilación de datos de entrenamiento

La generación de metadatos a la escala de DoorDash exige tanto precisión como eficiencia. Los modelos de lenguaje grande (LLM) disponibles en el mercado suelen ser imprecisos o tener un coste prohibitivo; por ello, parte de nuestro sistema de IA se basa en modelos altamente especializados y ajustados. Sin embargo, el entrenamiento de dichos modelos requiere la anotación de miles de etiquetas en miles de millones de entidades del catálogo, lo que convierte el etiquetado de datos en una de las mayores limitaciones del ciclo de desarrollo. En un flujo de trabajo tradicional, la generación de ese volumen de datos de entrenamiento y evaluación depende en gran medida de la anotación humana, lo que hace que la iteración de los modelos sea lenta, costosa y difícil de escalar.

Figura 4: Nuestro sistema de anotación basado en inteligencia artificial utiliza agentes específicos de generación y evaluación para crear y validar de forma eficiente etiquetas de alta calidad destinadas al entrenamiento de modelos especializados y ajustados con precisión.

Para solucionar este problema, hemos desarrollado un sistema de anotación de datos basado en IA, que se muestra en la figura 4, capaz de generar y validar etiquetas de alta calidad. Hemos creado un conjunto similar de agentes de optimización automática del contexto, generación y evaluación, diseñados específicamente para las tareas de etiquetado. Nuestros modelos, pequeños y ajustados con precisión, redujeron los costes de inferencia en aproximadamente un 90 % en comparación con los modelos de lenguaje a gran escala (LLM), al tiempo que alcanzaron un rendimiento equivalente.

Optimización de la inferencia a gran escala en modelos LLM

Dada la envergadura de DoorDash, los millones de artículos únicos del menú, los miles de millones de opciones de menú y los cientos de miles de actualizaciones diarias requieren una actualización continua de los metadatos. Recurrir a llamadas a la API sincrónicas, artículo por artículo, para realizar una recuperación completa de datos llevaría semanas, lo que haría inviables las actualizaciones diarias y, además, aumentaría los costes de infraestructura y de los modelos. 

Figura 5: Nuestro flujo de trabajo distribuido de inferencia de modelos de lenguaje a gran escala (LLM) utiliza la deduplicación, la distribución mediante Spark, el procesamiento por lotes y la reasignación de resultados para transformar la generación a gran escala, que antes suponía un cuello de botella que ralentizaba el proceso, en un proceso eficiente y de alto rendimiento.

Para hacer frente a estos retos, hemos diseñado un proceso distribuido de inferencia de modelos de lenguaje grande (LLM), tal y como se muestra en la figura 5, con el fin de eliminar la computación redundante y maximizar el rendimiento. Nuestro enfoque se basa en cuatro mecanismos clave:

  • Eliminación de duplicados: Muchos comerciantes comparten nombres y descripciones idénticos de artículos; un procesamiento sin filtrar enviaría repetidamente datos idénticos al modelo. Eliminamos los duplicados mediante coincidencias exactas de características, evitando llamadas redundantes al modelo.
  • Distribución en Spark: Dividimos los datos únicos restantes en fragmentos y los distribuimos entre un clúster de nodos de trabajo de Spark para su procesamiento en paralelo.
  • Procesamiento por lotes: Aprovechamos las API de modelos de lenguaje grande (LLM) por lotes para enviar cargas útiles agrupadas al modelo, lo que maximiza el rendimiento y la rentabilidad. En el caso de los modelos entrenados, fragmentamos los datos, lo que nos permite volver a ejecutar el proceso en múltiples GPU.
  • Reasignación de resultados: Tras el procesamiento, reasignamos los resultados del modelo a las entidades originales para preservar la integridad de los datos.

En conjunto, estas optimizaciones transforman la generación de metadatos a gran escala, que antes era un cuello de botella lento y costoso, en un proceso altamente eficiente, escalable y rentable, reduciendo el tiempo necesario para completar los datos históricos de más de un mes a tan solo unos días.

Impulsando una mejor experiencia del cliente 

Nuestros metadatos constituyen la base de numerosas aplicaciones posteriores en toda la plataforma DoorDash. Al transformar el texto no estructurado de los menús en atributos precisos y estructurados, abrimos la puerta a muchas nuevas posibilidades, entre las que se incluyen mejorar la búsqueda y el descubrimiento por parte de los clientes, permitir el filtrado de platos relevantes, la personalización y la generación de métricas para el análisis, tal y como se muestra en la figura 6:

Figura 6: Los metadatos estructurados constituyen la base de las aplicaciones posteriores de DoorDash, lo que permite la personalización para los clientes, el filtrado y una búsqueda mejorada.

Conclusión

La plataforma de metadatos basada en IA supone un cambio fundamental en la forma en que DoorDash entiende los productos y los establecimientos de su plataforma. Gracias a la IA, hemos desarrollado una comprensión semántica profunda de cada producto y establecimiento, transformando datos de entrada inconsistentes y no estructurados en atributos ricos, precisos y estructurados. Al combinar un proceso de generación de datos distribuido a gran escala con una evaluación automatizada rigurosa y medidas de seguridad que incluyen la intervención humana, hemos demostrado que la IA generativa puede implementarse de forma fiable y rentable en entornos de producción de gran volumen. La infraestructura de metadatos resultante no solo impulsa las funciones actuales de búsqueda y descubrimiento, sino que establece una base de datos sólida y de alta calidad que dará paso a la próxima generación de experiencias personalizadas tanto para los comerciantes como para los consumidores.

Tras nuestra anterior descripción técnica sobre Ask DoorDash, esta tercera entrada de la serie del blog analiza en profundidad el marco de evaluación que sustenta el sistema. Próximamente publicaremos análisis en profundidad sobre la plataforma y la experiencia de usuario.


Introducción

Crear un agente de IA útil resulta complicado cuando la calidad solo se puede apreciar a través de informes dispersos y comprobaciones manuales. Ese era el problema al que nos enfrentábamos con Ask DoorDash, nuestra experiencia de pedidos mediante agente lanzada recientemente. En la fase inicial de desarrollo, la evaluación se basaba principalmente en los comentarios de los empleados y en pruebas manuales. Esas señales resultaban útiles, pero eran escasas y se centraban en los escenarios que ya sabíamos que debíamos tener en cuenta.

Creamos un sistema de evaluación para poder medir la calidad de los agentes a gran escala. La señal de calidad pasó de una media de un comentario enviado por un empleado a 2.000 sesiones calificadas automáticamente al día. Esa señal más amplia nos ayudó a detectar antes los fallos de los agentes que minaban la confianza y a dar prioridad a los modos de fallo recurrentes; gracias a ello, logramos una mejora de 8 puntos en las puntuaciones de calidad de los agentes antes del lanzamiento a nivel nacional, reduciendo las tasas de error casi a la mitad y cumpliendo nuestro objetivo de lanzamiento en producción. El sistema de evaluación también agilizó considerablemente la validación previa al lanzamiento: una prueba de regresión exhaustiva que antes llevaba más de 6 horas realizar manualmente ahora se ejecuta en unos 20 minutos, lo que permite evaluar cambios tan importantes como la migración a un modelo base que redujo la latencia en un 35 % sin perder calidad.

En esta entrada se explica cómo desarrollamos ese sistema de evaluación: las rúbricas que definen el éxito, el generador de transcripciones que reconstruye las sesiones, el simulador que crea ejecuciones repetibles sin conexión y el evaluador basado en un modelo de lenguaje grande (LLM) calibrado que permite que la evaluación a nivel de sesión sea escalable.

Los retos fundamentales

Ask DoorDash ayuda a los usuarios a descubrir restaurantes o a hacer la compra a través de conversaciones de varios turnos. Detrás de la conversación, el agente utiliza herramientas para interactuar con el sistema de DoorDash y actuar en nombre del usuario. Eso significa que la calidad del agente debe evaluarse a lo largo de toda la interacción, y no solo en función de una única respuesta. La evaluación debe tener en cuenta tanto los mensajes dirigidos al usuario como las llamadas ocultas a las herramientas.

Figura 1: La evaluación debe tener en cuenta tanto la conversación visible como la trayectoria oculta de la herramienta.

Para desarrollar el conjunto de pruebas de evaluación de Ask DoorDash es necesario convertir el problema abierto de la calidad de los agentes en requisitos concretos del sistema. La tabla siguiente resume los principales retos que tuvimos que resolver y cómo cada uno de ellos influyó en el diseño.

RetoRequisito
Objetivos abiertos. Un objetivo del usuario puede tener muchos resultados aceptables; rara vez hay una única respuesta correcta. Expresa cada objetivo en forma de rúbrica: unos criterios lo suficientemente específicos como para evaluar siempre de la misma manera, pero lo suficientemente amplios como para tener en cuenta las diferentes vías válidas que permite una tarea.
Visibilidad de la ejecución. La calidad de un agente no puede evaluarse únicamente a partir de la conversación. El evaluador también necesita ver qué hizo el agente entre bastidores. Cada criterio requiere consultar diferentes partes de ese registro de ejecución.Realiza un seguimiento de la sesión y reconstrúyela en vistas específicas según los criterios, de modo que cada evaluador pueda ver los detalles de la conversación y la ejecución necesarios para ese elemento de la rúbrica, sin información irrelevante que enturbie el seguimiento.
No hay un ensayo seguro. No es posible probar un cambio con usuarios reales, ni reproducir una sesión anterior con un agente modificado. Generar sesiones bajo demanda: un usuario simulado guía al agente a través de un escenario elegido, manteniendo fijos los datos del entorno para que el mismo escenario se desarrolle siempre de la misma manera.
Evaluación a gran escala. Determinar si una sesión ha sido útil para el usuario requiere un criterio propio de un ser humano, pero la evaluación humana no es escalable.Un juez automatizado que sustituye a un revisor humano: un modelo de lenguaje grande (LLM) calibrado a partir de sesiones etiquetadas por humanos, de modo que los veredictos sean fiables.
Dos entornos. La calidad en el desarrollo y la calidad en la producción pueden diferir, y necesitamos ambas.Evalúa las sesiones reales y simuladas con la misma rúbrica y el mismo evaluador, de modo que un resultado obtenido fuera de línea sea válido para la producción y que un fallo en producción pueda reproducirse fuera de línea.

Qué evaluamos y dónde

Ask DoorDash utiliza una arquitectura multiagente. El mensaje de un usuario llega primero al agente «Orchestrator», que redirige la solicitud a un agente de dominio especializado (por ejemplo, el «Restaurant Discovery Agent»). A continuación, el agente de dominio seleccionado se encarga de gestionar la conversación directamente o devuelve el control al «Orchestrator» cuando es necesario redirigir la solicitud. 

El sistema de evaluación refleja esa estructura. Dado que los distintos fallos se producen en diferentes puntos del proceso, evaluamos cada capa en el lugar donde se puede medir de forma más directa: el enrutamiento en el Orchestrator, las medidas de seguridad a lo largo de todo el flujo y la capacidad específica de cada tarea en cada agente de dominio.

Figura 2: La evaluación refleja la arquitectura de tiempo de ejecución del agente.

En el interior del arnés de evaluación

Detrás de estas evaluaciones hay un único conjunto de herramientas cuyas partes se corresponden con los requisitos descritos anteriormente. Una rúbrica define cómo debe ser una buena sesión, y un generador de transcripciones convierte una sesión sin procesar en un documento legible para un evaluador. Un modelo de lenguaje grande (LLM), calibrado en comparación con revisores humanos, puntúa esa transcripción según la rúbrica. A continuación, un simulador genera sesiones bajo demanda para ejecuciones sin conexión. Dado que estas partes se complementan entre sí, las abordamos en ese orden específico, empezando por la rúbrica.

Rúbrica

Una rúbrica define los criterios que se utilizan para evaluar una sesión. Para elaborar una buena rúbrica es necesario encontrar un equilibrio entre la especificidad y la generalizabilidad. Los criterios deben ser lo suficientemente específicos como para garantizar una calificación coherente, pero también lo suficientemente generales como para aceptar todas las respuestas válidas. Dado que muchas tareas no tienen una única «respuesta correcta», la rúbrica debe describir cómo es una sesión satisfactoria, en lugar de prescribir un resultado exacto. La tabla siguiente ofrece ejemplos de dimensiones y criterios de cada evaluación. Cada criterio se califica mediante una marca binaria, y las marcas individuales se suman para obtener una puntuación final a nivel de sesión.

EvalAgenteDimensiónEjemplo de criterio
BarandillaTodos los agentesCalidad de la comunicaciónEl agente se limitó a dar una respuesta breve y no explicó su razonamiento al usuario.
Confianza e integridadEl asistente no facilitó información que pudiera demostrarse que fuera falsa ni hizo afirmaciones que contradijeran rotundamente lo que se le había mostrado al cliente
CapacidadDescubrimiento de restaurantesSatisfacción de restriccionesLos restaurantes recomendados cumplen con los requisitos específicos de la solicitud en cuanto a plazo de entrega, presupuesto y dieta.
Diversidad de resultadosLa colección ofrece una gran variedad, en lugar de piezas casi idénticas
Compras de alimentaciónEjecución de las comprasSe atienden las solicitudes explícitas del usuario para modificar la lista de la compra.
Relevancia del artículoLos elementos seleccionados son relevantes para los objetivos estatales del usuario.

Lo que se considera un buen flujo depende de la intención del usuario. Una reposición de la compra, una solicitud de receta y una búsqueda de restaurantes definen el éxito de forma diferente. Algunos flujos también dependen de herramientas o habilidades diseñadas específicamente para ello, por lo que no todos los criterios se aplican a todas las sesiones.

Cada criterio cuenta con un paso de elegibilidad. Antes de puntuarlo, el juez decide en primer lugar si el criterio es aplicable a la sesión. Si no lo es, el juez se salta ese paso. De este modo, no se resta puntuación a un proceso de elaboración de recetas por omitir un paso específico del reordenamiento. Las rúbricas de «guardrail» y «capacidad» funcionan así tanto en sesiones de producción reales en línea como en sesiones simuladas fuera de línea.

Fuera de línea, también utilizamos una rúbrica tipo lista de comprobación: una lista específica para cada escenario que detalla lo que debe resultar de una ejecución correcta. Para una sesión titulada «Lista de la compra para tacos vegetarianos para dos personas por menos de 60 dólares», la lista de comprobación verifica que cada artículo sea un ingrediente relevante para preparar tacos vegetarianos y que el subtotal sea igual o inferior a 60 dólares.

Estas comprobaciones proporcionan a la evaluación fuera de línea una señal con menor varianza que los criterios generales y de uso múltiple por sí solos. Nos permiten comprobar comportamientos específicos de forma directa, lo que hace que una muestra pequeña resulte más útil y facilita una iteración más rápida. Los aspectos técnicos de la configuración de la prueba se tratan en la sección sobre el simulador de conversación que figura a continuación.

Cada criterio está redactado de tal forma que pueda verificarse a partir de la propia sesión. Esto permite que una misma rúbrica sea utilizada tanto por un evaluador humano durante la calibración como por el sistema de inteligencia artificial (LLM) a gran escala. Ambos necesitan disponer de la sesión en un formato legible, que es precisamente lo que genera el generador de transcripciones.

Generador de transcripciones

Instrumentamos cada sesión del agente con OpenTelemetry. Cada sesión se convierte en un rastro, que almacenamos en una instancia interna de ClickHouse. Sus tramos registran los pasos que ha seguido el agente, incluyendo las entradas del usuario, las salidas del modelo, las llamadas y respuestas de las herramientas, y los widgets mostrados al usuario. Ese registro completo es la materia prima a partir de la cual comienza cada evaluación.

El registro sin procesar está completo, pero resulta difícil calificarlo directamente. Algunas respuestas de las herramientas son muy extensas, y gran parte del contenido mantiene el registro bien estructurado, como el andamiaje del esquema y los campos que no aportan información sobre la calidad del agente. Además, la evidencia relativa a un criterio puede estar repartida a lo largo de varios tramos o turnos, por lo que es necesario reordenarla antes de que un evaluador pueda utilizarla.

El generador de transcripciones es un conjunto de scripts en Python que se ejecuta sobre los registros almacenados antes de la evaluación. Reúne los fragmentos dispersos, elimina los tokens que no aportan información relevante y recorta las cargas útiles excesivamente largas. El resultado es una visión compacta de la conversación y del trabajo que hay detrás de ella. Un evaluador puede calificar esa visión de forma más coherente que el registro sin procesar.

No todos los criterios requieren una visión completa. Cada criterio declara las pruebas de las que depende, y el creador proporciona al juez únicamente esa parte concreta. Una comprobación de fundamentación obtiene la afirmación del agente y el resultado de la herramienta en la que se basa. Una comprobación de diversidad examina las recomendaciones y la solicitud original. Una comprobación de narración analiza el texto que el agente fue transmitiendo mientras trabajaba. Delimitar el alcance de las pruebas permite que cada juicio se mantenga centrado.

Figura 3: El generador de transcripciones transforma los registros sin procesar en vistas específicas según los criterios, lo que permite una evaluación más centrada y coherente.

Simulador de conversaciones

El simulador de conversaciones nos permite evaluar a un agente candidato antes de que entre en contacto con usuarios reales, generando sesiones realistas con un usuario simulado —un modelo de lenguaje grande (LLM) que hace las veces de comprador—. Cada ejecución parte de un escenario que define la solicitud inicial, el objetivo del usuario y cómo debe reaccionar ante las preguntas o los resultados, lo que da lugar a conversaciones comparables de varios turnos. Cuando un escenario depende de un estado externo, como pedidos anteriores en Safeway, un carrito en curso o el inventario de la tienda, el sistema utiliza «fixtures»: datos pregrabados que se devuelven en lugar de llamadas en tiempo real. Esto mantiene cada ejecución anclada al mismo estado, evitando desviaciones debidas a cambios en el catálogo, la disponibilidad en tienda o el historial de la cuenta de prueba. Por ejemplo, el escenario de repetición de pedido comienza con «Repite mi pedido habitual» y fija get_reorder_items a un historial de pedidos pregrabado.

// simulating reorder scenario
{
  "evalId": "mt-reorder",
  "sessionInput": {
    "state": {
      "__tool_fixture_pack_names": [
        "reorder_history_v1"
      ],
      "max_turns": 3
    }
  },
  "conversationScenario": {
    "startingPrompt": "Reorder my usuals",
    "conversationPlan": "You want to reorder your usual groceries.."
  }
// ...
}// reorder_history_v1 — returned in place of the live get_reorder_items call
{
  "success": true,
  "orders": [
    { "store_name": "Albertsons", "order_date": "2026-04-22T18:30:00Z",
      "items": [
        {"name": "Meadow Gold Whole Milk Jug (1 gal)",     "quantity": 2},
        {"name": "Oroweat 100% Whole Wheat Bread (24 oz)", "quantity": 1},
        {"name": "Signature Select Hass Avocados (5 ct)",  "quantity": 1},
        {"name": "Ben & Jerry's Half Baked Ice Cream",     "quantity": 1}
        // ... more items
      ] }
    // ... more historical orders
  ]
}

En cada ejecución de este escenario se observan exactamente estos pedidos. Esto hace que el resultado esperado sea predecible: la lista seleccionada por el agente debe extraerse del historial de pedidos fijo, y el juez puede evaluarla comparándola con ese mismo conjunto de artículos en cada ocasión.

La simulación de conversaciones hizo viable la parte de entrada de la evaluación fuera de línea. En el caso de Ask DoorDash, un barrido exhaustivo típico abarca 50 escenarios con 8 pruebas cada uno, lo que genera un total de 400 conversaciones. Sin la simulación, generar ese conjunto obligaría al desarrollador a chatear con el agente de forma local, conversación a conversación. A razón de aproximadamente 1 minuto por conversación, eso llevaría más de 6 horas. El simulador reduce esa fase de generación a unos 20 minutos.

Máster en Derecho (LLM) como juez

En la práctica, la evaluación de los agentes es un problema de medición con un ciclo de retroalimentación muy ajustado. Necesitamos muestras suficientes para estimar la calidad de la producción cada día, y puntuaciones lo suficientemente rápidas como para detectar regresiones antes de que se extiendan. La misma restricción se aplica antes del lanzamiento: cada cambio propuesto genera sus propias sesiones, y la evaluación debe proporcionar resultados con la rapidez suficiente para mantenerse dentro del ciclo de desarrollo, en lugar de convertirse en un cuello de botella para el lanzamiento.

Esa escala descarta la revisión humana como vía predeterminada para la calificación. Un revisor puede tomar la decisión correcta ante una transcripción compleja, pero la revisión de cada sesión resulta costosa. Puede incluir numerosos turnos, llamadas a herramientas, resultados de modelos y widgets renderizados, y el revisor tiene que relacionar las afirmaciones del agente con las pruebas que figuran en el historial.

La revisión humana sigue siendo esencial, pero la utilizamos allí donde tiene mayor impacto: en la definición de rúbricas, en el etiquetado de conjuntos de calibración y en la auditoría del comportamiento de los evaluadores. La mayor parte de la calificación recae en un evaluador basado en un modelo de lenguaje grande (LLM), que lee la transcripción preparada y la puntúa según la rúbrica.

Un juez de LLM solo resulta útil si coincide con los revisores humanos.

Aplicamos la optimización de indicaciones GEPA para refinar los límites de decisión del evaluador. El algoritmo propone de forma iterativa revisiones de las indicaciones del evaluador y conserva aquellas que mejoran la concordancia con las etiquetas humanas en un conjunto de validación. Esta calibración es un proceso continuo: a medida que evolucionan las rúbricas, por ejemplo, cuando se añaden nuevas capacidades, recopilamos nuevas etiquetas y recalibramos el evaluador.

El juez puntúa cada criterio de forma independiente. Recibe el criterio y las pruebas en las que se basa, y a continuación emite un veredicto acompañado de una breve justificación. Con este sistema, hemos ampliado el control de calidad, pasando de recibir aproximadamente un comentario al día enviado por los empleados a 2.000 sesiones calificadas automáticamente al día.

Servicio de evaluación

La creación de un entorno de evaluación escalable depende en gran medida de una infraestructura de plataforma sólida. El almacenamiento de trazas, la ejecución de evaluaciones en tiempo real, el desarrollo de criterios de evaluación basados en la interfaz de usuario y los flujos de trabajo de anotación tienen un coste. Empezamos con un equipo de plataforma integrada que desarrolló estos componentes junto con el marco de evaluación de Ask DoorDash, creando un estrecho ciclo de retroalimentación entre el desarrollo de la plataforma y el diseño de la evaluación. Esto permitió que la infraestructura y el marco evolucionaran conjuntamente. Esa estrecha colaboración aceleró el desarrollo de la evaluación para Ask DoorDash y ahora está dando forma a un servicio de evaluación compartido: un camino allanado que otros equipos de DoorDash pueden adoptar rápidamente, al tiempo que lo personalizan para sus propios casos de uso.

El ciclo de retroalimentación

El sistema de evaluación nos ofrece una forma escalable de medir la calidad de los agentes. La siguiente pregunta es cómo influye esa medición en el ciclo de desarrollo.

Agrupación de fallos por temas

Una ejecución diaria de evaluación puede poner de manifiesto muchos fallos, pero analizarlos uno por uno hace que el ciclo de iteración se centre en casos aislados. El fallo más reciente o sorprendente puede acaparar la atención a la hora de solucionarlo, incluso cuando no sea el modo de fallo más habitual. Necesitamos identificar los patrones más generales que subyacen a los fallos y la frecuencia con la que se producen, para poder priorizar los problemas que tienen mayor impacto en todas las sesiones.

La rúbrica nos ofrece un punto de partida útil. Cada sesión fallida ya incluye el criterio que ha incumplido, por lo que los criterios de la rúbrica actúan como grupos temáticos naturales. Un fallo en la base, la falta de una sustitución y una narración deficiente son problemas distintos y, por lo general, deben analizarse por separado. Agrupar los fallos de esta manera convierte una larga lista de ejemplos en un conjunto de temas ordenados por importancia.

De la detección a la resolución

El análisis de clústeres nos indica qué es lo que falla con mayor frecuencia, pero para determinar por qué falla y cómo solucionarlo es necesario tener en cuenta el contexto de implementación. A medida que el desarrollo impulsado por la IA agiliza la generación de código y la realización de cambios, el cuello de botella pasa a ser la elección del cambio adecuado y la validación de su impacto. Partiendo de un clúster de fallos, un agente de programación puede inspeccionar las trazas de los fallos, las rutas de código relevantes, los cambios recientes y las investigaciones previas. Cuando la solución está clara, puede redactar directamente una solicitud de incorporación de cambios; en el caso de cambios que requieren un aprendizaje rápido o en contexto, elabora un diagnóstico y propone un cambio para que lo revise un humano.

Habilidades de los agentes

Organizamos estos flujos de trabajo de desarrollo basados en la evaluación en forma de «Agent Skills». Cada «skill» define una tarea repetible, como la clasificación de fallos en clústeres o la investigación de un modo de fallo. Esto facilita que otros equipos adopten el flujo de trabajo y nos permite mejorarlo con el tiempo. Cuando una «skill» clasifica erróneamente un clúster o propone una solución poco eficaz, actualizamos la «skill» en lugar de aplicar un parche a una ejecución puntual, y esa mejora se aplica a futuras invocaciones.

El sistema de evaluación proporciona la señal, y Agent Skills la transforma en un flujo de trabajo operativo. Juntos, convierten al sistema de evaluación en algo más que un simple marcador: un plano de control para la iteración que integra en un único ciclo la supervisión de producción, la agrupación de fallos, la investigación asistida por agentes y la validación previa al lanzamiento.

Figura 4: El ciclo de retroalimentación convierte la evaluación en un proceso continuo que va desde los fallos observados hasta las mejoras validadas.

De la señal de evaluación al impacto en la producción

Reducción de la fuga de razonamiento

Un problema reciente con un agente de la compra ilustra en la práctica el ciclo de desarrollo basado en la evaluación. Las puntuaciones diarias en línea revelaron un repunte en las fugas de razonamiento. El agente completó la tarea, pero en su narración dirigida al usuario utilizaba ocasionalmente un lenguaje propio del sistema, como «reordenar habilidad», nombres de herramientas o expresiones propias del software, como «recoger» y «en paralelo». La respuesta sonaba más a la de un agente de programación que a la de un asistente de compras.

El diagnóstico apuntaba a un diseño rápido, por lo que unificamos las reglas de comunicación del agente y separamos las instrucciones internas sobre habilidades del lenguaje dirigido al usuario. Validamos el cambio fuera de línea con los escenarios más propensos a este modo de fallo en el tráfico de producción y observamos que la tasa de fugas se redujo en un 11 %. También llevamos a cabo una evaluación exhaustiva de los escenarios clave y no detectamos ninguna regresión atribuible. Tras la implementación, la monitorización en línea confirmó una mejora significativa.

Figura 5: Eval permitió identificar y reducir las fugas de razonamiento en los mensajes dirigidos a los usuarios.

Reducción de riesgos en la migración a un modelo base

Cuando se lanzó Gemini 3.5 Flash a mediados de mayo, nuestros agentes funcionaban con Claude Sonnet 4.6. Las pruebas de rendimiento de Flash pusieron de manifiesto una oportunidad: reducir la latencia de «Ask DoorDash» para que el agente pareciera más receptivo y no se percibiera como bloqueado. Sin embargo, cambiar al modelo básico es arriesgado, ya que puede alterar el comportamiento de los agentes en todo el sistema. Necesitábamos asegurarnos de que la calidad se mantuviera antes de exponer a los usuarios a este cambio.

Sometimos a Flash al conjunto de pruebas offline y las puntuaciones cayeron en picado. La evaluación puso de manifiesto patrones concretos de fallo, y orientamos a los agentes de programación de IA hacia esos patrones para que formularan hipótesis y realizaran experimentos. Lo que se descubrió no fue una brecha de capacidad, sino de compatibilidad. Flash formateaba algunos parámetros de las herramientas de forma diferente a Sonnet e interpretaba partes de una indicación del sistema que se habían ajustado implícitamente a las convenciones de Sonnet. Las bajas puntuaciones reflejaban un sistema adaptado a Sonnet, no un modelo más débil.

That diagnosis pointed to a set of small, targeted fixes. Some were deterministic guards on tool inputs – Flash would occasionally pass a search query as a JSON object like {“dishes”: […]} where the tool’s signature declared a plain string, so we coerced these back into the expected shape instead of dropping the call. Others were prompt updates that stated explicitly what Sonnet had inferred on its own, such as using the exact store name from the data and not embellishing beyond what the tool results support. We were not changing the model; we were correcting the environment around it.

Al volver a ejecutar la evaluación, Flash recuperó la paridad de calidad con Sonnet, dentro del margen de variación del sistema de pruebas. Migramos los agentes de producción y supervisamos la calidad y la interacción en el tráfico real. El resultado se mantuvo: una reducción de la latencia del 35 % sin pérdida alguna en los indicadores de calidad.

Junto con el ejemplo de la fuga de razonamiento, esto demuestra que el sistema de pruebas funciona en ambos sentidos: convierte las señales de calidad de producción en correcciones y reduce los riesgos de los cambios deliberados en el sistema antes de su implementación.

Lecciones aprendidas

Los jueces necesitan transcripciones adaptadas a la pregunta. El registro sin procesar suele contener más información de la que requiere el criterio. Algunos fragmentos no guardan relación con el criterio. Incluso los fragmentos útiles pueden incluir estructuras de esquema, campos repetidos y tokens de carga útil que solo existen para garantizar que los datos estén bien formados. Obtenemos mejores resultados eliminando lo que es irrelevante y conservando las pruebas de las que realmente depende el criterio.

Es necesario controlar el entorno; de lo contrario, la puntuación medirá el ruido. Tanto la deriva de los factores previos como el propio indeterminismo del agente pueden alterar el resultado, lo que dificulta determinar si un cambio ha sido realmente beneficioso. Los «fixtures» congelan el entorno previo, y los escenarios fijos mantienen estables las condiciones de la tarea, por lo que es más probable que la variación de las métricas refleje el comportamiento del agente en lugar del de su entorno.

Un resultado obtenido fuera de línea solo tiene importancia si se traslada a la evaluación en línea. Por eso se utilizan la misma rúbrica y el mismo evaluador calibrado en ambos entornos. Si en la evaluación en línea y fuera de línea se emplean evaluadores ajustados de forma independiente, sus puntuaciones pueden divergir de formas difíciles de conciliar.

El sistema de evaluación también genera sus propios informes de errores. Una parte considerable de los fallos señalados se deben a errores en el conjunto de pruebas, más que a problemas con los agentes; por lo general, se trata de un falso positivo del evaluador o de una laguna en el seguimiento que le impide tener una visión completa. Solucionar estos problemas de forma paralela garantiza la fiabilidad de la evaluación.

Conclusión

Para los agentes de producción, la evaluación no puede ser algo secundario. Tiene que formar parte del sistema desde el principio. Pero la puntuación de las sesiones es solo el primer paso. El problema más difícil es convertir esas puntuaciones en un mejor comportamiento por parte de los agentes.

El sistema de control de calidad cierra la brecha entre la medición y la mejora. Amplió el seguimiento diario de la calidad, pasando de aproximadamente un comentario enviado por un empleado a 2.000 sesiones evaluadas automáticamente, y redujo las pruebas de regresión exhaustivas de más de 6 horas realizadas manualmente a unos 20 minutos. Estas mejoras nos permitieron detectar antes los problemas de producción, dar prioridad a los modos de fallo recurrentes y validar cambios importantes antes de que llegaran a los usuarios. El resultado fue un impacto medible en la producción, incluida una mejora de 8 puntos en las puntuaciones de calidad de los agentes antes del lanzamiento a nivel nacional y una migración validada del modelo base que redujo la latencia en un 35 % sin perder calidad.

Un sistema de evaluación escalable requiere una infraestructura de plataforma sólida. La estrecha colaboración con el equipo de la plataforma aceleró el desarrollo del sistema de evaluación de agentes para Ask DoorDash. Este trabajo preliminar está dando forma ahora a un servicio de evaluación compartido.

Y aquí viene la advertencia obligatoria de «La IA avanza rápido»: cuando redacté por primera vez este artículo a principios de marzo, empecé diciendo algo así como que «la IA está al caer» y que deberíamos prepararnos para ella. Al releerlo solo un par de meses después, la frase me parece notablemente desfasada: la IA ya no está al caer; ha llegado. Las grandes empresas tecnológicas generan ahora más del 75 % de su código mediante IA, y las empresas más pequeñas y menos punteras les están siguiendo rápidamente los pasos. Para cuando leas este artículo, ¡esta premisa podría parecer ya tan absurda como la anterior!

Sin embargo, creo que las conclusiones de este artículo siguen siendo relevantes. Lo que expongo aquí es mi trayectoria personal hacia el dominio de la IA. Teniendo en cuenta todo lo anterior, me considero, como mucho, un usuario de nivel intermedio, pero llegar hasta aquí me ha exigido mucha experimentación y escuchar muchos más podcasts de lo que estoy dispuesto a admitir. Lo que a muchos desarrolladores aún les sigue resultando complicado no es utilizar la IA para el autocompletado o las ediciones rápidas, sino confiarle a un agente una tarea más compleja y obtener como resultado algo coherente, revisable y útil. Si ese flujo de trabajo aún no te ha acabado de cuajar, este artículo es para ti.

En las siguientes secciones, repasaré mi trayectoria: desde que Cursor era mi compañero predeterminado para programar IA, pasando por mis primeros y confusos intentos de utilizar Claude Code, hasta los experimentos con equipos de agentes que, en su mayoría, dieron lugar a resultados de IA de baja calidad y muy costosos, y finalmente el ciclo de investigación → planificación → implementación que hizo que el trabajo con agentes de larga duración resultara viable.

A continuación, voy a presentar un pequeño proyecto al que llamo «Agentic Orchestrator», que resume todas estas lecciones. Como se muestra en la figura 1, se trata de un aburrido orquestador basado en una máquina de estados que creé para convertir a los agentes en proyectos ambiciosos de una sola vez. ¿Y lo mejor de todo? ¡Es de código abierto

Figura 1: El panel de control principal de Agentic Orchestrator, que permite realizar un seguimiento de múltiples funciones en diferentes fases de desarrollo.

Pero empecemos por el principio.

Antes del bucle: mi fase del cursor

Cursor es una herramienta increíble para aumentar la productividad que combina la comodidad de un entorno de desarrollo totalmente integrado con la potencia de la IA agentiva para abordar tareas de distintos niveles de complejidad. Va mejorando con el tiempo, a medida que los modelos y las herramientas ganan en capacidad. Se convirtió en mi herramienta imprescindible en 2025 y durante 2026. No recuerdo haber escrito muchas líneas de código a mano, a menos que cuente el uso incesante de la tecla de tabulación.

Pero a medida que sentía cada vez más curiosidad por saber hasta dónde podía llevar el desarrollo de agentes, empecé a toparme con las limitaciones de Cursor y del desarrollo basado en tabulaciones en general. El principal problema era que no conseguía que funcionara de forma fiable durante el tiempo suficiente como para crear funciones complejas con total autonomía. 

Gracias a las innovadoras funciones que ofrece Opus, de Anthropic, en el sector ya se hablaba de los agentes de ejecución prolongada y de su capacidad para generar características de un solo golpe sin intervención humana. ¡Quería experimentar todo eso por mí mismo! Por eso, había llegado el momento de dar el salto a la nueva sensación de la que todo el mundo hablaba: Claude Code.

Mi relación complicada con Claude Code

Imagínate esto: tus amigos y compañeros de trabajo presumen de cómo pueden automatizar todos los aspectos de sus vidas, mientras que tus intentos por automatizar incluso las cosas más sencillas fracasan estrepitosamente. Así estaba yo allá por marzo de 2026.

Varias personas de distintas empresas y con diferentes perfiles técnicos intentaban convencerme de que ya habíamos alcanzado la singularidad. Ya no se necesitaban humanos en el proceso, decían; la IA encarnaría todos tus deseos y los haría realidad, incluyendo suplantarte en Slack, atender llamadas de Zoom, preparar un espresso espectacular y, por supuesto, escribir código. Lo único que tenía que hacer, según ellos, era pasarme a Claude Code con Opus 4.6 para ver cómo mi mundo se ponía patas arriba. ¡Y así lo hice! Sin embargo, en mi caso, resultó ser peor que usar modelos equivalentes con Cursor.

Me gustan las herramientas basadas en terminal tanto como a cualquier otro programador, pero con Claude Code he perdido la capacidad de interactuar directamente para revisar cada cambio por separado. En teoría, esto se compensaría con una mejor coordinación y las herramientas que ofrece el entorno de desarrollo, pero al final el modelo seguía siendo el mismo. Y no es que Cursor no tuviera herramientas o un modo de diseño. Entonces, ¿qué pasa?

Resulta que Claude Code conlleva un cambio de mentalidad: ya no tienes que interactuar con tu código. Tienes que cambiar tu flujo de desarrollo, confiar en el agente e iterar por completo mediante indicaciones. 

Era hora de empezar a experimentar y intentar conseguir ese espresso de ensueño preparado con la máquina Opus.

Comienzo de los experimentos: ¡Agentes, agentes, agentes!

Recuerda cuál es mi objetivo principal: conseguir que la IA desarrolle una característica compleja de forma autónoma.

Mientras exploraba la documentación de Claude Code, encontré una función experimental llamada «equipos de agentes». Esta función permite a los usuarios invocar a un equipo de agentes con diferentes personalidades y funciones para que modifiquen distintas partes del código y, a continuación, fusionen sus resultados en un producto final funcional… o, al menos, esa es la teoría.

En la práctica, mi experiencia con este enjambre de agentes salió mal por razones que no esperaba. Al principio supuse que lo más difícil sería dar las instrucciones, así que me centré en eso. Creé perfiles muy elaborados, le dije a un agente que era «el mejor desarrollador de Go que jamás haya existido», convertí a otro en un «revisor sénior meticuloso» y organicé cómo se pasarían el trabajo entre ellos. Básicamente, era una especie de «influencer motivacional» para los modelos de lenguaje. Pero nada de eso surtió efecto. ¡Los halagos no aumentan la capacidad! El modelo no se guarda sus verdaderas habilidades hasta que le digas que es brillante. El personaje era puro teatro; más allá de esa puesta en escena, el resultado era exactamente tan bueno o tan malo como iba a ser en cualquier caso.

Mi fiasco con las personas fue, en gran medida, inofensivo. En el peor de los casos, fue una pérdida de contexto. El verdadero problema fue que el paralelismo multiplica la divergencia. Cada agente trabajaba a partir de su propia interpretación de unas especificaciones ambiguas, hacía sus propias suposiciones independientes e inventaba su propia versión de la interfaz donde se suponía que debían encajar dos piezas. Cada agente era plausible a nivel local. Nada era coherente a nivel global. Así que, cuando llegó el momento de fusionar, las piezas no encajaban; había contratos que no coincidían, lógica duplicada y dos mitades de una funcionalidad en las que cada una asumía que la otra mitad funcionaba de forma diferente.

¿El resultado final? En el caso de funciones triviales, los equipos de agentes funcionaban correctamente. Sin embargo, para cualquier cosa que pudiera justificar realmente la complejidad de una configuración multiagente, el código de IA que salía de esas sesiones resultaba totalmente inutilizable. Me vi obligado a descartar solicitudes de incorporación de cambios completas que habían requerido horas de procesamiento precisamente por este motivo.

Así que di un paso atrás. La lección no era que los agentes no pudieran gestionar la complejidad, ni que tener más agentes fuera peor que tener uno solo. Era que me había estado planteando la pregunta equivocada. No dejaba de intentar que los agentes colaboraran, se coordinaran, se pusieran de acuerdo y fusionaran su trabajo, cuando el verdadero problema era que no había nada en torno a lo cual pudieran coordinarse. No existía una fuente de verdad compartida. No se transferían artefactos de una fase a la siguiente. No había separación entre el pensamiento y la acción. Los agentes no eran el problema. Lo era el espacio vacío que había entre ellos. Así que dejé de preguntarme cómo conseguir que un equipo de agentes trabajara en conjunto y empecé a preguntarme lo contrario: ¿qué estructura de apoyo liberaría a cada agente de la necesidad de colaborar, de modo que pudiera realizar únicamente una tarea concreta y bien definida sobre un artefacto fijo que ya se hubiera producido? Dejó de ser una cuestión de «lanzar agentes contra el problema» y pasó a centrarse más en construir las vías y dejar que los agentes circulasen por ellas tramo a tramo. 

Este nuevo enfoque fue lo que, al final, me llevó por un camino muy diferente.

Mi gran avance: investigación, entrevistas, planificación, iteraciones y revisores críticos

Tras el desastre con el equipo de agentes, hice algo radical: hablé con gente —es decir, con seres humanos de verdad—. Busqué a ingenieros que, de alguna manera, hubieran dado con la clave para conseguir que Claude realizara un trabajo significativo de forma autónoma. Lo que aprendí cambió por completo mi modelo mental.

La primera revelación me llegó a través de una charla inspiradora de Humanlayer sobre lo que ellos denominan el marco RPI —investigación, planificación, implementación—. La idea es aparentemente sencilla: en lugar de endosarle a un agente unas especificaciones completas y cruzar los dedos, se divide el trabajo en fases cognitivas diferenciadas. En primer lugar, el agente investiga el código fuente leyendo los archivos pertinentes, comprendiendo los patrones y trazando las dependencias. A continuación, elabora un plan: un documento de implementación detallado y por fases con rutas de archivo específicas, fragmentos de código y criterios de éxito. Solo una vez completado esto, procede a la implementación, trabajando a partir de su propio plan en lugar de basarse en una vaga comprensión de unas especificaciones que ya había olvidado a medias hace 30 000 tokens.

Se trataba de una filosofía fundamentalmente diferente del enfoque de «aquí tienes las especificaciones, ponlas en marcha» que yo había estado utilizando. Cada fase tiene un objetivo concreto y bien definido. Cada fase produce un artefacto concreto que se convierte en la entrada para la siguiente. Y, lo que es más importante, cada fase encaja perfectamente dentro de una ventana de contexto porque no intenta abarcar todo el problema de una sola vez. La investigación no tiene que pensar en los detalles de implementación. La planificación no tiene que escribir código. La implementación no tiene que redescubrir el código base, porque el plan ya le indica exactamente dónde buscar.

La segunda revelación fue aún más sencilla, cortesía de la habilidad «grill-me» de Matt Pocock: deja que el agente te entreviste. En lugar de pasar horas redactando la indicación perfecta que anticipe todos los casos extremos y aclare todas las ambigüedades, ¡deja que el agente te haga preguntas! Resulta que una sesión de ida y vuelta con un agente que acaba de investigar tu código vale más que horas de ingeniería de indicaciones previa. El agente sabe lo que necesita; solo tienes que darle permiso para preguntar. Te sorprendería lo relevantes que son a veces estas preguntas. Al fin y al cabo, tiene todo el sentido del mundo; una de las cosas que aprendes a medida que avanzas en tu carrera es a delegar. Cuando lo haces, la mayoría de las veces los ingenieros a los que has delegado el trabajo te plantearán preguntas. No quieren hacer suposiciones erróneas sobre lo que tenías en mente. ¿Por qué iban a ser diferentes los agentes?

Pero la tercera y más importante lección que aprendí fue sobre lo que en el sector se conoce comúnmente como «el bucle».

Verás, incluso si implementas RPI, sigues teniendo dos problemas. El primero es el problema de la ventana de contexto: una implementación compleja podría requerir más tokens de los que puede contener una sola sesión. El agente podría llegar al 80 % del plan y luego empezar a perder coherencia. O podría encontrarse con un error de compilación inesperado que lo haga entrar en una espiral. El segundo problema es más sutil: la autoevaluación carece prácticamente de valor. Un agente que acaba de pasar media hora implementando una funcionalidad no debería tener que decidir después si esa implementación es realmente buena.

El «loop» resuelve el primer problema. Un revisor antagonista resuelve el segundo. ¿Y lo mejor de todo? Todo el asunto es vergonzosamente sencillo. En esencia, sigue siendo básicamente un bucle «while» de Bash, solo que con una puerta de revisión, como se muestra aquí:

while [ iteration < max_iterations ]; do
      run the implementation agent with the objective and current progress
      check if the agent reported SUCCESS or RETRY
      if RETRY → feed the progress back in and go again
      if SUCCESS → run an antagonistic reviewer in a fresh context window
          if APPROVED → done
          if CHANGES_REQUESTED → feed the review back in and go again
  done

Eso es todo. Ese es el secreto. Ejecutas el agente, este realiza algunas tareas, actualiza un archivo de progreso indicando «esto es lo que he hecho, esto es lo que queda» y, a continuación, emite una señal: AGENT_LOOP_STATUS: SUCCESS o AGENT_LOOP_STATUS: RETRY. Si indica RETRY, inicias una nueva sesión con una ventana de contexto limpia, pero le pasas el archivo de progreso para que sepa por dónde se quedó. Si indica SUCCESS, no te fías. Llamas al antagonista.

Cuando hablo de «revisor antagonista», no me refiero a un agente que sea grosero o que se ponga en contra por el simple gusto de hacerlo (aunque eso es muy divertido de ver; ¡deberías probarlo!). Me refiero a un agente independiente cuya función sea mostrarse escéptico de forma profesional. Lee el plan, revisa los cambios, comprueba las pruebas, busca requisitos que se hayan pasado por alto, señala los supuestos poco sólidos y plantea la pregunta que el agente encargado de la implementación tiene menos incentivos para hacer: «¿Está esto realmente terminado?»

La clave está en la ventana de contexto independiente. Si el propio agente revisa su propio trabajo, mantiene todos los supuestos, atajos e impulso narrativo de la implementación. Recuerda por qué tomó una decisión, por lo que es más probable que la defienda. Un revisor imparcial no tiene ese apego. Ve el estado del repositorio, el objetivo establecido y los artefactos de la implementación. Esa separación genera la presión crítica justa para detectar el tipo de errores que, de otro modo, pasarían desapercibidos hasta la revisión humana.

Esto resuelve ambos modos de fallo de la forma más pragmática posible. En lugar de intentar que una sola sesión perdure durante toda la implementación, se acepta que las sesiones son efímeras y se diseña en función de ello. Cada iteración obtiene una ventana de contexto limpia. Cada iteración lee el archivo de progreso, comprende lo que se ha hecho y se centra en lo que viene a continuación. El archivo de progreso se convierte en la memoria a largo plazo del agente, mientras que el revisor se convierte en el sistema inmunológico que impide que un trabajo defectuoso se declare silenciosamente como finalizado.

Los más versados en el tema de los agentes quizá ya se hayan dado cuenta de que se trata de un «bucle de Ralph». El crítico más crítico ha aportado la pieza que faltaba: no se trata de «seguir adelante hasta que esté terminado», sino de «seguir adelante hasta que otra persona con una mirada fresca esté de acuerdo en que “terminado” significa “terminado”».

La combinación de las fases del RPI, el bucle y la revisión antagónica supuso un auténtico cambio radical. Por primera vez, pude encargarle a Claude una funcionalidad moderadamente compleja —algo que requeriría unos cuantos miles de líneas de código repartidas en varios archivos— y volver a encontrar una implementación que funcionara. No funcionaba siempre, pero sí lo hacía con la suficiente frecuencia como para que dejara de considerar la programación autónoma como un simple truco de salón y empezara a verla como una herramienta.

La idea central era sólida: dividir el trabajo en fases, hacer que cada fase genere artefactos, traspasar los límites del contexto y no permitir nunca que el agente que ha escrito el código sea el único que juzgue si este es bueno.

Espacio de trabajo desordenado

Aunque estaba encantado con mi capacidad para crear elementos complejos con muy pocos ajustes al final, tras este gran avance, me dejé llevar por el entusiasmo. Mi espacio de trabajo empezó a parecerse a lo que se ve en la figura 2, pero multiplicado por cinco o seis: uno por cada elemento en el que estaba trabajando simultáneamente.

Figura 2: Mi entorno de trabajo tradicional: varias sesiones de Claude y paneles de terminal, cada uno de los cuales sigue una fase diferente del bucle RPI.

El flujo de trabajo funcionaba, pero resultaba engorroso llevarlo a cabo manualmente. Para cada funcionalidad, tenía una sesión de IA dedicada a investigar el código fuente, otra a convertir esa investigación en un plan de implementación y, a continuación, un ciclo en el que respondía a preguntas de aclaración, revisaba el plan y ponía en marcha la implementación. Eso era manejable para una sola funcionalidad. En cuanto intenté aplicarlo a cinco o seis funcionalidades al mismo tiempo, me vi obligado a cambiar constantemente de contexto entre terminales, planes, ramas y conversaciones a medio terminar.

Mi primer instinto fue volver a recurrir a los agentes. Le pedí a un agente gestor que implementara el marco RPI-plus-loop utilizando subagentes, para poder gestionarlo todo desde una única instancia de Claude. Sin embargo, ya traumatizado por mi experiencia previa con los equipos de agentes, decidí crear una herramienta en su lugar. Me complace anunciar que esta herramienta ya es de código abierto para que todo el mundo pueda disfrutarla.

Te presentamos Agentic Orchestrator

Y así es como nació Agentic Orchestrator. Se trata de una interfaz de usuario de terminal (TUI) que toma el marco «investigación → planificación → implementación», lo mejora y lo integra en una solución de ingeniería real.

La idea central es sencilla: no le pidas a una IA que gestione otras IA. En su lugar, crea un marco que dirija el ciclo de vida de las funciones y deja que cada sesión de IA se centre en hacer bien una sola cosa. El orquestador se encarga de la infraestructura, incluidas las transiciones de estado, el aislamiento del árbol de trabajo, la gestión de sesiones, el seguimiento del progreso y la recuperación tras fallos. El agente se encarga del razonamiento. Se trata de una orquestación predecible sobre agentes impredecibles.

De los bucles de Bash a una máquina de estados real

¿Te acuerdas del bucle «while» de Bash que hemos visto antes? Es aquel en el que se ejecuta el agente, se comprueba su estado y se devuelve información sobre el progreso. Agentic Orchestrator parte de esa misma idea y le da forma concreta. Cada función avanza a través de una máquina de estados bien definida, tal y como se muestra en la figura 3: Base de conocimientos → consulta → investigación → diseño → planificación → implementación → revisión → publicación → finalizado.

Figura 3: El nuevo y mejorado ciclo de desarrollo.

RPI tiene ahora un aspecto un poco diferente al de antes. Esto es el resultado de muchas semanas de experimentación, que han dado lugar a un flujo de trabajo que me permite crear elementos muy complejos con total confianza en una única sesión de larga duración. No, no se me ocurre ningún acrónimo ingenioso para describirlo, pero en la Tabla 1 se muestra en qué consiste cada paso y cuál es su función.

FaseSalidaPor qué existe
Base de conocimientosUn mapa reutilizable de arquitectura, convenciones, API, dependencias y comandos de verificaciónPermite que cada fase posterior parta de una base de referencia real, en lugar de tener que volver a crear el repositorio desde cero.
ConsultaAclaración de preguntas y respuestas de los usuarios mediante el patrón «grill-me»Saca a la luz las incógnitas antes de que ningún agente empiece a hacer conjeturas.
InvestigaciónInvestigación documental con referencias concretas a expedientes y análisis del comportamiento actualDescribe la realidad, no la solución, sobre la que se basará la planificación del sustrato factual. 
DiseñoDocumento de diseño: Planteamiento del problema, solución, historias de usuario, decisiones, elementos explícitamente excluidos del alcanceProporciona la fuente de información de referencia de la función, elaborada mediante una revisión de diseño específica con el agente.
Hoja de rutaLista ordenada de secciones verticales delgadas de extremo a extremoPermite a los agentes ejecutar fragmentos delimitados y verificables, en lugar de planes extensos que abarcan todas las capas a la vez.
Planificación por fasesPlan por fases aprobado con tareas, criterios de aceptación y expectativas de verificaciónHace que el trabajo sea lo suficientemente concreto como para llevarlo a cabo; las críticas opcionales en la fase de planificación permiten detectar los planes deficientes antes de que el código resulte costoso.
AplicaciónCódigo, pruebas, archivo de progreso, informe de verificaciónPermite que una nueva ventana de contexto continúe desde donde se detuvo la sesión anterior; este archivo de progreso garantiza que el bucle se ejecute con rigor.
Revisión finalAprobación o solicitudes de modificación detalladasPermite a un revisor que no está involucrado en la implementación decidir si «terminado» significa realmente «terminado».

Tabla 1: Explicación de cada paso del nuevo ciclo de desarrollo.

La aburrida infraestructura

 Las fases son la parte visible. Por debajo, el orquestador se encarga del trabajo poco glamuroso que convierte un flujo de trabajo que, de otro modo, sería manual, en un sistema que sigue funcionando aunque cierre el portátil. Entre bastidores, varios componentes se encargan de que todo siga funcionando:

  • Árboles de trabajo: Cada característica se ejecuta en su propio árbol de trabajo de Git, lo que significa que varias características pueden avanzar por el proceso de integración en el mismo repositorio sin interferir entre sí.
  • La TUI: Esta interfaz ofrece un panel de control que permite realizar un seguimiento de todo lo que está en curso: lo que se está investigando, lo que está bloqueado, lo que hay que revisar y lo que está listo para publicarse.
  • Recuperación tras fallos y gestión de sesiones: dado que la máquina de estados se guarda de forma permanente, no perderás el progreso por motivos como el cierre del terminal, una sesión bloqueada o un fallo grave.
  • Acciones posteriores a la publicación: incluso después de que la solicitud de incorporación de cambios se haya publicado, el orquestador sigue estando ahí para ayudarte. Puedes hacer un rebase con respecto a la rama «main», solicitar refactorizaciones específicas, volver a un estado anterior, ajustar la implementación o resolver los comentarios de revisión que vayan llegando sin salir de la TUI.
  • Transiciones de fase deterministas: el código decide qué se ejecuta a continuación, conserva los artefactos y garantiza el cumplimiento de los controles de revisión, mientras que el agente se encarga de pensar; no puede ir inventando el flujo de trabajo sobre la marcha.

Esta es la parte que no debe dejarse en manos de los agentes. Los agentes son probabilísticos; pueden perder la pista del estado, saltarse un paso o seguir adelante con seguridad partiendo de una suposición errónea. Cuanto más impredecible se vuelve la capa de inteligencia, más valioso resulta contar con un marco determinista y «aburrido» que la rodee.

¿Funciona esto?

Los resultados pueden variar. 

En marzo, Anthropic publicó este artículo sobre agentes de larga duración en el que planteaban un reto con la siguiente indicación:

Crea un generador de videojuegos retro en 2D con funciones como un editor de niveles, un editor de sprites, comportamientos de entidades y un modo de prueba en el que se pueda jugar.

Probé lo mismo con Agentic Orchestrator utilizando el modo totalmente autónomo; es decir, sin necesidad de que los humanos dieran ninguna respuesta. Tras 12 horas, 250 dólares y sin ningún ajuste adicional, este fue el resultado:

Es cierto que en este caso se utilizó Opus 4.7 en todas las fases, a diferencia de la versión 4.5 que utilizó Anthropic en su demostración. 

Esto empieza a parecerse mucho a un espresso preparado con Opus.

Entonces, ¿ya hemos resuelto el problema de la ingeniería de software?

Todavía no, pero a estas alturas estamos bastante cerca de resolver el problema de la codificación.

Los modelos están mejorando a un ritmo tal que la planificación trimestral parece una era geológica. Las funciones que hoy requieren cinco iteraciones de bucle podrían realizarse mañana de una sola vez. Seguiremos ampliando el límite de la ventana de contexto, hasta el punto de que el patrón de bucle deje de ser necesario. La fase de revisión que detecta los errores de un agente irá perdiendo importancia a medida que los agentes cometan menos errores. Si tenemos suerte, el propio Agentic Orchestrator quedará obsoleto en unas semanas, al volverse innecesario gracias a modelos capaces de retener una característica completa en su «mente» sin necesidad de un archivo de progreso que les recuerde lo que estaban haciendo. Sinceramente, ese sería el mejor resultado posible. No lo creé porque quisiera crear un orquestador. Lo creé porque los agentes no supervisados no eran lo suficientemente buenos como para funcionar sin uno.

Pero incluso en un mundo en el que los modelos sean diez veces más capaces de lo que son hoy en día, hay una cosa de la que estoy cada vez más convencido: el conocimiento humano sobre un ámbito concreto y nuestra comprensión fundamental de los sistemas son insustituibles.

Esto es lo que he aprendido tras semanas de trabajar con este flujo de trabajo: la calidad del resultado sigue dependiendo de lo que se introduzca. Los agentes no son mágicos. Son amplificadores. Si les das una indicación imprecisa, obtendrás una implementación imprecisa. Si no entiendes el código lo suficientemente bien como para responder a sus preguntas, harán suposiciones, y esas suposiciones serán erróneas.

El papel del ingeniero de software está cambiando, no desapareciendo.

Cuando tu lenguaje de programación es el inglés, las habilidades que importan cambian. Sigues teniendo que ser un buen ingeniero, posiblemente más que antes, pero la naturaleza del trabajo cambia. Hay que escribir menos y pensar más, menos sintaxis y más arquitectura. Dejaremos de preguntarnos cómo implementar algo y empezaremos a preguntarnos qué deberíamos implementar y por qué. El valor del ingeniero de software ya no reside en escribir código. Reside en saber cómo es el código adecuado y ser capaz de expresarlo con claridad para que un agente pueda producirlo.

El modelo por el que me he decantado es más o menos así: durante el día, el ser humano se dedica a tareas propias de un ser humano. Redactas instrucciones. Respondes a preguntas. Revisas planes. Tomas decisiones sobre casos extremos y compensaciones. Después, los agentes se ponen manos a la obra y llevan a cabo la implementación durante horas —por la noche, durante la hora de comer o mientras estás en reuniones—. Cuando vuelves al ordenador, puedes revisar la solicitud de incorporación de cambios (PR), retocar lo que sea necesario, publicar y seguir adelante. El ser humano aporta la intención y el criterio. La máquina aporta el trabajo y la resistencia. Es la delegación en su forma más pura y, como toda delegación, requiere que quien delega sepa realmente de qué está hablando.

Una reflexión sobre la intensidad laboral, la adicción y la salud mental

Quiero cambiar de tono ahora, porque esta parte es importante.

En el debate sobre la productividad de la IA existe una idea que viene más o menos así: «Las herramientas de IA te permiten disponer de más tiempo para que puedas centrarte en el trabajo creativo y de alto valor». Suena maravilloso. Pero, según mi experiencia, también es, en gran medida, erróneo.

Un estudio reciente de BCG realizado entre 1.488 trabajadores reveló algo que tuvo un gran impacto: la productividad autoevaluada aumentaba cuando se utilizaban entre una y tres herramientas de IA, pero se desplomaba al utilizar cuatro o más. Los trabajadores señalaron un mayor esfuerzo mental, una mayor fatiga mental y una mayor sobrecarga de información cuando la IA requería una mayor supervisión. La autora del estudio, Julie Bedard, de BCG, describió que los trabajadores sentían que estaban «alcanzando los límites de su capacidad intelectual».

Y yo también lo noté. Esto es lo que ocurrió realmente cuando conseguí que el flujo de trabajo «agente» funcionara a la perfección. No trabajé menos horas. Trabajé las mismas horas, pero con una intensidad mucho mayor. En lugar de escribir código durante ocho horas, me pasé ocho horas seguidas tomando decisiones, cambiando de una función a otra, revisando implementaciones, respondiendo a preguntas de los agentes y redactando instrucciones. El tiempo de inactividad mecánico, el teclear, la depuración, ese respiro que tenía mientras escribía el código repetitivo y reflexionaba sobre lo que estaba haciendo, todo eso había desaparecido. Cada minuto implicaba tomar decisiones. Cada minuto aumentaba mi carga cognitiva.

Al final del día me sentía más cansado, no menos. Estaba más agotado, no con más energía. Y hay una sutil adicción a ello: cuando puedes poner en marcha una función antes de acostarte y despertarte con un comunicado de prensa, la tentación de poner en marcha tres funciones antes de acostarte es abrumadora. Los agentes no se cansan. Pero tú sigues siendo el cuello de botella para cada pregunta que te hacen y cada plan que te proponen. El trabajo se acumula y, si no tienes cuidado, te abruma a ti también.

No tengo una solución clara para esto. Nos encontramos en un período de transición complicado en el que las herramientas han superado nuestra capacidad para utilizarlas de forma sostenible. Todos estamos descubriendo cómo funciona una forma de trabajar fundamentalmente nueva, y fingir que todo son ventajas no ayuda en nada a quienes intentan adaptarse a ella.

Tómate descansos. Establece límites. Recuerda que los agentes seguirán ahí por la mañana. Y si te encuentras actualizando el panel de control a medianoche para ver si ha pasado la fase de revisión, cierra el portátil. Lo digo por experiencia propia. Las relaciones públicas pueden esperar.

¡Ve a crear algo!

Empecé diciendo que, como mucho, soy un usuario de nivel intermedio. Incluso después de haber escrito todo esto, sigo creyendo lo mismo. La diferencia es que ahora conozco el perfil de la curva de aprendizaje y puedo decirte: merece la pena recorrerla.

Esto es lo que le diría a alguien que empezara desde cero hoy mismo: No intentes abarcar demasiado. Empieza con una tarea pequeña en Cursor o Claude Code. Acostúmbrate al ritmo de dar instrucciones, revisar y repetir. Después, prueba el marco RPI con una sola función: primero investiga, luego planifica y, por último, implementa. No necesitas nada sofisticado. Solo abre tres sesiones de Claude, una para cada fase, y pasa los resultados manualmente. Comprueba la diferencia que supone que el agente cuente con el contexto de su propia investigación, en lugar de una indicación escrita a toda prisa por ti.

En cuanto lo entiendas —y lo entenderás—, empezarás a ver las lagunas que unas herramientas mejores pueden cubrir. Quizá desarrolles tu propio orquestador. Quizá utilices el mío. Quizá, para cuando leas esto, ya haya algo mejor que ambos. No pasa nada. Los marcos de trabajo y las herramientas seguirán cambiando. Los modelos mentales no, al menos no tan rápido. Investiga antes de planificar. Planifica antes de implementar. Repite el proceso cuando te quedes sin contexto. Deja que el agente haga preguntas. Y conoce tu código lo suficientemente bien como para responderlas.

La máquina de café espresso aún no es totalmente automática. Pero tampoco es ya una cafetera manual. Nos encontramos en algún punto del espectro semiautomático, y los cafés mejoran cada semana.

Ahora ve a probar cosas nuevas. Y cuando encuentres algo que funcione, compártelo, porque te aseguro que habrá alguien más que se encuentre exactamente en la misma situación en la que tú estabas el mes pasado.

DoorDash funciona a base de numerosos microservicios. Una sola solicitud de un usuario puede requerir datos de varios servicios, como metadatos de los establecimientos, menús, disponibilidad, precios y contexto de gestión de pedidos. A medida que el tráfico de DoorDash crecía en los inicios de la empresa, muchos servicios solicitaban repetidamente los mismos datos de baja mutación en intervalos de tiempo muy cortos.

Aunque los datos no hubieran cambiado, cada solicitud seguía activando llamadas gRPC, cálculos repetidos y, en ocasiones, lecturas de la base de datos del backend. A la escala de DoorDash, esto generaba un consumo innecesario de recursos del servicio, una mayor carga en la base de datos y un empeoramiento de la latencia P90/P99.

Estas llamadas repetidas también aumentaban el riesgo de fiabilidad. Cuando una dependencia se ralentizaba o dejaba de estar disponible, los reintentos y el aumento de la concurrencia podían extender la presión a los servicios dependientes, convirtiendo un pequeño problema en un incidente de mayor envergadura.

Las cachés locales resultaban útiles, pero eran específicas de cada servicio, presentaban inconsistencias y obligaban a cada equipo a desarrollar y mantener su propia lógica de almacenamiento en caché. Necesitábamos una capa de almacenamiento en caché compartida que permitiera reducir la duplicación de trabajo, protegiera los servicios de nivel superior durante interrupciones parciales y pudiera implementarse sin necesidad de modificar el código de las aplicaciones.

Eso nos motivó a crear Entity Cache.

Lo que hemos creado

Entity Cache es un proxy de almacenamiento en caché transparente para HTTP/gRPC que se ejecuta dentro de la malla de servicios basada en Envoy de DoorDash. Se integra en la ruta de la solicitud y sirve las respuestas a las que se accede con mayor frecuencia desde una caché centralizada, sin que sea necesario que cada servicio implemente su propia lógica de almacenamiento en caché.

Dado que Entity Cache está integrado en la malla de servicios, los servicios siguen realizando las mismas llamadas HTTP o gRPC que antes. La incorporación se lleva a cabo a través de la configuración de la malla de servicios, por lo que no es necesario modificar el código del cliente ni el del servicio de origen.

Por ejemplo, un punto final de gRPC se puede enrutar a través de Entity Cache con una configuración como esta:

- name: example-service/grpc/50051
  redirect:
    enabled: true
    entity_cache: true
    endpoints:
      - path: ^/example.v1.ExampleService/GetExample$
        headers:
          - name: :method
            string_match:
              exact: POST
        rollout: 1

Al servir respuestas almacenadas en caché antes de que las solicitudes lleguen a los servicios de nivel superior, Entity Cache ayuda a DoorDash a:

  • Mejorar la latencia evitando las llamadas HTTP/gRPC repetidas entre servicios.
  • Reducir la eliminando los cálculos repetitivos y las lecturas de la base de datos en el backend.
  • Aumentar la fiabilidad suministrando datos almacenados en caché cuando los servicios de origen sean lentos o no estén disponibles.
  • Reducción de los costes de infraestructura gracias a la reducción del uso innecesario de recursos informáticos y de bases de datos.
  • Reducir el esfuerzo de ingeniería al proporcionar una caché centralizada en lugar de exigir que cada servicio cree su propia capa de almacenamiento en caché.

Desde su lanzamiento, Entity Cache se ha implementado en numerosos puntos finales de los niveles 0 y 1 con baja mutación. En la actualidad, atiende más de 1,5 millones de solicitudes por segundo, alcanza tasas de acierto en caché superiores al 90 % en muchos puntos finales y se ha convertido en una capa de rendimiento y fiabilidad para toda la plataforma, construida sobre la base de la malla de servicios de DoorDash.

Descripción general de la arquitectura a alto nivel

Entity Cache se implementa como un proxy de almacenamiento en caché dedicado que se integra con nuestra malla de servicios basada en Envoy. Los servicios de los clientes no tienen que modificar su código. Tal y como se muestra en la figura 1, la malla de servicios redirige automáticamente las solicitudes salientes primero a Entity Cache, con el servicio de origen configurado como alternativa. Cuando llega una solicitud, Entity Cache comprueba si existe una respuesta válida almacenada en caché. Si es así, dicha respuesta se devuelve inmediatamente; en caso de que no haya ninguna respuesta en caché, la solicitud se reenvía al servicio de origen, que genera una respuesta que luego se almacena en caché para futuras solicitudes.

Figura 1: Entity Cache se sitúa entre la malla de servicios y los servicios de origen, sirviendo respuestas almacenadas en caché procedentes de Valkey cuando se produce una coincidencia y reenviando las solicitudes sin coincidencia a los servicios de origen para obtener datos actualizados. Tanto los eventos de invalidación de Kafka como Cache Advisor proporcionan señales de actualidad e incorporación, de modo que el almacenamiento en caché resulte seguro, transparente y se pueda gestionar de forma centralizada.
  • Ruta de la solicitud: Envoy redirige las solicitudes primero a Entity Cache y, si es necesario, recurre al servicio de origen. Si se encuentra la entrada en la caché, Entity Cache sirve la respuesta directamente desde Valkey, sin pasar por las dependencias de origen. Si no se encuentra la entrada, reenvía la solicitud al servicio de origen, almacena la respuesta en Valkey según la política de caché y la devuelve al cliente.
  • Proceso de invalidación de la caché: Cuando los datos subyacentes cambian, los servicios de origen emiten eventos de cambio como parte de sus flujos de trabajo normales de escritura. Estos eventos fluyen a través de Kafka hacia Entity Cache. En lugar de eliminar las entradas almacenadas en caché en todas las instancias, Entity Cache registra que se ha actualizado una entidad específica y anota la hora de la actualización. En cada solicitud, Entity Cache compara la hora en que se almacenó en caché la respuesta con la hora de actualización registrada. Si la respuesta almacenada en caché es anterior a la hora de actualización, se considera obsoleta. A continuación, Entity Cache recupera datos actualizados del servicio de origen y actualiza la caché. Este enfoque evita el complejo proceso de eliminación distribuida, al tiempo que garantiza que los datos actualizados se reflejen rápidamente.
  • Ruta de análisis del tráfico: Entity Cache comprueba continuamente la exactitud utilizando una muestra del tráfico de producción. Para un subconjunto de solicitudes, compara las respuestas almacenadas en caché con las respuestas en tiempo real de los servidores de origen y calcula la divergencia en segundo plano. Este mecanismo de validación garantiza que el almacenamiento en caché siga siendo preciso a lo largo del tiempo y proporciona la base de seguridad necesaria para implementaciones controladas. Para respaldar esto, hemos creado Cache Advisor, un servicio independiente centrado en identificar puntos finales con bajas tasas de mutación que sean buenos candidatos para el almacenamiento en caché. Se ejecuta de forma independiente en el punto de entrada de los servidores de origen utilizando el filtro de procesamiento externo de Envoy para observar los patrones de solicitud y detectar estas oportunidades.
  • Conmutación automática en caso de fallo: Envoy recurre automáticamente al servicio de origen si Entity Cache deja de estar disponible.

Funcionalidades implementadas

Entity Cache no es una única optimización, sino un conjunto de funciones centradas en la fiabilidad y el rendimiento, diseñadas para funcionar de forma conjunta a la escala de DoorDash. En esta sección se destacan los mecanismos fundamentales que hacen que el almacenamiento en caché sea seguro, predecible y eficaz en entorno de producción.

1. Degradación gradual con TTL duales: Como se muestra en la figura 2, Entity Cache utiliza dos umbrales de caducidad: un tiempo de vida (TTL) «blando» que define la frescura —por ejemplo, 60 segundos— y un TTL «duro» que define la antigüedad máxima absoluta —por ejemplo, cinco minutos—. En condiciones normales, los datos almacenados en caché se actualizan según la definición del TTL flexible. Cuando los servicios de origen se ralentizan o dejan de estar disponibles, Entity Cache sigue sirviendo datos ligeramente obsoletos desde la caché en lugar de propagar errores a los clientes.

Figura 2: La caché de entidades utiliza la antigüedad de los datos para decidir si servir los datos desde la caché, actualizarlos desde el servidor de origen o solicitar datos nuevos. La conclusión clave es que los TTL «blandos» permiten seguir sirviendo datos caducados de forma fluida cuando el servidor de origen es lento, mientras que los TTL «duros» obligan a realizar una nueva consulta una vez superada la antigüedad máxima.

Este diseño resultó fundamental durante una interrupción del servicio en la fase inicial que se prolongó durante varias horas, ya que Entity Cache siguió proporcionando datos almacenados en caché obsoletos, pero válidos, en lugar de fallar, lo que evitó un incidente que hubiera afectado a toda la plataforma.

2. Invalidación de la caché en tiempo real con listas de exclusión: la eliminación directa en una flota de proxies distribuidos requeriría reconstruir las claves de la caché, coordinar entre pods y gestionar condiciones de carrera en las que los datos obsoletos podrían volver a escribirse inmediatamente después de su eliminación. Además, supone una sobrecarga de memoria para el seguimiento de las asociaciones de claves. El enfoque basado en marcas de tiempo evita la coordinación entre pods y sigue siendo correcto incluso si los eventos llegan desordenados.

Tradicionalmente, el almacenamiento en caché obliga a elegir entre TTL largos, que favorecen el rendimiento, y TTL cortos, que favorecen la consistencia. Entity Cache resuelve este problema mediante la invalidación basada en eventos, utilizando una lista de exclusión. Cuando los datos subyacentes cambian, los servicios de origen publican un evento de invalidación en Kafka. Un consumidor de Entity Cache registra una marca de tiempo de invalidación en Valkey para la entidad y los identificadores afectados. Cuando se produce una coincidencia en la caché, Entity Cache comprueba esta entrada. Si el objeto almacenado en caché se recuperó antes de la marca de tiempo de invalidación, se considera obsoleto y se actualiza desde el origen. En lugar de eliminar las claves de la caché, el sistema se basa en la comparación de marcas de tiempo. Cada objeto almacenado en caché guarda su hora de recuperación; la invalidación simplemente registra una marca de tiempo más reciente. Este diseño permite a los puntos finales mantener TTL flexibles de larga duración para obtener altas tasas de aciertos, al tiempo que se logra una consistencia casi en tiempo real, con una latencia de invalidación P99 fijada en aproximadamente un segundo.

3. Detección de valores atípicos basada en Envoy — con conmutación automática por error: Entity Cache se integra con nuestra malla de servicios basada en Envoy. Tal y como se muestra en la figura 3, Envoy supervisa el estado de los pods de caché y expulsa automáticamente de la piscina de equilibrio de carga aquellos que no funcionan correctamente. Si todos los pods de caché dejan de funcionar correctamente, Envoy redirige el tráfico directamente a los servicios de origen, lo que garantiza la disponibilidad incluso en caso de fallos totales de la caché.

Figura 3: La malla de servicios envía el tráfico normal a los pods de Entity Cache que funcionan correctamente y excluye de la ruta de equilibrio de carga a los pods que no funcionan correctamente. Si la ruta de la caché no está disponible, el tráfico se redirige por completo al servicio de origen, lo que garantiza la disponibilidad.

Este diseño de recambio automático permite que Entity Cache aumente la resiliencia sin introducir un nuevo punto único de fallo. Durante la puesta en marcha, si una configuración incorrecta provoca que los pods de caché dejen de funcionar, el tráfico se redirige automáticamente a la fuente original. Los equipos pueden habilitar el almacenamiento en caché con total confianza.

Escalabilidad hasta millones de solicitudes por segundo

El hecho de gestionar millones de solicitudes por segundo provocó cuellos de botella a nivel del sistema, en los que las pequeñas ineficiencias se amplificaban rápidamente. La asignación de memoria, la coordinación de solicitudes y el comportamiento de la caché comenzaron a afectar a la latencia de cola y a la estabilidad de las etapas anteriores. Para mantener el rendimiento, nos centramos en reducir la contienda, suavizar los patrones de tráfico y eliminar el trabajo redundante en las rutas más transitadas.

  • Gestión de la memoria a gran escala: las asignaciones frecuentes en las rutas más transitadas aumentaban la presión sobre la recolección de basura (GC) y provocaban picos de latencia. Implementamos un sistema personalizado de agrupación de búferes para reutilizar la memoria y minimizar las asignaciones. Esto redujo la sobrecarga de la GC, estabilizó el uso de la memoria y redujo la latencia de sobrecarga de las solicitudes P99 a unos 2,1 ms, al tiempo que se mantenía un rendimiento constante.
  • Avalancha de caché a gran escala: en el caso de las entidades muy solicitadas, la caducidad basada en el TTL concentraba el tráfico de actualización en un único momento, lo que provocaba picos en la carga de origen. Implementamos una actualización anticipada probabilística basada en el algoritmo XFetch. A medida que las entradas se acercan a su TTL flexible, cada solicitud tiene una probabilidad cada vez mayor de desencadenar una actualización. Esto distribuye el tráfico a lo largo del tiempo, reduciendo los picos y estabilizando la carga de origen.
  • Concurrencia a escala de millones de solicitudes: las solicitudes concurrentes solían duplicar el mismo trabajo, especialmente en el establecimiento de conexiones y en las faltas de caché con claves muy solicitadas. Introdujimos un patrón de «vuelo único» utilizando estructuras atómicas y sin bloqueos. La técnica «compare and swap» garantiza que solo una goroutine realice una conexión o una recuperación por clave, mientras que las demás reutilizan el resultado. La deduplicación se lleva a cabo por pod sin necesidad de coordinación entre pods. Esto eliminó el trabajo redundante y redujo la contienda. El rendimiento por pod se multiplicó aproximadamente por cinco, las tasas de asignación disminuyeron entre un 50 % y un 60 %, y los picos de latencia P99 se redujeron hasta en un 80 %.
  • Identificar qué elementos almacenar en caché: con miles de puntos finales, identificar manualmente los candidatos más adecuados para el almacenamiento en caché no resultaba escalable. 

Hemos desarrollado Cache Advisor para analizar el tráfico real de producción y orientar la implementación. Al ejecutarse en el punto de entrada a través del filtro de procesamiento externo de Envoy, toma muestras de las solicitudes, supervisa la estabilidad de las respuestas y calcula la frecuencia de actualización. Recomienda valores de TTL y destaca las mejores opciones. De este modo, se identificaron más de 130 oportunidades de implementación, lo que permitió una adopción más amplia y segura del almacenamiento en caché.

Repercusión en los usuarios y las empresas

Entity Cache se ha convertido en una capa fundamental de fiabilidad en DoorDash, y actualmente gestiona más de 1,5 millones de solicitudes por segundo con un 99,99999 % de disponibilidad. Se han incorporado más de 100 puntos de conexión repartidos en 50 servicios, lo que ha supuesto mejoras cuantificables en cuanto a latencia, escalabilidad y resistencia ante fallos.

Desde el punto de vista del rendimiento, Entity Cache añade una sobrecarga mínima a la vez que ofrece mejoras sustanciales:

  • Latencia de overhead de las solicitudes P99 de aproximadamente 2,1 ms
  • Índice de aciertos en la caché que se mantiene constantemente por encima del 90 %
  • Reducción del 60 % al 95 % en las solicitudes de los servidores de origen durante el funcionamiento normal
  • Reducción de la latencia de hasta el 90 % para los terminales recién incorporados
  • Incluso en el caso de los servicios con cachés locales, la latencia de extremo a extremo suele reducirse aproximadamente a la mitad debido al menor número de llamadas de red entre servicios en la salida del cliente.

Más allá del rendimiento, Entity Cache ha reforzado considerablemente la fiabilidad de la plataforma. Durante varios incidentes en producción, evitó que hasta el 90 % de las solicitudes llegaran a servicios de nivel superior que presentaban un deterioro en el servicio. Al proporcionar datos obsoletos pero válidos cuando era necesario, ha protegido los servicios frente a las interrupciones de los servicios de nivel superior, ha eliminado la amplificación provocada por picos de tráfico mediante la actualización probabilística y ha reducido el alcance de los picos de tráfico.

La supervisión continua de las divergencias permite una adopción segura, lo que da a los equipos la confianza necesaria para habilitar el almacenamiento en caché sin poner en riesgo la exactitud de los datos. Si bien el ahorro en los costes de infraestructura es un efecto secundario, la reducción de la carga en las etapas iniciales también ha disminuido los requisitos de aprovisionamiento y ha mejorado la eficiencia general en toda la plataforma.

Próximos pasos

  1. Distribución dinámica del tráfico basada en la comparación de tasas de error: En la actualidad, la distribución del tráfico entre la caché de entidades y el servidor de origen se basa en una configuración estática. Estamos desarrollando un sistema de redireccionamiento dinámico del tráfico que ajusta el enrutamiento en función de comparaciones en tiempo real de las tasas de error, enviando más tráfico al servidor de origen cuando el estado de la caché se deteriora y volviendo a la configuración anterior a medida que el estado mejora.
  2. Aislamiento de «vecinos ruidosos» por clúster de caché de origen: actualmente , todos los servicios comparten un único clúster de caché. Estamos avanzando hacia clústeres de caché dedicados para cada servicio de alto tráfico, con el fin de establecer límites de recursos bien definidos y evitar que los problemas de un servicio afecten a los demás.
  3. Limitación adaptativa de la concurrencia: los límites de concurrencia estáticos no son óptimos, ya que o bien desperdician capacidad cuando la carga es baja, o bien provocan picos de latencia cuando la carga es alta. Estamos implementando una limitación adaptativa que mide continuamente el rendimiento del sistema y ajusta automáticamente la concurrencia en función de la latencia y el rendimiento observados, lo que permite maximizar la capacidad al tiempo que se mantienen los objetivos de latencia.

Agradecimientos

La creación de Entity Cache fue un esfuerzo colaborativo en el que participaron numerosos equipos de DoorDash. Nos gustaría agradecer especialmente al equipo de Infraestructura Básica: Dakota Baber, Hochuen Wong, Yifan Yang y Tejas Lodaya, cuyas aportaciones fueron inestimables para desarrollar, gestionar y ampliar la plataforma.

También queremos expresar nuestro agradecimiento a Ivar Lazzaro, Muneeb Ansari, Karthik Katooru, Pushkar Raste, Matt Ranney, Thai Pham, Allen Meng, Madhav Gali, Jay Weinstein, Matt Zimmerman y Sebastian Yates por su orientación, sus comentarios y su apoyo a lo largo de todo el proyecto.