Cómo depurar un agente de IA que "alucina" en producción

By Carlos Montiel | Especialista en IA Empresarial
Publicado: 2026-07-28 | Por: Carlos Montiel | Lectura: ~5 minutos

"El modelo alucinó" no es un diagnóstico, es una queja. El trabajo real empieza cuando conviertes ese reporte vago en una causa raíz reproducible — y la mayoría de las veces la causa no está en el modelo, está en tu pipeline.

Antes de depurar, define qué tipo de alucinación es

No todas las alucinaciones tienen la misma causa raíz. Clasifica el incidente antes de tocar código:

- **Invención factual pura** — el modelo afirma algo falso sin que haya contexto relacionado en el prompt. Suele ser un problema de conocimiento paramétrico mal aplicado. - **Contradicción del contexto provisto** — el modelo tenía la información correcta en el prompt (documento recuperado, tool result) y aun así respondió algo distinto. Este es el más grave, porque indica que el modelo está ignorando el grounding que le diste. - **Sobregeneralización de un patrón** — responde con seguridad algo que "suena" correcto para ese tipo de pregunta pero no aplica al caso específico.

El segundo tipo casi siempre apunta a un problema de tu pipeline (context engineering, no el modelo). El primero y el tercero suelen necesitar ajustes de prompt o modelo.

Paso uno: reproduce con el `request_id` exacto

Todo lo que hagas depende de poder reproducir el fallo. Loguea el `request_id` de cada llamada desde el día uno — es gratis y resuelve el 80% de la fricción de debugging después.

response = client.messages.create( model="claude-opus-4-8", max_tokens=1024, messages=messages, ) logger.info("llm_call", extra={ "request_id": response._request_id, "model": response.model, "stop_reason": response.stop_reason, "input_tokens": response.usage.input_tokens, "cache_read_tokens": response.usage.cache_read_input_tokens, })

Sin el prompt exacto y el `request_id` guardados, "reproducir" el bug significa adivinar qué se le mandó al modelo hace tres días. Guarda el payload completo (system, messages, tools) asociado a cada respuesta que llega a producción — no solo el output.

Paso dos: audita el contexto que realmente recibió el modelo

El error más común: asumes que el modelo tenía cierta información porque "está en la base de datos", pero nunca verificas que efectivamente llegó al prompt. Antes de culpar al modelo, imprime el prompt exacto que se envió y verifica:

- ¿El documento relevante fue recuperado por tu paso de RAG, o el retrieval falló silenciosamente? - ¿El contexto llegó completo o fue truncado por un límite de tokens? - ¿El tool result que el modelo necesitaba llegó con `is_error: true` y el modelo improvisó una respuesta en vez de reportar el error?

# Auditoría mínima: reconstruye exactamente lo que vio el modelo def audit_context(messages): for m in messages: if isinstance(m["content"], list): for block in m["content"]: if block.get("type") == "tool_result" and block.get("is_error"): print(f"ADVERTENCIA: tool_result con error no manejado: {block}")

Si el modelo respondió con seguridad sobre algo que no estaba en su contexto, no alucinó por capricho — probablemente rellenó un hueco que tu pipeline le dejó.

Paso tres: verifica si el problema es de temperatura/effort, no de conocimiento

En modelos que soportan `effort`, un nivel bajo puede hacer que el modelo responda rápido sin verificar internamente su propia respuesta contra el contexto provisto. Si el caso de uso es sensible a precisión (extracción legal, datos financieros, respuestas médicas), sube el nivel de esfuerzo antes de rediseñar todo el prompt.

# Si ves alucinaciones en tareas donde precisión > velocidad response = client.messages.create( model="claude-opus-4-8", max_tokens=2048, thinking={"type": "adaptive"}, output_config={"effort": "high"}, # sube desde "low"/"medium" messages=messages, )

Paso cuatro: fuerza al modelo a admitir cuando no sabe

Un patrón que reduce alucinaciones de forma medible: instruir explícitamente que decir "no tengo esa información" es una respuesta válida y preferida sobre inventar algo plausible.

system_prompt = """ Responde únicamente con información presente en el contexto provisto. Si la respuesta no está en el contexto, di exactamente: "No tengo esa información en el contexto disponible" — no completes con conocimiento general ni supongas. Si tienes que citar un dato, cita el fragmento exacto del contexto que lo respalda. """

Este ajuste por sí solo suele reducir alucinaciones de contradicción de contexto de forma significativa — pero requiere que tu contexto realmente tenga la información cuando la necesitas, o el modelo va a decir "no sé" con demasiada frecuencia (un problema distinto pero más manejable).

Paso cinco: construye un set de regresión, no un fix puntual

Cuando encuentres un caso de alucinación reproducible, no lo arregles ad hoc y sigas adelante — conviértelo en un caso de test permanente. Un set de 30-50 casos reales (no sintéticos) que corres cada vez que cambias el prompt o el modelo es la única defensa real contra regresiones silenciosas.

casos_de_regresion = [ { "input": "...", "contexto": "...", "debe_contener": ["dato_correcto_esperado"], "no_debe_contener": ["dato_que_alucinaba_antes"], }, # ... 30-50 casos reales capturados de producción ] def correr_regresion(casos, prompt_version): fallos = [] for caso in casos: respuesta = ejecutar(caso, prompt_version) if any(malo in respuesta for malo in caso["no_debe_contener"]): fallos.append(caso) return fallos

Cuando el modelo mismo puede ayudarte a diagnosticar

Una técnica subutilizada: pídele al modelo que audite su propia respuesta contra el contexto, en una segunda llamada separada.

prompt_auditoria = f""" Aquí está el contexto que se le dio a un modelo y la respuesta que generó. Verifica, oración por oración, si cada afirmación está respaldada por el contexto o no. Contexto: {contexto} Respuesta a auditar: {respuesta_original} Para cada oración de la respuesta, marca: RESPALDADA | NO RESPALDADA | PARCIALMENTE RESPALDADA, con la cita exacta si aplica. """

Esta segunda llamada es barata (puedes usar un modelo más chico) y detecta contradicciones de contexto de forma mucho más confiable que revisar el output a ojo. Es, en esencia, el mismo principio que el patrón de reflexión que cubro más adelante — solo que aplicado como herramienta de debugging en vez de como parte del flujo de producción.

La disciplina real aquí no es una técnica única, es el orden: reproducir, auditar contexto, ajustar effort, forzar admisión de incertidumbre, y solo al final tocar el prompt de fondo — con un set de regresión que evite que el próximo despliegue rompa lo que acabas de arreglar.

Carlos Montiel
Arquitecto de Soluciones IA Empresarial
Especialista en LLMs, Agentes y Orquestación
guatemalia.com/#contacto · info@guatemalia.com

¿Necesitas implementar IA en tu empresa?

Carlos Montiel es arquitecto de soluciones IA empresarial. Implementa LLMs, Agentes, RAG y orquestadores en empresas de Guatemala y Latinoamérica. Contáctalo para una consultoría.

Contactar a Carlos Montiel

info@guatemalia.com