Fuentes alucinadas: cuando los agentes inventan fuentes

Las fuentes alucinadas aparecen cuando un agente cita enlaces, documentos o datos que no existen. Por qué pasa y cómo detectarlo.
En esta página
  1. El problema
  2. Por qué pasa
  3. Fallos más frecuentes
  4. Citas de URL no verificadas (Unfetched URL citations)
  5. Snippet en lugar de evidencia (Search-as-evidence)
  6. Deriva de citas entre pasos (Citation drift)
  7. Pseudocitas sin cobertura de claims (Claim-source mismatch)
  8. Cómo detectar estos problemas
  9. Cómo distinguir fuentes alucinadas de una respuesta solo inexacta
  10. Cómo frenar estos fallos
  11. Dónde se implementa en la arquitectura
  12. Autoevaluación
  13. FAQ
  14. Páginas relacionadas

El problema

La solicitud parece estándar: preparar un resumen corto de cambios en policy y añadir fuentes.

En trazas se ve otra cosa: en un run el agente devolvió 7 citas, pero la verificación mostró que 3 fuentes nunca se fetchearon y 2 llevan a 404. Para el usuario, la respuesta suena segura, pero no es reproducible.

El sistema no se cae.

Simplemente devuelve citas plausibles sin evidencia real.

Analogía: imagina un auditor que en su informe pone referencias a "carpetas en el archivo", pero nadie ha visto esas carpetas. El documento parece profesional hasta que alguien verifica las fuentes. En sistemas de agentes, las fuentes alucinadas funcionan igual.

Por qué pasa

Las fuentes alucinadas normalmente no aparecen por un solo error de modelo, sino por falta de control estricto de citas en runtime.

LLM tiene un sesgo fuerte hacia respuestas "completas", por eso sin verificación estricta el modelo tiende más a inventar una cita que a devolver una respuesta sin fuente.

En producción, normalmente pasa así:

  1. el agente genera citas como parte de una respuesta "completa";
  2. los snippets de búsqueda se toman como evidence aunque la página nunca se abrió;
  3. source_id no está ligado a snapshots de evidence;
  4. sin verificación de citas, runtime deja pasar fuentes unfetched o inválidas;
  5. si fail-closed no está configurado, las fuentes inventadas llegan al usuario.

En traza se ve como crecimiento de citations_count mientras cae citation_validity_rate.

El problema no es una sola URL mala.

Runtime no bloquea citas no verificadas antes de la salida final.

Fallos más frecuentes

En producción aparecen sobre todo cuatro patrones repetidos de fuentes alucinadas.

Citas de URL no verificadas (Unfetched URL citations)

El agente cita una URL que nunca pasó por http.get o kb.read en ese run.

Causa típica: las citas no están restringidas a source_id del evidence store.

Snippet en lugar de evidencia (Search-as-evidence)

La respuesta incluye "fuentes" de resultados de búsqueda, pero el agente no tiene confirmación del contenido real de la página.

Causa típica: search results mezclados con la capa de evidence.

Deriva de citas entre pasos (Citation drift)

En un paso temprano la fuente era válida, pero tras retry o truncation la respuesta final apunta a otro documento.

Causa típica: no existe un enlace estable claim -> source_id -> snapshot hash.

Pseudocitas sin cobertura de claims (Claim-source mismatch)

La respuesta tiene bloque de citas, pero los claims clave no tienen fuente correspondiente.

Causa típica: la validación revisa solo "hay links", no cobertura de claims.

Cómo detectar estos problemas

Las fuentes alucinadas se detectan bien por la combinación de métricas de cita y retrieval.

MétricaSeñal de fuentes alucinadasQué hacer
citation_validity_ratebaja la proporción de citas validadasintroducir verificación fail-closed por source_id
unfetched_source_ratemuchas URL unfetched en respuestasprohibir URL-citations sin evidence snapshot
source_404_rateparte de las fuentes no abreverificar estado y URL canónica durante fetch
claim_without_citation_rateclaims sin vínculo a fuenteañadir claim-level coverage check
citation_stop_reason_ratecitations:invalid frecuente en runtimerevisar calidad de retrieval y policy de tools

Cómo distinguir fuentes alucinadas de una respuesta solo inexacta

No toda inexactitud de texto implica fuentes inventadas. La pregunta clave: si la fuente se puede reproducir técnicamente para cada claim crítico.

Normal si:

  • cada cita apunta a source_id que existe en evidence store;
  • hay metadatos de snapshot (URL, timestamp, hash);
  • la verificación de claims muestra cobertura de las conclusiones clave.

Peligroso si:

  • la respuesta contiene URL que no estuvieron en la fase de fetch;
  • las citas existen "de forma" pero no cubren claims principales;
  • las respuestas no son reproducibles al nivel run (run_id -> source_id -> snapshot).

Cómo frenar estos fallos

En la práctica, se ve así:

  1. todas las fuentes pasan por evidence store (snapshot + hash + timestamp);
  2. el modelo devuelve citas solo como source_id, no URLs arbitrarias;
  3. citation verifier comprueba que todos los source_id existen, fueron fetched y están permitidos por policy;
  4. si la verificación falla, runtime devuelve stop reason y safe fallback.

Guard mínimo para validar citas:

PYTHON
from dataclasses import dataclass
import hashlib
import time


@dataclass(frozen=True)
class EvidenceMeta:
    source_id: str
    url: str
    fetched_at: float
    text_sha256: str


class EvidenceStore:
    def __init__(self):
        self.items: dict[str, EvidenceMeta] = {}

    def add_snapshot(self, source_id: str, url: str, text: str) -> None:
        self.items[source_id] = EvidenceMeta(
            source_id=source_id,
            url=url,
            fetched_at=time.time(),
            text_sha256=hashlib.sha256(text.encode("utf-8")).hexdigest(),
        )

    def has(self, source_id: str) -> bool:
        return source_id in self.items


def verify_citations(cited_source_ids: list[str], store: EvidenceStore) -> str | None:
    # cited_source_ids are expected to come from structured output
    if not cited_source_ids:
        return "citations:missing"

    unknown = [sid for sid in cited_source_ids if not store.has(sid)]
    if unknown:
        return "citations:unknown_source_id"

    return None

Este es un guard básico. En producción suele ampliarse con claim-level coverage check, allowlist para citation tools y stop reason separado para URL unfetched. verify_citations(...) se llama antes del render final, para que el usuario no vea fuentes inválidas.

Dónde se implementa en la arquitectura

En producción, el control de fuentes alucinadas casi siempre se reparte entre tres capas del sistema.

Tool Execution Layer se ocupa del fetch de evidence: estado de respuesta, normalización de URL, snapshots y hash. Si esta capa no guarda pruebas, las citas no pueden verificarse de forma fiable.

Agent Runtime controla structured output, citation verification, stop reasons y fallback fail-closed. Aquí se decide si la respuesta llega al usuario.

Memory Layer mantiene el vínculo run-evidence: run_id, source_id, retention y reproducibilidad. Sin esta capa, el equipo no puede hacer una auditoría sólida del incidente.

Autoevaluación

Verificación rápida antes del release. Marca los puntos y mira el estado abajo.
Este es un sanity-check corto, no una auditoría formal.

Progreso: 0/8

⚠ Hay señales de riesgo

Faltan controles básicos. Cierra los puntos clave del checklist antes del release.

FAQ

Q: ¿No basta con pedirle al modelo que "siempre añada fuentes"?
A: Puedes pedirlo, pero no es suficiente. Sin verificación runtime de citas, es formato, no evidencia.

Q: ¿Los search results pueden usarse como evidencia?
A: Normalmente no. Search solo da candidatos. La evidencia es solo lo que se fetch y se guarda como snapshot.

Q: ¿Es obligatorio guardar el texto completo de la fuente?
A: No siempre. Mínimo para auditoría: URL, timestamp, hash y source_id estable. El texto completo se añade cuando hace falta replay o citas exactas.

Q: ¿Qué mostrar al usuario cuando las citas son inválidas?
A: Stop reason explícita, qué ya se verificó, y siguiente paso seguro: respuesta partial sin fuentes no verificadas o rerun con verificación.


Un incidente de fuentes alucinadas casi nunca parece un fallo ruidoso. Es una pérdida de confianza silenciosa que normalmente se descubre solo al revisar fuentes. Por eso los agentes de producción necesitan no solo buenas respuestas, sino disciplina estricta de citas.

Páginas relacionadas

Si este problema aparece en producción, también conviene revisar:

⏱️ 7 min de lecturaActualizado 12 de marzo de 2026Dificultad: ★★☆
Implementar en OnceOnly
Guardrails for loops, retries, and spend escalation.
Usar en OnceOnly
# onceonly guardrails (concept)
version: 1
budgets:
  max_steps: 25
  max_tool_calls: 12
  max_seconds: 60
  max_usd: 1.00
policy:
  tool_allowlist:
    - search.read
    - http.get
controls:
  loop_detection:
    enabled: true
    dedupe_by: [tool, args_hash]
  retries:
    max: 2
    backoff_ms: [200, 800]
stop_reasons:
  enabled: true
logging:
  tool_calls: { enabled: true, store_args: false, store_args_hash: true }
Integrado: control en producciónOnceOnly
Guardrails para agentes con tool-calling
Lleva este patrón a producción con gobernanza:
  • Presupuestos (pasos / topes de gasto)
  • Kill switch y parada por incidente
  • Audit logs y trazabilidad
  • Idempotencia y dedupe
  • Permisos de herramientas (allowlist / blocklist)
Mención integrada: OnceOnly es una capa de control para sistemas de agentes en producción.
Ejemplo de policy (concepto)
# Example (Python — conceptual)
policy = {
  "budgets": {"steps": 20, "seconds": 60, "usd": 1.0},
  "controls": {"kill_switch": True, "audit": True},
}

Autor

Nick — ingeniero que construye infraestructura para agentes de IA en producción.

Enfoque: patrones de agentes, modos de fallo, control del runtime y fiabilidad del sistema.

🔗 GitHub: https://github.com/mykolademyanov


Nota editorial

Esta documentación está asistida por IA, con responsabilidad editorial humana sobre la exactitud, la claridad y la relevancia en producción.

El contenido se basa en fallos reales, post-mortems e incidentes operativos en sistemas de agentes de IA desplegados.