Serie: Aprender a programar con IA

Hoy, todos los llamadores de LLM recibieron barreras de longitud de prompt

Un pico de costo, una auditoría, y barreras de longitud de prompt en cada llamador de LLM.

Cada llamador de LLM, una barrera Presupuestos de tokens por llamador, jerarquía de truncamiento, telemetría, aplicación en CI SIN LÍMITE 5 llamadores, sin tope de longitud ACOTADO presupuestado, registrado, acotado LLMCallGuard Truncar y registrar Respaldo grueso Fallar ruidosamente Puerta de regresión en CI
Una barrera compartida convierte la amplificación silenciosa de costo en un fallo ruidoso y acotado.

Un prompt sin límite es un ataque de amplificación de costo esperando ocurrir. RakuAI trata la disciplina de longitud de prompt como infraestructura de seguridad, aplicada en el build, no dejada a la memoria.

El runtime llama a LLMs en más lugares de los que había estado rastreando. Está el obvio (el XRAssistantService que impulsa experiencias de AR basadas en voz). Está el menos obvio (la capa de comportamiento de NPC, donde el cerebro de un agente en el mundo es parcialmente una llamada a un LLM). Está el menos obvio de todos (herramientas de tiempo de desarrollo que han empezado a colarse en el build del runtime: validadores de esquema, analizadores de depuración, un resumidor automático de playtest).

Cada uno de esos lugares se había escrito de forma independiente durante los últimos seis meses. Cada uno se revisó en el momento del PR. Ninguno de ellos, hasta este fin de semana, tenía una disciplina uniforme sobre la longitud de prompt.

Este es el post sobre por qué eso se convirtió en un problema, qué encontró la auditoría, y cómo se ven las nuevas barreras.

Cómo salió a la luz el problema

El disparador fue una verificación rutinaria de monitoreo de costos. Al revisar el gasto diario de la API de LLM, un entorno de desarrollo específico estaba gastando quince veces lo que los demás. Mismo número de agentes, misma carga de trabajo de prueba, mismo modelo. Quince veces el costo.

Rastrear el pico llevó a la ruta de código del resumidor de playtest. El resumidor toma una sesión de playtest terminada, empaqueta el estado de escena relevante en un prompt, lo envía a un LLM en la nube, y recibe de vuelta un análisis estructurado de la sesión. La función se había escrito cuando las escenas eran pequeñas. El “estado de escena relevante” era un resumen estructurado de lo ocurrido. Con el tiempo, el resumen había crecido. Un entorno de desarrollo específico había estado ejecutando playtests largos que producían resúmenes enormes. El resumidor enviaba esos resúmenes sin verificar al modelo. El modelo cobraba por token.

La corrección para ese llamador individual fue obvia. Limitar la longitud del resumen. Truncar si es necesario. Registrar cuándo ocurre el truncamiento.

La pregunta más profunda fue la que hice a continuación: ¿cuántos otros llamadores en el runtime tienen la misma vulnerabilidad? Fui a averiguarlo. La auditoría fue el trabajo real.

Qué encontró la auditoría

Once lugares en el runtime que llaman a un LLM. De esos once:

  • Dos tenían verificaciones explícitas de longitud y comportamiento razonable ante el desbordamiento (truncar, registrar, reintentar con contexto más pequeño). Estos estaban bien.
  • Cinco no tenían ninguna verificación de longitud. Enviaban lo que fuera que el llamador les entregara.
  • Tres tenían una verificación de longitud pero era demasiado generosa para ser útil (cien mil tokens, muy por encima de cualquier uso sensato pero muy por debajo de lo catastrófico).
  • Uno era una ruta de depuración que no debería haber estado en el binario de producción en absoluto; tenía una verificación de longitud pero se podía eludir fácilmente mediante una bandera de depuración.

Los cinco sin verificación de longitud eran los urgentes. Cubrían: el resumidor de playtest (ya identificado), el cerebro de comportamiento de NPC (potencialmente enorme si un NPC podía observar una escena compleja), el validador de esquema (podía recibir un archivo arbitrario), el descriptor de estado del mundo (podía describir un fragmento de mundo arbitrariamente grande), y una de las herramientas de diagnóstico orientadas al desarrollador.

Cada uno de estos había aterrizado en un PR separado. Cada PR había sido razonable de forma aislada. La disciplina agregada de “cada llamador de LLM tiene un tope de longitud” no había sido trabajo de nadie. Así que nadie lo había hecho.

Cómo se ven las barreras

Una pequeña pieza de infraestructura aterrizó el sábado por la mañana y se aplicó a cada llamador a lo largo del día.

Una utilidad compartida LLMCallGuard. Cada lugar que habla con un LLM ahora pasa por esta utilidad en lugar de construir solicitudes directamente. La utilidad toma una plantilla de prompt, un payload de contexto, y un modelo objetivo. Hace cumplir un tope de longitud (configurable por modelo, con valores por defecto sensatos basados en la ventana de contexto documentada del modelo). Registra la longitud real del prompt usado en nivel INFO para el caso presupuestado, en nivel WARNING cuando tiene que truncar, y en nivel ERROR cuando el truncamiento no logra ajustarse al tope.

Presupuestos por llamador. Cada llamador de LLM en el runtime ahora tiene un presupuesto explícito de tokens por llamada. El presupuesto está por debajo de la ventana de contexto del modelo porque queremos dejar margen para la respuesta y queremos fallar de forma ruidosa antes de que el modelo falle silenciosamente. Los presupuestos van de unos pocos miles de tokens (el validador de esquema) a veinte mil tokens (el resumidor de playtest, con un tope real que previene el incidente original).

Telemetría. Cada llamada a un LLM ahora registra el tamaño del prompt, el tamaño de la respuesta, el modelo, el presupuesto consumido, y la latencia. La telemetría es lo que me permite notar el próximo incidente antes de que llegue la factura.

Una jerarquía de modos de fallo. Cuando el payload de un llamador excede el presupuesto, la utilidad intenta una secuencia de correcciones en orden. Primero, intenta truncar de forma inteligente (preservar el contexto más reciente, descartar el más antiguo, mantener intacto el prompt de sistema). Segundo, si el truncamiento inteligente aún no encaja, intenta un truncamiento más grueso (descartar secciones enteras). Tercero, si ningún truncamiento encaja, falla ruidosamente con un error claro en lugar de enviar una solicitud sobredimensionada que el modelo rechazará. La jerarquía significa que la mayoría de los casos se recuperan con elegancia, los casos extremos fallan de forma observable, y ningún llamador jamás envía un payload sin límite.

Una verificación de CI que evita la regresión. El código nuevo que habla con un LLM tiene que pasar por LLMCallGuard. El escaneo de CI encuentra cualquier llamada directa nueva a un LLM que elude la utilidad y marca el PR. El patrón es el mismo que usó la auditoría de seguridad hace unos fines de semana para los endpoints de administración: hacer cumplir la disciplina en el build, no en la revisión.

Qué aprendí

Tres cosas.

La disciplina que no es trabajo de nadie es disciplina que no ocurre. Los once llamadores de LLM habían sido cada uno razonables en el momento del PR. El comportamiento colectivo no se había revisado porque nadie era dueño de la preocupación transversal. La corrección fue convertir la preocupación transversal en una pieza de infraestructura por la que cada llamador tiene que pasar, lo que hace que la disciplina sea imposible de olvidar.

El costo es una preocupación de seguridad. Había estado pensando en los “prompts sin límite” como una preocupación de corrección o robustez. El pico de costo del entorno de desarrollo me enseñó a pensarlo como una preocupación de seguridad. Un atacante que pueda influir en el contenido de una llamada a un LLM desde el runtime puede acumular un costo arbitrario en el operador. Las mismas defensas (topes de longitud, aplicación de presupuesto, telemetría) protegen tanto contra fallos de robustez como contra ataques de amplificación de costo.

Auditar con una cadencia. La auditoría de hoy encontró cinco vulnerabilidades que la revisión de PR había pasado por alto. La próxima auditoría encontrará otras. La disciplina de ejecutar un pase de auditoría programado sobre una preocupación transversal específica es la única forma confiable que he encontrado para sacar a la luz las cosas que la revisión pasa por alto.

Qué deberían llevarse los socios y constructores de esto

Si estás ejecutando algo que llama a un LLM desde código de producción y no has auditado cada llamador en busca de disciplina de longitud de prompt, hazlo. La auditoría es pequeña. Los hallazgos son probables. El costo de hacerlo hoy es mucho menor que el costo de hacerlo después de un incidente.

Si eres un laboratorio de IA construyendo agentes que llaman a otros LLMs, la métrica a optimizar es “si el agente señala cuando está construyendo un prompt sin límite.” La mayoría de los agentes no lo hacen. Los que sí lo hacen son en los que confío para trabajo serio.

Si estás evaluando un motor para una asociación y el motor se integra con LLMs en la nube, pregunta sobre la disciplina de longitud de prompt. La respuesta correcta es “cada llamador pasa por una utilidad compartida, con presupuestos por llamador, con telemetría, con un guardián de CI.” La respuesta equivocada es “todavía no hemos visto ese problema.”

Sábado por la tarde. Cada llamador de LLM en el runtime ahora pasa por la misma barrera. La próxima cadencia de auditoría está en el calendario.

De vuelta a construir.

Construye sobre un runtime que protege cada llamada a un LLM

RakuAI es el runtime espacial nativo de IA que tu modelo impulsa en producción, con presupuestos de longitud de prompt, telemetría, y aplicación en CI integrados en el límite. Descubre lo que la infraestructura disciplinada desbloquea para tu stack.

← Todas las entradas