8 min de lectura

Cómo colisionan los agentes de IA concurrentes en cuentas de producción

Los agentes de IA concurrentes pueden sobrescribirse en producción. Define límites de propiedad, rechaza escrituras obsoletas, usa las concesiones temporales con cuidado y audita cada acción.

Cómo colisionan los agentes de IA concurrentes en cuentas de producción

Dos ejecuciones autónomas sobre una misma cuenta de producción no se vuelven seguras porque cada una tenga una descripción de tarea diferente. Comparten un sistema mutable y cualquier plan que elaboren puede quedar obsoleto antes de la siguiente llamada a la API. Si ambas pueden cambiar el mismo recurso, necesitas un límite de propiedad que el servicio haga cumplir.

El fallo habitual es más silencioso que una caída espectacular. Un agente añade un miembro a un grupo mientras otro sustituye toda la pertenencia del grupo a partir de una lectura antigua. Ambas solicitudes devuelven éxito. La solicitud posterior elimina al miembro que añadió la primera. Cada ejecución siguió sus instrucciones. La API aceptó una secuencia incorrecta.

Trata cada ejecución de un agente como un cliente concurrente no confiable, con credenciales reales y tiempos imperfectos. Dale un área limitada de la que sea responsable, condiciona las solicitudes de escritura a la versión que leyó y registra suficiente contexto para explicar después un cambio rechazado o aceptado. La revisión humana sigue siendo útil, pero no puede sustituir a un receptor que detecte estados obsoletos.

Separa el límite de la tarea del límite de escritura

El límite de una tarea indica lo que se pidió lograr a un agente. El límite de escritura indica qué objetos mutables puede cambiar. Son cosas distintas, y los equipos sufren cuando las tratan como intercambiables.

«Actualiza el despliegue de staging» parece una instrucción limitada. Aun así, puede tocar una etiqueta de imagen compartida, un indicador de lanzamiento, una regla de tráfico, un registro DNS, un registro de migraciones de base de datos y un canal de notificaciones. Un agente puede obedecer el texto de la tarea y chocar con una ejecución de lanzamiento que sea responsable de uno de esos objetos.

Define la propiedad en términos que el servicio receptor pueda comprobar. Los buenos límites nombran identificadores de recursos persistentes, no categorías vagas de trabajo:

  • un entorno y un registro de despliegue
  • un inquilino o una cuenta de cliente
  • una solicitud de extracción y su rama
  • un ticket de incidente y los recursos incluidos en su conjunto de cambios
  • una ventana de mantenimiento con una lista explícita de objetivos

Evita límites como «trabajo del backend» o «limpieza de producción». Son etiquetas para personas. No indican a una API qué escritura debería fallar.

Un registro de propiedad útil contiene el ID de ejecución, el ID del recurso, la operación permitida y la caducidad. Guárdalo cerca del servicio que controla el recurso. Si un controlador de despliegues es responsable del indicador de lanzamiento, ese controlador debe validar quién puede avanzarlo. Una hoja de cálculo, un mensaje de chat o una instrucción del prompt no pueden bloquear una solicitud que llega después de que la persona que la escribió se haya ido a casa.

Crea un pequeño mapa de conflictos antes de conceder acceso de escritura

Para cada trabajo automatizado, enumera los recursos que lee, escribe, elimina y usa como valor compartido predeterminado. Después, marca cada par de trabajos que pueda escribir el mismo identificador o cuyo dato de entrada pueda ser cambiado por el otro. No es burocracia. Saca a la luz colisiones que los permisos basados en roles ocultan.

Por ejemplo, un agente que rota un token de servicio y otro que actualiza la configuración de una integración quizá nunca llamen al mismo endpoint. El escritor de la configuración puede leer la referencia al token actual y publicar después el documento de configuración completo, cuando la rotación ya haya cambiado esa referencia. El conflicto está en la versión del documento, no en un comando idéntico.

Si no puedes describir el conjunto de escritura de una ejecución, no le concedas permisos amplios de escritura en producción. Haz que prepare una propuesta o limítala a un espacio de nombres de recursos hasta que puedas describir el límite.

Una respuesta correcta todavía puede borrar un cambio válido

El comportamiento de «gana la última escritura» es una política de pérdida de datos cuando los clientes envían representaciones completas. Parece inofensivo en las demostraciones porque cada cliente lee y escribe de inmediato. Los agentes suelen pasar minutos inspeccionando registros, generando un plan, solicitando aprobación y reintentando una llamada después de un tiempo de espera agotado.

Considera un servicio con un recurso notification-policy. Devuelve esta representación al agente A:

{
  "id": "prod-alerts",
  "version": 41,
  "destinations": ["[email protected]"],
  "severity": "high"
}

El agente A planea añadir un destino de respaldo. Durante la revisión, el agente B cambia severity de high a critical y escribe correctamente la versión 42. Entonces, el agente A envía una sustitución completa basada en la versión 41:

{
  "destinations": ["[email protected]", "[email protected]"],
  "severity": "high"
}

Si el endpoint acepta la solicitud, deshace silenciosamente el cambio de B. Ningún agente necesita tener un error. La API permitió que una observación antigua sobrescribiera un hecho más reciente.

Las actualizaciones parciales reducen el área expuesta, pero no eliminan el problema. Un parche que añade un destino todavía puede infringir una cuota nueva, una política de enrutamiento actualizada o una eliminación ocurrida después de la lectura. El servicio debe decidir si el parche sigue siendo válido frente al estado actual.

Por eso, «solo dejamos que los agentes usen PATCH» no es un diseño de concurrencia. Es una forma de escritura más pequeña. Sigues necesitando una condición que conecte la escritura con el estado que observó el agente.

Condiciona cada solicitud que cambie el estado

El control de concurrencia optimista suele ser la primera defensa adecuada para las escrituras de los agentes. El cliente lee una versión, una etiqueta ETag, un número de generación o un token de revisión. Después lo devuelve junto con la actualización prevista. El servicio acepta la escritura solo si el valor actual sigue coincidiendo.

RFC 9110 define If-Match precisamente para este tipo de solicitud. El servidor evalúa la condición antes de aplicar el método. Si la etiqueta de entidad ya no coincide, el servidor rechaza el método con 412 Precondition Failed. No es una molestia de la API. Es el servidor negándose a fingir que un plan obsoleto sigue siendo correcto.

Una actualización HTTP condicional puede tener este aspecto:

GET /v1/notification-policies/prod-alerts

HTTP/1.1 200 OK
ETag: "41"
Content-Type: application/json

{"destinations":["[email protected]"],"severity":"high"}

El agente lleva esa ETag a su escritura:

PATCH /v1/notification-policies/prod-alerts
If-Match: "41"
Content-Type: application/json
Idempotency-Key: run-7f3c-add-backup

{"destinations":["[email protected]","[email protected]"]}

Si otro escritor ha producido la ETag "42", devuelve un rechazo claro:

HTTP/1.1 412 Precondition Failed
Content-Type: application/json

{
  "error": "stale_version",
  "resource": "notification-policy/prod-alerts",
  "expected_etag": "41",
  "current_etag": "42",
  "retryable": false
}

No marques este error como reintentable si el agente puede reenviar ciegamente el mismo cuerpo. Un reintento debe empezar con una lectura actualizada y una decisión nueva. Puede descubrir que el resultado deseado ya existe, que la política más reciente invalida el cambio o que una persona debe elegir entre dos resultados enfrentados.

En las bases de datos, usa el predicado equivalente dentro de la propia mutación. Una actualización típica comprueba la versión en la cláusula WHERE y trata cero filas afectadas como un conflicto:

UPDATE notification_policy
SET destinations = :destinations,
    version = version + 1
WHERE id = :id
  AND version = :observed_version;

Nunca leas una versión y después emitas una actualización incondicional en una segunda operación. La comprobación y el cambio de estado deben producirse juntos en la autoridad que almacena el estado.

La idempotencia detiene duplicados, no desacuerdos

Los equipos suelen poner una clave de idempotencia en un endpoint y declarar resueltas las escrituras concurrentes. Una clave de idempotencia evita que la misma solicitud lógica produzca su efecto dos veces. No indica al servicio si dos solicitudes diferentes son compatibles.

Un tiempo de espera agotado en la red hace concreta esta diferencia. Un agente envía una solicitud para crear un despliegue, pero pierde la respuesta. Al reintentar con la misma clave de idempotencia, debería recibir el resultado original en lugar de crear un segundo despliegue. Eso es supresión de duplicados.

Ahora imagina dos agentes que seleccionan candidatos de lanzamiento diferentes para el mismo entorno de producción. Envían cuerpos diferentes y claves de idempotencia diferentes. Ambas solicitudes pueden ser perfectamente idempotentes y, aun así, una debería perder porque el indicador de lanzamiento ha cambiado.

Usa ambos controles en los endpoints de escritura importantes:

  • Una clave de idempotencia vincula los reintentos y las entregas duplicadas con una sola operación completada.
  • Una precondición de versión rechaza una escritura cuya decisión depende de un estado obsoleto del recurso.
  • Una invariante del lado del servidor comprueba reglas que deben mantenerse incluso en una escritura actual, como un número máximo de credenciales activas.

Guarda la clave de idempotencia junto con una huella de la solicitud y la respuesta completada. Si el autor reutiliza la clave con un cuerpo diferente, recházala. Devolver la primera respuesta para una operación distinta crea un caos de depuración y puede ocultar un error del cliente.

Sé estricto con la caducidad. Un servicio debe conservar una clave el tiempo suficiente para cubrir su comportamiento real de reintentos, pero un almacén de idempotencia no es un historial permanente de comandos. El registro de auditoría es donde conservas el historial.

Usa concesiones temporales solo para trabajos que no pueden solaparse

Detén todas las acciones de los agentes
Bloquea el almacén con Touch ID para denegar todas las acciones hasta que una persona lo desbloquee.

Algunas acciones duran tanto que las comprobaciones optimistas por sí solas empeoran la experiencia. Una migración de base de datos, un trabajo de reconciliación destructivo o un cambio de operación pueden implicar muchas escrituras dependientes. En esos casos, concede a una ejecución una concesión temporal breve sobre el recurso.

Una concesión temporal debe tener un propietario, una caducidad y un valor de cercado. El valor de cercado importa porque un trabajador cuya concesión haya caducado puede despertar y continuar después de que otro trabajador haya adquirido una nueva. Cada escritura protegida debe llevar el token monotónicamente creciente de la concesión, y el servicio debe rechazar un token más antiguo que el último aceptado.

Sin cercado, un servicio de bloqueos puede informar al agente A de que su concesión caducó, pero no puede impedir que una solicitud retrasada de A llegue a la base de datos. El servicio de destino tiene que rechazarla. Este es el paso que los equipos omiten cuando dicen que tienen un bloqueo distribuido.

Mantén las concesiones limitadas y breves. No bloquees «producción» durante toda una investigación autónoma. Bloquea migration/customer-1842 o release/prod-eu, y haz que la ejecución renueve la concesión solo mientras siga avanzando. Una concesión debe caducar de forma segura si desaparece el proceso del agente, su portátil o su red.

No uses una concesión para cubrir ediciones de configuración normales que admiten comprobaciones de versión. Los bloqueos largos convierten los cambios rutinarios en colas y después la gente aprende a saltárselos. Una respuesta 412 seguida de un plan actualizado cuesta menos que una caída causada por un titular de bloqueo obsoleto.

La identidad del agente debe sobrevivir a la puerta de enlace

Un token de producción compartido da a todas las ejecuciones el mismo nombre en el servicio. Después de una colisión, puedes ver que actuó el token, pero no qué proceso planificó el cambio, qué aprobación lo cubría o qué ejecución debes detener. Eso hace lenta la limpieza y demasiado amplia la revocación.

Da a cada proceso de agente una identidad de sesión distinta y transmite después un identificador de correlación estable a cada solicitud de destino. El servicio de destino debe registrar la identidad, el ID de ejecución, el ID de solicitud, el recurso objetivo, la versión observada, el resultado y su propia versión resultante. No escondas esta información en prosa dentro de un mensaje de commit.

Sallyport mantiene las credenciales de API y SSH fuera del proceso del agente mientras ejecuta la acción, lo que ayuda a conservar un límite entre el contexto de planificación del agente y el secreto. Su autorización por sesión puede identificar un proceso de agente recién iniciado antes de que ese proceso comience una ejecución. Esa autorización controla quién puede actuar, pero no sustituye a las precondiciones del lado del destino.

No permitas que el agente elija su propia identidad efectiva en una cabecera arbitraria. Haz que la puerta de enlace o el servicio de destino vinculen la identidad a partir de una sesión autenticada. De lo contrario, una ejecución puede afirmar después que era el coordinador de despliegues y tus registros se convierten en una representación vacía.

En SSH se aplica el mismo principio, aunque el protocolo de red sea distinto. Usa principales separados o cuentas restringidas para clases de trabajo diferentes. Haz que los registros de comandos remotos incluyan un identificador de ejecución y evita una única cuenta de shell compartida que pueda editar todos los directorios de las aplicaciones.

El momento de la aprobación no es el momento de la transacción

Revoca una ejecución en conflicto
Sessions registra cada ejecución de agente, para que puedas revocar un proceso cuando aparezca trabajo en conflicto.

Una persona puede aprobar la solicitud de un agente y aun así aprobar una escritura que se vuelva incorrecta diez segundos después. Es normal en un sistema concurrente. La aprobación se refiere a la autoridad y la intención en el momento de la revisión. No congela el recurso.

El diseño peligroso pide a una persona que apruebe una frase amplia como «actualizar la configuración de producción» y después permite que el agente realice una secuencia de lecturas y escrituras cuando llegue a ellas. Un diseño más seguro muestra el objetivo y el efecto previsto, y deja que el servicio haga cumplir la versión o la concesión cuando llegue la escritura.

Cuando una precondición falla después de la aprobación, no reutilices automáticamente esa aprobación para un plan modificado. El agente debe informar del conflicto con términos concretos: qué recurso cambió, qué versión observó, qué campo cambió si el servicio puede determinarlo y si su resultado propuesto sigue siendo necesario. Entonces una persona puede aprobar una acción nueva o el agente puede realizar una operación inocua después de volver a leer.

La aprobación por llamada es adecuada para operaciones en las que cada uso entraña un riesgo considerable, como eliminar una credencial de producción o cambiar una regla de enrutamiento visible externamente. Para lotes normales de escrituras limitadas y condicionales, la aprobación por ejecución suele ser más útil, porque permite al operador revisar la identidad y el alcance sin crear el hábito de hacer clic de forma automática.

No confundas un montón de aprobaciones con control. Si los operadores no pueden ver el ID del recurso, la operación y el resultado actual del conflicto, están aprobando una frase mientras el servicio hace el trabajo real en otro lugar.

Una respuesta de conflicto necesita un responsable definido

Una escritura obsoleta rechazada es un resultado de seguridad correcto, pero solo si la ejecución sabe qué hacer después. «Reintentar ante un error» es el valor predeterminado equivocado. Convierte un desacuerdo en una carrera automatizada.

Clasifica cada ruta de escritura antes de permitir la ejecución autónoma. La clase determina quién resuelve el conflicto:

Tipo de cambioAnte un conflicto de versiónResponsable
Añadir un recurso independiente con nombre únicoVolver a leer y reintentar si el nombre sigue libreAgente
Actualizar un campo calculado a partir de datos actualesVolver a leer, recalcular y reintentarAgente
Avanzar un indicador de lanzamiento compartidoDetenerse y presentar ambas opcionesResponsable del lanzamiento
Cambiar la pertenencia a accesos o los permisosDetenerse y solicitar revisiónResponsable de la cuenta
Eliminar o sustituir un documento de configuración compartidoDetenerse salvo que una concesión explícita lo cubraOperador designado

La idea no es volver cautos a los agentes. Es distinguir el recálculo del juicio. Un agente puede reintentar de forma segura un informe generado a partir de entradas actuales. No debería elegir entre dos versiones de producción aprobadas, dos decisiones de acceso o dos planes de reversión distintos solo porque haya visto un 412.

Haz que las respuestas de conflicto sean legibles por máquina. Incluye la identidad del recurso, la versión actual, la categoría del conflicto y si el endpoint permite un nuevo intento automático. Un 409 impreciso con una página de error HTML empuja al agente a adivinar.

Prueba la colisión que esperas que ocurra

No esperes al tráfico de producción para demostrar que tus comprobaciones funcionan. Crea una prueba que pause una ejecución entre la lectura y la escritura, permita que una segunda ejecución cambie el mismo recurso y después libere la primera. Verifica cuatro resultados:

  1. La primera escritura falla sin cambiar el recurso.
  2. La respuesta identifica una versión obsoleta, no un error genérico del servidor.
  3. El agente no reenvía automáticamente su cuerpo antiguo.
  4. Tus diarios pueden vincular ambos intentos con sus identidades de ejecución y aprobaciones.

Ejecuta la misma prueba con un tiempo de espera agotado y un reintento para demostrar que el comportamiento de idempotencia es independiente. Son rutas de fallo diferentes y necesitan resultados esperados distintos.

Audita la acción intentada y el estado resultante

Conserva pruebas resistentes a manipulaciones
Su registro de auditoría cifrado y encadenado mediante hashes conserva pruebas de las secuencias de acciones aceptadas y rechazadas.

Una cuenta de producción necesita dos registros después de una colisión de agentes: la ruta del comando y el historial autoritativo del recurso. Los registros de la puerta de enlace explican quién solicitó una acción y a través de qué sesión aprobada. Los registros del servicio explican si cambió el estado, qué versión ganó y por qué falló una solicitud.

No te conformes con un registro de actividad que diga «PATCH correcto». Registra el identificador del recurso, el método, el ID de correlación de la solicitud, la precondición enviada por el cliente, la clave de idempotencia o una referencia segura a ella, el estado de respuesta y la ETag resultante. Si tu servicio conserva un historial a nivel de campo, captura allí los campos modificados en lugar de intentar deducirlos de la transcripción del agente.

Sallyport proyecta sus diarios Sessions y Activity a partir de un registro de auditoría cifrado y encadenado mediante hashes. Si lo usas para acciones de agentes, ejecuta esta comprobación cuando investigues una secuencia cuestionada:

sp audit verify

El comando verifica la cadena sin conexión sobre el texto cifrado y no necesita la clave del almacén. Puede establecer si ese diario local permaneció intacto; compáralo con los registros de solicitudes del servicio de destino antes de afirmar que sabes qué ocurrió.

Aquí también importan las reglas de conservación y acceso. Una transcripción del agente puede incluir razonamientos erróneos o detalles operativos copiados, mientras que un diario de solicitudes debería ser un registro factual y compacto. Conserva las pruebas necesarias para reconstruir la autoridad y las transiciones de estado y limita quién puede consultarlas.

El paralelismo corresponde a conjuntos de recursos independientes

No necesitas una única cola global para todas las ejecuciones autónomas. Necesitas una regla que permita avanzar al trabajo independiente y haga explícita la mutación compartida. Divide por inquilino, entorno, rama del repositorio, servicio u otro espacio de nombres de recursos que el servicio pueda verificar.

Un diseño práctico de producción cuenta con un coordinador que asigna a cada ejecución un conjunto de escritura y concede credenciales o acceso a la puerta de enlace solo para ese conjunto. El coordinador no decide si cada cambio es acertado. Evita que dos trabajadores lleguen por accidente con autoridad superpuesta. Los servicios receptores siguen haciendo cumplir las versiones y las invariantes, porque los coordinadores fallan, las asignaciones cambian y las personas inician trabajos de emergencia fuera de la ruta normal.

Cuando una acción abarca varios recursos, evita llamarla un cambio atómico si los servicios no pueden realizar realmente una transacción conjunta. Registra el estado previsto, ordena las escrituras para que los pasos posteriores puedan validar los anteriores y define la compensación antes de ejecutar. Una acción de compensación también necesita una comprobación del estado actual. Volver a una instantánea antigua puede borrar un cambio legítimo ocurrido después de la ejecución original.

La primera prueba de producción debería ser deliberadamente aburrida: elige un recurso de configuración compartido, inicia dos ejecuciones de agente desde la misma versión y haz que propongan ediciones incompatibles. Si el servicio acepta ambas, corrige ese endpoint antes de dar a cualquiera de las ejecuciones un alcance mayor. La autonomía resulta menos interesante después de una colisión, y precisamente por eso conviene provocar primero la colisión en una prueba controlada.

FAQ

¿Qué se considera agentes de IA concurrentes?

Son concurrentes cuando sus periodos de autoridad se superponen y ambos pueden emitir una escritura que afecte al mismo estado real. Tener hilos de chat, máquinas o credenciales diferentes no cambia eso. Si una ejecución puede actuar sobre un estado que la otra observó antes, trátalas como concurrentes.

¿Pueden entrar en conflicto dos agentes si trabajan en repositorios diferentes?

Sí. Una cuenta de producción suele contener valores predeterminados compartidos, cuotas, vinculaciones de IAM, nombres DNS, configuraciones de facturación e indicadores de despliegue que pueden hacer que trabajos aparentemente independientes se crucen. La propiedad a nivel de recurso es más segura que asumir que proyectos separados implican áreas de impacto separadas.

¿Bastan las aprobaciones humanas para evitar conflictos entre agentes?

No. La aprobación demuestra que una persona permitió una solicitud en un momento concreto, pero no que la solicitud siga teniendo sentido después de que otro escritor cambie el estado. El servicio receptor debe rechazar las escrituras obsoletas mediante versiones, precondiciones, concesiones temporales o un control equivalente.

¿Cuándo debo usar una clave de idempotencia y cuándo una comprobación de versión?

Usa una clave de idempotencia cuando el riesgo sea que una solicitud repetida, causada por un reintento, un tiempo de espera agotado o una entrega duplicada, produzca el efecto dos veces. Usa una precondición de versión cuando el riesgo sea una actualización aparentemente válida basada en una representación antigua. Las API de escritura maduras suelen necesitar ambas.

¿Resuelven las escrituras concurrentes de agentes los bloqueos distribuidos?

Un bloqueo distribuido solo ayuda cuando todos los escritores lo respetan y su caducidad, propiedad y comportamiento ante fallos están definidos. No corrige un endpoint que acepta actualizaciones obsoletas. Empieza con precondiciones aplicadas por el servicio y añade concesiones temporales breves para trabajos exclusivos de larga duración si hace falta.

¿Debería tener cada agente de IA sus propias credenciales de producción?

Da a cada ejecución autónoma una identidad y un conjunto de permisos separados, aunque ambas actúen en nombre del mismo equipo. Las credenciales de administrador compartidas eliminan la trazabilidad y hacen que la revocación sea indiscriminada. La identidad del agente debe aparecer tanto en la puerta de enlace de acciones como en los registros del servicio de destino.

¿Qué debe ocurrir durante un cambio de emergencia en producción?

Una ejecución de emergencia sigue necesitando la misma protección contra conflictos en el servicio, porque la urgencia no convierte un estado obsoleto en correcto. Proporciona al operador una vía de emergencia documentada, con alcance limitado, caducidad breve y una revisión más estricta después. No crees una excepción permanente porque un agente la necesitara con rapidez una vez.

¿Qué debe registrar una pista de auditoría para las acciones de los agentes?

Un registro de escrituras debe conservar el recurso de destino, la identidad del actor, el identificador de la solicitud, la versión anterior, la transición solicitada, el resultado y la versión devuelta por el servicio. Una transcripción que diga que un agente «actualizó producción» es demasiado vaga para investigar una colisión. Mantén estable el identificador de correlación entre reintentos.

¿Pueden los agentes autónomos desplegarse en paralelo de forma segura?

Solo cuando cada cambio afecte a un recurso independiente y el servicio verifique ese límite. Por ejemplo, varias solicitudes de extracción independientes pueden ejecutarse a la vez, mientras que dos trabajos que modifiquen el indicador de lanzamiento de un mismo entorno deberían serializarse. El trabajo en paralelo es útil; la autoridad paralela sobre un objeto mutable suele ser imprudente.

¿Cómo puedo verificar un registro de auditoría de Sallyport?

sp audit verify comprueba la integridad del registro de auditoría cifrado y encadenado mediante hashes de Sallyport sin necesitar la clave del almacén. Puede mostrar si ese registro local de acciones fue alterado, pero no sustituye a los registros propios de solicitudes y recursos del servicio de destino. Compara ambos registros al investigar una escritura cuestionada.

Sallyport

Sallyport ejecuta llamadas de API y comandos SSH por tu agente de IA. Las claves se quedan en una bóveda local de tu Mac; tú apruebas cada ejecución y cada acción queda en un registro sellado.

© 2026 Sallyport · Código abierto bajo Apache-2.0 · Oleg Sotnikov