Registra un hash del arreglo de mensajes antes de cada llamada
Tu agente de IA no es tonto. Tu código está editando su memoria a sus espaldas. El modelo responde perfecto en un playground limpio y luego se descarrila apenas pasa por tu app. Antes de reportar un bug contra el modelo, mira lo único que tú controlas: el arreglo de mensajes (messages array) que envías en cada llamada.
Por qué el modelo está bien pero tu agente no
Las APIs de chat son sin estado (stateless). El proveedor no guarda memoria de tu conversación — tú eres dueño del historial completo y reenvías toda la lista de mensajes en cada request (Anthropic y OpenAI funcionan así). Ese diseño es limpio, pero significa que cada capa entre tu usuario y el modelo tiene la oportunidad de tocar el arreglo primero: un resumidor que recorta turnos viejos, un retriever que inyecta contexto, un middleware que reordena mensajes de sistema, un reintento que descarta el último turno. El modelo solo ve el arreglo que le entregas. Si ese arreglo está silenciosamente mal, la respuesta del modelo está silenciosamente mal — y parece que el modelo alucinó.
La auditoría de una línea: haz un hash del historial
No puedes revisar a ojo un arreglo de 40 mensajes en cada llamada. Así que no lo hagas. Calcula un hash estable de los mensajes justo antes de enviarlos, y regístralo:
import hashlib, json
def messages_fingerprint(messages):
blob = json.dumps(messages, sort_keys=True, ensure_ascii=False)
return hashlib.sha256(blob.encode("utf-8")).hexdigest()[:12]
fp = messages_fingerprint(messages)
logger.info("llm.call turns=%d fp=%s", len(messages), fp)
response = client.chat.completions.create(model=MODEL, messages=messages)
Ahora la regla es trivial de verificar: el hash solo debería cambiar cuando se agrega un turno nuevo. Si el fingerprint cambia entre dos llamadas pero no se agregó ningún turno de usuario o de asistente, alguna capa reescribió el historial. sort_keys=True hace que la serialización sea independiente del orden, así que el orden de las claves nunca dispara una falsa alarma — un hash distinto significa que el contenido o la forma del arreglo realmente cambió.
Leer la señal
| Lo que ves | Lo que significa |
|---|---|
El hash cambia, turns subió en 1 | Normal — se agregó un turno nuevo. |
El hash cambia, turns sin cambios | Una capa editó un turno existente en su lugar. |
El hash cambia, turns bajó | Algo descartó o truncó el historial. |
| El hash del mensaje de sistema difiere entre llamadas | Se rompió el prompt caching — cada llamada es un cache miss. |
| Mismo fingerprint, respuesta incorrecta | Ahora puedes confiar en el arreglo — investiga el modelo o los parámetros. |
Esa última fila es la verdadera ganancia: el fingerprint te deja descartar la plomería. Una vez que el hash es estable y correcto, te ganaste el derecho de culpar al modelo.
Trucos avanzados
- Haz un hash del system prompt por separado. Registra un segundo fingerprint solo para
messages[0] (o el campo system). Un prefijo de sistema idéntico byte a byte es la clave del prompt caching; si ese hash se mueve — un timestamp interpolado, un request ID, un nombre de usuario — estás pagando el precio de input completo en cada llamada y probablemente no lo sabes.
- Haz diff, no solo detectes. Cuando dos llamadas adyacentes tienen el mismo conteo de
turnos pero hashes distintos, registra un diff compacto del arreglo (o los hashes por mensaje) para ver cuál turno fue mutado, no solo que algo lo fue.
- Verifica en las pruebas. Convierte la invariante en un test: corre tu wrapper, captura
el arreglo en el límite, y verifica que el fingerprint solo avance cuando agregas. Esto atrapa una regresión que corrompe el contexto en CI en lugar de en producción.
- Registra en el límite, no arriba. Pon la llamada del fingerprint lo más cerca posible
de la llamada de red — idealmente en el wrapper del cliente. Cualquier cosa registrada antes de un middleware no puede ver lo que ese middleware hizo.
Recursos
- Using the Messages API — la API es stateless; tú eres dueño del historial
- OpenAI Chat Completions reference — el arreglo
messagesy los roles - Python
hashlib— SHA-256 para un fingerprint estable - Python
json.dumps—sort_keyspara serialización independiente del orden - Reel: Log a Hash of the Messages Array Before Every Call (Yeda AI Tips #154)
Yeda AI Tips — un tip de IA al día te libera del trabajo tedioso.